6. İstemci Tarafında JavaScript Doğrulaması
Önceki bölümde sunucu tarafında doğrulama konusunu ele almıştık. Şimdi bir Spring uygulamasının mimarisine geri dönelim MVC:
![]() |
BD
Şu ana kadar, istemciye gönderilen sayfalar Javascript içermiyordu. Şimdi, ilk etapta istemci tarafında doğrulamalar yapmamızı sağlayacak bu teknolojiyi ele alacağız. Prensip şöyledir:
- değerleri web sunucusuna gönderen Javascript’tir;
- böylece POST komutu çalıştırılmadan önce, verilerin geçerliliğini kontrol edebilir ve veriler geçersizse POST komutunun çalışmasını engelleyebilir;
Sunucu tarafında doğruladığımız formu kullanacağız. Artık bu formu hem istemci tarafında hem de sunucu tarafında doğrulama imkanı sunacağız.
Not: Konu karmaşıktır. Bu konuya ilgi duymayan okuyucular doğrudan 7. paragrafa geçebilirler.
6.1. Projenin özellikleri
Projenin özelliklerini tanıtmak için birkaç görünümünü sunuyoruz. Başlangıç sayfası, URL ve [http://localhost:8080/js01.html] ile oluşturulur
![]() |
Doğrulamalar hem istemci hem de sunucu tarafında uygulanmıştır. POST, değerlerin istemci tarafında geçerli kabul edilmesi durumunda gerçekleştiğinden, sunucu tarafındaki doğrulamalar her zaman başarılı olur. Bu nedenle, istemci tarafındaki doğrulamaları devre dışı bırakmak için bir bağlantı sunulmuştur. Bu modda, daha önce incelediğimiz çalışma şekline geri dönülür. İşte bir örnek:
123 ![]() |
- [1]'te, girilen değerler;
- [2]'te, girişlerle ilgili hata mesajları;
- [3]'te, her bir hata için aşağıdakileri içeren bir hata özeti:
- doğrulanmış alanın adı,
- hata kodu,
- bu hata koduna ait varsayılan mesaj;
Şimdi, istemci tarafında doğrulamayı etkinleştirelim:
![]() |
- [1]'te, girilen değerler. Hatalı girdilerin özel bir stile sahip olduğu görülebilir;
- [2]'te, hatalı girdilerle ilişkili hata mesajları. Bunlar, sunucu tarafından üretilenlerle aynıdır;
- [3-4]'te artık hiçbir şey yoktur, çünkü hatalı girişler olduğu sürece sunucuya yönelik POST işlemi gerçekleşmez;
6.2. Sunucu tarafında doğrulama
6.2.1. Yapılandırma
İlk olarak, [springmvc-validation-client] adlı yeni bir Maven projesi oluşturuyoruz:
![]() |
Projeyi şu şekilde geliştiriyoruz:
![]() |
[Config] sınıfı projeyi yapılandırır. Bu sınıf, önceki projelerdekiyle aynıdır:
package istia.st.springmvc.config;
import java.util.Locale;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
@Configuration
@ComponentScan({ "istia.st.springmvc.controllers", "istia.st.springmvc.models" })
@EnableAutoConfiguration
public class Config extends WebMvcConfigurerAdapter {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
return messageSource;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Bean
public CookieLocaleResolver localeResolver() {
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
localeResolver.setCookieName("lang");
localeResolver.setDefaultLocale(new Locale("fr"));
return localeResolver;
}
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".xml");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCacheable(true);
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
@Bean
SpringTemplateEngine templateEngine(SpringResourceTemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
}
[Main] sınıfı, projenin yürütülebilir sınıfıdır:
package istia.st.springmvc.main;
import istia.st.springmvc.config.Config;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
public class Main {
public static void main(String[] args) {
// uygulama başlatılıyor
ApplicationContext context = SpringApplication.run(Config.class, args);
// Spring tarafından bulunan bean'lerin listesi görüntüleniyor
System.out.println("Liste des beans Spring");
String[] beanNames = context.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
}
- 13. satırda, Spring Boot, [Config] yapılandırma dosyasıyla başlatılır;
- 15-20. satırlar: Örnek olarak, Spring tarafından yönetilen nesnelerin listesini nasıl görüntüleyeceğimizi gösteriyoruz. Bu, bazen Spring'in bileşenlerimizden birini yönetmediğini düşündüğümüz durumlarda yararlı olabilir. Bu, bunu doğrulamanın bir yoludur. Aynı zamanda Spring Boot tarafından yapılan otomatik yapılandırmayı kontrol etmenin bir yoludur. Konsolda, aşağıdakine benzer bir liste elde edilir:
[Config] sınıfında tanımlanan nesneleri vurguladık.
6.2.2. Form şablonu
Projeyi incelemeye devam edelim:
![]() |
[Form01] sınıfı, gönderilen değerleri alacak olan sınıftır. Şu şekildedir:
package istia.st.springmvc.models;
import java.util.Date;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Future;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;
import org.springframework.format.annotation.DateTimeFormat;
public class Form01 {
// gönderilen değerler
@NotNull
@AssertFalse
private Boolean assertFalse;
@NotNull
@AssertTrue
private Boolean assertTrue;
@NotNull
@Future
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateInFuture;
@NotNull
@Past
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateInPast;
@NotNull
@Max(value = 100)
private Integer intMax100;
@NotNull
@Min(value = 10)
private Integer intMin10;
@NotNull
@NotBlank
private String strNotEmpty;
@NotNull
@Size(min = 4, max = 6)
private String strBetween4and6;
@NotNull
@Pattern(regexp = "^\\d{2}:\\d{2}:\\d{2}$")
private String hhmmss;
@NotNull
@Email
@NotBlank
private String email;
@NotNull
@Length(max = 4, min = 4)
private String str4;
@Range(min = 10, max = 14)
@NotNull
private Integer int1014;
@NotNull
@DecimalMax(value = "3.4")
@DecimalMin(value = "2.3")
private Double double1;
@NotNull
private Double double2;
@NotNull
private Double double3;
@URL
@NotBlank
private String url;
// istemci tarafında doğrulama
private boolean clientValidation = true;
// yerel
private String lang;
...
}
Daha önce karşılaştığımız doğrulayıcıları burada da görüyoruz. Ayrıca, özel doğrulama kavramını da tanıtacağız. Bu, önceden tanımlanmış bir doğrulayıcıyla formalize edilemeyen bir doğrulamadır. Burada, [double1+double2]'in [10,13] aralığında olmasını isteyeceğiz.
6.2.3. Denetleyici
[JsController] denetleyicisi şu şekildedir:
![]() |
package istia.st.springmvc.controllers;
import istia.st.springmvc.models.Form01;
...
@Controller
public class JsController {
@RequestMapping(value = "/js01", method = RequestMethod.GET, produces = "text/html; charset=UTF-8")
public String js01(Form01 formulaire, Locale locale, Model model) {
setModel(formulaire, model, locale, null);
return "vue-01";
}
...
// vue-01 görünüm şablonunun hazırlanması
private void setModel(Form01 formulaire, Model model, Locale locale, String message) {
...
}
}
- 9. satırda, [/js01] eylemi;
- 10. satır: [Form01] türünde bir nesne oluşturulur ve [form01] anahtarıyla ilişkilendirilerek otomatik olarak şablona eklenir;
- satır 10: yerel ayar ve şablon parametrelere eklenir;
- 11. satır: Bu bilgilerle şablon hazırlanır;
- 12. satır: [vue-01.xml] görünümü görüntülenir;
[setModel] yöntemi şu şekildedir:
// vue-01 görünümünün modelinin hazırlanması
private void setModel(Form01 formulaire, Model model, Locale locale, String message) {
// sadece fr-FR ve en-US yerel ayarları desteklenir
String language = locale.getLanguage();
String country = null;
if (language.equals("fr")) {
country = "FR";
formulaire.setLang("fr_FR");
}
if (language.equals("en")) {
country = "US";
formulaire.setLang("en_US");
}
model.addAttribute("locale", String.format("%s-%s", language, country));
// olası mesaj
if (message != null) {
model.addAttribute("message", message);
}
}
- [setModel] yönteminin amacı, şablona şunları eklemektir:
- yerel ayar bilgilerini,
- son parametre olarak geçirilen mesaj;
- 14. satır: şablona yerel ayar bilgileri (dil, ülke) eklenir;
- 16-18. satırlar: parametre olarak geçirilen mesaj varsa, bu mesaj yerel ayarlara eklenir;
- 8. ve 12. satırlar: yerel ayar bilgileri aynı zamanda [Form01] formunda da saklanır. JavaScript bu bilgileri kullanacaktır;
[vue-01.xml] formuna girilen değerler, aşağıdaki [/js02] eylemine gönderilecektir:
@RequestMapping(value = "/js02", method = RequestMethod.POST, produces = "text/html; charset=UTF-8")
public String js02(@Valid Form01 formulaire, BindingResult result, RedirectAttributes redirectAttributes, Locale locale, Model model) {
Form01Validator validator = new Form01Validator(10, 13);
validator.validate(formulaire, result);
...
}
- 2. satır: [@Valid Form01 formulaire] notu, gönderilen değerlerin [Form01] sınıfındaki doğrulayıcılara tabi tutulmasını sağlar. [10,13] aralığında [double1+double2] adlı özel bir doğrulama olduğunu biliyoruz. 3. satıra geldiğimizde, bu doğrulama yapılmamıştır;
- 3. satır: Aşağıdaki [Form01Validator] nesnesi oluşturulur:
![]() |
package istia.st.springmvc.validators;
import istia.st.springmvc.models.Form01;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public class Form01Validator implements Validator {
// doğrulama aralığı
private double min;
private double max;
// oluşturucu
public Form01Validator(double min, double max) {
this.min = min;
this.max = max;
}
@Override
public boolean supports(Class<?> classe) {
return Form01.class.equals(classe);
}
@Override
public void validate(Object form, Errors errors) {
// doğrulanmış nesne
Form01 form01 = (Form01) form;
// [double1]'in değeri
Double double1 = form01.getDouble1();
if (double1 == null) {
return;
}
// [double2]'in değeri
Double double2 = form01.getDouble2();
if (double2 == null) {
return;
}
// [double1+double2]
double somme = double1 + double2;
// doğrulama
if (somme < min || somme > max) {
errors.rejectValue("double2", "form01.double2", new Double[] { min, max }, null);
}
}
}
- 8. satır: Özel bir doğrulama uygulamak için, Spring [Validator] arayüzünü uygulayan bir sınıf oluşturuyoruz. Bu arayüzün iki yöntemi vardır: 21. satırdaki [supports] ve 26. satırdaki [validate];
- 21-23. satırlar: [supports] yöntemi, [Class] türünde bir nesne alır. Bu yöntemin, bu sınıfı desteklediğini belirtmek için true değerini, aksi takdirde false değerini döndürmesi gerekir;
- 22. satır: [Form01Validator] sınıfının yalnızca [Form01] türündeki nesneleri geçerli kıldığını belirtiyoruz;
- 15-18. satırlar: [double1+double2] kısıtlamasını [10,13] aralığında uygulamak istediğimizi hatırlayalım. Bu aralığa bağlı kalmak yerine, [double1+double2] kısıtlamasını [min, max] aralığında kontrol edeceğiz. Bu nedenle, bu iki parametreye sahip bir oluşturucumuz var;
- 26. satır: [validate] yöntemi, doğrulanmış nesnenin bir örneği (burada [Form01]'in bir örneği) ve şu anda bilinen hataların koleksiyonu ([Errors errors]) ile çağrılır. [validate] yöntemi tarafından yapılan doğrulama başarısız olursa, [Errors errors] koleksiyonunda yeni bir öğe oluşturmalıdır;
- 43. satır: Doğrulama başarısız oldu. [Errors.rejectValue] yöntemi kullanılarak [Errors errors] koleksiyonuna bir öğe eklenir; bu yöntemin parametreleri şunlardır:
- parametre 1: genellikle hatalı alanın adıdır. Burada [double1, double2] alanları test edilmiştir. İkisinden birini girebilirsiniz,
- ilişkili hata mesajı ya da daha doğrusu dışsallaştırılmış mesaj dosyalarındaki anahtarı girebiliriz:
[messages_fr.properties]
form01.double2=[double2+double1] doit être dans l''intervalle [{0},{1}]
[messages_en.properties]
form01.double2=[double2+double1] must be in [{0},{1}
Burada {0} ve {1} ile parametreleştirilmiş mesajlar bulunmaktadır. Dolayısıyla bu mesaja iki değer sağlanması gerekmektedir. [Errors.rejectValue] yönteminin üçüncü parametresi bunu gerçekleştirir.
- Dördüncü parametre ise hata için varsayılan bir mesajdır;
[/js02] eylemine geri dönelim:
@RequestMapping(value = "/js02", method = RequestMethod.POST, produces = "text/html; charset=UTF-8")
public String js02(@Valid Form01 formulaire, BindingResult result, RedirectAttributes redirectAttributes, Locale locale, Model model) {
Form01Validator validator = new Form01Validator(10, 13);
validator.validate(formulaire, result);
if (result.hasErrors()) {
StringBuffer buffer = new StringBuffer();
for (ObjectError error : result.getAllErrors()) {
buffer.append(String.format("[name=%s,code=%s,message=%s]", error.getObjectName(), error.getCode(), error.getDefaultMessage()));
}
setModel(formulaire, model, locale, buffer.toString());
return "vue-01";
} else {
redirectAttributes.addFlashAttribute("form01", formulaire);
return "redirect:/js01.html";
}
}
- 4. satır: [Form01Validator] doğrulayıcısı şu parametrelerle çalıştırılır:
- 1. parametre: doğrulanmakta olan nesne,
- parametre 2: bu nesnenin hata listesi. Bu, eylemin parametreleri olarak geçirilen [BindingResult result] nesnesidir. Doğrulama başarısız olursa, bu nesneye bir hata daha eklenecektir;
- 5. satır: Doğrulama hatası olup olmadığı kontrol edilir;
- 7-10. satırlar: Hata listesi taranarak her bir hata için aşağıdakiler kaydedilir:
- doğrulanmış nesnenin adı,
- hata kodu,
- varsayılan hata mesajı;
- 10. satır: Bu bilgilerle [vue-01.xml] görünüm şablonu oluşturulur. Bu sefer, çeşitli hata mesajlarının birleştirilmiş ve kısaltılmış hali olan bir mesaj vardır;
- 12-15. satırlar: Gönderilen tüm değerler geçerliyse, gönderilen değerleri Flash özniteliğine yerleştirerek müşteriyi [/js01] eylemine yönlendiririz;
6.2.4. Görünüm
[vue-01.xml] görünümü karmaşıktır. Burada sadece küçük bir bölümünü sunacağız:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring 4 MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/form01.css" />
<script type="text/javascript" src="/js/jquery/jquery-1.10.2.min.js"></script>
...
</head>
<body>
<!-- başlık -->
<h3>
<span th:text="#{form01.title}"></span>
<span th:text="${locale}"></span>
</h3>
<!-- menü -->
<p>
...
</p>
<!-- form -->
<form action="/someURL" th:action="@{/js02.html}" method="post" th:object="${form01}" name="form" id="form">
<table>
<thead>
<tr>
<th class="col1" th:text="#{form01.col1}">Contrainte</th>
<th class="col2" th:text="#{form01.col2}">Saisie</th>
<th class="col3" th:text="#{form01.col3}">Validation client</th>
<th class="col4" th:text="#{form01.col4}">Validation serveur</th>
</tr>
</thead>
<tbody>
<!-- zorunlu -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
</td>
</tr>
...
</tbody>
</table>
<p>
<!-- onay düğmesi -->
<input type="submit" th:value="#{form01.valider}" value="Valider" onclick="javascript:postForm01()" />
</p>
</form>
<!-- sunucu tarafı doğrulayıcı mesajı -->
<br/>
<fieldset class="fieldset">
<legend>
<span th:text="#{server.error.message}"></span>
</legend>
<span th:text="${message}" class="error"></span>
</fieldset>
</body>
</html>
Bu sayfa, dışsallaştırılmış mesaj dosyalarında bulunan bir dizi mesajı kullanır:
[messages_fr.properties]
form01.title=Formulaire - Validations côté client - locale=
form01.col1=Contrainte
form01.col2=Saisie
form01.col3=Validation client
form01.col4=Validation serveur
form01.valider=Valider
server.error.message=Erreurs détectées par les validateurs côté serveur
[messages_en.properties]
form01.title=Form - Client side validation - locale=
form01.col1=Constraint
form01.col2=Input
form01.col3=Client validation
form01.col4=Server validation
form01.valider=Validate
server.error.message=Errors detected by the validators on the server side
Sayfanın koduna geri dönelim:
- 8. satır: Burada göz ardı edebileceğimiz çok sayıda JavaScript kütüphanesi içe aktarımı;
- 14. satır: sunucu tarafından şablona yerleştirilen yerel ayarı görüntüler;
- 59. satır: sunucu tarafından şablona yerleştirilen mesajı görüntüler;
33-44. satırlardaki kod yenidir. Bunu inceleyelim:
<!-- gerekli -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
</td>
</tr>
En kolayı, belki de bu Thymeleaf segmenti tarafından oluşturulan HTML koduna bakmak olabilir:
<!-- zorunlu -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" id="strNotEmpty" name="strNotEmpty" value="" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
</td>
</tr>
İstemci tarafında [jquery.validate] adlı bir doğrulama kütüphanesi kullanacağız. Tüm [data-x] öznitelikleri bu kütüphane içindir. İstemci tarafındaki doğrulama devre dışı bırakıldığında, bu öznitelikler kullanılmayacaktır. Dolayısıyla şimdilik bunları anlamaya gerek yoktur. Sadece şu Thymeleaf satırına odaklanabiliriz:
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
Bu satır, aşağıdaki HTML satırını oluşturur:
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" id="strNotEmpty" name="strNotEmpty" value="" />
Yukarıda, [data-val-required="Le champ est obligatoire"] özniteliğini oluştururken bir zorluk vardır. Aslında, özniteliğe atanan değer, dışsallaştırılmış mesaj dosyalarından gelir. Bu nedenle, bu değeri elde etmek için bir Thymeleaf ifadesi kullanmak zorundayız. Bu ifade şöyledir: [th:attr="data-val-required=#{NotNull}"]. Bu ifade değerlendirilir ve değeri, oluşturulan HTML etiketine olduğu gibi yerleştirilir. Adı [th:attr]'tir, çünkü bu etiket Thymeleaf'te önceden tanımlanmamış öznitelikleri oluşturmak için kullanılır. [th:text, th:value, th:class, ...] gibi önceden tanımlanmış özniteliklerle karşılaştık, ancak [th:data-val-required] adlı bir öznitelik mevcut değildir.
6.2.5. Stil sayfası
Yukarıda, [class="field-validation-valid"] gibi CSS sınıflarıyla karşılaşıyoruz. Bu sınıflardan bazıları, JavaScript doğrulama kütüphanesi tarafından kullanılıyor. Bunlar, aşağıdaki [form01.css] dosyasında tanımlanmıştır:
![]() |
@CHARSET "UTF-8";
/*özel stiller*/
body {
background-image: url("/images/standard.jpg");
}
.col1 {
background: lightblue;
}
.col2 {
background: Cornsilk;
}
.col3 {
background: AliceBlue;
}
.col4 {
background: Lavender;
}
.error {
color: red;
}
.fieldset{
background: Lavender;
}
/* Doğrulama yardımcıları için stiller
-----------------------------------------------------------*/
.field-validation-error {
color: #f00;
}
.field-validation-valid {
display: none;
}
.input-validation-error {
border: 1px solid #f00;
background-color: #ücret;
}
.validation-summary-errors {
font-weight: bold;
color: #f00;
}
.validation-summary-valid {
display: none;
}
6.3. İstemci tarafında doğrulama
6.3.1. jQuery ve JavaScript'in temelleri
İstemci tarafında doğrulama, JavaScript ile gerçekleştirilir. JavaScript geliştirmeyi kolaylaştıran birçok işlev sunan jQuery çerçevesinden yararlanacağız. Bu bölümdeki ve sonraki bölümlerdeki komut dosyalarını anlamak için bilmeniz gereken jQuery'in temellerini sunuyoruz.
HTML adlı statik bir dosya oluşturup bunu [JQuery-01.html] klasörüne yerleştiriyoruz:
![]() |
Bu dosyanın içeriği şu şekilde olacaktır:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JQuery-01</title>
<script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script>
</head>
<body>
<h3>Rudiments de JQuery</h3>
<div id="element1">
Elément 1
</div>
</body>
</html>
- 6. satır: jQuery dosyasının içe aktarılması;
- 10-12. satırlar: [element1] kimliğine sahip bir sayfa öğesi. Bu öğeyle biraz oynayacağız.
[jquery-1.11.1.min.js] dosyasını indirmemiz gerekiyor. jQuery dosyasının en son sürümünü URL ve [http://jquery.com/download/] dosyalarında bulabiliriz:

İndirdiğimiz dosyayı [static / js] klasörüne yerleştireceğiz:
![]() |
Bu işlem tamamlandıktan sonra, Chrome ile [jQuery-01.html] statik görünümünü çağırın: [1-2]:
![]() |
Google Chrome'da, geliştirme araçlarını görüntülemek için [Ctrl-Maj-I] komutunu girin: [3]. [Console] ve [4] sekmeleri, JavaScript kodunu çalıştırmanıza olanak tanır. Aşağıda, girmeniz gereken JavaScript komutlarını ve bunların açıklamalarını veriyoruz.
JS | sonuç |
|
: [element1] kimliğine sahip tüm öğelerin koleksiyonunu döndürür; dolayısıyla normalde 0 veya 1 öğeden oluşan bir koleksiyon olur, çünkü bir sayfada iki özdeş kimlik bulunamaz (HTML). | ![]() |
|
: Koleksiyondaki tüm öğelere [blabla] metnini atar. Bu işlem, sayfanın görüntülediği içeriği değiştirir | ![]() |
|
koleksiyondaki öğeleri gizler. [blabla] metni artık görüntülenmez. | ![]() |
|
: koleksiyonu yeniden görüntüler. Bu sayede, [element1] kimliğine sahip öğenin, öğeyi gizleyen CSS style='display: none;' özniteliğine sahip olduğunu görebiliriz. | |
|
: koleksiyondaki öğeleri görüntüler. [blabla] metni yeniden görünür. Bu görüntüyü sağlayan, CSS style='display : block;' özniteliğidir. | ![]() |
|
: koleksiyondaki tüm öğelere bir öznitelik atar. Buradaki öznitelik [style] ve değeri [color: red]'tir. [blabla] metni kırmızıya döner. | ![]() |
![]() | |
![]() |
Tüm bu işlemler sırasında tarayıcının URL değerinin değişmediğine dikkat edilmelidir. Web sunucusuyla herhangi bir veri alışverişi gerçekleşmemiştir. Her şey tarayıcının içinde gerçekleşmektedir. Şimdi sayfanın kaynak koduna bir göz atalım:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JQuery-01</title>
<script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script>
</head>
<body>
<h3>Rudiments de JQuery</h3>
<div id="element1">
Elément 1
</div>
</body>
</html>
Bu, başlangıçtaki metindir. 10-12. satırlardaki öğe üzerinde yaptığımız işlemlerin hiçbirini yansıtmamaktadır. JavaScript hata ayıklaması yaparken bunu hatırlamak önemlidir. Bu nedenle, görüntülenen sayfanın kaynak kodunu görüntülemek çoğu zaman gereksizdir.
Bundan sonra gelecek olan jS komut dosyalarını anlamak için yeterli bilgiye sahibiz.
6.3.2. jS doğrulama kütüphaneleri
jQuery ekosistemindeki kütüphaneleri kullanacağız. jQuery etrafında, kendi kütüphanelerini oluşturan bir dizi proje bulunmaktadır. Microsoft tarafından oluşturulan ve jQuery vakfına bağışlanan [jquery.validate.unobstrusive] doğrulama kütüphanesini kullanacağız. Bundan sonra bu kütüphaneye MS doğrulama kütüphanesi veya daha kısaca MS kütüphanesi olarak atıfta bulunacağız. Bu kütüphaneyi edinmek için Microsoft Visual Studio ortamı gereklidir. Başka bir yolla nasıl edinilebileceğini görmedim. [Visual Studio Community] veya [http://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx] (Aralık 2014) gibi ücretsiz bir sürüm kullanılabilir. Aşağıdaki adımları takip etmekle ilgilenmeyen okuyucular, bu kütüphaneyi ve bu belgenin web sitesinde yer alan örneklerde dayandığı diğer kütüphaneleri indirebilirler.
Visual Studio ile [1-4] adlı bir konsol projesi oluşturulur:
|
![]() |
- [5], konsol projesi;
- [6-7]: Projeye [NuGet] paketlerini ekleyeceğiz. [NuGet], Visual Studio'da DLL biçimindeki kütüphaneleri ve aynı zamanda jS kütüphanelerini indirmeyi sağlayan bir işlevdir.
![]() |
- [9-10]'e dönüştürmek için [jQuery] anahtar kelimesiyle arama yapın;
- [11-13]'e dönüştürmek için, belirtilen sırayla istemci tarafında doğrulama için gerekli olan jS kütüphanelerini indirin;
- [14]'te, yakında kullanacağımız [Microsoft jQuery Unobtrusive Ajax] kütüphanesini de indirin;
![]() |
- [15-16]'te, [globalize] anahtar kelimesiyle paket araması yapın;
- [17] için, [jQuery.Validation.Globalize] kütüphanesini indirin;
![]() |
Bu çeşitli indirmeler, [18] projesinin [Scripts] klasörüne bir dizi jS kütüphanesi yüklemiştir. Bunların hepsi gerekli değildir. Her dosyanın iki kopyası vardır:
- [js]: kütüphanenin okunabilir sürümü;
- [min.js]: kütüphanenin okunamaz, "minified" olarak adlandırılan versiyonu. Aslında tam olarak okunamaz değildir. Metin halindedir. Ancak anlaşılabilir değildir. Üretim ortamında kullanılması gereken sürüm budur, çünkü bu dosya karşılık gelen [js] sürümünden daha küçüktür ve dolayısıyla istemci/sunucu arasındaki veri alışverişinin hızını artırır;
[min.map] sürümleri zorunlu değildir. [cultures] klasöründe, yalnızca uygulama tarafından yönetilen kültürleri saklayabilirsiniz.
Windows Gezgini ile bu dosyaları [springmvc-validation-client] projesinin [static / js / jquery] klasörüne kopyalayın ve yalnızca gerekli olan [20] dosyalarını saklayın:
![]() |
[21]'te sadece iki dil ayarı saklanır:
- [fr-FR]: Fransa Fransızcası;
- [en-US]: USA'teki İngilizce;
6.3.3. Doğrulama kütüphanelerinin içe aktarılması
Bu kütüphanelerin kullanılabilmesi için [vue-01.xml] görünümü aracılığıyla içe aktarılması gerekir:
<head>
<title>Spring 4 MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/form01.css" />
<script type="text/javascript" src="/js/jquery/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="/js/jquery/jquery.validate.min.js"></script>
<script type="text/javascript" src="/js/jquery/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript" src="/js/jquery/globalize/globalize.js"></script>
<script type="text/javascript" src="/js/jquery/globalize/cultures/globalize.culture.fr-FR.js"></script>
<script type="text/javascript" src="/js/jquery/globalize/cultures/globalize.culture.en-US.js"></script>
<script type="text/javascript" src="/js/client-validation.js"></script>
<script type="text/javascript" src="/js/local.js"></script>
<script th:inline="javascript">
/*<![CDATA[*/
var culture = [[${locale}]];
Globalize.culture(culture);
/*]]>*/
</script>
</head>
- 11. satır: Henüz bahsetmediğimiz bir jS dosyasının içe aktarılması;
- 13-18. satırlar: Thymelaf tarafından yorumlanan bir jS komut dosyası. Bu komut dosyası, istemci tarafında yerel ayarları yönetir;
6.3.4. İstemci tarafında yerel ayar yönetimi
İstemci tarafında yerelleştirme, aşağıdaki jS betiği ile gerçekleştirilir:
<script th:inline="javascript">
/*<![CDATA[*/
var culture = [[${locale}]];
Globalize.culture(culture);
/*]]>*/
</script>
- 3-4. satırlar: Thymeleaf [[${locale}]] ifadesinin bulunduğu jS kodu. Bu ifadenin kendine özgü sözdizimine dikkat edin. Bunun nedeni, ifadenin JavaScript içinde yer almasıdır. [[${locale}]] ifadesi, görünüm modelindeki [locale] anahtarının değeriyle değiştirilecektir;
Bu satırlardan oluşturulan HTML akışındaki sonuç şöyledir:
<script>
/*<![CDATA[*/
var culture = 'en-US';
Globalize.culture(culture);
/*]]>*/
</script>
3-4. satırlar, istemci tarafındaki dil ayarını belirler. Yalnızca iki tanesini yönetiyoruz: [fr-FR] ve [en-US]. Bu nedenle yalnızca iki dil dosyası içe aktardık:
<script type="text/javascript" src="/js/jquery/globalize/cultures/globalize.culture.fr-FR.js"></script>
<script type="text/javascript" src="/js/jquery/globalize/cultures/globalize.culture.en-US.js"></script>
İstemci tarafında kullanılacak dil, sunucu tarafında belirlenir. Sunucu tarafındaki koda geri dönelim:
@RequestMapping(value = "/js01", method = RequestMethod.GET, produces = "text/html; charset=UTF-8")
public String js01(Form01 formulaire, Locale locale, Model model) {
setModel(formulaire, model, locale, null);
return "vue-01";
}
// vue-01 görünüm şablonunun hazırlanması
private void setModel(Form01 formulaire, Model model, Locale locale, String message) {
// sadece fr-FR ve en-US yerel ayarları desteklenir
String language = locale.getLanguage();
String country = null;
if (language.equals("fr")) {
country = "FR";
formulaire.setLang("fr_FR");
}
if (language.equals("en")) {
country = "US";
formulaire.setLang("en_US");
}
model.addAttribute("locale", String.format("%s-%s", language, country));
...
}
- 20. satır: [fr-FR] veya [en-US] yerel ayarı, [vue-01.xml] görünüm şablonuna (4. satır) eklenir. Burada bir karışıklık kaynağı göze çarpmaktadır. Fransızca yerel ayarı, istemci tarafında [fr-FR] olarak gösterilirken, sunucu tarafında [fr_FR] olarak gösterilmektedir. Bu nedenle, 14. ve 18. satırlarda, gönderilen değerleri alan [Form01 formulaire] nesnesinde bu biçimde depolanmaktadır;
Aşağıdaki önemli noktaya dikkat edilmelidir.
<script>
/*<![CDATA[*/
var culture = 'en-US';
Globalize.culture(culture);
/*]]>*/
</script>
Sunucu tarafından iletilen yerel ayarlara göre müşterinin dil ayarını değiştirir. Bu, sayfa tarafından görüntülenen mesajları uluslararası hale getirmez. Yalnızca, bir ülkenin dil ayarlarına bağlı olan belirli bilgilerin yorumlanma şeklini değiştirir. [fr_FR] kültüründe, [12,78] sayısının geçerli olduğu halde, [en-US] kültüründe geçersizdir. Bu durumda [12.78] yazılmalıdır. Aynı şekilde, [12/01/2014] tarihi, [fr-FR] kültüründe geçerliyken, [en-US] kültüründe [01/12/2014] yazılması gerekir. [jquery / globalize] klasöründeki dosyalar bu tür sorunları yönetir:
![]() |
Hata mesajlarının uluslararasılaştırılması yalnızca sunucu tarafında yönetilir. HTML / jS sayfasının, sunucu tarafından yönetilen yerel ayara uygun hata mesajlarını içerdiğini göreceğiz: [fr_FR] yerel ayarı için Fransızca, [en_US] yerel ayarı için İngilizce.
6.3.5. Hata mesajı dosyaları
[vue-01.xml] görünümü aşağıdaki uluslararasılaştırılmış mesajları kullanır:
![]() |
[messages_fr.properties]
NotNull=Le champ est obligatoire
NotEmpty=La donnée ne peut être vide
NotBlank=La donnée ne peut être vide
typeMismatch=Format invalide
Future.form01.dateInFuture=La date doit être postérieure ou égale à celle d''aujourd'hui
Past.form01.dateInPast=La date doit être antérieure ou égale à celle d''aujourd'hui
Min.form01.intMin10=La valeur doit être supérieure ou égale à 10
Max.form01.intMax100=La valeur doit être inférieure ou égale à 100
Size.form01.strBetween4and6=La chaîne doit avoir entre 4 et 6 caractères
Length.form01.str4=La chaîne doit avoir quatre caractères exactement
Email.form01.email=Adresse mail invalide
URL.form01.url=URL invalide
Range.form01.int1014=La valeur doit être dans l''intervalle [10,14]
AssertTrue=Seule la valeur True est acceptée
AssertFalse=Seule la valeur False est acceptée
Pattern.form01.hhmmss=Tapez l''heure sous la forme hh:mm:ss
form01.hhmmss.pattern=^\\d{2}:\\d{2}:\\d{2}$
DateInvalide.form01=Date invalide
form01.str4.pattern=^.{4,4}$
form01.int1014.max=14
form01.int1014.min=10
form01.strBetween4and6.pattern=^.{4,6}$
form01.intMax100.value=100
form01.intMin10.value=10
form01.double1.min=2.3
form01.double1.max=3.4
Range.form01.double1=La valeur doit être dans l'intervalle [2,3-3,4]
form01.title=Formulaire - Validations côté client - locale=
form01.col1=Contrainte
form01.col2=Saisie
form01.col3=Validation client
form01.col4=Validation serveur
form01.valider=Valider
form01.double2=[double2+double1] doit être dans l''intervalle [{0},{1}]
form01.double3=[double3+double1] doit être dans l''intervalle [{0},{1}]
locale.fr=Français
locale.en=English
client.validation.true=Activer la validation client
client.validation.false=Inhiber la validation client
DecimalMin.form01.double1=Le nombre doit être supérieur ou égal à 2,3
DecimalMax.form01.double1=Le nombre doit être inférieur ou égal à 3,4
server.error.message=Erreurs détectées par les validateurs côté serveur
[messages_en.properties]
NotNull=Field is required
NotEmpty=Field can''t be empty
NotBlank=Field can''t be empty
typeMismatch=Invalid format
Future.form01.dateInFuture=Date must be greater or equal to today''s date
Past.form01.dateInPast=Date must be lower or equal today''s date
Min.form01.intMin10=Value must be higher or equal to 10
Max.form01.intMax100=Value must be lower or equal to 100
Size.form01.strBetween4and6=String must have between 4 and 6 characters
Length.form01.str4=String must be exactly 4 characters long
Email.form01.email=Invalid mail address
URL.form01.url=Invalid URL
Range.form01.int1014=Value must be in [10,14]
AssertTrue=Only value True is allowed
AssertFalse=Only value False is allowed
Pattern.form01.hhmmss=Time must follow the format hh:mm:ss
form01.hhmmss.pattern=^\\d{2}:\\d{2}:\\d{2}$
DateInvalide.form01=Invalid Date
form01.str4.pattern=^.{4,4}$
form01.int1014.max=14
form01.int1014.min=10
form01.strBetween4and6.pattern=^.{4,6}$
form01.intMax100.value=100
form01.intMin10.value=10
form01.double1.min=2.3
form01.double1.max=3.4
Range.form01.double1=Value must be in [2.3,3.4]
form01.title=Form - Client side validation - locale=
form01.col1=Constraint
form01.col2=Input
form01.col3=Client validation
form01.col4=Server validation
form01.valider=Validate
form01.double2=[double2+double1] must be in [{0},{1}]
form01.double3=[double3+double1] must be in [{0},{1}]
locale.fr=Français
locale.en=English
client.validation.true=Activate client validation
client.validation.false=Inhibate client validation
DecimalMin.form01.double1=Value must be greater or equal to 2.3
DecimalMax.form01.double1=Value must be lower or equal to 3.4
server.error.message=Errors detected by the validators on the server side
[messages.properties] dosyası, İngilizce mesaj dosyasının bir kopyasıdır. Sonuç olarak, [fr]'ten farklı tüm yerel ayarlar İngilizce mesajları kullanacaktır. [messages_fr.properties] dosyasının, [fr_XX] yerel ayarları (örneğin [fr_CA] veya [fr_FR]) için kullanıldığı hatırlatılmalıdır.
[vue-01.xml] görünümü, bu mesajların anahtarlarını kullanır. Bu anahtarlara atanan değerleri öğrenmek isteyen okuyucuların, bu paragrafa geri dönerek bilgileri inceleyebilecekleri belirtilir.
6.3.6. Yerel ayar değişikliği
[vue-01.xml] görünümü dört bağlantı içerir:
<body>
<!-- başlık -->
<h3>
<span th:text="#{form01.title}"></span>
<span th:text="${locale}"></span>
</h3>
<!-- menü -->
<p>
<a id="locale_fr" href="javascript:setLocale('fr_FR')">
<span th:text="#{locale.fr}"></span>
</a>
<a id="locale_en" href="javascript:setLocale('en_US')">
<span style="margin-left:30px" th:text="#{locale.en}"></span>
</a>
<a id="clientValidationTrue" href="javascript:setClientValidation(true)">
<span style="margin-left:30px" th:text="#{client.validation.true}"></span>
</a>
<a id="clientValidationFalse" href="javascript:setClientValidation(false)">
<span style="margin-left:30px" th:text="#{client.validation.false}"></span>
</a>
</p>
<!-- form -->
<form action="/someURL" th:action="@{/js02.html}" method="post" th:object="${form01}" name="form" id="form">
...
bunlardan bazıları aşağıda gösterilmiştir [1]:
![]() |
Yerel ayarı Fransızca veya İngilizce olarak değiştirebilen iki bağlantıyı inceleyelim:
<a id="locale_fr" href="javascript:setLocale('fr_FR')">
<span th:text="#{locale.fr}"></span>
</a>
<a id="locale_en" href="javascript:setLocale('en_US')">
<span style="margin-left:30px" th:text="#{locale.en}"></span>
</a>
Bu bağlantılara tıklandığında, jS dosyasında bulunan [local.js] [2] komut dosyası çalıştırılır. Her iki durumda da jS ve [setLocale] işlevleri çağrılır:
// yerel ayar
function setLocale(locale) {
// yerel ayar güncellenir
lang.val(locale);
// form gönderiliyor - bu, istemci tarafındaki doğrulama işlevlerini tetiklemiyor - bu nedenle istemci tarafındaki doğrulama devre dışı bırakılmadı
document.form.submit();
}
- satırı anlamak için bir ön açıklamaya ihtiyaç vardır. [vue-01.xml] görünümü, [lang] adlı gizli bir alan içerir:
<input type="hidden" th:field="*{lang}" th:value="*{lang}" value="true" />
Bu alan, [Form01]'teki [lang] alanına karşılık gelir:
// yerel
private String lang;
Gizli alanlar, gönderilen değerleri zenginleştirmek istendiğinde kullanışlıdır. JavaScript, bu alanlara bir değer atamaya olanak tanır ve bu değer, kullanıcı tarafından yapılan normal bir giriş gibi gönderilir. Thymeleaf tarafından oluşturulan HTML kodu şöyledir:
<input type="hidden" value="en_US" id="lang" name="lang" />
[value] parametresinin değeri, HTML oluşturulduğu anda [Form01.lang] alanının değeridir. Dikkat edilmesi gereken nokta, [id="lang"] düğümünün jS kimliğidir. Bu kimlik, aşağıdaki [] işlevi tarafından kullanılır:
// küresel değişkenler
var lang;
// belge hazır
$(document).ready(function() {
// küresel referanslar
lang = $("#lang");
});
// yerel
function setLocale(locale) {
// yerel ayar güncelleniyor
lang.val(locale);
// form gönderiliyor - bilinmeyen bir nedenden dolayı bu, istemcideki doğrulama işlevlerini tetiklemiyor
// bu nedenle doğrulama engellenmedi
document.form.submit();
}
- 5-8. satırlar: jS [$(document).ready(f)] işlevi, tarayıcı sunucu tarafından gönderilen belgenin tamamını yüklediğinde çalıştırılan bir işlevdir. Bu işlevin parametresi bir işlevdir. Yüklenen belgenin jS ortamını başlatmak için jS [$(document).ready(f)] işlevi kullanılır;
- 7. satır: [$("#lang")] ifadesi, bir jQuery ifadesidir. Değeri, [id='lang'] özniteliğine sahip DOM düğümüne bir referanstır;
- 2. satır: Bir fonksiyonun dışında bildirilen değişkenler, fonksiyonlar için küreseldir. Burada bu, [$(document).ready()] içinde başlatılan [lang] değişkeninin, 11. satırdaki [setLocale] fonksiyonunda da bilindiği anlamına gelir;
- 13. satır: [lang] ile tanımlanan düğümün [value] özniteliğini değiştirir. lang değeri [xx_XX] ise, düğümün HTML etiketi şu şekilde olur:
<input type="hidden" value="xx_XX" id="lang" name="lang" />
JavaScript, DOM öğelerinin değerlerini değiştirmeye olanak tanır (Belge Nesne Modeli).
- 16. satır: [document], DOM'i belirtir. [document.form] ise bu belgede bulunan ilk formu belirtir. Bir HTML belgesinde birden fazla <form> etiketi ve dolayısıyla birden fazla form bulunabilir. Burada ise sadece bir tane var. [document.form.submit], bu formu, kullanıcı [type='submit'] özniteliğine sahip bir düğmeye tıklamış gibi gönderir. Form değerleri hangi eyleme gönderiliyor? Bunu öğrenmek için, [vue-01.xml] içindeki formun [form] etiketine bakmak gerekir:
<!-- form -->
<form action="/someURL" th:action="@{/js02.html}" method="post" th:object="${form01}" name="form" id="form">
Gönderilen değerleri alacak eylem, [th:action] özniteliği ile belirtilen eylemdir. Dolayısıyla bu, [/js02.html] eylemi olacaktır. Bu isimde, [.html] sonekinin kaldırılacağını ve sonuçta [/js02] eyleminin yürütüleceğini hatırlatmak isteriz. Anlaşılması gereken önemli nokta, [lang] düğümünün yeni değeri olan [xx_XX]'in, [lang=xx_XX] biçiminde gönderileceğidir. Oysa uygulamamızı, [lang] parametresini yakalayıp bunu yerel ayar değişikliği olarak yorumlayacak şekilde yapılandırdık. Dolayısıyla sunucu tarafında yerel ayar, [xx_XX] olacak. Şimdi, yürütülecek olan [/js02] eylemine bakalım:
@RequestMapping(value = "/js02", method = RequestMethod.POST, produces = "text/html; charset=UTF-8")
public String js02(@Valid Form01 formulaire, BindingResult result, RedirectAttributes redirectAttributes, Locale locale, Model model) {
Form01Validator validator = new Form01Validator(10, 13);
validator.validate(formulaire, result);
if (result.hasErrors()) {
StringBuffer buffer = new StringBuffer();
for (ObjectError error : result.getAllErrors()) {
buffer.append(String.format("[name=%s,code=%s,message=%s]", error.getObjectName(), error.getCode(),
error.getDefaultMessage()));
}
setModel(formulaire, model, locale, buffer.toString());
return "vue-01";
} else {
redirectAttributes.addFlashAttribute("form01", formulaire);
return "redirect:/js01.html";
}
}
// vue-01 görünüm şablonunun hazırlanması
private void setModel(Form01 formulaire, Model model, Locale locale, String message) {
// Yalnızca fr-FR ve en-US yerel ayarları desteklenmektedir
String language = locale.getLanguage();
String country = null;
if (language.equals("fr")) {
country = "FR";
formulaire.setLang("fr_FR");
}
if (language.equals("en")) {
country = "US";
formulaire.setLang("en_US");
}
model.addAttribute("locale", String.format("%s-%s", language, country));
...
}
- 2. satır: [/js02] eylemi, [Locale locale] parametresinde kapsüllenmiş yeni yerel ayar [xx_XX]'i alacaktır:
- 5-12. satırlar: Gönderilen değerlerden bazıları geçersizse, [vue-01.xml] görünümü, yeni [xx_XX] yerel ayarını kullanan hata mesajlarıyla birlikte görüntülenecektir. Ayrıca, 11. satır, [locale=xx-XX] değişkeninin şablona eklenmesini sağlar. İstemci tarafında bu değer, istemci tarafındaki yerel ayarları güncellemek için kullanılacaktır. Bu süreci daha önce açıklamıştık;
- 14-15. satırlar: Gönderilen değerlerin tümü geçerliyse, bir sonraki [/js01] eylemine yönlendirme yapılır:
@RequestMapping(value = "/js01", method = RequestMethod.GET, produces = "text/html; charset=UTF-8")
public String js01(Form01 formulaire, Locale locale, Model model) {
setModel(formulaire, model, locale, null);
return "vue-01";
}
- 2. satırda, yeni yerel ayar [xx_XX] eklenir;
- 3. satır: [setModel] yöntemi, müşterinin yerel ayarını [xx-XX] olarak ayarlayacaktır;
Şimdi [vue-01.xml] görünümünde yerel ayarın etkisine bakalım. Şu an için bunu tam olarak sunmadık çünkü 300'den fazla satırdan oluşuyor. Bununla birlikte, satırların büyük bir kısmı aşağıdakine benzer bir dizinin tekrarıdır:
<!-- gerekli -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
</td>
</tr>
Bu kod, aşağıdaki [1] parçasını görüntüler:
![]() |
[2] hata mesajı, 5. satırdaki [th:attr="data-val-required=#{NotNull}"] özniteliğinden kaynaklanmaktadır. [#{NotNull}], yerelleştirilmiş bir mesajdır. Sunucu tarafındaki yerel ayara göre, 5. satır şu etiketi oluşturur:
<input type="text" data-val="true" data-val-required="Field is required" id="strNotEmpty" name="strNotEmpty" />
ya da şu etiket:
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" id="strNotEmpty" name="strNotEmpty" />
[data-x] öznitelikleri, jS doğrulama kütüphanesi tarafından kullanılır.
Sonuç olarak, iki yerel ayar değiştirme bağlantısının:
- girdilen değerlerin POST işlemine tabi tutulmasına neden olur;
- hem sunucu tarafında hem de istemci tarafında yerel ayarı değiştirir;
- HTML sayfasını oluştururlar; bu sayfa, jS doğrulama kütüphanesine yönelik hata mesajlarını da beraberinde getirir ve bu mesajlar seçilen yerel ayarın dilinde görüntülenir;
6.3.7. POST, girilen değerleri
[vue-01.xml] görünümüne girilen değerleri gönderen [Valider] düğmesini inceleyelim. Bu düğmenin kodu HTML şu şekildedir:
<!-- onay düğmesi -->
<input type="submit" value="Valider" onclick="javascript:postForm01()" />
Tarayıcıda JavaScript etkinse, düğmeye tıklandığında [postForm01] yöntemi çalıştırılır. Bu işlev [False] boole değerini döndürürse, submit işlevi çalıştırılmayacaktır. Başka bir değer döndürürse, bu işlev çalıştırılacaktır. Bu işlev, [local.js] dosyasında bulunur:
![]() |
Aşağıdaki 6. satırda [vue-01.xml] görünümü tarafından içe aktarılır:
<head>
<title>Spring 4 MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/form01.css" />
...
<script type="text/javascript" src="/js/local.js"></script>
</head>
Bu dosyada şu kod bulunur:
// global değişkenler
var formulaire;
var clientValidation;
var double1;
var double2;
var double3;
...
$(document).ready(function() {
// global referanslar
formulaire = $("#form");
clientValidation = $("#clientValidation");
double1 = $("#double1");
double2 = $("#double2");
double3 = $("#double3");
...
});
....
// form gönderimi
function postForm01() {
...
}
- 8-16. satırlar: jS [$(document).ready(f)] işlevi, tarayıcı sunucu tarafından gönderilen belgenin tamamını yüklediğinde çalıştırılan bir işlevdir. Bu işlevin parametresi bir işlevdir. jS [$(document).ready(f)] işlevi, yüklenen belgenin jS ortamını başlatmak için kullanılır;
- 10-14. satırlar: Bu satırları anlamak için hem Thymeleaf koduna hem de oluşturulan HTML koduna bakmak gerekir;
İlgili Thymeleaf kodu şöyledir:
<form action="/someURL" th:action="@{/js02.html}" method="post" th:object="${form01}" name="form" id="form">
...
<input type="text" th:field="*{double1}" th:value="*{double1}" ... />
...
<input type="text" th:field="*{double2}" th:value="*{double2}" />
...
<input type="text" th:field="*{double3}" th:value="*{double3}" ... />
...
<input type="hidden" th:field="*{clientValidation}" th:value="*{clientValidation}" value="true" />
Bu kod, aşağıdaki HTML kodunu oluşturur:
<form action="/js02.html" method="post" name="form" id="form">
...
<input type="text" id="double1" name="double1" .../>
....
<input type="text" value="" id="double2" name="double2" />
...
<input value="" id="double3" name="double3" .../>
...
<input type="hidden" value="false" id="clientValidation" name="clientValidation" />
Her bir [th:field='x'] özniteliği, HTML, [name='x'] ve [id='x'] olmak üzere iki öznitelik üretir. [name] özniteliği, gönderilen değerlerin adıdır. Dolayısıyla, bir HTML <input type='text'> etiketinde [name='x'] ve [value='y'] özniteliklerinin varlığı, gönderilen değerlere x=y dizesini ekleyecektir. name1=val1&name2=val2&... [id='x'] özniteliği ise JavaScript tarafından kullanılır. Bu öznitelik, DOM (Belge Nesne Modeli) öğesini tanımlamak için kullanılır. Yüklenen HTML belgesi, aslında DOM adlı bir JavaScript ağacına dönüştürülür; bu ağacın her düğümü, [id] özniteliği ile tanımlanır.
Şimdi [$(document).ready()] işlevinin koduna geri dönelim:
// global değişkenler
var formulaire;
var clientValidation;
var double1;
var double2;
var double3;
...
$(document).ready(function() {
// genel referanslar
formulaire = $("#form");
clientValidation = $("#clientValidation");
double1 = $("#double1");
double2 = $("#double2");
double3 = $("#double3");
...
});
....
// form gönderimi
function postForm01() {
...
}
- 10. satır: [$("#form")] ifadesi, bir jQuery ifadesidir. Değeri, [id='form '] özniteliğine sahip DOM düğümüne bir referanstır;
- 10-14. satırlar: DOM'in beş düğümüne ilişkin referanslar alınır;
- satır 2-6: Bir fonksiyonun dışında tanımlanan değişkenler, fonksiyonlar için küreseldir. Burada bu, [$(document).ready()] içinde başlatılan [formulaire, clientValidation , double1, double2, double3] değişkenlerinin, 19. satırdaki [postForm01] fonksiyonunda da tanınacağı anlamına gelir;
Şimdi, [postForm01] işlevini inceleyelim:
// form gönderimi
function postForm01() {
// istemci tarafında doğrulama modu
var validationActive = clientValidation.val() === "true";
if (validationActive) {
// sunucudaki hatalar siliniyor
clearServerErrors();
// form doğrulama
if (!formulaire.validate().form()) {
// gönderme yok
return false;
}
}
// İngilizce formatında gerçek değerler
var value1 = double1.val().replace(",", ".");
double1.val(value1);
var value2 = double2.val().replace(",", ".");
double2.val(value2);
var value3 = double3.val().replace(",", ".");
double3.val(value3);
// gönderme işleminin gerçekleşmesine izin verilir
return true;
}
Bu jS fonksiyonunun, formdaki [submit] fonksiyonundan önce çalıştırıldığını hatırlayalım. Eğer [false] (satır 11) boole değerini döndürürse, form gönderimi gerçekleşmez. Başka bir değer döndürürse (satır 22), form gönderimi gerçekleşir.
- Önemli kod 4-12. satırlardadır;
- 4. satır: Gizli alan [clientValidation]'in değeri alınır. Bu değer, istemci tarafında doğrulama etkinleştirilmesi gerekiyorsa 'true', aksi takdirde 'false'dır;
- 6. satır: istemci tarafında doğrulama yapılıyorsa, kullanıcının yerel ayarını yeni değiştirdiği için sunucuda bulunabilecek hata mesajları silinir;
- 9. satır: [formulaire] değişkeninin, HTML <form> etiketinin düğümünü, yani formu temsil ettiğini hatırlayalım. Bu formda, henüz tanıtmadığımız ve sonraki paragraflarda ele alınacak olan jS doğrulayıcıları bulunmaktadır. [formulaire.validate().form()] ifadesi, formda bulunan tüm jS doğrulayıcılarının çalıştırılmasını zorlar. Test edilen değerlerin tümü geçerliyse değeri [true], aksi takdirde [false] olur;
- 11. satır: Test edilen değerlerden en az biri geçersizse [false] değeri döndürülür. Bu, formdan sunucuya [submit]'in gönderilmesini engeller;
- 15-20. satırlar: [double1, double2, double3] kimlikleri, formdaki üç gerçek sayıyı temsil eder. Kültüre göre girilen değer farklılık gösterir. [fr-FR] kültüründe [10,37] yazılırken, [en-US] kültüründe [10.37] yazılır. Bu, veri girişi ile ilgilidir. [fr-FR] kültüründe, [double1] için gönderilen değer [double1=10,37] gibi görünecektir. Sunucu tarafına ulaştığında, [10,37] değeri reddedilecektir çünkü sunucu, Java'da gerçek sayıların varsayılan biçimi olan [10.37]'i beklemektedir. Ayrıca, 15-20. satırlarda, bu sayılar için girilen değerlerdeki virgül, nokta ile değiştirilir;
- 15. satır: [double1.val()] ifadesi, [double1] düğümü için girilen karakter dizisini oluşturur. [double1.val().replace(",", ".")] ifadesi ise bu dizideki virgülleri noktalara dönüştürür. Sonuç, [value1] dizesidir;
- 16. satır: [double1.val(value1)] komutu, [double1] düğümüne [value1] değerini atar.
Teknik olarak, kullanıcı gerçek değer olan [double1] yerine [10,37]'i girmişse, önceki talimatların ardından [double1] düğümü [10.37] değerine sahip olur ve gönderilecek değer [param1=val1&double1=10.37¶m2=val2] olur; bu değer sunucu tarafından kabul edilir;
- 22. satır: Formdaki [submit]'in çalışması için [true] değerini döndürürüz;
Şunu unutmayalım: jS [postForm01] işlevi:
- istemci tarafında doğrulama etkinse formdaki tüm jS doğrulayıcılarını çalıştırır ve girilen değerlerden herhangi biri geçersiz olarak bildirildiyse formdaki [submit]'in sunucuya gönderilmesini engeller;
- [submit] komutunun çalışmasına izin verir; bunun nedeni, istemci tarafında doğrulamanın etkin olmaması ya da etkin olmasına rağmen girilen tüm değerlerin geçerli olmasıdır;
Geriye [3] satırındaki komut kalır:
// sunucudaki hatalar siliniyor
clearServerErrors();
[clearServerErrors] işlevinin amacı, [vue-01.xml] görünümünün 4. sütununda bulunan mesajları silmektir:
![]() |
Yukarıdaki ekran görüntüsünde, [English] bağlantısına tıklandığında, jS doğrulama kuralları tetiklenmeden girilen değerlerin POST olarak kaydedildiğini gördük. POST işlevi geri döndüğünde, [Server Validation] sütununa varsa hata mesajları yazılır. Şimdi, jS ve [3] doğrulayıcıları etkin durumdayken [Validate] [2] düğmesine tıklarsak, o zaman [Client Validation] ve [4] sütunları mesajlarla doldurulur. Herhangi bir işlem yapılmazsa, [Server Validation] sütununda bulunanlar kalacak ve bu durum karışıklığa yol açacaktır; çünkü jS doğrulayıcıları tarafından tespit edilen hatalarda sunucuya yük binmez. Bunu önlemek için, [postForm01] işlevinde [Server Validation] sütununu siliyoruz. Bu işi yapan işlev []'dir:
function clearServerErrors() {
// sunucudaki hata mesajları siliniyor
$(".error").each(function(index) {
$(this).text("");
});
}
Hata mesajlarının bir özelliği, hepsinin [error] sınıfına ait olmasıdır. Örneğin, [vue-01.html]'teki tablonun ilk satırı için:
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
Ve DOM'teki bu sınıfa sahip tek düğümler bunlardır. Bu özelliği [clearServerErrors] işlevinde kullanıyoruz:
function clearServerErrors() {
// sunucudaki hata mesajlarını sil
$(".error").each(function(index) {
$(this).text("");
});
}
- 3. satır: [$(".error")] ifadesi, DOM'teki [error] sınıfına sahip düğümlerin koleksiyonunu döndürür;
- 3. satır: [$(".error").each(function(index){f}] ifadesi, koleksiyondaki her bir düğüm için [f] işlevini çalıştırır. Bu işlev, burada kullanılmayan [index] parametresini alır; bu parametre, koleksiyondaki düğümün numarasıdır;
- 4. satır: [$(this)] ifadesi, yinelemedeki geçerli düğümü belirtir. Bu düğüm, HTML <span> etiketidir. [$(this).text("")] ifadesi, <span> etiketi tarafından görüntülenen metne boş bir dize atar;
Şimdi çeşitli jS doğrulayıcılarını inceleyeceğiz.
6.3.8. [required] Doğrulayıcısı
Formun ilk öğesini inceleyelim:
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki dizilim tarafından oluşturulur:
<!-- gerekli -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [strNotEmpty] alanıyla ilgilidir:
@NotNull
@NotBlank
private String strNotEmpty;
[1-2] kısıtlamaları gereği, [strNotEmpty] alanı, [NotNull] gibi mevcut bir dize olmalı, boş olmamalı ve [NotBlank] gibi yalnızca boşluklardan oluşmamalıdır. Bu kısıtlamayı JavaScript kullanarak istemci tarafında da uygulamak istiyoruz.
5. ve 8. satırları inceleyelim. 11. satırda bir sorun yok. Bu satır, [strNotEmpty] alanıyla ilgili hata mesajını görüntülüyor. Önce 5. satırdan başlayalım:
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
Bu koddan yola çıkarak Thymeleaf şu etiketi oluşturacaktır:
<input type="text" data-val="true" data-val-required="Field is required" id="strNotEmpty" name="strNotEmpty" value="x" />
- [data-val='true'] özniteliği, jQuery doğrulama kütüphaneleri tarafından kullanılır. Bu özniteliğin varlığı, düğümün değerinin doğrulamaya tabi tutulduğunu gösterir;
- [data-val-X='msg'] özniteliği iki bilgi verir. [X], doğrulayıcının adıdır; [msg] ise, doğrulayıcının uygulandığı düğümün geçersiz bir değerine ilişkin hata mesajıdır. Bu sadece bir bilgidir. Hata mesajının görüntülenmesine neden olmaz;
- [required], Microsoft’un [jquery.validate.unobstrusive] doğrulama kütüphanesi tarafından tanınan bir doğrulayıcıdır. Bunu tanımlamaya gerek yoktur. Ancak ilerleyen bölümlerde her zaman böyle olmayacaktır;
- [data-x] etiketleri, HTML5 tarafından yok sayılır. Bunlar, yalnızca bunları kullanacak bir JavaScript varsa işe yarar;
Şimdi 8. satırı inceleyelim:
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
Bu satır, [required] doğrulayıcısının hata mesajını görüntülemek için kullanılır. Hata varsa, jS doğrulama kütüphanesi, tablodaki HTML satırını dinamik olarak aşağıdaki kodla değiştirecektir:
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" id="strNotEmpty" name="strNotEmpty" value="" aria-required="true" aria-invalid="true" aria-describedby="strNotEmpty-error" class="input-validation-error">
</td>
<td class="col3">
<span class="field-validation-error" data-valmsg-for="strNotEmpty" data-valmsg-replace="true">
<span id="strNotEmpty-error" class="">Le champ est obligatoire</span>
</span>
</td>
<td class="col4">
<span class="error"></span>
</td>
</tr>
</tr>
- 4. satır: [strNotEmpty] düğümünün sınıfı değişti. [input-validation-error] oldu; bu nedenle hatalı alan kırmızı renkle gösteriliyor;
- 7. satır: [span] düğümünün sınıfı değişti. [field-validation-error] oldu; bu da [span] düğümünün metninin kırmızı renkte görüntülenmesine neden olacak;
- 8. satır: Daha önce boş olan [span], artık [Le champ est obligatoire] metnine sahiptir. Bu metin, 4. satırdaki [data-val-required="Le champ est obligatoire"] etiketinden gelmektedir;
- 7. satır: 4. satırdaki [strNotEmpty] düğümünün hata mesajını görüntülemek için, 7. satırda [data-valmsg-for="strNotEmpty"] ve [data-valmsg-replace="true"] özniteliklerini kullanmanız gerekir;
6.3.9. [assertfalse] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki sıra ile oluşturulur:
<!-- gerekli, assertfalse -->
<tr>
<td class="col1">required, assertfalse</td>
<td class="col2">
<input type="radio" th:field="*{assertFalse}" value="true" data-val="true"
th:attr="data-val-required=#{NotNull},data-val-assertfalse=#{AssertFalse}" />
<label th:for="${#ids.prev('assertFalse')}">true</label>
<input type="radio" th:field="*{assertFalse}" value="false" data-val="true"
th:attr="data-val-required=#{NotNull},data-val-assertfalse=#{AssertFalse}" />
<label th:for="${#ids.prev('assertFalse')}">false</label>
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="assertFalse" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('assertFalse')}" th:errors="*{assertFalse}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [assertFalse] alanıyla ilgilidir:
@NotNull
@AssertFalse
private Boolean assertFalse;
Bu kısıtlamayı istemci tarafında JavaScript ile uygulamak istiyoruz. 12-17. satırlar artık standart hale gelmiştir:
- 12-14. satırlar: [assertFalse] alanında bir hata olması durumunda, 6. satırdaki [data-val-assertfalse] özniteliğinde bulunan mesajı veya aynı satırdaki [data-val-required] özniteliğinde bulunan mesajı görüntüler. Bu mesajların yerelleştirilmiş olduğunu, yani kullanıcı tarafından önceden seçilen dilde veya herhangi bir seçim yapılmamışsa Fransızca olarak görüntüleneceğini hatırlatırız;
- 5-10. satırlar: Kullanıcı bunlardan birine tıkladığında tetiklenen JavaScript doğrulayıcıları içeren radyo düğmelerini görüntüler.
Her iki düğme de aynı şekilde oluşturulmuştur. İlkini inceleyelim:
<input type="radio" th:field="*{assertFalse}" value="true" data-val="true" th:attr="data-val-required=#{NotNull},data-val-assertfalse=#{AssertFalse}" />
Thymeleaf tarafından işlendikten sonra bu satır şu hale gelir:
<input type="radio" value="true" data-val="true" data-val-required="Le champ est obligatoire" data-val-assertfalse="Seule la valeur False est acceptée" id="assertFalse1" name="assertFalse" />
[data-val="true"] adlı doğrulayıcılarımız var. Bunlardan iki tane var. Biri [required] [data-val-required="Le champ est obligatoire"], diğeri ise [assertfalse] [data-val-assertfalse="Seule la valeur False est acceptée"] adlı doğrulayıcı. [data-val-X] özniteliğinin değeri, X doğrulayıcısının hata mesajıdır.
[required] doğrulayıcısını daha önce görmüştük. Buradaki yenilik, girilen bir değere birden fazla doğrulayıcı ekleyebilmemizdir. [required] doğrulayıcısı, MS (Microsoft) doğrulama kütüphanesinde tanınıyor olsa da, [assertFalse] doğrulayıcısı için durum böyle değildir. Bu nedenle, yeni bir doğrulayıcı oluşturmayı öğreneceğiz. Birkaç tane oluşturacağız ve bunlar [client-validation.js] adlı bir dosyaya yerleştirilecek:
![]() |
Bu dosya, diğerleri gibi, [vue-01.xml] görünümü tarafından içe aktarılır (aşağıdaki 6. satır):
<head>
<title>Spring 4 MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/form01.css" />
...
<script type="text/javascript" src="/js/client-validation.js"></script>
...
</head>
[assertfalse] doğrulayıcısının eklenmesi, aşağıdaki iki jS işlevinin oluşturulmasıyla gerçekleşir:
// -------------- assertfalse
$.validator.addMethod("assertfalse", function(value, element, param) {
return value === "false";
});
$.validator.unobtrusive.adapters.add("assertfalse", [], function(options) {
options.rules["assertfalse"] = options.params;
options.messages["assertfalse"] = options.message.replace("''", "'");
});
Dürüst olmak gerekirse, benim için hâlâ tam anlamıyla bir muamma olan JavaScript konusunda uzman değilim. Temelleri basit olsa da, bu temeller üzerine kurulu kütüphaneler genellikle oldukça karmaşıktır. Yukarıdaki kod satırlarını yazarken, internette bulduğum kodlardan ilham aldım. Bana yol gösteren bağlantı [http://jsfiddle.net/LDDrk/] oldu. Hâlâ mevcutsa, okuyucuların bu bağlantıya göz atmasını öneririm çünkü çalışır durumda bir örnek de içeren kapsamlı bir kaynaktır. Bu kaynak, yeni bir doğrulayıcının nasıl oluşturulacağını gösterir ve bu bölümdeki tüm doğrulayıcıları oluşturmamı sağladı. Kodumuza geri dönelim:
- 2-4. satırlar: yeni doğrulayıcıyı tanımlar. [$.validator.addMethod] işlevi, birinci parametre olarak doğrulayıcının adını, ikinci parametre olarak da onu tanımlayan bir işlevi bekler;
- 2. satır: işlevin üç parametresi vardır:
- [value]: doğrulanacak değer. Değer geçerliyse işlev [true] değerini, aksi takdirde [false] değerini döndürmelidir,
- [element]: Doğrulanacak değerin ait olduğu HTML öğesi,
- [param]: bir doğrulayıcının parametreleriyle ilişkili değerleri içeren bir nesne. Bu kavramı henüz ele almadık. Burada [assertFalse] doğrulayıcısının herhangi bir parametresi yoktur. [value] değerinin geçerli olup olmadığı, ek bilgilere gerek kalmadan belirlenebilir. Ancak [value] değerinin [min, max] aralığında bir gerçek sayı olup olmadığını kontrol etmek gerekseydi, durum farklı olurdu. Bu durumda, [min] ve [max] değerlerini bilmemiz gerekir. Bu iki değere doğrulayıcının parametreleri denir;
- 6-9. satırlar: MS doğrulama kütüphanesi için gerekli bir işlev. [$.validator.unobtrusive.adapters.add] işlevi, birinci parametre olarak doğrulayıcının adını, ikinci parametre olarak doğrulayıcının parametre dizisini, üçüncü parametre olarak ise bir işlevi bekler;
- [assertFalse] doğrulayıcısının parametresi yoktur. Bu nedenle ikinci parametre boş bir dizidir;
- fonksiyonun tek bir parametresi vardır: doğrulanacak öğeyle ilgili bilgileri içeren bir [options] nesnesi; bu nesne için [rules] ve [messages] adlı iki yeni özellik tanımlanmalıdır;
- 7. satır: [assertFalse] doğrulayıcısı için [rules] kuralları tanımlanmaktadır. Bu kurallar, [assertFalse] doğrulayıcısının parametreleridir ve 2. satırdaki [param] parametresininkilerle aynıdır. Bu parametreler [options.params] içinde bulunur;
- 8. satır: [assertFalse] doğrulayıcısının hata mesajını tanımlar. Bu, [options.message] içinde bulunur. Hata mesajlarıyla ilgili şu zorlukla karşılaşıyoruz. Mesaj dosyalarında şu mesajı bulacağız:
Range.form01.int1014=La valeur doit être dans l''intervalle [10,14]
Çift tırnak işareti, Thymeleaf için gereklidir. Thymeleaf bunu tek tırnak işareti olarak yorumlar. Tek tırnak işareti kullanılırsa, Thymeleaf tarafından görüntülenmez. Şimdi bu mesajlar, MS doğrulama kütüphanesi için de hata mesajları olarak kullanılacak. Ancak JavaScript, bu mesajlarda iki tırnak işareti gösterecektir. 8. satırda, hata mesajındaki çift apostrofu tek apostrofla değiştiriyoruz.
Neler olduğunu biraz görmek için, jS kütüphanesinden bir log kodu ekleyebiliriz:
// günlükler
var logs = {
assertfalse : true
}
// -------------- assertfalse
$.validator.addMethod("assertfalse", function(value, element, param) {
// günlükler
if (logs.assertfalse) {
console.log(jSON.stringify({
"[assertfalse] value" : value
}));
console.log("[assertfalse] element");
console.log(element);
console.log(jSON.stringify({
"[assertfalse] param" : param
}));
}
// geçerlilik testi
return value === "false";
});
$.validator.unobtrusive.adapters.add("assertfalse", [], function(options) {
// günlükler
if (logs.assertfalse) {
console.log(jSON.stringify({
"[assertfalse] options.params" : options.params
}));
console.log(jSON.stringify({
"[assertfalse] options.message" : options.message
}));
console.log(jSON.stringify({
"[assertfalse] options.messages" : options.messages
}));
}
// kod
options.rules["assertfalse"] = options.params;
options.messages["assertfalse"] = options.message.replace("''", "'");
});
Bu kod, jSON JSON3 [http://bestiejs.github.io/json3/] kütüphanesini kullanır. Günlükleri etkinleştirirsek (3. satır), konsolda şu çıktılar elde edilir:
Sayfa ilk yüklendiğinde şu günlük kayıtları görülür:
jS [$.validator.unobtrusive.adapters.add] işlevi çalıştırıldı. Şu bilgiler elde edilir:
- [options.params], [assertFalse] doğrulayıcısının herhangi bir parametresi olmadığı için boş bir nesnedir;
- [options.message], [data-val-assertFalse] özniteliğinde [assertFalse] doğrulayıcısı için oluşturduğumuz hata mesajıdır;
- [options.messages], doğrulanmış öğenin diğer hata mesajlarını içeren bir nesnedir. Burada, [data-val-required] özniteliğine eklediğimiz hata mesajını buluyoruz;
Şimdi [assertFalse] alanına hatalı bir değer girelim ve doğrulama işlemini yapalım:
Böylece şu günlük kayıtları elde ederiz:
![]() |
Burada şunlar görülüyor:
- test edilen değer [true]'tir (118. satır);
- test edilen HTML öğesi, [assertFalse1] kimliğine sahip radyo düğmesidir (satır 122);
- [assertFalse] doğrulayıcısının herhangi bir parametresi yoktur (satır 123);
İşte bu kadar. Bütün bunlardan ne çıkarabiliriz?
Bir X jS doğrulayıcısı için şunları tanımlamamız gerekir:
- doğrulanacak HTML etiketinde, hem X doğrulayıcısını hem de hata mesajını tanımlayan [data-val-X='msg'] özniteliğini;
- [client-validation.js] dosyasına eklenecek iki jS işlevi:
- [$.validator.addMethod("X", function(value, element, param)],
- [$.validator.unobtrusive.adapters.add("X", [param1, param2], function(options)] ;
Bundan sonra, bu ilk doğrulayıcı için yapılanlara dayanarak sadece yeni olanları sunacağız.
6.3.10. [asserttrue] Doğrulayıcı
Bu doğrulayıcı, elbette [assertFalse] doğrulayıcısına benzerdir.
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki dizilim tarafından oluşturulur:
<!-- gerekli, asserttrue -->
<tr>
<td class="col1">asserttrue</td>
<td class="col2">
<select th:field="*{assertTrue}" data-val="true" th:attr="data-val-asserttrue=#{AssertTrue}">
<option value="true">True</option>
<option value="false">False</option>
</select>
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="assertTrue" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('assertTrue')}" th:errors="*{assertTrue}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [assertTrue] alanıyla ilgilidir:
@NotNull
@AssertTrue
private Boolean assertTrue;
1-16. satırlarda yeni bir şey yoktur. Bu satırlar, [client-validation.js] dosyasında tanımlanması gereken [asserrtrue] doğrulayıcısını kullanır:
// -------------- asserttrue
$.validator.addMethod("asserttrue", function(value, element, param) {
return value === "true";
});
$.validator.unobtrusive.adapters.add("asserttrue", [], function(options) {
options.rules["asserttrue"] = options.params;
options.messages["asserttrue"] = options.message.replace("''", "'");
});
6.3.11. [date] ve [past] doğrulayıcıları
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki sıra tarafından oluşturulur:
<!-- gerekli, tarih, geçmiş -->
<tr>
<td class="col1">required, date, past</td>
<td class="col2">
<input type="date" th:field="*{dateInPast}" th:value="*{dateInPast}" data-val="true"
th:attr="data-val-required=#{NotNull},data-val-date=#{DateInvalide.form01},data-val-past=#{Past.form01.dateInPast}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="dateInPast" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('dateInPast')}" th:errors="*{dateInPast}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [dateInPast] alanıyla ilgilidir:
@NotNull
@Past
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateInPast;
Tarih doğrulayıcılarının satırı şöyledir:
<input type="date" th:field="*{dateInPast}" th:value="*{dateInPast}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-date=#{DateInvalide.form01},data-val-past=#{Past.form01.dateInPast}" />
Burada üç adet [data-val-X] doğrulayıcısı bulunmaktadır: required, date, past. [client-validation.js] dosyasında bu iki yeni doğrulayıcıyla ilişkili işlevleri tanımlamamız gerekiyor:
logs.date = true;
// -------------- tarih
$.validator.addMethod("date", function(value, element, param) {
// geçerlilik
var valide = Globalize.parseDate(value, "yyyy-MM-dd") != null;
// günlükler
if (logs.date) {
console.log(jSON.stringify({
"[date] value" : value,
"[date] valide" : valide
}));
}
// sonuç
return valide;
});
$.validator.unobtrusive.adapters.add("date", [], function(options) {
options.rules["date"] = options.params;
options.messages["date"] = options.message.replace("''", "'");
});
ve
logs.past = true;
// -------------- geçmiş
$.validator.addMethod("past", function(value, element, param) {
// geçerlilik
var valide = value <= new Date().toISOString().substring(0, 10);
// günlükler
if (logs.past) {
console.log(jSON.stringify({
"[past] value" : value,
"[past] valide" : valide
}));
}
// sonuç
return valide;
});
$.validator.unobtrusive.adapters.add("past", [], function(options) {
options.rules["past"] = options.params;
options.messages["past"] = options.message.replace("''", "'");
});
Kodu açıklamadan önce, bugünden sonraki bir tarih girdiğimizde ortaya çıkan günlük kayıtlarına bir göz atalım:
İlk dikkat çeken nokta, doğrulanacak tarihin [aaaa-mm-jj] biçiminde bir karakter dizisi olarak gelmesidir. Bu da aşağıdaki satırları açıklıyor:
var valide = Globalize.parseDate(value, "yyyy-MM-dd") != null;
[globalize.js] kütüphanesi, yukarıdaki [Globalize.parseDate] işlevini sağlar. İlk parametre, karakter dizisi olarak tarih; ikinci parametre ise tarih formatıdır. Sonuç, tarih geçersizse bir null işaretçisi, aksi takdirde ise geçerli tarihtir.
[past] doğrulayıcısının geçerliliği aşağıdaki kodla kontrol edilir:
var valide = value <= new Date().toISOString().substring(0, 10);
Aşağıda, [new Date().toISOString().substring(0, 10)] ifadesinin bir konsolda değerlendirilmesi gösterilmektedir:
![]() |
[value] karakter dizisi, geçerli olabilmesi için alfabetik olarak [new Date().toISOString().substring(0, 10)] dizisinden önce gelmelidir.
Kullanılan Chrome sürümünün tarihi [yyyy-mm-dd] biçiminde gösterdiğine dikkat edilmelidir. Bu durumun geçerli olmadığı bir tarayıcıda, kullanıcıya bu giriş biçimini kullanması gerektiği açıkça belirtilmelidir.
6.3.12. [future] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki dizilim tarafından oluşturulur:
<!-- gerekli, tarih, gelecek -->
<tr>
<td class="col1">required, date, future</td>
<td class="col2">
<input type="date" th:field="*{dateInFuture}" th:value="*{dateInFuture}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-date=#{DateInvalide.form01},data-val-future=#{Future.form01.dateInFuture}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="dateInFuture" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('dateInFuture')}" th:errors="*{dateInFuture}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [dateInFuture] alanıyla ilgilidir:
@NotNull
@Future
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateInFuture;
- 5. satırda, yeni bir [data-val-future] doğrulayıcısı görünür;
Bu doğrulayıcı, elbette [past] doğrulayıcısına çok benziyor. [client-validation.js]'e eklenecek iki işlev şunlardır:
// -------------- gelecek
$.validator.addMethod("future", function(value, element, param) {
var now = new Date().toISOString().substring(0, 10);
return value > now;
});
$.validator.unobtrusive.adapters.add("future", [], function(options) {
options.rules["future"] = options.params;
options.messages["future"] = options.message.replace("''", "'");
});
6.3.13. [int] ve [max] doğrulayıcıları
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki sıra tarafından oluşturulur:
<!-- zorunlu, tamsayı, max(100) -->
<tr>
<td class="col1">required, int, max(100)</td>
<td class="col2">
<input type="text" th:field="*{intMax100}" th:value="*{intMax100}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-int=#{typeMismatch},data-val-max=#{Max.form01.intMax100},data-val-max-value=#{form01.intMax100.value}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="intMax100" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('intMax100')}" th:errors="*{intMax100}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [intMax100] alanıyla ilgilidir:
@NotNull
@Max(value = 100)
private Integer intMax100;
5. satırda iki yeni doğrulayıcı bulunmaktadır: [int] ve [max]. İkincisinin bir parametresi vardır: maksimum değer. 5. satır tarafından oluşturulan HTML kodunu inceleyelim:
<!-- zorunlu, int, max(100) -->
<tr>
<td class="col1">required, int, max(100)</td>
<td class="col2">
<input type="text" data-val="true" data-val-int="Format invalide" data-val-max-value="100" data-val-required="Le champ est obligatoire" data-val-max="La valeur doit être inférieure ou égale à 100" value="" id="intMax100" name="intMax100" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="intMax100" data-valmsg-replace="true"></span>
</td>
<td class="col4">
</td>
</tr>
[data-X]'in çeşitli özniteliklerinin anlamlarını hatırlayalım:
- [data-val="true"], HTML öğesine doğrulayıcıların atandığını gösterir;
- [data-val-required], [required] doğrulayıcısını mesajıyla birlikte tanıtır;
- [data-val-int], [int] doğrulayıcısını mesajıyla birlikte sunar;
- [data-val-max], [max] doğrulayıcısını mesajıyla birlikte ekler;
- [data-val-max-value="100"], [max] doğrulayıcısı için [value] adlı bir parametre ekler. [100] bu parametrenin değeridir. Bir doğrulayıcının parametreleri kavramıyla ilk kez karşılaşıyoruz.
[client-validation.js] dosyası, aşağıdaki [int] doğrulayıcısıyla zenginleştirilmiştir:
logs.int = true;
// -------------- tamsayı
$.validator.addMethod("int", function(value, element, param) {
// geçerlilik
valide = /^\s*[-\+]?\s*\d+\s*$/.test(value);
// günlükler
if (logs.int) {
console.log(jSON.stringify({
"[int] value" : value,
"[int] valide" : valide,
}));
}
// sonuç
return valide;
});
$.validator.unobtrusive.adapters.add("int", [], function(options) {
options.rules["int"] = options.params;
options.messages["int"] = options.message.replace("''", "'");
});
- 5. satır: [value] dizesinin gerçekten bir tamsayı olup olmadığını doğrulamak için bir düzenli ifade kullanılır. Bu tamsayı işaretli olabilir;
İşte birkaç günlük örneği:
[max] doğrulayıcısı, [client-validation.js]'e şu şekilde eklenir
// -------------- max, [int] veya [number] ile birlikte kullanılmalıdır
logs.max = true;
$.validator.addMethod("max", function(value, element, param) {
// günlükler
if (logs.max) {
console.log(jSON.stringify({
"[max] value" : value,
"[max] param" : param
}));
}
// geçerlilik
var val = Globalize.parseFloat(value);
if (isNaN(val)) {
// günlükler
if (logs.max) {
console.log(jSON.stringify({
"[max] valide" : true
}));
}
// sonuç
return true;
}
var max = Globalize.parseFloat(param.value);
var valide = val <= max;
// günlükler
if (logs.max) {
console.log(jSON.stringify({
"[max] valide" : valide
}));
}
// sonuç
return valide;
});
$.validator.unobtrusive.adapters.add("max", [ "value" ], function(options) {
options.rules["max"] = options.params;
options.messages["max"] = options.message.replace("''", "'");
});
Şimdi, [data-val-max-value="100"] özniteliği tarafından eklenen [max] doğrulayıcısının [value] parametresini ele alacağız.
- 35. satırda, [value] parametresi, [$.validator.unobtrusive.adapters.add] işlevinin ikinci parametresine eklenmiştir;
- 3. satırda, [param] nesnesi artık boş olmayacak, {"value":100} değerini içerecektir;
3-33. satırlardaki kodu anlamak için, aynı HTML öğesi üzerinde birden fazla doğrulayıcı olduğunda şunları bilmek gerekir:
- doğrulayıcıların yürütme sırası bilinmez;
- bir doğrulayıcı öğeyi geçersiz olarak bildirdiği anda doğrulayıcıların yürütülmesi durur. Bu durumda, geçersiz öğeye bu doğrulayıcının hata mesajı atanır;
Kodu inceleyelim:
- 12. satır: Bir sayı olup olmadığı kontrol edilir. [int] doğrulayıcısı, [max] doğrulayıcısından önce çalıştırılmışsa, geçersiz bir değer doğrulayıcıların çalışmasını durdurduğu için bu koşul mutlaka geçerlidir;
- 13-22. satırlar: Eğer bir sayı yoksa, bu, [int] doğrulayıcısının henüz çalıştırılmadığı anlamına gelir. Bu durumda, test edilen değerin geçerli olduğu belirtilir; böylece [int] doğrulayıcısının işini yapmasına ve kendi hata mesajıyla öğeyi geçersiz olarak bildirmesine olanak tanınır;
- 23-24. satırlar: [value]'in geçerliliğini hesaplar;
İşte bazı günlük kayıtları:
Girilen değer | günlükler |
| |
| |
|
6.3.14. [min] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki dizilim tarafından oluşturulur:
<!-- gerekli, int, min(10) -->
<tr>
<td class="col1">required, int, min(10)</td>
<td class="col2">
<input type="text" th:field="*{intMin10}" th:value="*{intMin10}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-int=#{typeMismatch},data-val-min=#{Min.form01.intMin10},data-val-min-value=#{form01.intMin10.value}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="intMin10" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('intMin10')}" th:errors="*{intMin10}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [intMin10] alanıyla ilgilidir:
@NotNull
@Min(value = 10)
private Integer intMin10;
5. satır, [min] [data-val-int=#{typeMismatch}] adlı yeni bir doğrulayıcıyı, [value] [data-val-min-value=#{form01.intMin10.value}"] parametresiyle ekler. Bu durum, [max] doğrulayıcısına benzer. [client-validation.js] dosyasına aşağıdaki kod eklenir:
logs.min = true;
//-------------- min, [int] veya [number] ile birlikte kullanılmalıdır
$.validator.addMethod("min", function(value, element, param) {
// günlükler
if (logs.min) {
console.log(jSON.stringify({
"[min] value" : value,
"[min] param" : param
}));
}
// geçerlilik
var val = Globalize.parseFloat(value);
if (isNaN(val)) {
// günlükler
if (logs.min) {
console.log(jSON.stringify({
"[min] valide" : true
}));
}
// sonuç
return true;
}
var min = Globalize.parseFloat(param.value);
var valide = val >= min;
// günlükler
if (logs.min) {
console.log(jSON.stringify({
"[min] valide" : valide
}));
}
// sonuç
return valide;
});
$.validator.unobtrusive.adapters.add("min", [ "value" ], function(options) {
options.rules["min"] = options.params;
options.messages["min"] = options.message.replace("''", "'");
});
İşte bazı çalıştırma günlükleri:
Girilen değer | günlükler |
| |
| |
|
6.3.15. [regex] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki dizilim tarafından oluşturulur:
<!-- gerekli, regex -->
<tr>
<td class="col1">required, regex</td>
<td class="col2">
<input type="text" th:field="*{strBetween4and6}" th:value="*{strBetween4and6}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-regex=#{Size.form01.strBetween4and6}, data-val-regex-pattern=#{form01.strBetween4and6.pattern}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strBetween4and6" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strBetween4and6')}" th:errors="*{strBetween4and6}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [strBetween4and6] alanıyla ilgilidir:
@NotNull
@Size(min = 4, max = 6)
private String strBetween4and6;
5. satır, aşağıdaki HTML'i oluşturur:
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" data-val-regex="La chaîne doit avoir entre 4 et 6 caractères" data-val-regex-pattern="^.{4,6}$" value="" id="strBetween4and6" name="strBetween4and6" />
Bu etiket, [regex] [data-val-regex="La chaîne doit avoir entre 4 et 6 caractères"] doğrulayıcısını, [pattern] [data-val-regex-pattern="^.{4,6}$"] parametresiyle birlikte ekler. [pattern] parametresi, doğrulanacak değerin uyması gereken düzenli ifadedir. Burada düzenli ifade, dizenin 4 ile 6 arasında herhangi bir karakterden oluştuğunu doğrular. [regex] doğrulayıcısı, MS doğrulama kütüphanesinde önceden tanımlanmıştır. Dolayısıyla [client-validation.js] dosyasına eklenecek bir şey yoktur.
6.3.16. [email] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki sıra tarafından oluşturulur:
<!-- gerekli, e-posta -->
<tr>
<td class="col1">required, email</td>
<td class="col2">
<input type="text" th:field="*{email}" th:value="*{email}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-email=#{Email.form01.email}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="email" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [email] alanıyla ilgilidir:
@NotNull
@Email
@NotBlank
private String email;
- satır, aşağıdaki HTML satırını oluşturur:
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" data-val-email="Adresse mail invalide" value="" id="email" name="email" />
Bu etiket, [email] [data-val-email="Adresse mail invalide"] doğrulayıcısını başlatır. [email] doğrulayıcısı, MS doğrulama kütüphanesinde önceden tanımlanmıştır. Dolayısıyla, [client-validation.js] dosyasına eklenecek bir şey yoktur.
6.3.17. [range] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki sıra tarafından oluşturulur:
<!-- gerekli, tamsayı, aralık (10,14) -->
<tr>
<td class="col1">required, int, range (10,14)</td>
<td class="col2">
<input type="text" th:field="*{int1014}" th:value="*{int1014}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-int=#{typeMismatch}, data-val-range=#{Range.form01.int1014},data-val-range-max=#{form01.int1014.max},data-val-range-min=#{form01.int1014.min}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="int1014" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('int1014')}" th:errors="*{int1014}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [int1014] alanıyla ilgilidir:
@Range(min = 10, max = 14)
@NotNull
private Integer int1014;
- satır, aşağıdaki HTML satırını oluşturur:
<input type="text" data-val="true" data-val-range-max="14" data-val-range="La valeur doit être dans l''intervalle [10,14]" data-val-int="Format invalide" data-val-required="Le champ est obligatoire" data-val-range-min="10" value="" id="int1014" name="int1014" />
Bu etiket, iki parametreye sahip yeni bir [range] [data-val-range="La valeur doit être dans l''intervalle [10,14]"] adlı yeni bir doğrulayıcı ekler; bu doğrulayıcının iki parametresi vardır: [min] [data-val-range-min="10"] ve [max] [data-val-range-max="14"].
[client-validation.js] dosyasında, [range] doğrulayıcısını şu şekilde tanımlıyoruz:
// -------------- aralık, [int] veya [number] ile birlikte kullanılmalıdır
logs.range=true
$.validator.addMethod("range", function(value, element, param) {
// günlükler
if (logs.range) {
console.log(jSON.stringify({
"[range] value" : value,
"[range] param" : param
}));
}
// geçerlilik
var val = Globalize.parseFloat(value);
if (isNaN(val)) {
// günlükler
if (logs.min) {
console.log(jSON.stringify({
"[range] valide" : true
}));
}
// tamamlandı
return true;
}
var min = Globalize.parseFloat(param.min);
var max = Globalize.parseFloat(param.max);
var valide = val >= min && val <= max;
// günlükler
if (logs.range) {
console.log(jSON.stringify({
"[range] valide" : valide
}));
}
// tamamlandı
return valide;
});
$.validator.unobtrusive.adapters.add("range", [ "min", "max" ], function(options) {
options.rules["range"] = options.params;
options.messages["range"] = options.message.replace("''", "'");
});
Bu, daha önce incelediğimiz [min] ve [max] doğrulayıcılarına çok benzemektedir.
İşte birkaç günlük örneği:
Girilen değer | günlükler |
| |
| |
|
6.3.18. [number] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki dizilim tarafından oluşturulur:
<!-- double1 : zorunlu, sayı, aralık (2,3; 3,4) -->
<tr>
<td class="col1">double1 : required, number, range (2.3,3.4)</td>
<td class="col2">
<input type="text" th:field="*{double1}" th:value="*{double1}" data-val="true"
th:attr="data-val-required=#{NotNull},data-val-number=#{typeMismatch},data-val-range=#{Range.form01.double1},data-val-range-max=#{form01.double1.max},data-val-range-min=#{form01.double1.min}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="double1" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('double1')}" th:errors="*{double1}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [double1] alanıyla ilgilidir:
@NotNull
@DecimalMax(value = "3.4")
@DecimalMin(value = "2.3")
private Double double1;
- satır, aşağıdaki HTML satırını oluşturur:
<input type="text" data-val="true" data-val-number="Format invalide" data-val-range-max="3.4" data-val-range="La valeur doit être dans l'intervalle [2,3-3,4]" data-val-required="Le champ est obligatoire" data-val-range-min="2.3" value="" id="double1" name="double1" />
Etiket, [data-val-number="Format invalide"] özniteliğine sahip yeni bir [number] doğrulayıcısı ekler. Bu doğrulayıcı, [client-validation.js] dosyasında şu şekilde tanımlanmıştır:
// -------------- sayı
logs.number = true;
$.validator.addMethod("number", function(value, element, param) {
var valide = !isNaN(Globalize.parseFloat(value));
// günlükler
if (logs.number) {
console.log(jSON.stringify({
"[number] value" : value,
"[number] valide" : valide
}));
}
// sonuç
return valide;
});
$.validator.unobtrusive.adapters.add("number", [], function(options) {
options.rules["number"] = options.params;
options.messages["number"] = options.message.replace("''", "'");
});
İşte birkaç günlük örneği:
Girilen değer | günlükler |
Gerçek sayıların kültüre bağlı olduğu bilinmektedir. Yukarıda, [fr-FR] kültüründeyiz. [2.5] (İngilizce notasyon) girildiğinde sayı kabul edilir. Bunun nedeni, her iki notasyonu da kabul eden [Globalize.parseFloat]'tir:
İngilizceye geçip [+2,5] ve [+2.5] girişlerini yapalım. Günlük kayıtları şu şekildedir:
Girilen değer | günlükler |
[2,5] ile ilgili bir sorun var. [2.5] yazılması gerekirken, bu değer geçerli bir değişken olarak bildirilmiş. Bunun nedeni [Globalize.parseFloat]'tir:
Yukarıda, [Globalize.parseFloat] virgülü yok sayıyor ve sayının 25 olduğunu varsayıyor. [en-US] kültüründe, bir gerçek sayı ondalık nokta ve bazen binleri ayırmak için kullanılan virgüller içerebilir.
Durumu şu şekilde iyileştirebiliriz:
// -------------- sayı
logs.number = true;
$.validator.addMethod("number", function(value, element, param) {
// Yalnızca [fr-FR] ve [en-US] türleri yönetilir
var pattern_fr_FR = /^\s*[-+]?[0-9]*\,?[0-9]+\s*$/;
var pattern_en_US = /^\s*[-+]?[0-9]*\.?[0-9]+\s*$/;
var culture = Globalize.culture().name;
// geçerlilik testi
var valide;
if (culture === "fr-FR") {
valide = pattern_fr_FR.test(value);
} else if (culture === "en-US") {
valide = pattern_en_US.test(value);
} else {
valide = !isNaN(Globalize.parseFloat(value));
}
// günlükler
if (logs.number) {
console.log(jSON.stringify({
"[number] value" : value,
"[number] culture" : culture,
"[number] valide" : valide
}));
}
// sonuç
return valide;
});
- 5. satır: [fr-FR] kültürü için bir gerçek sayının düzenli ifadesi;
- 6. satır: [en-US] kültürü için bir gerçek sayının düzenli ifadesi;
- 7. satır: o anki kültürün adı. Örneğimizde, bu yukarıdaki iki kültürden biri olacaktır;
- satır 9-16: girilen değerin geçerlilik testi;
- 15. satır: Kültürün ne [fr-FR] ne de [en-US] olması durumu için önlem alınmıştır;
Günlükler artık şu şekilde görünmektedir:
Kültür [fr-FR]
Girilen değer | günlükler |
| |
| |
| |
|
Kültür [en-US]
Girilen değer | günlükler |
| |
| |
|
6.3.19. [custom3] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki dizilim tarafından oluşturulur:
<!-- double3: zorunlu, sayı, custom3 -->
<tr>
<td class="col1">double3 : required, number, custom3</td>
<td class="col2">
<input type="text" th:field="*{double3}" th:value="*{double3}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-number=#{typeMismatch},data-val-custom3=${custom3.message},data-val-custom3-field=${custom3.otherFieldName},data-val-custom3-max=${custom3.max},data-val-custom3-min=${custom3.min}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="double3" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('double3')}" th:errors="*{double3}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [double3] alanıyla ilgilidir:
@NotNull
private Double double3;
Burada, girilen bir değeri değil, girilen iki değer arasındaki ilişkiyi doğrulayan bir doğrulayıcıyı inceleyeceğiz. Burada, [double1+double3]'in [10,13] aralığında olmasını istiyoruz.
- satır, aşağıdaki HTML satırını oluşturur:
<input type="text" data-val="true" data-val-custom3-min="10.0" data-val-number="Invalid format"
data-val-custom3="[double3+double1] must be in [10,13]" data-val-custom3-max="13.0" data-val-custom3-field="double1" data-val-required="Field is required" value="" id="double3" name="double3" />
Bu satır, [data-val-custom3="[double3+double1] must be in [10,13]"] özniteliği ile bildirilen yeni [custom3] doğrulayıcısını ekler. Bu doğrulayıcının parametreleri şunlardır:
- [field], [data-val-custom3-field="double1"] özniteliği ile tanımlanmıştır. Bu parametre, [double3]'in geçerliliğinin hesaplanmasında değeri kullanılan alanı belirtir;
- [min], [data-val-custom3-min="10.0"] özniteliği tarafından tanımlanmıştır. Bu parametre, [min, max] aralığının en küçük değeridir ve [double1+double3] bu aralıkta yer almalıdır;
- [max], [data-val-custom3-max="13.0"] özniteliği ile tanımlanmıştır. Bu parametre, [double1+double3]'in içinde bulunması gereken [min, max] aralığının üst sınırıdır;
Bu doğrulayıcı, [client-validation.js] içinde şu şekilde yönetilir:
// -------------- custom3, [number] ile birlikte kullanılır
logs.custom3 = true;
$.validator.addMethod("custom3", function(value1, element, param) {
// ikinci değer
var value2 = $("#" + param.field).val();
// günlükler
if (logs.custom3) {
console.log(jSON.stringify({
"[custom3] value1" : value1,
"[custom3] param" : param,
"[custom3] value2" : value2
}))
}
// ilk değer
var valeur1 = Globalize.parseFloat(value1);
if (isNaN(valeur1)) {
// işi [number] doğrulayıcısına bırakıyoruz
if (logs.custom3) {
console.log(jSON.stringify({
"[custom3] valide" : true
}))
}
return true;
}
// ikinci değer
var valeur2 = Globalize.parseFloat(value2);
if (isNaN(valeur2)) {
// geçerlilik hesaplaması yapılamıyor
if (logs.custom3) {
console.log(jSON.stringify({
"[custom3] valide" : false
}))
}
return false;
}
// geçerlilik hesaplaması
var min = Globalize.parseFloat(param.min);
var max = Globalize.parseFloat(param.max);
var somme = valeur1 + valeur2;
var valide = somme >= min && somme <= max;
// günlükler
if (logs.custom3) {
console.log(jSON.stringify({
"[custom3] valide" : valide
}))
}
// sonuç
return valide;
});
$.validator.unobtrusive.adapters.add("custom3", [ "field", "max", "min" ], function(options) {
options.rules["custom3"] = options.params;
options.messages["custom3"] = options.message.replace("''", "'");
});
İşte birkaç günlük örneği:
Girilen değerler [double1,double3] | günlükler |
| |
| |
| |
|
6.3.20. [url] Doğrulayıcı
![]() |
[1] satırı, [vue-01.xml] görünümündeki aşağıdaki dizilim tarafından oluşturulur:
<!-- gerekli, url -->
<tr>
<td class="col1">required, url</td>
<td class="col2">
<input type="text" th:field="*{url}" th:value="*{url}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-url=#{URL.form01.url}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="url" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('url')}" th:errors="*{url}" class="error">Donnée erronée</span>
</td>
</tr>
Bu satırlar, [Form01] formundaki [url] alanıyla ilgilidir:
@URL
@NotBlank
private String url;
- satır, aşağıdaki HTML satırını oluşturur:
<input type="text" data-val="true" data-val-url="Invalid URL" data-val-required="Field is required" value="" id="url" name="url" />
Bu satır, [data-val-url] özniteliğine sahip [url] doğrulayıcısını ekler. Bu doğrulayıcı, jQuery doğrulama kütüphanesinde önceden tanımlanmıştır. [client-validation.js]'e eklenecek bir şey yoktur.
6.3.21. İstemci Tarafında Doğrulamanın Etkinleştirilmesi / Devre Dışı Bırakılması
İstemci tarafında doğrulama etkin olduğu sürece, sunucu tarafında doğrulama hiçbir zaman görünmez; çünkü gönderilen değerler, yalnızca istemci tarafında geçerli olarak onaylandıkları takdirde sunucuya ulaşır. Sunucu tarafında doğrulamanın işlediğini görmek için istemci tarafında doğrulamayı devre dışı bırakmak gerekir. [vue-01.xml] görünümü, bu etkinleştirme/devre dışı bırakma işlemini yönetmek için iki bağlantı sunar:
<a id="clientValidationTrue" href="javascript:setClientValidation(true)">
<span style="margin-left:30px" th:text="#{client.validation.true}"></span>
</a>
<a id="clientValidationFalse" href="javascript:setClientValidation(false)">
<span style="margin-left:30px" th:text="#{client.validation.false}"></span>
</a>
Bu iki bağlantı aynı anda görünmez:
![]() | ![]() |
Bu bağlantıların HTML çevirisi şöyledir:
<a id="clientValidationTrue" href="javascript:setClientValidation(true)">
<span style="margin-left:30px">Activer la validation client</span>
</a>
<a id="clientValidationFalse" href="javascript:setClientValidation(false)">
<span style="margin-left:30px">Inhiber la validation client</span>
</a>
jS [setClientValidation] komut dosyası, [local.js] dosyasında tanımlanmıştır (yukarıya bakınız). Bu dosyanın [$(document).ready] işlevinde, doğrulama bağlantıları kullanılır:
// belge hazır
$(document).ready(function() {
// genel referanslar
...
activateValidationTrue = $("#clientValidationTrue");
activateValidationFalse = $("#clientValidationFalse");
clientValidation = $("#clientValidation");
...
// doğrulama bağlantıları
// clientValidation, sunucu tarafından konumlandırılan gizli bir alandır
var validate = clientValidation.val();
setClientValidation2(validate === "true");
});
- 5. satır: istemci tarafındaki doğrulama etkinleştirme bağlantısına bir referans;
- 6. satır: istemci tarafındaki doğrulama devre dışı bırakma bağlantısına bir referans;
- 7. satır: etkinleştirmenin son durumunu boole değeri biçiminde saklayan, formdaki gizli bir alana referans [true : validation client activée, false : validation client désactivée]. Bu alan, [vue-01.xml] görünümünde şu şekilde yer almaktadır:
<input type="hidden" th:field="*{clientValidation}" th:value="*{clientValidation}" value="true" />
ve [Form01] formundaki [clientValidation] alanına karşılık gelir:
// istemci doğrulaması
private boolean clientValidation = true;
- 11. satır: gizli alanın değeri alınır;
- 12. satır: Aşağıdaki [setClientValidation2] işlevi çağrılır:
function setClientValidation2(activate) {
// bağlantılar
if (activate) {
// istemci tarafında doğrulama etkindir
activateValidationTrue.hide();
activateValidationFalse.show();
// formdaki doğrulama kuralları ayrıştırılıyor
$.validator.unobtrusive.parse(formulaire);
} else {
// istemci tarafı doğrulama devre dışıdır
activateValidationFalse.hide();
activateValidationTrue.show();
// form doğrulayıcıları devre dışı bırakılıyor
formulaire.data('validator', null);
}
}
- satır 1: [activate] parametresinin değeri, istemci tarafında doğrulamanın etkinleştirilmesi gerekiyorsa [true], aksi takdirde false olur;
- 5-6. satırlar: devre dışı bırakma bağlantısı gösterilir, etkinleştirme bağlantısı ise gizlenir;
- 8. satır: istemci tarafında doğrulamanın çalışabilmesi için, belgeyi [data-val-X] doğrulayıcılarını arayarak ayrıştırmak (analiz etmek) gerekir. [$.validator.unobtrusive.parse] işlevinin parametresi, ayrıştırılacak formun jS kimliğidir;
- 11-12. satırlar: Etkinleştirme bağlantısı gösterilir, devre dışı bırakma bağlantısı gizlenir;
- 14. satır: Formdaki doğrulayıcılar devre dışı bırakılır. Bu andan itibaren, formda jS doğrulayıcıları yokmuş gibi davranılır;
[setClientValidation2] işlevi ne işe yarar? Bu işlev, POST'i yönetmek için kullanılır. [clientValidation] alanı gizli bir alan olduğu için, bu alan gönderilir ve sunucu tarafından geri gönderilen formla birlikte geri gelir. Böylece, bu değer kullanılarak istemci tarafındaki doğrulama, POST işleminden önceki haline geri getirilir. Zira, istekler arasında jS için bir bellek yoktur. Bu nedenle sunucunun, yeni görünümde jS'i başlatmaya yarayan bilgileri iletmesi gerekir. Bu işlem genellikle [$(document).ready] işlevinde gerçekleştirilir.
Şimdi, istemci tarafındaki doğrulamayı etkinleştirme/devre dışı bırakma bağlantılarına yapılan tıklamaları yöneten [setClientValidation] işlevine geri dönelim:
// istemci tarafında doğrulama
function setClientValidation(activate) {
// istemci tarafı doğrulamanın etkinleştirilmesi/devre dışı bırakılması yönetiliyor
setClientValidation2(activate);
// kullanıcının seçimini gizli alanda kaydediliyor
clientValidation.val(activate ? "true" : "false");
// ek ayarlamalar
if (activate) {
// istemci tarafı doğrulama etkindir
// sunucudaki tüm hata mesajları silinir
clearServerErrors();
// form onaylanır
formulaire.validate().form();
} else {
// istemci tarafı doğrulama devre dışı
// istemcideki tüm hata mesajları siliniyor
clearClientErrors();
}
}
- 4. satır: az önce incelediğimiz [setClientValidation2] fonksiyonu kullanılır;
- 6. satır: Kullanıcının seçimini, bir sonraki POST işlevinden döndüğünde geri almak üzere gizli alana kaydediyoruz;
- 11. satır: istemci tarafı doğrulama etkinse, görünümdeki [serveur] sütunundaki hata mesajları silinir. [clearServerErrors] işlevini 6.3.7. paragrafta açıklamıştık;
- 13. satır: Olası hata mesajlarının görünümün [client] sütununda görüntülenmesi için jS doğrulayıcıları çalıştırılır;
- 17. satır: Müşteri doğrulaması devre dışı bırakılmışsa, görünümdeki [client] sütunundaki hata mesajları silinir. Chrome geliştirici konsolunda, hatalı bir öğenin HTML kodunu inceleyelim:
<td class="col2">
<input type="text" data-val="true" data-val-int="Format invalide" data-val-max-value="100" data-val-required="Le champ est obligatoire" data-val-max="La valeur doit être inférieure ou égale à 100" value="" id="intMax100" name="intMax100" aria-required="true" class="input-validation-error" aria-describedby="intMax100-error">
</td>
<td class="col3">
<span class="field-validation-error" data-valmsg-for="intMax100" data-valmsg-replace="true">
<span id="intMax100-error" class="">Le champ est obligatoire</span>
</span>
</td>
- 2. satırda, tablonun 2. sütununda hatalı öğenin stilinin [class="input-validation-error"] olduğunu görüyoruz;
- 5. satırda, tablonun 3. sütununda hata mesajının stilinin [class="field-validation-error"] olduğunu görüyoruz;
Bu durum tüm hatalı öğeler için geçerlidir. Bu iki bilgiyi aşağıdaki [clearClientErrors] işlevinde kullanıyoruz:
// istemci hatalarını temizle
function clearClientErrors() {
// istemci hata mesajları siliniyor
$(".field-validation-error").each(function(index) {
$(this).text("");
});
// hatalı girişlerin sınıfı CSS olarak değiştiriliyor
$(".input-validation-error").each(function(index) {
$(this).removeClass("input-validation-error");
});
}
- 4-6. satırlar: DOM sınıfına sahip tüm öğeleri arar ve bunların görüntülediği metni sileriz. Hata mesajları bu şekilde silinir;
- 8-10. satırlar: DOM'teki, [input-validation-error] sınıfına sahip tüm öğeler aranır ve bu sınıf onlardan kaldırılır. Böylece kırmızı renkle işaretlenmiş olan hatalı öğe, orijinal stiline geri döner;


















































