- İ: İstemci katmanı. Çoğu zaman bir web tarayıcısıdır.
- S: Sunum katmanı. Uygulamanın kullanıcıya dönük yüzünü oluşturmaktan sorumludur. Sunum mantığını içerir.
- İM: İş Mantığı katmanı. İşin asıl yapıldığı yerdir.
- T: Tümleştirme katmanı. Kurumsal uygulamalar geliştirilirken çoğu zaman kurum içindeki ya da dışındaki diğer yazılımlarla etkileşim kurması istenir. Tümleştirme katmanı bu iletişimin sorunsuz gerçekleşmesinden sorumludur.
- K: Kaynak katmanı. Verilerin kalıcı olarak saklandığı katmandır. Veritabanı (Oracle, MySQL, DB2 gibi), Dizin sunucusu (Active Directory, OpenLDAP), CRM (Oracle Siebel, Microsoft Dynamics), ERP uygulaması gibi çok farklı türde olabilir.
Şekil-1 Web uygulamalarında katmanlar |
İstemci ile sunucu arasındaki etkileşim istek-cevap örüntüsündedir. Uygulamanın arayüzünün değişmesi için mutlaka sunucuya bir isteğin gitmesi gerekir.
Klasik Web uygulamalarında, tüm sorumluluk sunucu taraftadır. Her türlü işlem sunucu tarafta gerçekleştirilir. İstemcinin (Web tarayıcısının) herhangi bir sorumluluğu bulunmaz. Bu nedenle Web tarayıcısına herhangi bir eklenti kurulmasına da gerek bulunmaz. Bu nedenle web tarayıcısı, süper ince istemci olarak isimlendirilir:Şekil-2 Klasik Web mimarisi |
Şekil-3 Ajax teknolojisinin kullanıldığı durum |
Java Server Faces bu MVC tabanlı çatılar arasında Java EE 5'den itibaren standart bir şartname olması özelliği ile öne çıkmaktadır. JSF, masaüstü uygulama geliştirirken edindiğimiz deneyimleri web uygulaması geliştirirken de kullanmamıza olanak sağlar. Böylelikle hızlı web uygulaması geliştirebiliriz. Ancak sadece JSF kullanarak uygulama geliştirmek mümkün değildir. JSF'deki görsel bileşenler hem sayıca hem de yetenekleri açısından kısıtlıdır. Mutlaka JSF bileşen çözümlerinden birini kullanmak gerekir. Bu noktada PrimeFaces, RichFaces, IceFaces bileşen kütüphaneleri öne çıkmaktadır. Bunlar arasında en yetenekli bileşenleri PrimeFaces sunmaktadır.
Sunucu Tarafta Doğrulama
Katmanlı mimaride doğrulamayı hangi katmanda yapmak gerekir? Sunum?, İş Mantığı?, Tümleştirme? Bunun cevabını Java EE 6 ile gelen Bean Validation (JSR-303) şartnamesi veriyor: Tüm katmanlarda geçerleme yapmak gerekir. Doğrulama aslında bir İlgi (=Aspect)'dir. Her katmanda aynı doğrulama kuralını tekrar tekrar tanımlamak yerine bir kez tanımlayıp, damgaları (=Annotation) kullanarak Alan/View Model/Entity sınıflarındaki özniteliklerle ilişkilendiriyoruz. Standard damgaların sayısı fazla değil: @Min, @Max, @DecimalMin, @DecimalMax, @Digits, @NotNull, @Null, @Past, @Pattern, @Size, @AssertTrue, @AssertFalse. Ancak yeni kısıtlar tanımlayarak genişletilebilinir. Yeni kısıtlar oluşturmanın iki yolu bulunuyor. Bunlardan ilkinde aslında yeni bir kısıt tanımlamış olmuyoruz. Sadece standart ile gelen kısıtları birlikte kullanıyoruz ve bu birlikteliğe bir isim veriyoruz. Şimdi bunu bir kaç örnekle inceleyelim:
package com.example.web.validation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; import javax.validation.constraints.Pattern;
/** * * @author Binnur Kurt (binnur.kurt@gmail.com) */@Target(value = ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Pattern(regexp="^\\+?[a-z0-9](([-+.]|[_]+)?[a-z0-9]+)*@([a-z0-9]+(\\.|\\-))+[a-z]{2,6}$", message="{validation.email}") @Constraint(validatedBy={}) public @interface Email { String message() default "{validation.email}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
@Email kısıtı aslında yeni bir kısıt değil. Sadece @Pattern kısıtının kullanımına bir kısa yol oluşturduk. Bu sayede e-posta geçerlilik sınaması için düzenli ifadeyi hatırlamamız ya da kopyala-yapıştır yapmamız gerekmeyecek. Kısıtı tekrar kullanılabilir hale getirdik. E-posta düzenli ifadesinin bakımını yapmak da kolay olacak.
- StrongPassword
package com.example.web.validation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size;/** * * @author Binnur Kurt (binnur.kurt@gmail.com) */@Size(min=6,message="{validation.strongPassword1}") @Pattern.List({ @Pattern(regexp="^.*\\d+.*$",message="{validation.strongPassword2}"), @Pattern(regexp="^.*[_-]+.*$",message="{validation.strongPassword3}") }) @Constraint(validatedBy = {}) @Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface StrongPassword { String message() default "{validation.strongPassword1}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
@StrongPassword kısıtı @Pattern ve @Size kısıtlarını birlikte kullanıyor. Güçlü parola için parolanın en az altı karakter olmasını ve bu karakterlerin en az bir rakam ve {_, -} kümesinden de bir karakter içermesini istiyoruz.
- Username
package com.example.web.validation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; import javax.validation.constraints.Pattern; /** * * @author Binnur Kurt (binnur.kurt@gmail.com) */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) @Pattern.List({ @Pattern(regexp = "^[a-zA-Z].*$", message = "{validation.username1}"), @Pattern(regexp = "^[a-zA-z0-9]{5,}$", message = "{validation.username2}") }) @Constraint(validatedBy = {}) public @interface Username { String message() default "{validation.username3}"; Class<? extends Payload>[] payload() default {}; Class<?>[] groups() default {}; }
Iban.java:
package com.example.web.validation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Target(value = ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = IbanValidator.class) public @interface Iban { String message() default "{validation.iban}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
package com.example.web.validation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Target(value={ElementType.FIELD,ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy=TCKimlikNoValidator.class) public @interface TcKimlikNo { String message() default "{validation.identityNo}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
IbanValidator.java:
package com.example.web.validation; import java.util.Collections; import java.util.Map; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class IbanValidator implements ConstraintValidator<Iban, String> { private static final long MAX = 999999999; private static final long MODULUS = 97; @Override public void initialize(Iban iban) { } @Override public boolean isValid(String value, ConstraintValidatorContext ctx) { if (value == null || value.length() < 5) { return false; } try { int modulusResult = calculateModulus(value); return (modulusResult == 1); } catch (Exception ex) { return false; } } private int calculateModulus(String code) throws Exception { String reformattedCode = code.substring(4) + code.substring(0, 4); long total = 0; for (int i = 0; i < reformattedCode.length(); i++) { int charValue = Character.getNumericValue(reformattedCode.charAt(i)); if (charValue < 0 || charValue > 35) { throw new Exception("Invalid Character[" + i + "] = '" + charValue + "'"); } total = (charValue > 9 ? total * 100 : total * 10) + charValue; if (total > MAX) { total = (total % MODULUS); } } return (int) (total % MODULUS); } }
package com.example.web.validation; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class TCKimlikNoValidator implements ConstraintValidator<TcKimlikNo, String> { @Override public void initialize(TcKimlikNo tcKimlikNo) { } @Override public boolean isValid(String value, ConstraintValidatorContext ctx) { if (!value.matches("^\\d{11}$")) { return false;
}
int[] digits = new int[11];
for (int i = 0; i < digits.length; ++i) {
digits[i] = value.charAt(i) - '0';
}
int x = digits[0];
int y = digits[1]; for (int i = 1; i < 5; i++) {
x += digits[2 * i];
} for (int i = 2; i <= 4; i++) { y += digits[2 * i - 1]; } int c1 = 7 * x - y; if (c1 % 10 != digits[9]) { return false; } int c2 = 0; for (int i = 0; i < 10; ++i) {
c2 += digits[i];
}
if (c2 % 10 != digits[10]) {
return false;
} return true; } }
package com.example.imdb.web.model; import java.io.Serializable; import javax.enterprise.context.SessionScoped; import javax.inject.Inject; import javax.inject.Named; import com.example.web.validation.Email; import com.example.web.validation.Iban; import com.example.web.validation.StrongPassword; import com.example.web.validation.Username; import com.example.web.validation.TcKimlikNo; @Named("UserVM") @SessionScoped public class UserViewModel implements Serializable{ @Email(message="You must enter a valid e-mail") private String email; @Iban(message="You must enter a valid iban!") private String iban; @TcKimlikNo(message="You must enter a valid identity no!") private String identityNo; @Username private String username; @StrongPassword private String password; . . . }
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Logon Page</title> </h:head> <h:body> <f:view> <h:form> <h:panelGrid columns="3"> <p:outputLabel for="email" value="E-mail:" /> <p:inputText id="email" required="true" requiredMessage="You must enter an e-mail!" value="#{UserVM.email}"> </p:inputText> <p:message id="emailError" for="email" /> <p:outputLabel for="iban" value="Iban:" /> <p:inputText id="iban" required="true" requiredMessage="You must enter an iban!" value="#{UserVM.iban}" /> <p:message id="ibanError" for="iban" /> <p:outputLabel for="identityNo" value="Identity no:" /> <p:inputText id="identityNo" required="true" requiredMessage="You must enter an identity No!" value="#{UserVM.identityNo}" /> <p:message id="identityNoError" for="identityNo" /> <p:outputLabel for="username" value="Username:" /> <p:inputText id="username" required="true" requiredMessage="You must enter a username!" value="#{UserVM.username}"> </p:inputText> <p:message id="usernameError" for="username" /> <p:outputLabel for="password" value="Password:" /> <h:panelGroup> <p:password id="password" required="true" requiredMessage="You must enter a valid year!" value="#{UserVM.password}"> </p:password> <p:message id="passwordError" for="password" /> </h:panelGroup> <p:commandButton action="#{UserVM.doLogon}" value="Logon" update="emailError usernameError passwordError ibanError identityNoError"/> </h:panelGrid> </h:form> </f:view> </h:body> </html>
Doğrulama yapılacak ekran görüntüsü |
Hatalı verilerle dolu ekran görüntüsü |
JSF Yaşam Döngüsü |
Render Response evresinde hata mesajları eklenen HTML cevabı oluşturulur ve cevap tarayıcıya gönderilir:
Bu çözümde doğrulama sunucu tarafta gerçekleşmektedir. Ancak özellikle iki nedenden dolayı istemci tarafta da doğrulama yapmak gerekir:
Burada istemci tarafta doğrulamayı açmak için primefaces.CLIENT_SIDE_VALIDATION parametresinin değerini true yapmamız gerekir. İstemci tarafta doğrulamayı Javascript (JS) kullanarak gerçekleştireceğiz. Ama öncelikle daha önce yukarıda Bean Validation için kısıt tasarlarken yaptığımıza benzer bir kodlama yapacağız. Iban ve TcKimlikNo damgalarında daha önce sunucu tarafta hangi sınıfın doğrulama yapacağını @Constraint(validatedBy = IbanValidator.class) ve @Constraint(validatedBy=TCKimlikNoValidator.class) damgaları ile tanımlamıştık. Şimdi ise aynı damgalarda istemci tarafta doğrulama ile tanımlama yapacağımız sınıfları tanıtacağız:
Iban.java:
TcKimlikNo.java:
@ClientConstraint(resolvedBy = IbanClientValidator.class) ve @ClientConstraint(resolvedBy = TcKimlikNoClientValidator.class) damgalarında adı geçen sınıflara bir bakalım:
IbanClientValidator.java:
TcKimlikNoClientValidator.java:
Gördüğünüz gibi sunucu taraftaki kodda doğrulama ile ilgili herhangi bir kod yok. Buradaki en önemli metod, istemci tarafta doğrulama yapacak JS kodu tanımlayan bir etiket döndüren getValidatorId(). İstemci tarafta bu etiketlere karşı düşen JS kodu yazıyoruz:
iban-validator.js:
tckimlik-validator.js:
PrimeFaces.validator['Iban'] ve PrimeFaces.validator['TcKimlikNo'] aracılığı ile IbanClientValidator ve TcKimlikClientNoValidator sınıfları arasında bağı kurmuş oluyoruz. Şimdi, istemci tarafta doğrulamayı açtığımız çözümün VDL'ine (logon-csv.xhtml) bir bakalım:
İstemci tarafta doğrulama özelliğini çalıştırmak için <p:commandButton> takısında validateClient özniteliğinin değerini true olarak veriyoruz. Giriş elemanında bir değer verip, elemanı terk ettiğimizde, o eleman için JS dosya içinde verdiğimiz doğrulama çalıştırılır: <p:clientValidator event="blur" />. Tarayıcıdaki doğrulama yapılmış ekran görüntüsüne bakalım:
Ağ kaydına baktığımızda, doğrulama için sunucuya gitmediğini, doğrulamanın istemci tarafta gerçekleştiğini görüyoruz. Son olarak @Username ve @StrongPassword Bean Validation damgaları için istemci tarafta doğrulama yapmak üzere tasarladığımız çözümlere bakalım:
EmailClientValidator.java:
StrongPasswordClientValidator.java:
UsernameClientValidator.java:
Hata iletilerinin gösterildiği ekran sunucu tarafta oluşturuldu |
Web tarayıcısında, Logon butonuna basıldığında sunucuya giden isteği ve cevap süresini gösteren geliştirici araçları ekranı |
- Uygulamanın başarımı artacaktır. Doğrulama istemci tarafta da gerçekleştirildiği için başarısız girişlerde istemci sunucu arasında zaman kaybettirecek ve sunucunun yükünü arttıracak gereksiz istekler oluşmayacaktır.
- Daha yüksek bir kullanıcıyı deneyimi yaşanacaktır.
İstemci Tarafta Doğrulama
İstemci tarafta doğrulama yapalım ya da yapmayalım sunucu tarafta mutlaka doğrulama yapmamız gerekir. JSF, istemci tarafta doğrulama yapmak için hazır bir çözüm sunmaz. Ancak PrimeFaces, JSR-303'de sunucu tarafta yapılan doğrulamaya benzer bir çözümü istemci tarafta gerçeklememizi sağlayan bir mekanizma sunuyor. Şimdi bu mekanizmayı inceleyeceğiz.
PrimeFaces'da istemci tarafta doğrulama yapmak için öncelikle, web.xml'de bu özelliği açmamız gerekir:
İstemci tarafta doğrulama yapalım ya da yapmayalım sunucu tarafta mutlaka doğrulama yapmamız gerekir. JSF, istemci tarafta doğrulama yapmak için hazır bir çözüm sunmaz. Ancak PrimeFaces, JSR-303'de sunucu tarafta yapılan doğrulamaya benzer bir çözümü istemci tarafta gerçeklememizi sağlayan bir mekanizma sunuyor. Şimdi bu mekanizmayı inceleyeceğiz.
PrimeFaces'da istemci tarafta doğrulama yapmak için öncelikle, web.xml'de bu özelliği açmamız gerekir:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>imdb-jsf</display-name> <welcome-file-list> <welcome-file>faces/logon.xhtml</welcome-file> </welcome-file-list> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <context-param> <param-name>primefaces.CLIENT_SIDE_VALIDATION</param-name> <param-value>true</param-value> </context-param> </web-app>
Iban.java:
@Target(value = ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = IbanValidator.class) @ClientConstraint(resolvedBy = IbanClientValidator.class) public @interface Iban { String message() default "{validation.iban}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
@Target(value = ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy=TCKimlikNoValidator.class) @ClientConstraint(resolvedBy = TcKimlikNoClientValidator.class) public @interface TcKimlikNo { String message() default "{validation.identityNo}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
IbanClientValidator.java:
package com.example.web.validation; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import javax.validation.metadata.ConstraintDescriptor; import org.primefaces.validate.bean.ClientValidationConstraint; public class IbanClientValidator implements ClientValidationConstraint { @Override public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) { Map<String,Object> metadata = new HashMap<String, Object>(); for (Object cd : constraintDescriptor.getComposingConstraints()) { if (cd instanceof ConstraintDescriptor) { Annotation annotation = ((ConstraintDescriptor) cd).getAnnotation();
if (annotation instanceof Iban){ metadata.put("data-message", ((Iban) annotation).message()); } } } return metadata; } @Override public String getValidatorId() { return Iban.class.getSimpleName(); } }
package com.example.web.validation; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import javax.validation.metadata.ConstraintDescriptor; import org.primefaces.validate.bean.ClientValidationConstraint; public class TcKimlikNoClientValidator implements ClientValidationConstraint { @Override public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) { Map<String, Object> metadata = new HashMap<String, Object>();
for (Object cd : constraintDescriptor.getComposingConstraints()) {
if (cd instanceof ConstraintDescriptor) {
Annotation annotation = ((ConstraintDescriptor) cd).getAnnotation();
if (annotation instanceof TcKimlikNo) {
metadata.put("data-message", ((TcKimlikNo) annotation).message());
}
}
}
return metadata;
} @Override public String getValidatorId() { return TcKimlikNo.class.getSimpleName(); } }
iban-validator.js:
PrimeFaces.validator['Iban'] = { MAX : 999999999, MODULUS : 97, throwError : function(detail) { throw { summary : 'Validation Error', detail : detail } }, calculateModulus : function(code) { var reformattedCode = code.substring(4) + code.substring(0, 4);
reformattedCode = reformattedCode.replace(/[A-Z]/g, function(match) {
return match.charCodeAt(0) - 55;
});
var total = 0;
for (i = 0; i < reformattedCode.length; i++) { charValue = reformattedCode.charCodeAt(i) - 48; if (charValue < 0 || charValue > 35) { return 0; } total = (Number(charValue) > 9 ? total * 100 : total * 10) + charValue; if (total < this.MAX) { total = (total % this.MODULUS); } } return total % this.MODULUS; }, validate : function(element, value) { if (value == undefined || value.length < 5) { this.throwError("This is not a valid IBAN!") } modulusResult = this.calculateModulus(value); if (modulusResult != 1) { messageId = element.data('message'); message = PrimeFaces.util.ValidationContext.getMessage(messageId).detail; this.throwError(message); } } };
PrimeFaces.validator['TcKimlikNo'] = { throwError : function(detail) { throw { summary : 'Validation Error', detail : detail } }, isValid : function(value) { if (value.match("^\\d{11}$")==null) { return false;
}
digits = new Array(11);
for (i=0;i<digits.length;++i) {
digits[i] = value.charCodeAt(i) - 48;
if (digits[i] < 0 || digits[i] > 9) {
return false;
}
}
x = digits[0];
y = digits[1];
for (i = 1; i < 5; i++) {
x += Number(digits[2 * i]); }
for (i = 2; i <= 4; i++) {
y += Number(digits[2 * i - 1]); }
c1 = 7 * x - y;
if (c1 % 10 != digits[9]) {
return false; }
c2 = 0; for (i = 0; i < 10; ++i) {
c2 += digits[i]; }
if (c2 % 10 != digits[10]) {
return false; }
return true;
}, validate : function(element, value) { if (value == undefined || value.length != 11) {
this.throwError("This is not a valid identity no!") }
if (!this.isValid(value)) {
messageId = element.data('message');
message = PrimeFaces.util.ValidationContext.getMessage(messageId).detail;
this.throwError(message);
}
} };
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Logon Page</title><script type="text/javascript" src="js/lang_en.js"></script><script type="text/javascript" src="js/iban-validator.js"></script> <script type="text/javascript" src="js/tckimlik-validator.js"></script>
<script type="text/javascript" src="js/username-validator.js"></script> <script type="text/javascript" src="js/strongpassword-validator.js"></script></h:head> <h:body> <f:view> <h:form> <h:panelGrid columns="3"> <p:outputLabel for="email" value="E-mail:" /> <p:inputText id="email"
required="true" requiredMessage="You must enter an e-mail!"
value="#{UserVM.email}"> <p:clientValidator event="blur" /> </p:inputText> <p:message id="emailError" for="email" /> <p:outputLabel for="iban" value="Iban:" /> <p:inputText id="iban"
required="true" requiredMessage="You must enter an iban!"
value="#{UserVM.iban}"> <p:clientValidator event="blur" /> </p:inputText> <p:message id="ibanError" for="iban" /> <p:outputLabel for="identityNo" value="Identity no:" /> <p:inputText id="identityNo"
required="true" requiredMessage="You must enter an identity No!" value="#{UserVM.identityNo}" >
<p:clientValidator event="blur" /> </p:inputText> <p:message id="identityNoError" for="identityNo" /> <p:outputLabel for="username" value="Username:" /> <p:inputText id="username"
required="true" requiredMessage="You must enter a username!" value="#{UserVM.username}"> <p:clientValidator event="blur" /> </p:inputText> <p:message id="usernameError" for="username" /> <p:outputLabel for="password" value="Password:" /> <h:panelGroup> <p:password id="password"
required="true" requiredMessage="You must enter a valid year!" value="#{UserVM.password}"> <p:clientValidator event="blur" /> </p:password> <p:commandButton action="#{UserVM.doLogon}" value="Logon"
validateClient="true"
update="emailError usernameError passwordError ibanError identityNoError"/> </h:panelGroup> <p:message id="passwordError" for="password" /> </h:panelGrid> </h:form> </f:view> </h:body> </html>
Doğrulamanın istemci tarafta gerçekleştiği ekran görüntüsü |
EmailClientValidator.java:
package com.example.web.validation; import java.util.HashMap; import java.util.Map; import javax.validation.constraints.Pattern; import javax.validation.metadata.ConstraintDescriptor; import org.primefaces.util.HTML; import org.primefaces.validate.bean.ClientValidationConstraint; public class EmailClientValidator implements ClientValidationConstraint { private static final String MESSAGE_METADATA = "data-p-pattern-msg"; private static final String MESSAGE_ID = "{javax.validation.constraints.Pattern.message}"; @Override public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) { for (Object o : constraintDescriptor.getComposingConstraints()) { if (o instanceof ConstraintDescriptor) { ConstraintDescriptor cd = (ConstraintDescriptor) o; Map<String,Object> metadata = new HashMap<String, Object>(); Map attrs = cd.getAttributes(); Object message = attrs.get("message"); metadata.put(HTML.VALIDATION_METADATA.PATTERN, attrs.get("regexp")); if(!message.equals(MESSAGE_ID)) { metadata.put(MESSAGE_METADATA, "You must enter a valid e-mail!"); } return metadata; } } return null; } @Override public String getValidatorId() { return Pattern.class.getSimpleName(); } }
package com.example.web.validation; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import javax.validation.metadata.ConstraintDescriptor; import org.primefaces.validate.bean.ClientValidationConstraint; public class StrongPasswordClientValidator implements ClientValidationConstraint { @Override public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) { int patternNo = 1, numberOfPatterns = 0; Map<String, Object> metadata = new HashMap<String, Object>(); for (Object o : constraintDescriptor.getComposingConstraints()) { if (o instanceof ConstraintDescriptor) { ConstraintDescriptor cd = (ConstraintDescriptor) o; Annotation annotation = cd.getAnnotation(); if (annotation instanceof Pattern) { Pattern pattern = (Pattern) annotation; String patternNoAsString = Integer.toString(patternNo); metadata.put("data-pattern".concat(patternNoAsString), pattern.regexp()); metadata.put("data-message".concat(patternNoAsString), pattern.message()); patternNo++; numberOfPatterns++; } else if (annotation instanceof Size) { Size size = (Size) annotation; metadata.put("data-size-min", size.min()); metadata.put("data-size-max", size.max()); metadata.put("data-size-message", size.message()); } } } metadata.put("data-no-of-patterns", numberOfPatterns); return metadata; } @Override public String getValidatorId() { return StrongPassword.class.getSimpleName(); } }
package com.example.web.validation; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import javax.validation.constraints.Pattern; import javax.validation.metadata.ConstraintDescriptor; import org.primefaces.validate.bean.ClientValidationConstraint; public class UsernameClientValidator implements ClientValidationConstraint { @Override public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) { int patternNo = 1, numberOfPatterns = 0; Map<String, Object> metadata = new HashMap<String, Object>(); for (Object o : constraintDescriptor.getComposingConstraints()) { if (o instanceof ConstraintDescriptor) { ConstraintDescriptor cd = (ConstraintDescriptor) o; Annotation annotation = cd.getAnnotation(); if (!(annotation instanceof Pattern)) continue; Pattern pattern = (Pattern) annotation; String patternNoAsString = Integer.toString(patternNo); metadata.put("data-pattern".concat(patternNoAsString), pattern.regexp()); metadata.put("data-message".concat(patternNoAsString), pattern.message()); patternNo++; numberOfPatterns++; } } metadata.put("data-no-of-patterns", numberOfPatterns); return metadata; } @Override public String getValidatorId() { return Username.class.getSimpleName(); } }
username-validation.js:
PrimeFaces.validator['Username'] = { throwError : function(detail) { throw { summary : 'Validation Error', detail : detail } }, validate : function(element, value) { if (value == undefined) { this.throwError("This is not a valid username!") } var noOfPatterns = Number(element.data('no-of-patterns')); patterns = []; messages = []; for (i = 1; i <= noOfPatterns; ++i) { patterns.push(element.data('pattern' + i)); messageId = element.data('message' + i); message = PrimeFaces.util.ValidationContext.getMessage(messageId); messages.push(message.detail); } for (i in patterns) { pattern = patterns[i]; var regex = new RegExp(pattern); if (!regex.test(value)) { this.throwError(messages[i]); } } } };
PrimeFaces.validator['StrongPassword'] = { throwError : function(detail) { throw { summary : 'Validation Error', detail : detail } }, validate : function(element, value) { if (value == undefined) { this.throwError("This is not a valid username!") } var noOfPatterns = Number(element.data('no-of-patterns')); patterns = []; messages = []; for (i = 1; i <= noOfPatterns; ++i) { patterns.push(element.data('pattern' + i)); messageId = element.data('message' + i); message = PrimeFaces.util.ValidationContext.getMessage(messageId); messages.push(message.detail); } for (i in patterns) { pattern = patterns[i]; var regex = new RegExp(pattern); if (!regex.test(value)) { this.throwError(messages[i]); } } messageId = element.data('size-message'); sizeMessage = PrimeFaces.util.ValidationContext.getMessage(messageId).detail; sizeMin= element.data('size-min'); sizeMax= element.data('size-max'); valueLength= value.length; if (valueLength<sizeMin || valueLength>sizeMax) this.throwError(sizeMessage); } };
Kodun tamamına Eclipse projesi olarak bu adresten ulaşabilirsiniz. JSF 2 ve PrimeFaces ile ilgili daha fazla detay öğrenmek isterseniz "Core JSF 2 and PrimeFaces 5" eğitimini incelemenizi öneririm.
No comments:
Post a Comment