Session 4 - JSF Validator & Converter
Pemrograman Web Lanjut
© 2016 Niko Ibrahim, MIT Fakultas Teknologi Informasi Universitas Kristen Maranatha
Tujuan Mahasiswa memahami bagaimana data yang dikirimkan melalui form dapat dikonversi ke dalam objek Java Mahasiswa memahami bagaimana proses konversi data terjadi Mahasiswa memahami bagaimana proses validasi data terjadi Mahasiswa memahami cara menampilkan pesan eror untuk konversi dan validasi data
Lecture’s Outline Proses Konversi dan Validasi Penggunaan Standard Converters Penggunaan Standard Validators Custom Converters and Validators Latihan dan Tutorial
Proses Validasi dan Konversi Data
Aplikasi web dapat menyimpan berbagai jenis tipe data. Namun, komponen input pada form hanya bisa menerima data dengan tipe String. Berikut penjelasan proses di atas: ◦ User meng-input data pada form sebagai sebuah “STRING” ◦ Pada saat browser mengirimkan inputan tsb ke server, nilai yang disubmit akan dikonversi ke dalam “local value” (berupa tanggal, int, float, dll), dan kemudian divalidasi berdasarkan kondisi tertentu. ◦ Jika proses konversi/validasi berjalan lancar, maka “local value” tsb akan disimpan di dalam property managed bean.
ID dari JSF Standard Converters Berikut ini adalah Standard Conveters yang ada di JSF:
BigDecimalConverter konversi String ke java.math.BigDecimal BigIntegerConverter konversi String ke java.math.BigInteger BooleanConverter konversi String ke java.lang.Boolean ByteConverter konversi String ke type java.lang.Byte CharacterConverter konversi String ke java.lang.Character DateTimeConverter konversi String ke java.util.Date dengan format default DoubleConverter konversi String ke java.lang.Double EnumConverter konversi String ke type java.lang.Enum FloatConverter konversi String ke java.lang.Float IntegerConverter konversi String ke java.lang.Integer LongConverter konversi String ke java.lang.Long NumberConverter konversi String ke java.lang.Number ShortConverter konversi String ke java.lang.Short
Penggunaan Atribut Converter Ada 3 cara untuk meng-attach converter pada suatu komponen; a) Menambahkan atribut “converter” pada tag komponen dan menyebutkan ID converter yang diinginkan
b)
Tanpa menggunakan attributes:
c)
Atau menggunakan cara berikut:
Atribut Number Converters Atribut
Keterangan
currencyCode
The ISO 4217 currency code, applied only when formatting currencies. A three-letter codes such as “USD” for the United States Dollar, “GBP” for the United Kingdom Pound, and “EUR” for the Euro. I found that not all codes listed in ISO 4217 were implemented.
currencySymbol
Currency symbol, is applied only when formatting currencies. If the currency code is set then currencySymbol will be ignored. This is the literal currency symbol, such as “$”.
groupingUsed
Flag specifying whether formatted output will contain grouping separators. Default value is true.
integerOnly
Flag specifying whether only the integer part of the value will be formatted and parsed. Default value is false.
maxFractionDigits
Maximum number of digits that will be formatted in the fractional portion of the output.
maxIntegerDigits
Maximum number of digits that will be formatted in the integer portion of the output.
minFractionDigits
Minimum number of digits that will be formatted in the fractional portion of the output.
Atribut Number Converters (cont.) Atribut
Keterangan
minIntegerDigits
Minimum number of digits that will be formatted in the integer portion of the output.
locale
A java.util.Locale used to define a language and country. If not specified, the Locale returned by FacesContext.getViewRoot().getLocale() will be used.
pattern
Custom formatting pattern which determines how the number string should be formatted and parsed. Examples: ###,### 123,456 $###,###.## $123,456.99 #.### 1.789
type
Specifies the number type.Valid values are “number”, “currency”, and “percent”. Default value is “number”.
Contoh Number Converter untuk OutputText
Pada contoh ini, kita gunakan atribut “locale” untuk memformat nilai mata uang:
Contoh Number Converter untuk InputText
Managed Bean: private int salary, discount; private double population; //constructor + getter + setter methods
Atribut DateTime Converters Atribut
Keterangan & Contoh
dateStyle
default Jan 1, 2006 1:20:45 PM short 1/1/06 1:20:45 PM medium Jan 1, 2006 1:20:45 PM long January 1, 2006 1:20:45 PM full Sunday, January 1, 2006 1:20:45 PM
locale
java.util.Locale(String language, String country) Locale.SPAIN, Locale.CANADA, etc.
pattern
Java.text.SimpleDateFormat yyyy.MM.dd ‘at’ HH:mm:ss z 2007.01.01 at 12:05:30 PDT EEE, MMM d ‘yy Mon, Jan 1, ‘07 h:mm a 10:05 AM hh ‘o’ ‘clock’ a, zzzz 12 o’ clock PM, Pacific Daylight Time
timeStyle
default Jan 1, 2007 10:05:30 AM short 1/1/07 10:05:30 AM medium Jan 1, 2006 10:05:30 AM long January 1, 2007 10:05:30 AM full Monday, January 1, 2006 10:05:30 AM
timeZone
java.util.TimeZone
type
Both Date and time. date Date only. time Time only.
Contoh convertDateTime untuk OutputText
Contoh convertDateTime untuk InputText
User harus meng-input dalam format “MM/dd/yyyy”, kalau tidak maka akan muncul pesan eror. JSF akan secara otomatis melakukan konversi input tersebut dari String menjadi java.util.Date
Pesan Error Pada Converter Pada saat terjadi eror pada conversi, maka akan terjadi dua hal berikut: 1. Komponen yang mengalami conversion error akan mengirimkan pesan dan mendeklarasikan dirinya sebagai invalid. 2. JSF akan menampilkan ulang halaman tersebut setelah proses validasi selesai. Halaman ini akan menampilkan semua nilai yang diinput oleh user (tidak ada inputan yang hilang)
Cara Menampilkan Pesan Error
Pesan eror sangat berguna agar user dapat melihat penyebab eror pada proses konversi dan validasi. Kita dapat menggunakan tag h:message Contoh:
Menampilkan SEMUA pesan Error
Tag h:message hanya menghasilkan satu pesan. Kita dapat menampilkan semua pesan (summary) yang dihasilkan oleh semua komponen dengan menggunakan tag h:messages. Tips: Untuk h:messages, biasanya kita gunakan atribut “table” agar pesan berbaris secara vertikal. Contoh:
Menggunakan Custom Error Message
Tag: converterMessage Contoh:
DO IT YOURSELF PROJECT Latihan Menggunakan Standard Converters
Untuk mengetahui lebih dalam mengenai penggunaan standart/build-in converter, buatlah sebuah aplikasi Web yang berfungsi untuk memproses pembayaran ecommerce. Data pembayaran memiliki:
◦ Jumlah yang harus dibayar (tipe double) ◦ Nomor kartu kredit (tipe String) ◦ Tanggal kadaluarsa kartu kredit (tipe Date)
Latihan 01: Converter Create, deploy, and run “Converter” project
Note: berikan pula “custom error message”
2. Using Standard Validators
Fungsi utama dari Validator adalah untuk melindungi data model dari ketidakkonsistenan yang dapat disebabkan apabila inputan tidak dapat divalidasi. JavaServer Faces memiliki mekanisme built-in untuk melakukan validasi seperti: ◦ Memeriksa panjang sebuah string ◦ Memeriksa batasan dari suatu angka (misal > 0 atau > 100) ◦ Memeriksa apakah suatu nilai diisi atau tidak
Standard Validator Atribut
Keterangan & Contoh
LengthValidator
Checks whether the length of a component’s value is within a certain range. This validator counts the number of characters. Minimum – The minimum acceptable number of characters. Maximum – The maximum acceptable number of characters.
LongRangeValidator
Checks whether the value of a component is within a certain range. The validator will attempt to convert the number to a Java long primitive. If minimum and maximum attributes are used the validator will ensure that the value entered is within the minimum and maximum range. If the minimum and maximum attribute are omitted then the validator ensures that the value is numeric. Minimum – The minimum acceptable numeric value. Maximum – The maximum acceptable numeric value.
DoubleRangeValidator
Checks whether the value of a component is within a certain range. The value must be numeric or convertible to a numeric value. The validator will attempt to convert the number into a Java double primitive. If minimum and maximum attributes are used the validator will ensure that the value entered is within the minimum and maximum range. If the minimum and maximum attribute are omitted then the validator only ensures that the value is numeric. Minimum – The minimum acceptable numeric value. Maximum – The maximum acceptable numeric value.
required
If a UIInput component does not have the required attribute set to “true” and the user does not enter a value, then the validator will not be called. Remember to set required=”true”, if you want to force validation.
Length Validator
Contoh validasi panjang inputan:
Range validator
Digunakan untuk mem-validasi inputan berupa angka Contoh validator berikut memeriksa apakah suatu angka inputan antara 10 dan 1000:
Untuk validasi nilai desimal, gunakan:
Checking for Required Values Untuk memeriksa apakah suatu nilai diisi atau tidak, kita gunakan atribut required="true": Contoh:
Semua tag input JSF dapat memiliki atribut required. Kita juga bisa menggabungkan penggunaan atribut required dengan validator lain: Contoh:
An alternate syntax Kita dapat menggunakan sintaks alternatif dalam menggunakan validator, yaitu menggunakan tag . Kita sebutkan saja ID dari validator beserta parameternya. Contoh:
Displaying Validation Errors Pesan error pada proses validasi sama seperti pada proses konversi. Tag:
◦ h:message atau ◦ h:messages
A Custom Message Sama seperti pada proses konversi, kita juga dapat memberikan “custom message” pada validasi. Contoh:
requiredMessage="#{msgs.cardRequired}" validatorMessage="#{msgs.cardInvalid}">
Bypassing Validation Kita dapat mengabaikan proses validasi. Misalnya, apabila kita ingin meletakkan tombol “Cancel” atau “Reset” pada sebuah form, maka kita harus melakukan pengabaian pada proses validasi dengan menggunakan atribut “immediate” Contoh:
Latihan 02:Validator
Modifikasi project sebelumnya dan berikan validator required pada semua inputan, amount > 1000, dan panjang kartu kredit > 13 dan < 16.
3. Programming with Custom Converters Pada aplikasi yang kompleks, seperti aplikasi e-commerce, kita seringkali membutuhkan converter dan validator di luar standar yang disediakan oleh JSF. Misalnya, kita perlu melakukan konversi tipe data selain “number” dan “date”, juga perlu melakukan validasi yang spesifik misalnya memeriksa suatu inputan kartu kredit. Pada dasarnya, sebuah converter merupakan suatu class yang mengkonversi strings dan objects. Sebuah converter harus selalu meng-implement interface Converter, yang memiliki dua buah method berikut:
◦ Object getAsObject(FacesContext context, UIComponent component, String newValue) berfungsi mengubah String menjadi object, method ini dipanggil ketika user memasukkan sebuah String, misalnya di dalam input textfield. (PROSES KONVERSI) ◦ String getAsString(FacesContext context, UIComponent component, Object value) berfungsi mengubah object menjadi String untuk ditampilkan di user interface. (PROSES FORMATTING)
Contoh Custom Converter: CreditCardConverter.java
Untuk mengilustrasikan custom converter, kita akan membuat sebuah class bernama “CreditCardConverter”, yang memungkinkan kita untuk menginput nomor kartu kredit dengan atau tanpa spasi. Contoh input kartu kredit yang diperbolehkan: ◦ 1234567890123456 (tanpa spasi)
◦ 1234 5678 9012 3456 (dengan spasi)
Pada class ini, perhatikan 2 method berikut: ◦ getAsObject: menghapus semua karakter spasi, memeriksa apakah ada karakter yang bukan digit, dan membuat object CreditCard ◦ getAsString: melakukan formatting nomor kartu kredit sesuai yang diinginkan user, digit-digit kartu kredit dipolakan sesuai dengan tipe-nya, sbb: Tipe kartu
Digit
Format
MasterCard
16
5xxx xxxx xxxx xxxx
Visa
16
4xxx xxxx xxxx xxxx
Visa
13
4xxx xxx xxx xxx
Discover
16
6xxx xxxx xxxx xxxx
American Express
15
37xx xxxxxx xxxxx
American Express
22
3xxxxx xxxxxxxx xxxxxxxx
Diners Club, Carte Blanche
14
3xxxx xxxx xxxxx
CreditCardConverter.java package mypkg; import import import import import
javax.faces.application.FacesMessage; javax.faces.component.UIComponent; javax.faces.context.FacesContext; javax.faces.convert.Converter; javax.faces.convert.ConverterException;
public class CreditCardConverter implements Converter { public Object getAsObject(FacesContext context, UIComponent component, String newValue) throws ConverterException { StringBuilder builder = new StringBuilder(newValue); boolean foundInvalidCharacter = false; char invalidCharacter = '\0'; int i = 0; while (i < builder.length() && !foundInvalidCharacter) { char ch = builder.charAt(i); if (Character.isDigit(ch)) i++; else if (Character.isWhitespace(ch)) builder.deleteCharAt(i); else { foundInvalidCharacter = true; invalidCharacter = ch; } } if (foundInvalidCharacter) { FacesMessage message = mypkg.util.Messages.getMessage( "mypkg.messages", "badCreditCardCharacter", new Object[]{ new Character(invalidCharacter) }); message.setSeverity(FacesMessage.SEVERITY_ERROR); throw new ConverterException(message); } return new CreditCard(builder.toString()); } // end of getAsObject
CreditCardConverter.java (cont.) public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException { // length 13: xxxx xxx xxx xxx // length 14: xxxxx xxxx xxxxx // length 15: xxxx xxxxxx xxxxx // length 16: xxxx xxxx xxxx xxxx // length 22: xxxxxx xxxxxxxx xxxxxxxx String v = value.toString(); int[] boundaries = null; int length = v.length(); if (length == 13) boundaries = new int[]{ 4, 7, 10 }; else if (length == 14) boundaries = new int[]{ 5, 9 }; else if (length == 15) boundaries = new int[]{ 4, 10 }; else if (length == 16) boundaries = new int[]{ 4, 8, 12 }; else if (length == 22) boundaries = new int[]{ 6, 14 }; else return v; StringBuilder result = new StringBuilder(); int start = 0; for (int i = 0; i < boundaries.length; i++) { int end = boundaries[i]; result.append(v.substring(start, end)); result.append(" "); start = end; } result.append(v.substring(start)); return result.toString(); } // end of getAsString } // end of class
CreditCard.java package mypkg; public class CreditCard { private String number; public CreditCard(String number) { this.number = number; } public String toString() { return number; } }
Using & Configuring Custom Validator (Menggunakan XML)
Agar custom converter bisa digunakan, maka kita harus mendefinisikannya di dalam faces-config.xml sbb: mypkg.CreditCard mypkg.CreditCardConverter
Sekarang kita bisa menggunakan tag f:converter dan menentukan id dari custom converter yang sudah kita buat:
Atau menggunakan converter attribute:
Using & Configuring Custom Validator (Menggunakan Annotation)
Kita dapat menggunakan annotation @FacesConverter pada class Custom Converter yg sudah kita buat sbb: @FacesConverter(“mypkg.CreditCard") public class CreditCardConverter implements Converter
Latihan 03: Converter02
Bukalah project Custom-Converter-dan-Validator-Original Perhatikan class custom converter yang telah disediakan: “CreditCardConverter.java” dan juga converter bean “CreditCard.java” Perhatikan managed bean “PaymentBean.java” yang sudah mengandung property CreditCard Pelajari cara penggunaan messages di aplikasi ini Tugas Anda: 1. 2. 3.
Berikan atribut value (payment.card) dan tag pada inputText kartu kredit di index.xhtml Berikan tag pada outputText kartu kredit di result.xhtml Berikan annotation pada CreditCardConverter, atau bisa juga mendefinisikan di dalam faces-config.xml
Lakukan pengujian dengan beberapa kasus nomor kartu
Latihan 03: Converter2 (screenshots)
Create, deploy, and run “Converter2” project
Hasil
4. Programming with Custom Validators
Selain custom converter, aplikasi yang kompleks juga seringkali membutuhkan custom validator di luar standar yang disediakan oleh JSF. Untuk mengimplementasikan customer validator class, kita membutuhkan dua proses yang sama seperti di custom converter: 1. Buat sebuah validator class yang mengimplementasi Validator interface: javax.faces.validator.Validator interface 2. Definisikan validator class tersebut di dalam file configuration(facesconfig.xml)
Validator interface hanya memiliki sebuah method:
◦
void validate: memvalidasi komponen yang mengandung class calidator ini.
Contoh kasus custom validator Pada input kartu kredit, kita perlu melakukan validasi nomor yang diinputkan. Salah satu algoritma yang sering digunakan sebagai validasi kartu kredit adalah Luhn Check. Penjelasan lengkap mengenai Luhn Check: http://www.merriampark.com/anatomycc.htm Contoh kartu kredit yang benar berdasarkan Luhn Check: 4111 1111 1111 1111
Luhn Check Algorithm private static boolean luhnCheck(String cardNumber) { int sum = 0; for(int i = cardNumber.length() - 1; i >= 0; i -= 2) { sum += Integer.parseInt(cardNumber.substring(i, i + 1)); if(i > 0) { int d = 2 * Integer.parseInt(cardNumber.substring(i - 1, i)); if(d > 9) d -= 9; sum += d; } } return sum % 10 == 0; }
CreditCardValidator.java package mypkg; import import import import import
javax.faces.application.FacesMessage; javax.faces.component.UIComponent; javax.faces.context.FacesContext; javax.faces.validator.Validator; javax.faces.validator.ValidatorException;
public class CreditCardValidator implements Validator { public void validate(FacesContext context, UIComponent component, Object value) { if(value == null) return; String cardNumber; if (value instanceof CreditCard) cardNumber = value.toString(); else cardNumber = getDigitsOnly(value.toString()); if(!luhnCheck(cardNumber)) { FacesMessage message = mypkg.util.Messages.getMessage( "mypkg.messages", "badLuhnCheck", null); message.setSeverity(FacesMessage.SEVERITY_ERROR); throw new ValidatorException(message); } }
CreditCardValidator.java (cont.) private static boolean luhnCheck(String cardNumber) { int sum = 0; for(int i = cardNumber.length() - 1; i >= 0; i -= 2) { sum += Integer.parseInt(cardNumber.substring(i, i + 1)); if(i > 0) { int d = 2 * Integer.parseInt(cardNumber.substring(i - 1, i)); if(d > 9) d -= 9; sum += d; } } return sum % 10 == 0; } private static String getDigitsOnly(String s) { StringBuilder digitsOnly = new StringBuilder (); char c; for(int i = 0; i < s.length (); i++) { c = s.charAt (i); if (Character.isDigit(c)) { digitsOnly.append(c); } } return digitsOnly.toString (); }
Using and Configuring Custom Validator (using faces-config.xml)
Now that we have created a validator, we need to register it in a configuration file (such as faces-config.xml), like this: mypkg.CreditCard mypkg.CreditCardValidator
You can use custom validators with the f:validator tag—for example, the following code fragment uses the credit card validator discussed above:
The validatorId specified for f:validator must correspond to a validator ID specified in the configuration file. The f:validator tag uses the validator ID to look up the corresponding class, creates an instance of that class if necessary, and invokes its validate method.
Using and Configuring Custom Validator (using annotation)
Kita dapat menggunakan annotation @FacesValidator pada class Custom Validator yg sudah kita buat sbb:
@FacesValidator(“mypkg.CreditCard") public class CreditCardValidator implements Validator
Latihan 04: Modifikasi Converter02 Modifikasilah project di latihan sebelumnya agar dapat memiliki mekanisme validasi angka kartu kredit berdasarkan algoritma Luhn Check TODO:
1. Tambahkan annotation @FacesValidator pada Custom Validator 2. Berikan tag pada input text
Latihan 04: screenshots
This validator is using “Luhn” algorithm to check the credit card numbers. See the documentation provided about this for details.
Tips: try to input 4111 1111 1111 1111
Hasil
That’s all for today!
Congratulations! At the end of this lecture you’ve known how to create: ◦ ◦ ◦ ◦
Standard converters Standard validators Custom converters Custom validators