<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 第四章 Controller接口控制器詳解(7 完)——跟著開濤學SpringMVC ### 4.16.2、數據驗證 **1、數據綁定失敗:**比如需要數字卻輸入了字母; **2、數據不合法:**可以認為是業務錯誤,通過自定義驗證器驗證,如用戶名長度必須在5-20之間,我們卻輸入了100個字符等; **3、錯誤對象:**當我們數據綁定失敗或驗證失敗后,錯誤信息存放的對象,我們叫錯誤對象,在Spring Web MVC中Errors是具體的代表者;線程不安全對象; **4、錯誤消息:**是硬編碼,還是可配置?實際工作應該使用配置方式,我們只是把錯誤碼(errorCode)放入錯誤對象,在展示時讀取相應的錯誤消息配置文件來獲取要顯示的錯誤消息(errorMessage); 4.16.2.1、驗證流程 ![](https://box.kancloud.cn/2016-05-15_5737edd871e75.JPG)? 1、首先進行數據綁定驗證,如果驗證失敗會通過MessageCodesResolver生成錯誤碼放入Errors錯誤對象; 2、數據不合法驗證,通過自定義的驗證器驗證,如果失敗需要手動將錯誤碼放入Errors錯誤對象; 4.16.2.2、錯誤對象和錯誤消息 錯誤對象的代表者是Errors接口,并且提供了幾個實現者,在Spring Web MVC中我們使用的是如下實現: ![](https://box.kancloud.cn/2016-05-15_5737edd884563.JPG) **相關的錯誤方法如下:** **Errors:**存儲和暴露關于數據綁定錯誤和驗證錯誤相關信息的接口,提供了相關存儲和獲取錯誤消息的方法: ``` package org.springframework.validation; public interface Errors { //=========================全局錯誤消息(驗證/綁定對象全局的)============================= //注冊一個全局的錯誤碼() void reject(String errorCode); //注冊一個全局的錯誤碼,當根據errorCode沒有找到相應錯誤消息時,使用defaultMessage作為錯誤消息 void reject(String errorCode, String defaultMessage); //注冊一個全局的錯誤碼,當根據errorCode沒有找到相應錯誤消息時(帶錯誤參數的),使用defaultMessage作為錯誤消息 void reject(String errorCode, Object[] errorArgs, String defaultMessage); //=========================全局錯誤消息(驗證/綁定整個對象的)============================= //=========================局部錯誤消息(驗證/綁定對象字段的)============================= //注冊一個對象字段的錯誤碼,field指定驗證失敗的字段名 void rejectValue(String field, String errorCode); void rejectValue(String field, String errorCode, String defaultMessage); void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage); //=========================局部錯誤消息(驗證/綁定對象字段的)============================= boolean hasErrors(); ////是否有錯誤 boolean hasGlobalErrors(); //是否有全局錯誤 boolean hasFieldErrors(); //是否有字段錯誤 Object getFieldValue(String field); //返回當前驗證通過的值,或驗證失敗時失敗的值; } ``` getFieldValue:可以得到驗證失敗的失敗值,這是其他Web層框架很少支持的,這樣就可以給用戶展示出錯時的值(而不是空或其他的默認值等)。 **BindingResult:**代表數據綁定的結果,繼承了Errors接口。 **BindException:**代表數據綁定的異常,它繼承Exception,并實現了BindingResult,這是內部使用的錯誤對象。 **示例:** **(1、控制器** ``` package cn.javass.chapter4.web.controller; //省略import public class ErrorController extends AbstractCommandController { public ErrorController() { setCommandClass(DataBinderTestModel.class); setCommandName("command"); } @Override protected ModelAndView handle(HttpServletRequest req, HttpServletResponse resp, Object command, BindException errors) throws Exception { //表示用戶名不為空 errors.reject("username.not.empty"); //帶有默認錯誤消息 errors.reject("username.not.empty1", "用戶名不能為空1"); //帶有參數和默認錯誤消息 errors.reject("username.length.error", new Object[]{5, 10}); //得到錯誤相關的模型數據 Map model = errors.getModel(); return new ModelAndView("bindAndValidate/error", model); } } ``` ``` errors.reject("username.not.empty"):注冊全局錯誤碼“username.not.empty”,我們必須提供messageSource來提供錯誤碼“username.not.empty”對應的錯誤信息(如果沒有會拋出NoSuchMessageException異常); ``` **errors.reject("username.not.empty1", "用戶名不能為空1"):**注冊全局錯誤碼“username.not.empty1”,如果從messageSource沒沒有找到錯誤碼“username.not.empty1”對應的錯誤信息,則將顯示默認消息“用戶名不能為空1”; **errors.reject("username.length.error", new Object[]{5, 10}):**錯誤碼為“username.length.error”,而且錯誤信息需要兩個參數,如我們在我們的配置文件中定義“用戶名長度不合法,長度必須在{0}到{1}之間”,則實際的錯誤消息為“用戶名長度不合法,長度必須在5到10之間” **errors.getModel():**當有錯誤信息時,一定將errors.getModel()放入我們要返回的ModelAndView中,以便使用里邊的錯誤對象來顯示錯誤信息。 `**(2、spring配置文件chapter4-servlet.xml**` ``` <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:messages"/> <property name="fileEncodings" value="utf-8"/> <property name="cacheSeconds" value="120"/> </bean> <bean name="/error" class="cn.javass.chapter4.web.controller.ErrorController"/> ``` **messageSource:**用于獲取錯誤碼對應的錯誤消息的,而且bean名字默認必須是messageSource。 messages.properties(需要執行NativeToAscii) ``` username.not.empty=用戶名不能為空 username.length.error=用戶名長度不合法,長度必須在{0}到{1}之間 ``` **(3、視圖頁面(WEB-INF/jsp/bindAndValidate/error.jsp)** ``` <%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <!-- 表單的默認命令對象名為command --> <form:form commandName="command"> <form:errors path="*"></form:errors> </form:form> ``` **form標簽庫:**此處我們使用了spring的form標簽庫; **&lt;form:form commandName="command"&gt;:**表示我們的表單標簽,commandName表示綁定的命令對象名字,默認為command; **&lt;form:errors path="*"&gt;&lt;/form:errors&gt;:**表示顯示錯誤信息的標簽,如果path為“*”表示顯示所有錯誤信息。 接下來我們來看一下 數據綁定失敗和數據不合法時,如何處理。 4.16.2.3、數據綁定失敗 如我們的DataBinderTestModel類: bool:boolean類型,此時如果我們前臺傳入非兼容的數據,則會數據綁定失敗; date:Date類型,此時如果我們前臺傳入非兼容的數據,同樣會數據綁定失敗; phoneNumber:自定義的PhoneNumberModel類型,如果如果我們前臺傳入非兼容的數據,同樣會數據綁定失敗。 **示例:** **(1、控制器,DataBinderErrorTestController。** ``` package cn.javass.chapter4.web.controller; //省略import public class DataBinderErrorTestController extends SimpleFormController { public DataBinderErrorTestController() { setCommandClass(DataBinderTestModel.class); setCommandName("dataBinderTest"); } @Override protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response, BindException errors) throws Exception { //如果表單提交有任何錯誤都會再回到表單展示頁面 System.out.println(errors); return super.showForm(request, response, errors); } @Override protected void doSubmitAction(Object command) throws Exception { System.out.println(command); //表單提交成功(數據綁定成功)進行功能處理 } @Override protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { super.initBinder(request, binder); //注冊自定義的屬性編輯器 //1、日期 DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); CustomDateEditor dateEditor = new CustomDateEditor(df, true); //表示如果命令對象有Date類型的屬性,將使用該屬性編輯器進行類型轉換 binder.registerCustomEditor(Date.class, dateEditor); //自定義的電話號碼編輯器 binder.registerCustomEditor(PhoneNumberModel.class, new PhoneNumberEditor()); } } ``` 此處我們使用SimpleFormController; **showForm:**展示表單,當提交表單有任何數據綁定錯誤會再回到該方法進行表單輸入(在此處我們打印錯誤對象); **doSubmitAction:**表單提交成功,只要當表單的數據到命令對象綁定成功時,才會執行; `**(2、spring配置文件chapter4-servlet.xml**` ``` <bean name="/dataBindError" class="cn.javass.chapter4.web.controller.DataBinderErrorTestController"> <property name="formView" value="bindAndValidate/input"/> <property name="successView" value="bindAndValidate/success"/> </bean> ``` **(3、視圖頁面(WEB-INF/jsp/bindAndValidate/**?**input.jsp)** ``` <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <!-- 表單的命令對象名為dataBinderTest --> <form:form commandName="dataBinderTest"> <form:errors path="*" cssStyle="color:red"></form:errors><br/><br/> bool:<form:input path="bool"/><br/> phoneNumber:<form:input path="phoneNumber"/><br/> date:<form:input path="date"/><br/> <input type="submit" value="提交"/> </form:form> ``` 此處一定要使用form標簽庫,借此我們可以看到它的強大支持(別的大部分Web框架所不具備的,展示用戶驗證失敗的數據)。 &lt;form:form commandName=_"dataBinderTest"_&gt;:指定命令對象為dataBinderTest,默認command; &lt;form:errors path=_"*"_?cssStyle=_"color:red"_&gt;&lt;/form:errors&gt;:顯示錯誤消息,當提交表單有錯誤時展示錯誤消息(數據綁定錯誤/數據不合法); &lt;form:input path=_"bool"_/&gt;:等價于(&lt;input type=’text’&gt;),但會從命令對象中取出bool屬性進行填充value屬性,或如果表單提交有錯誤會從錯誤對象取出之前的錯誤數據(而非空或默認值); &lt;input type=_"submit"_?value=_"__提交__"_/&gt;:spring沒有提供相應的提交按鈕,因此需要使用html的。 **(4、測試** 在地址欄輸入如下地址:http://localhost:9080/springmvc-chapter4/dataBindError ![](https://box.kancloud.cn/2016-05-15_5737edd897e13.JPG) 全部是錯誤數據,即不能綁定到我們的命令對象; 當提交表單后,我們又回到表單輸入頁面,而且輸出了一堆錯誤信息 ![](https://box.kancloud.cn/2016-05-15_5737edd8aa21f.JPG) 1、錯誤消息不可讀; 2、表單元素可以顯示之前的錯誤的數據,而不是默認值/空; **(5、問題** **這里最大的問題是不可讀的錯誤消息,如何讓這些錯誤消息可讀呢?** 首先我們看我們的showForm方法里輸出的“errors”錯誤對象信息: ``` org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 3 errors Field error in object 'dataBinderTest' on field 'bool': rejected value [www]; codes [typeMismatch.dataBinderTest.bool,typeMismatch.bool,typeMismatch.boolean,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dataBinderTest.bool,bool]; arguments []; default message [bool]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'boolean' for property 'bool'; nested exception is java.lang.IllegalArgumentException: Invalid boolean value [www]] Field error in object 'dataBinderTest' on field 'date': rejected value [123]; codes [typeMismatch.dataBinderTest.date,typeMismatch.date,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dataBinderTest.date,date]; arguments []; default message [date]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'date'; nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "123"] Field error in object 'dataBinderTest' on field 'phoneNumber': rejected value [123]; codes [typeMismatch.dataBinderTest.phoneNumber,typeMismatch.phoneNumber,typeMismatch.cn.javass.chapter4.model.PhoneNumberModel,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dataBinderTest.phoneNumber,phoneNumber]; arguments []; default message [phoneNumber]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'cn.javass.chapter4.model.PhoneNumberModel' for property 'phoneNumber'; nested exception is java.lang.IllegalArgumentException: 類型轉換失敗,需要格式[010-12345678],但格式是[123]] ``` 數據綁定失敗(類型不匹配)會自動生成如下錯誤碼(錯誤碼對應的錯誤消息按照如下順序依次查找): 1、typeMismatch.命令對象名.屬性名 2、typeMismatch.屬性名 3、typeMismatch.屬性全限定類名(包名.類名) 4、typeMismatch ⊙內部使用MessageCodesResolver解析數據綁定錯誤到錯誤碼,默認DefaultMessageCodesResolver,因此想要詳細了解如何解析請看其javadoc; ⊙建議使用第1個進行錯誤碼的配置。 因此修改我們的messages.properties添加如下錯誤消息(需要執行NativeToAscii): ``` typeMismatch.dataBinderTest.date=您輸入的數據格式錯誤,請重新輸入(格式:2012-03-19 22:17:17) #typeMismatch.date=2 #typeMismatch.java.util.Date=3 #typeMismatch=4 ``` 再次提交表單我們會看到我們設置的錯誤消息: ![](https://box.kancloud.cn/2016-05-15_5737edd8c8a1c.JPG) 到此,數據綁定錯誤我們介紹完了,接下來我們再看一下數據不合法錯誤。 4.16.2.4、數據不合法 1、比如用戶名長度必須在5-20之間,而且必須以字母開頭,可包含字母、數字、下劃線; 2、比如注冊用戶時 用戶名已經存在或郵箱已經存在等; 3、比如去一些論壇經常會發現,您發的帖子中包含×××屏蔽關鍵字等。 還有很多數據不合法的場景,在此就不羅列了,對于數據不合法,Spring Web MVC提供了兩種驗證方式: ◆編程式驗證器驗證 ◆聲明式驗證 先從編程式驗證器開始吧。 4.16.2.4.1、編程式驗證器 **一、驗證器接口** ``` package org.springframework.validation; public interface Validator { boolean supports(Class<?> clazz); void validate(Object target, Errors errors); } ``` **Validator接口:**驗證器,編程實現數據驗證的接口; **supports方法:**當前驗證器是否支持指定的clazz驗證,如果支持返回true即可; **validate方法:**驗證的具體方法,target參數表示要驗證的目標對象(如命令對象),errors表示驗證出錯后存放錯誤信息的錯誤對象。 **示例:** **(1、驗證器實現** ``` package cn.javass.chapter4.web.controller.support.validator; //省略import public class UserModelValidator implements Validator { private static final Pattern USERNAME_PATTERN = Pattern.compile("[a-zA-Z]\\w{4,19}"); private static final Pattern PASSWORD_PATTERN = Pattern.compile("[a-zA-Z0-9]{5,20}"); private static final Set<String> FORBINDDDEN_WORD_SET = new HashSet<String>(); static { FORBINDDDEN_WORD_SET.add("fuc k"); //刪掉空格 FORBINDDDEN_WORD_SET.add("admin"); } @Override public boolean supports(Class<?> clazz) { return UserModel.class == clazz;//表示只對UserModel類型的目標對象實施驗證 } @Override public void validate(Object target, Errors errors) { //這個表示如果目標對象的username屬性為空,則表示錯誤(簡化我們手工判斷是否為空) ValidationUtils.rejectIfEmpty(errors, "username", "username.not.empty"); UserModel user = (UserModel) target; if(!USERNAME_PATTERN.matcher(user.getUsername()).matches()) { errors.rejectValue("username", "username.not.illegal");//如果用戶名不合法 } for(String forbiddenWord : FORBINDDDEN_WORD_SET) { if(user.getUsername().contains(forbiddenWord)) { errors.rejectValue("username", "username.forbidden", new Object[]{forbiddenWord}, "您的用戶名包含非法關鍵詞");//用戶名包含屏蔽關鍵字 break; } } if(!PASSWORD_PATTERN.matcher(user.getPassword()).matches()) { errors.rejectValue("password","password.not.illegal", "密碼不合法");//密碼不合法 } } } ``` **supports方法:**表示只對UserModel類型的對象驗證; **validate方法:**數據驗證的具體方法,有如下幾個驗證: 1、用戶名不合法(長度5-20,以字母開頭,隨后可以是字母、數字、下劃線) _USERNAME_PATTERN_.matcher(user.getUsername()).matches() //使用正則表達式驗證 errors.rejectValue("username", "username.not.illegal");//驗證失敗為username字段添加錯誤碼 2、屏蔽關鍵詞:即用戶名中含有不合法的數據(如admin) user.getUsername().contains(forbiddenWord) //用contains來判斷我們的用戶名中是否含有非法關鍵詞 errors.rejectValue("username", "username.forbidden",?**new**?Object[]{forbiddenWord}, "您的用戶名包含非法關鍵詞");//驗證失敗為username字段添加錯誤碼(參數為當前屏蔽關鍵詞)(默認消息為"您的用戶名包含非法關鍵詞") 3、密碼不合法 在此就不羅列代碼了; 4、ValidationUtils ValidationUtils._rejectIfEmpty_(errors, "username", "username.not.empty"); 表示如果目標對象的username屬性數據為空,則添加它的錯誤碼; 內部通過(value == null || !StringUtils.hasLength(value.toString()))實現判斷value是否為空,從而簡化代碼。 `**(2、spring配置文件chapter4-servlet.xml**` ``` <bean id="userModelValidator" class="cn.javass.chapter4.web.controller.support.validator.UserModelValidator"/> <bean name="/validator" class="cn.javass.chapter4.web.controller.RegisterSimpleFormController"> <property name="formView" value="registerAndValidator"/> <property name="successView" value="redirect:/success"/> <property name="validator" ref="userModelValidator"/> </bean> ``` 此處使用了我們第4.9節創建的RegisterSimpleFormController。 **(3、錯誤碼配置(messages.properties),需要執行NativeToAscii** ``` username.not.empty=用戶名不能為空 username.not.illegal=用戶名錯誤,必須以字母開頭,只能出現字母、數字、下劃線,并且長度在5-20之間 username.forbidden=用戶名中包含非法關鍵詞【{0}】 password.not.illegal=密碼長度必須在5-20之間 ``` **(4、視圖頁面(/WEB-INF/jsp/registerAndValidator.jsp)** ``` <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <form:form commandName="user"> <form:errors path="*" cssStyle="color:red"></form:errors><br/> username:<form:input path="username"/> <form:errors path="username" cssStyle="color:red"></form:errors> <br/> password:<form:password path="password"/> <form:errors path="password" cssStyle="color:red"></form:errors> <br/> <input type="submit" value="注冊"/> </form:form> ``` form:errors path=_"username"__:_表示只顯示username字段的錯誤信息; **(5、測試** 地址:http://localhost:9080/springmvc-chapter4/validator ![](https://box.kancloud.cn/2016-05-15_5737edd8e3e84.JPG) 當我們輸入錯誤的數據后,會報錯(form:errors path=_"*"_顯示所有錯誤信息,而form:errors path=_"username"_只顯示該字段相關的)。 **問題:** 如MultiActionController控制器相關方法沒有提供給我們errors對象(Errors),我們應該怎么進行錯誤處理呢? 此處給大家一個思路,errors本質就是一個Errors接口實現,而且在頁面要讀取相關的錯誤對象,該錯誤對象應該存放在模型對象里邊,因此我們可以自己創建個errors對象并將其添加到模型對象中即可。 此處我們復制4.15節的UserController類為UserAndValidatorController,并修改它的create(新增)方法添加如下代碼片段: ``` BindException errors = new BindException(user, getCommandName(user)); //如果用戶名為空 if(!StringUtils.hasLength(user.getUsername())) { errors.rejectValue("username", "username.not.empty"); } if(errors.hasErrors()) { return new ModelAndView(getCreateView()).addAllObjects(errors.getModel()); } ``` **√?new?BindException(user, getCommandName(user)):**使用當前的命令對象,和命令對象的名字創建了一個BindException作為errors; **√StringUtils._hasLength_(user.getUsername()):**如果用戶名為空就是用errors.rejectValue("username", "username.not.empty");注入錯誤碼; **√errors.hasErrors():**表示如果有錯誤就返回到新增頁面并顯示錯誤消息; **√ModelAndView(getCreateView()).addAllObjects(errors.getModel()):**此處一定把errors對象的模型數據放在當前的ModelAndView中,作為當前請求的模型數據返回。 在瀏覽器地址欄輸入:http://localhost:9080/springmvc-chapter4/userAndValidator/create 到新增頁面 ![](https://box.kancloud.cn/2016-05-15_5737edd904038.JPG) 用戶名什么都不輸入,提交后又返回到新增頁面 而且顯示了錯誤消息說明我們的想法是正確的。 4.16.2.4.2、聲明式驗證器 從Spring3開始支持JSR-303驗證框架,支持XML風格和注解風格的驗證,目前在@RequestMapping時才能使用,也就是說基于Controller接口的實現不能使用該方式(但可以使用編程式驗證,有需要的可以參考hibernate validator實現),我們將在第七章詳細介紹。 到此Spring2風格的控制器我們就介紹完了,以上控制器從spring3.0開始已經不推薦使用了(但考慮到還有部分公司使用這些@Deprecated類,在此也介紹了一下),而是使用注解控制器實現(@Controller和@RequestMapping)。 [ 私塾在線學習網](http://sishuok.com/)原創內容([http://sishuok.com](http://sishuok.com/)) 原創內容,轉載請注明私塾在線【[http://sishuok.com/forum/blogPost/list/5837.html](http://sishuok.com/forum/blogPost/list/5837.html)】
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看