本系列文章主要索引詳情 點(diǎn)擊查看
通常情況下,我們都不希望用戶輸入非法的信息诀姚,這樣的話嘱能,我們就需要對(duì)表單添加一些校驗(yàn)邏輯滥朱。
工具
IntelliJ IDEA 16
JDK 1.8
Maven 3.5
Tomcat 1.8
表單校驗(yàn)
我們可以通過添加一些注解,來輔助完成校驗(yàn)限制毒涧。
1贮预、首先我們需要在DTO的ProfileForm類的屬性字段上添加限制注解:
package com.example.dto;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDate;
public class ProfileForm {
@Size(min = 2)
private String twitterHandle;
@Email
@NotNull
private String email;
@NotNull
private LocalDate birthDate;
public String getTwitterHandle() {
return twitterHandle;
}
public void setTwitterHandle(String twitterHandle) {
this.twitterHandle = twitterHandle;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public LocalDate getBirthDate() {
return birthDate;
}
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
@Override
public String toString() {
return "ProfileForm{" +
"twitterHandle='" + twitterHandle + '\'' +
", email='" + email + '\'' +
", birthDate='" + birthDate + '\'' +
'}';
}
}
這些注解來源于JSR-303規(guī)范,它詳細(xì)規(guī)定了bean的校驗(yàn)功能契讲,這個(gè)規(guī)范最流行的實(shí)現(xiàn)是hibernate-validator仿吞,它已經(jīng)包含在了Spring Boot之中。
我們使用了來自javax.validation.constraints包中的注解(在API中定義的)和org.hibernate.validator.constraints包的注解(額外限制)捡偏。我們可通過查閱validation-api和hibernate-validator的jar包文件來查看都有哪些可用注解唤冈。我們還可以查閱hibernate-validator的文檔來了解它提供的可用限制。
2银伟、完成了對(duì)DTO屬性的限制你虹,我們還學(xué)要在控制器中還需要聲明在表單提交時(shí),希望得到一個(gè)合法的模型彤避。在提交方法的表單的參數(shù)上添加@Valid注解:
package com.example.controller;
import com.example.date.LocalDateFormatter;
import com.example.dto.ProfileForm;
import java.util.Locale;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.validation.Valid;
@Controller
public class ProfileController {
@RequestMapping("/profile")
public String displayProfile(ProfileForm profileForm){
return "profile/profilePage";
}
@RequestMapping(value = "/profile" ,method = RequestMethod.POST)
public String saveProfile(@Valid ProfileForm profileForm, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "profile/profilePage";
}
System.out.println("Save Ok"+profileForm);
return "redirect:/profile";
}
@ModelAttribute("dataFormat")
public String localeFormat(Locale locale){
return LocalDateFormatter.getPattern(locale);
}
}
@Valid注解 : javax.validation.Valid 傅物, 聲明表單提交時(shí),進(jìn)行校驗(yàn)琉预,從而得到是否是一個(gè)合法的模型董饰。
BindingResult : Spring驗(yàn)證的錯(cuò)誤返回,來將驗(yàn)證錯(cuò)誤的信息返回到頁面圆米。
注意:如果表單中包含錯(cuò)誤信息卒暂,我們不進(jìn)行重定向,而是直接返回到同一個(gè)web頁面中娄帖,并在頁面中顯示錯(cuò)誤也祠。
3、最后我們需要在Web頁面中添加一個(gè)位置來展現(xiàn)這些錯(cuò)誤,profilePage.html文件中块茁,表單標(biāo)簽開始的地方添加如下代碼:
<ul th:if="${#fields.hasErrors('*')}" class="errorlist">
<li th:each="err:${#fields.errors('*')}" th:text="${err}">input is incorrect</li>
</ul>
注意:這段代碼必須添加在<form>...</form>標(biāo)簽中齿坷,如果添加在<form>...</form>之外桂肌,將會(huì)出現(xiàn)如下異常:
Could not bind form errors using expression "*". Please check this expression is being executed inside the adequate context (e.g. a <form> with a th:object attribute)
4、如果我們不輸入任何數(shù)據(jù)永淌,直接點(diǎn)提交崎场,則會(huì)顯示如下錯(cuò)誤提示:
5、如果我們輸入的信息不合法遂蛀,則會(huì)顯示如下:
自定義校驗(yàn)信息
從上面我們可以看出谭跨,這些顯示的錯(cuò)誤信息對(duì)我們并沒有什么用處,我們并不能完全區(qū)分出這些錯(cuò)誤信息是針對(duì)哪個(gè)輸入域李滴,所以螃宙,接下來我們需要完成的一項(xiàng)工作就是將錯(cuò)誤提示信息和對(duì)應(yīng)的輸入域關(guān)聯(lián)起來,幫助我們更清晰的了解我們的問題出在哪里所坯。
按照如下方式修改profilePage.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http:www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layout/default">
<head>
<meta charset="UTF-8"/>
<title>Your profile</title>
</head>
<body>
<div class="row" layout:fragment="content">
<h2 class="indigo-text center">Prosonal info</h2>
<!--/*@thymesVar id="profileForm" type="com.example.dto.ProfileForm"*/-->
<form th:action="@{/profile}" th:object="${profileForm}" method="post" class="col m8 s11 offset-m2" >
<div class="row">
<div class="input-field col s6">
<input th:field="${profileForm.twitterHandle}" id="twitterHandle" type="text" th:errorclass="invalid"/>
<label for="twitterHandle">Last name</label>
<div th:errors="*{twitterHandle}" class="red-text">Error</div>
</div>
<div class="input-field col s6">
<input th:field="${profileForm.email}" id="email" type="text" th:errorclass="invalid"/>
<label for="email">Email</label>
<div th:errors="*{email}" class="red-text">Error</div>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input id="birthDate" type="text" th:field="${profileForm.birthDate}" th:placeholder="${dataFormat}" th:errorclass="invalid"/>
<label for="birthDate">Birth Date</label>
<div th:errors="*{birthDate}" class="red-text">Error</div>
</div>
</div>
<div class="row s12">
<button class="btn waves-effect waves-light" type="submit" name="save">Submit<i class="mdi-content-snd right"></i> </button>
</div>
</form>
</div>
</body>
</html>
在表單的每個(gè)輸入域中添加 th:errorclass屬性谆扎,并在輸入域的下面新增一個(gè)th:errors標(biāo)簽,如果輸入域包含錯(cuò)誤的話芹助,將會(huì)有如下顯示:
現(xiàn)在我們已經(jīng)將錯(cuò)誤提示信息和輸入域進(jìn)行了綁定堂湖,但是我們可以發(fā)現(xiàn),有些提示信息并不適合展示給用戶状土,所以我們需要對(duì)錯(cuò)誤提示信息進(jìn)行自定義无蜂。
方法一:
Spring Boot會(huì)負(fù)責(zé)為我們創(chuàng)建信息源bean,信息源的默認(rèn)位置是 src/main/resource/messages.properties,如果我們沒有看到這個(gè)文件蒙谓,則創(chuàng)建messages.properties斥季,并添加以下文本:
Size.profileForm.twitterHandle=Please type in your twitter user name
Email.profileForm.email=Please specify a valid email address
NotNull.profileForm.email=Please specify your email address
PastLocalDate.profileForm.birthDate=Please specify a real birth date
NotNull.profileForm.birthDate=Please specify your birth date
typeMismatch.birthDate=Invalid birth date format
以上文本定義了錯(cuò)誤類型和對(duì)應(yīng)的輸入域,以及錯(cuò)誤提示信息累驮,并按照鍵值對(duì)的形式存在酣倾,解析錯(cuò)誤時(shí),根據(jù)錯(cuò)誤類型慰照,返回對(duì)應(yīng)的錯(cuò)誤提示信息到頁面灶挟。
在Spring中負(fù)責(zé)解析錯(cuò)誤信息的類是DefaultMessageCodesResolver。在進(jìn)行輸入域校驗(yàn)的時(shí)候毒租,這個(gè)類將會(huì)按照如下順序來嘗試解析信息:
1稚铣、編碼 + “.” + 對(duì)象 + “.” + 輸入域 (例: Size.profileForm.twitterHandle)
2、編碼 + “.” + 輸入域
3墅垮、編碼 + “.” + 輸入域類型
4惕医、編碼
現(xiàn)在我們將會(huì)看到我們自定義的錯(cuò)誤信息了:
在開發(fā)期,我們可以將信息源配置為每次都重新加載算色,我們只需要在application.properties文件中抬伺,添加
spring.messages.cache-seconds=0
其中 0 表示每次都重新加載,而 -1 則表示不進(jìn)行重新加載灾梦。
方法二:
有了上面的信息峡钓,我們接下來可以讓它更為具體妓笙,定義默認(rèn)信息的最佳實(shí)踐如下所示:
Size=the {0} field must be between {2} and {1} characters long
注意這里的占位符,每個(gè)校驗(yàn)錯(cuò)誤都有與之相關(guān)聯(lián)的一組參數(shù)能岩,通過運(yùn)行結(jié)果我們可以有清晰的了解:
方法三:
聲明錯(cuò)誤的最后一種方法是直接在檢驗(yàn)注解中定義錯(cuò)誤信息:
@Size(min = 2 ,message = "Please specify a valid twitter handle")
但是這種方式的缺點(diǎn)在于它無法與國際化功能兼容寞宫。
客戶端校驗(yàn)
通過使用HTML5的表單校驗(yàn)規(guī)范,現(xiàn)在實(shí)現(xiàn)客戶端校驗(yàn)已經(jīng)非常容易了拉鹃,如果瀏覽器是Internet Explorer 10 及以上的話辈赋,通過添加客戶端校驗(yàn)只需要指定正確的輸入域類型,不再講type屬性設(shè)置為text膏燕。
通過添加客戶端校驗(yàn)钥屈,我們可以預(yù)先校驗(yàn)表單,避免已知的不正確的請(qǐng)求對(duì)服務(wù)器造成過大的負(fù)載坝辫。
我們可以修改輸入域來啟動(dòng)簡單的客戶端校驗(yàn)篷就。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http:www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layout/default">
<head>
<meta charset="UTF-8"/>
<title>Your profile</title>
</head>
<body>
<div class="row" layout:fragment="content">
<h2 class="indigo-text center">Prosonal info</h2>
<!--/*@thymesVar id="profileForm" type="com.example.dto.ProfileForm"*/-->
<form th:action="@{/profile}" th:object="${profileForm}" method="post" class="col m8 s11 offset-m2" >
<div class="row">
<div class="input-field col s6">
<input th:field="${profileForm.twitterHandle}" id="twitterHandle" type="text" required="required" th:errorclass="invalid"/>
<label for="twitterHandle">Last name</label>
<div th:errors="*{twitterHandle}" class="red-text">Error</div>
</div>
<div class="input-field col s6">
<input th:field="${profileForm.email}" id="email" type="email" required="required" th:errorclass="invalid"/>
<label for="email">Email</label>
<div th:errors="*{email}" class="red-text">Error</div>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input id="birthDate" type="text" th:field="${profileForm.birthDate}" th:placeholder="${dataFormat}" required="required" th:errorclass="invalid"/>
<label for="birthDate">Birth Date</label>
<div th:errors="*{birthDate}" class="red-text">Error</div>
</div>
</div>
<div class="row s12">
<button class="btn waves-effect waves-light" type="submit" name="save">Submit<i class="mdi-content-snd right"></i> </button>
</div>
</form>
</div>
</body>
</html>
在每個(gè)表單輸入域中添加屬性 required="required",將強(qiáng)制用戶輸入非空的值近忙,而修改type=“email”腻脏,會(huì)為對(duì)應(yīng)的輸入域進(jìn)行基本的E-mail格式校驗(yàn)。
上一篇:Spring Boot框架開發(fā)Web項(xiàng)目之七 日期的使用和輸出日志
下一篇:Spring Boot 框架開發(fā)Web項(xiàng)目之九 Spring Boot項(xiàng)目的打包和部署