springMVC如何對輸入數(shù)據(jù)校驗(yàn)實(shí)現(xiàn)代碼
前言
數(shù)據(jù)的校驗(yàn)是交互式網(wǎng)站一個(gè)不可或缺的功能,數(shù)據(jù)驗(yàn)證分為客戶端驗(yàn)證和服務(wù)器端驗(yàn)證。前端的js校驗(yàn)可以涵蓋大部分的校驗(yàn)職責(zé),如用戶名唯一性,生日格式,郵箱格式校驗(yàn)等等常用的校驗(yàn);但是為了避免用戶繞過瀏覽器,使用http工具直接向后端請求一些違法數(shù)據(jù),服務(wù)端的數(shù)據(jù)校驗(yàn)也是必要的,可以防止臟數(shù)據(jù)落到數(shù)據(jù)庫中,如果數(shù)據(jù)庫中出現(xiàn)一個(gè)非法的郵箱格式,也會(huì)讓運(yùn)維人員頭疼不已,服務(wù)器端驗(yàn)證是整個(gè)應(yīng)用阻止非法數(shù)據(jù)的最后防線,通過在應(yīng)用中編程實(shí)現(xiàn)。
客戶端驗(yàn)證在大多數(shù)情況下,使用 JavaScript 進(jìn)行客戶端驗(yàn)證的步驟如下:
- 編寫驗(yàn)證函數(shù)。
- 在提交表單的事件中調(diào)用驗(yàn)證函數(shù)。
- 根據(jù)驗(yàn)證函數(shù)來判斷是否進(jìn)行表單提交。
服務(wù)器端驗(yàn)證對于系統(tǒng)的安全性、完整性、健壯性起到了至關(guān)重要的作用。服務(wù)器端驗(yàn)證Spring MVC 的 Converter 和 Formatter 在進(jìn)行類型轉(zhuǎn)換時(shí)是將輸入數(shù)據(jù)轉(zhuǎn)換成領(lǐng)域?qū)ο蟮膶傩灾担ㄒ环N Java 類型),一旦成功,服務(wù)器端驗(yàn)證器就會(huì)介入。也就是說,在 Spring MVC 框架中先進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換,再進(jìn)行服務(wù)器端驗(yàn)證。在 Spring MVC 框架中可以利用 Spring 自帶的驗(yàn)證框架驗(yàn)證數(shù)據(jù),也可以利用 JSR 303 實(shí)現(xiàn)數(shù)據(jù)驗(yàn)證。
JSR303/JSR-349,hibernate validation,spring validation之間的關(guān)系
JSR303是一項(xiàng)標(biāo)準(zhǔn),JSR-349是其的升級版本,添加了一些新特性,他們規(guī)定一些校驗(yàn)規(guī)范即校驗(yàn)注解,如@Null,@NotNull,@Pattern,他們位于javax.validation.constraints包下,只提供規(guī)范不提供實(shí)現(xiàn)。而hibernate validation是對這個(gè)規(guī)范的實(shí)踐(不要將hibernate和數(shù)據(jù)庫orm框架聯(lián)系在一起),他提供了相應(yīng)的實(shí)現(xiàn),并增加了一些其他校驗(yàn)注解,如@Email,@Length,@Range等等,他們位于org.hibernate.validator.constraints包下。而萬能的spring為了給開發(fā)者提供便捷,對hibernate validation進(jìn)行了二次封裝,顯示校驗(yàn)validated bean時(shí),你可以使用spring validation或者h(yuǎn)ibernate validation,而spring validation另一個(gè)特性,便是其在springmvc模塊中添加了自動(dòng)校驗(yàn),并將校驗(yàn)信息封裝進(jìn)了特定的類中。這無疑便捷了我們的web開發(fā)。本文主要介紹在springmvc中自動(dòng)校驗(yàn)的機(jī)制。
springMVC輸入數(shù)據(jù)校驗(yàn)實(shí)現(xiàn)
首先在maven項(xiàng)目中引入相關(guān)jar包
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>3.0.0</version> </dependency>
開啟spring的Valid功能
<mvc:annotation-driven />
創(chuàng)建需要被校驗(yàn)的實(shí)體類
import org.hibernate.validator.constraints.Length; import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Pattern; //與數(shù)據(jù)庫中users對應(yīng) public class UserInfo { private int id; @Pattern(regexp = Constants.USERNAMR, message = Constants.USERNAMRERROR) private String username; @NotBlank(message = Constants.NAMEERROR) private String name; @Email(message = Constants.EMAILERROR) private String email; @Length(min = 6, max = 16, message = Constants.PASSWORDERROR) private String password; @Pattern(regexp = Constants.PHONE, message = Constants.PHONEERROR) private String phoneNum; //...get/set方法 }
這些注解還是比較淺顯易懂的,字段上的注解名稱即可推斷出校驗(yàn)內(nèi)容,每一個(gè)注解都包含了message字段,用于校驗(yàn)失敗時(shí)作為提示信息,特殊的校驗(yàn)注解,如Pattern(正則校驗(yàn)),還可以自己添加正則表達(dá)式。
JSR提供的校驗(yàn)注解: @Null 被注釋的元素必須為 null @NotNull 被注釋的元素必須不為 null @AssertTrue 被注釋的元素必須為 true @AssertFalse 被注釋的元素必須為 false @Min(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值 @Max(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值 @DecimalMin(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值 @DecimalMax(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值 @Size(max=, min=) 被注釋的元素的大小必須在指定的范圍內(nèi) @Digits (integer, fraction) 被注釋的元素必須是一個(gè)數(shù)字,其值必須在可接受的范圍內(nèi) @Past 被注釋的元素必須是一個(gè)過去的日期 @Future 被注釋的元素必須是一個(gè)將來的日期 @Pattern(regex=,flag=) 被注釋的元素必須符合指定的正則表達(dá)式 Hibernate Validator提供的校驗(yàn)注解: @NotBlank(message =) 驗(yàn)證字符串非null,且長度必須大于0 @Email 被注釋的元素必須是電子郵箱地址 @Length(min=,max=) 被注釋的字符串的大小必須在指定的范圍內(nèi) @NotEmpty 被注釋的字符串的必須非空 @Range(min=,max=,message=) 被注釋的元素必須在合適的范圍內(nèi)
我們將message錯(cuò)誤信息放在一個(gè)Constants類中
public class Constants { public static final String PHONE = "^1[3|4|5|7|8][0-9]{9}$"; public static final String USERNAMR = "^NH[0-9]{7}$"; public static final String NAMEERROR = "用戶名不能為空"; public static final String PHONEERROR = "請輸入一個(gè)正確的電話號碼"; public static final String EMAILERROR= "請輸入一個(gè)正確的郵箱地址"; public static final String USERNAMRERROR = "請輸入一個(gè)正確的用戶編號"; public static final String PASSWORDERROR = "密碼的長度為6~16位"; public static final String DATENOTNULL = "日期非空"; }
在@Controller中校驗(yàn)數(shù)據(jù)
@Valid 和 BindingResult 是一一對應(yīng)的,如果有多個(gè)@Valid,那么每個(gè)@Valid后面跟著的BindingResult就是這個(gè)@Valid的驗(yàn)證結(jié)果,順序不能亂
//用戶添加 @RequestMapping("/save.do") //@PreAuthorize("authentication.principal.username == 'NH1905001'") @PreAuthorize("hasRole('ROLE_ADMIN')") public String save(@Valid @ModelAttribute(value="userInfo") UserInfo userInfo, BindingResult result) throws Exception { if(result.hasErrors()){ List<FieldError> errors = result.getFieldErrors(); for (FieldError fieldError : errors) { System.out.println("錯(cuò)誤消息提示:" + fieldError.getDefaultMessage()); System.out.println("錯(cuò)誤的字段是?" + fieldError.getField()); System.out.println(fieldError); System.out.println("------------------------"); } return "user-add"; }else { userService.save(userInfo); return "redirect:findAll.do"; } }
錯(cuò)誤對象的代表者是 Errors 接口,存儲和暴露關(guān)于數(shù)據(jù)綁定錯(cuò)誤和驗(yàn)證錯(cuò)誤相關(guān)信息的接口,提供了相關(guān)存儲和獲取錯(cuò)誤消息的方法,具有如下幾個(gè)實(shí)現(xiàn)類:
- BindingResult:代表數(shù)據(jù)綁定的結(jié)果,繼承了 Errors 接口;
- BindException:代表數(shù)據(jù)綁定的異常,它繼承 Exception,并實(shí)現(xiàn)了BindingResult,這是內(nèi)部使用的錯(cuò)誤對象;
Errors接口中的方法
void addAllErrors(Errors var1); boolean hasErrors(); int getErrorCount(); List<ObjectError> getAllErrors(); boolean hasGlobalErrors(); int getGlobalErrorCount(); List<ObjectError> getGlobalErrors(); @Nullable ObjectError getGlobalError(); boolean hasFieldErrors(); int getFieldErrorCount(); List<FieldError> getFieldErrors(); @Nullable FieldError getFieldError(); boolean hasFieldErrors(String var1); int getFieldErrorCount(String var1); List<FieldError> getFieldErrors(String var1); @Nullable FieldError getFieldError(String var1); @Nullable Object getFieldValue(String var1); @Nullable Class<?> getFieldType(String var1);
根據(jù)方法名字就可以知道方法的作用
輸出的校驗(yàn)信息
錯(cuò)誤消息提示:用戶名不能為空 錯(cuò)誤的字段是?name Field error in object 'userInfo' on field 'name': rejected value []; codes [NotBlank.userInfo.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.name,name]; arguments []; default message [name]]; default message [用戶名不能為空] ------------------------ 錯(cuò)誤消息提示:請輸入一個(gè)正確的郵箱地址 錯(cuò)誤的字段是?email Field error in object 'userInfo' on field 'email': rejected value [111]; codes [Email.userInfo.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.email,email]; arguments []; default message [email],[Ljavax.validation.constraints.Pattern$Flag;@462d227d,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@2a8eb300]; default message [請輸入一個(gè)正確的郵箱地址] ------------------------ 錯(cuò)誤消息提示:請輸入一個(gè)正確的用戶編號 錯(cuò)誤的字段是?username Field error in object 'userInfo' on field 'username': rejected value []; codes [Pattern.userInfo.username,Pattern.username,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.username,username]; arguments []; default message [username],[Ljavax.validation.constraints.Pattern$Flag;@63f401ef,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@72436888]; default message [請輸入一個(gè)正確的用戶編號] ------------------------ 錯(cuò)誤消息提示:請輸入一個(gè)正確的電話號碼 錯(cuò)誤的字段是?phoneNum Field error in object 'userInfo' on field 'phoneNum': rejected value []; codes [Pattern.userInfo.phoneNum,Pattern.phoneNum,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.phoneNum,phoneNum]; arguments []; default message [phoneNum],[Ljavax.validation.constraints.Pattern$Flag;@63f401ef,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@5d528277]; default message [請輸入一個(gè)正確的電話號碼] ------------------------ 錯(cuò)誤消息提示:密碼的長度為6~16位 錯(cuò)誤的字段是?password Field error in object 'userInfo' on field 'password': rejected value []; codes [Length.userInfo.password,Length.password,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.password,password]; arguments []; default message [password],16,6]; default message [密碼的長度為6~16位] ------------------------
數(shù)據(jù)校驗(yàn)錯(cuò)誤信息回顯
controller處理方法的形參pojo定義的對象與此類型同名 ,首字母小寫,此時(shí)spring能自動(dòng)將該對象名為key,此對象作為value,保存到request中。當(dāng)然,也可以通過@Valid @ModelAttribute(value=“userInfo”) UserInfo userInfo自定義名稱。
modelAttribute="userInfo"中userInfo與controller方法的形參pojo定義的對象同名 。
注意頁面需要引入
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<form:form modelAttribute="userInfo" action="${pageContext.request.contextPath}/user/save.do" method="post"> <!-- 正文區(qū)域 --> <section class="content"> <!--產(chǎn)品信息--> <div class="panel panel-default"> <div class="panel-heading">用戶信息</div> <div class="row data-type"> <div class="col-md-2 title">用戶名稱</div> <div class="col-md-4 data"> <input type="text" class="form-control" name="username" placeholder="用戶名稱" value=""> </div> <div class="col-md-6 data"> <form:errors path="username" cssStyle="color:red"/> </div> <div class="col-md-2 title">姓名</div> <div class="col-md-4 data"> <input type="text" class="form-control" name="name" placeholder="姓名" value=""> </div> <div class="col-md-6 data"> <form:errors path="name" cssStyle="color:red"/> </div> <div class="col-md-2 title">密碼</div> <div class="col-md-4 data"> <input type="password" class="form-control" name="password" placeholder="密碼" value=""> </div> <div class="col-md-6 data"> <form:errors path="password" cssStyle="color:red"/> </div> <div class="col-md-2 title">郵箱</div> <div class="col-md-4 data"> <input type="text" class="form-control" name="email" placeholder="郵箱" value=""> </div> <div class="col-md-6 data"> <form:errors path="email" cssStyle="color:red"/> </div> <div class="col-md-2 title">聯(lián)系電話</div> <div class="col-md-4 data"> <input type="text" class="form-control" name="phoneNum" placeholder="聯(lián)系電話" value=""> </div> <div class="col-md-6 data"> <form:errors path="phoneNum" cssStyle="color:red"/> </div> <div class="col-md-2 title">用戶狀態(tài)</div> <div class="col-md-4 data"> <select class="form-control select2" style="width: 100%" name="status"> <option value="0" selected="selected">關(guān)閉</option> <option value="1">開啟</option> </select> </div> </div> </div> <!--訂單信息/--> <!--工具欄--> <div class="box-tools text-center"> <button type="submit" class="btn bg-maroon">保存</button> <button type="button" class="btn bg-default" onclick="history.back(-1);">返回</button> </div> <!--工具欄/--> </section> <!-- 正文區(qū)域 /--> </form:form>
數(shù)據(jù)校驗(yàn)錯(cuò)誤信息回顯方法2
通過model方式在request中存儲指定key與value,如下:
//改變客戶到公海 @RequestMapping("/transformClients.do") public String transformClientsById(@Valid @ModelAttribute("publicSea") PublicSea publicSea, BindingResult result, Model model) throws Exception { if(result.hasErrors()){ model.addAttribute("failueError",failueError.getDefaultMessage()); model.addAttribute("failueDesc",publicSea.getFailueDesc()); model.addAttribute("cNumber",publicSea.getcNumber()); return "publicSea-change"; }else { return "redirect:findAll.do"; } }
客戶端代碼
<form action="${pageContext.request.contextPath}/clients/transformClients.do" method="post"> <!-- 正文區(qū)域 --> <section class="content"> <!--產(chǎn)品信息--> <div class="panel panel-default"> <div class="panel-heading">跟蹤失敗原因</div> <div class="row data-type"> <input type="text" style="display:none" name="cNumber" placeholder="線索Id" value="${cNumber}"> <div class="col-md-2 title rowHeight2x">跟蹤失敗描述</div> <div class="col-md-10 data rowHeight2x"> <textarea class="form-control" rows="3" placeholder="跟蹤失敗描述" name="failueDesc">${failueDesc}</textarea> </div> <div class="col-md-12 data rowHeight2x"> <label>${failueError}</label> </div> </div> </div> <!--訂單信息/--> <!--工具欄--> <div class="box-tools text-center"> <button type="submit" class="btn bg-maroon">保存</button> <button type="button" class="btn bg-default" onclick="history.back(-1);">返回</button> </div> <!--工具欄/--> </section> <!-- 正文區(qū)域 /--> </form>
分組校驗(yàn)
自定義校驗(yàn)
手動(dòng)校驗(yàn)
基于方法校驗(yàn)
到此這篇關(guān)于springMVC如何對輸入數(shù)據(jù)校驗(yàn)的文章就介紹到這了,更多相關(guān)springMVC數(shù)據(jù)校驗(yàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?boot?啟動(dòng)流程及外部化配置方法
平時(shí)我們開發(fā)Spring boot 項(xiàng)目的時(shí)候,一個(gè)SpringBootApplication注解加一個(gè)main方法就可以啟動(dòng)服務(wù)器運(yùn)行起來,那它到底是怎么運(yùn)行起來的呢?這篇文章主要介紹了Spring?boot?啟動(dòng)流程及外部化配置,需要的朋友可以參考下2022-12-12JAVA中Context的詳細(xì)介紹和實(shí)例分析
這篇文章主要介紹了JAVA中Context的詳細(xì)介紹和實(shí)例分析,Context是維持android各組件能夠正常工作的一個(gè)核心功能類。如果感興趣來學(xué)習(xí)一下2020-07-07Java實(shí)現(xiàn)多個(gè)sheet頁數(shù)據(jù)導(dǎo)出功能
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)多個(gè)sheet頁數(shù)據(jù)導(dǎo)出功能的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03Java網(wǎng)絡(luò)編程之簡單的服務(wù)端客戶端應(yīng)用實(shí)例
這篇文章主要介紹了Java網(wǎng)絡(luò)編程之簡單的服務(wù)端客戶端應(yīng)用,以實(shí)例形式較為詳細(xì)的分析了java網(wǎng)絡(luò)編程的原理與服務(wù)器端客戶端的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04Java簡單實(shí)現(xiàn)銀行ATM系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java簡單實(shí)現(xiàn)銀行ATM系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Java中5種方式實(shí)現(xiàn)String反轉(zhuǎn)
下面小編就為大家?guī)硪黄狫ava中5種方式實(shí)現(xiàn)String反轉(zhuǎn)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。2016-06-06mybatis-plus批處理IService的實(shí)現(xiàn)示例
這篇文章主要介紹了mybatis-plus批處理IService的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08