① Spring MVC 主框架將 ServletRequest 對象及目標方法的入參實例傳遞給 WebDataBinderFactory 實例,以建立 DataBinder 實例對象前端
② DataBinder 調用裝配在 Spring MVC 上下文中的 ConversionService 組件進行數據類型轉換、數據格式化工做。將 Servlet 中的請求信息填充到入參對象中java
③ 調用 Validator 組件對已經綁定了請求消息的入參對象進行數據合法性校驗,並最終生成數據綁定結果 BindingData 對象jquery
④ Spring MVC 抽取 BindingResult 中的入參對象和校驗錯誤對象,將它們賦給處理方法的響應入參spring
Spring MVC 經過反射機制對目標處理方法進行解析,將請求消息綁定處處理方法的入參中。數據綁定的核心部件是 DataBinder,運行機制以下:後端
binderFactory //綁定器工廠根據當前請求,其餘信息;建立出數據綁定器; //數據綁定器負責將請求中的數據綁定到pojo中 WebDataBinder binder = binderFactory.createBinder(request, attribute, name); if (binder.getTarget() != null) { //數據綁按期間進行類型轉換以及格式化工做 bindRequestParameters(binder, request); //數據校驗:email;birth;BindingResult組件中會封裝錯誤信息; validateIfApplicable(binder, parameter); //數據校驗錯誤信息處理 if (binder.getBindingResult().hasErrors()) { //若是出錯有處理 if (isBindExceptionRequired(binder, parameter)) { \\parameter指目標方法正在處理的當前參數 saveEmp(Employee emp) protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) { int i = parameter.getParameterIndex();//獲取參數索引 Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();//獲取當前方法全部參數的參數類型 //若是下一個參數是Errors旗下的,就返回成功;不然就是沒人處理; boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1])); return !hasBindingResult; } //若是沒人處理就拋異常 throw new BindException(binder.getBindingResult()); } } }
SpringMVC默認使用的是DefaultFormattingCOnversionService
ConversionService converters = 負責數據類型轉換及格式化;都是裏面的每個轉換器負責工做;
@org.springframework.format.annotation.DateTimeFormat java.lang.Long -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@7c515e0,@org.springframework.format.annotation.NumberFormat java.lang.Long -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
@org.springframework.format.annotation.DateTimeFormat java.time.LocalDate -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.time.LocalDate -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@34d07c25
@org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.time.LocalDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@2fbd9c99
@org.springframework.format.annotation.DateTimeFormat java.time.LocalTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.time.LocalTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@317cb8e5
@org.springframework.format.annotation.DateTimeFormat java.time.OffsetDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.time.OffsetDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@4c6fb0c7
@org.springframework.format.annotation.DateTimeFormat java.time.OffsetTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.time.OffsetTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@616a3ae3
@org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.time.ZonedDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@48de4b92
@org.springframework.format.annotation.DateTimeFormat java.util.Calendar -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@7c515e0
@org.springframework.format.annotation.DateTimeFormat java.util.Date -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@7c515e0
@org.springframework.format.annotation.NumberFormat java.lang.Double -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
@org.springframework.format.annotation.NumberFormat java.lang.Float -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
@org.springframework.format.annotation.NumberFormat java.lang.Integer -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
@org.springframework.format.annotation.NumberFormat java.lang.Short -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
@org.springframework.format.annotation.NumberFormat java.math.BigDecimal -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
@org.springframework.format.annotation.NumberFormat java.math.BigInteger -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@1ae88e8d
java.lang.Character -> java.lang.Number : org.springframework.core.convert.support.CharacterToNumberFactory@15499bcc
java.lang.Character -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@314796e3
java.lang.Enum -> java.lang.String : org.springframework.core.convert.support.EnumToStringConverter@67a9e5f5
java.lang.Long -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$LongToCalendarConverter@2425e96f
java.lang.Long -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$LongToDateConverter@37be4c53
java.lang.Number -> java.lang.Character : org.springframework.core.convert.support.NumberToCharacterConverter@64e80876
java.lang.Number -> java.lang.Number : org.springframework.core.convert.support.NumberToNumberConverterFactory@24d24a7d
java.lang.Number -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@2d2b9f78
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.lang.Long: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@7c515e0,java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Long: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalDate: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.lang.String -> java.time.LocalDate: org.springframework.format.datetime.standard.TemporalAccessorParser@1b95054a
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.lang.String -> java.time.LocalDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@1cb17371
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.lang.String -> java.time.LocalTime: org.springframework.format.datetime.standard.TemporalAccessorParser@183beaef
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.OffsetDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.lang.String -> java.time.OffsetDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@5b5278c0
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.OffsetTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.lang.String -> java.time.OffsetTime: org.springframework.format.datetime.standard.TemporalAccessorParser@43da3826
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@7bfa429f,java.lang.String -> java.time.ZonedDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@ff5bcf4
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Calendar: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@7c515e0
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Date: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@7c515e0
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Double: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Float: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Integer: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Short: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigDecimal: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigInteger: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@592e7da0
java.lang.String -> java.lang.Boolean : org.springframework.core.convert.support.StringToBooleanConverter@1795e212
java.lang.String -> java.lang.Character : org.springframework.core.convert.support.StringToCharacterConverter@7f0a5c2
java.lang.String -> java.lang.Enum : org.springframework.core.convert.support.StringToEnumConverterFactory@3ee79e1e
java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@35ac0acf
java.lang.String -> java.time.Instant: org.springframework.format.datetime.standard.InstantFormatter@72824112
java.lang.String -> java.util.Locale : org.springframework.core.convert.support.StringToLocaleConverter@5f141e60
java.lang.String -> java.util.Properties : org.springframework.core.convert.support.StringToPropertiesConverter@34316a3
java.lang.String -> java.util.UUID : org.springframework.core.convert.support.StringToUUIDConverter@54f52170
java.time.Instant -> java.lang.String : org.springframework.format.datetime.standard.InstantFormatter@72824112
java.time.ZoneId -> java.util.TimeZone : org.springframework.core.convert.support.ZoneIdToTimeZoneConverter@309ed382
java.util.Calendar -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToLongConverter@783071dc
java.util.Calendar -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToDateConverter@18da2904
java.util.Date -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$DateToLongConverter@3a5ea3fa
java.uti...
ConversionService 是 Spring 類型轉換體系的核心接口。
能夠利用 ConversionServiceFactoryBean 在 Spring 的 IOC 容器中定義一個 ConversionService.
Spring 將自動識別出 IOC 容器中的 ConversionService,並在 Bean 屬性配置及
Spring MVC 處理方法入參綁定等場合使用它進行數據的轉換
可經過 ConversionServiceFactoryBean 的 converters 屬性註冊自定義的類型轉換器api
</bean> <bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean"> <!-- 咱們的類型轉換器要賦值給他 --> <property name="converters"> <!-- 給set賦值 --> <set> <ref bean="myStringToEmployeeConvertor"/> </set> </property> </bean> <!-- 靜態資源被SpringMVC攔截到了,因此jquery 404 --> <!-- SpringMVC處理不了的資源,如今交給tomcat的DefaultServlet; default-servlet-name: default-servlet-name="default";若是隻有它,動態資源就完蛋了; --> <!--靜態資源訪問ok --> <mvc:default-servlet-handler/> <!--動態資源就能訪問;開掛版的mvc模式 --> <!-- 轉換器採用自定義的 --> <mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>
Spring 定義了 3 種類型的轉換器接口,實現任意一個轉換器接口均可以做爲自定義轉換器註冊到 ConversionServiceFactoryBean 中:數組
Converter<S,T>:將 S 類型對象轉爲 T 類型對象瀏覽器
ConverterFactory:將相同系列多個 「同質」 Converter 封裝在一塊兒。若是但願將一種類型的對象轉換爲另外一種類型及其子類的對象(例如將 String 轉換爲 Number 及 Number 子類(Integer、Long、Double 等)對象)可以使用該轉換器工廠類tomcat
GenericConverter:會根據源類對象及目標類對象所在的宿主類中的上下文信息進行類型轉換mvc
public class MyStringToEmployeeConvertor implements Converter<String, Employee>{ @Autowired DepartmentDao dao; @Override public Employee convert(String source) { // TODO Auto-generated method stub Employee employee = new Employee(null, "haha", "hahah", 0,null); System.out.println("MyStringToEmployeeConvertor開始工做啦......."+source); //admin-aaa@qq.com-0-101 if(!"".equals(source)&&source!=null){ //把字符串按照"-"進行分割,獲得的數據保存在數組中 String[] split = source.split("-"); employee.setLastName(split[0]); employee.setEmail(split[1]); employee.setGender(Integer.parseInt(split[2])); Department department = dao.getDepartment(Integer.parseInt(split[3])); employee.setDepartment(department); } return employee; }
hibernate-validator-5.0.0.CR2.jar
hibernate-validator-annotation-processor-5.0.0.CR2.jar
classmate-0.8.0.jar
jboss-logging-3.1.1.GA.jar
validation-api-1.1.0.CR1.jar
二、加註解
給須要校驗的javaBean屬性上加註解;給javaBean加校驗註解
private Integer id; @NotEmpty @Length(min=5,max=15) private String lastName; @Email private String email; //1 male, 0 female private Integer gender=1; /** * pattern:指定日期格式 */ @DateTimeFormat(pattern="yyyy-MM-dd") @Past private Date birthDay;
三、告訴SpringMVC這個javaBean須要校驗;@Valid
必定注意:全部的ModelAttribute要所有統一;
* 在員工更新操做以前;在點擊提交以前,提早運行查出數據
* 校驗成功失敗的信息,以及校驗失敗後怎麼作?
* 給參數後面緊跟一個Errors、或者BindingResult
public String empUpdate(@Valid @ModelAttribute("employee") Employee employee,Errors errors){
//後端把錯誤顯示出來 if(errors.getFieldErrorCount()>0){ System.out.println("類型轉換出錯誤了"); //一、獲取產生的全部的錯誤 List<FieldError> fieldErrors = errors.getFieldErrors(); for(FieldError fieldError:fieldErrors){ System.out.println(fieldError.getField()+"-"+fieldError.getDefaultMessage()); } return "/edit"; } System.out.println(employee); employeeDao.save(employee); return "redirect:/emps"; }
Spring MVC 除了會將表單/命令對象的校驗結果保存到對應的 BindingResult 或 Errors 對象中外,還會將全部校驗結果保存到「隱含模型」
即便處理方法的簽名中沒有對應於表單/命令對象的結果入參,校驗結果也會保存在 「隱含對象」 中。
隱含模型中的全部數據最終將經過 HttpServletRequest 的屬性列表暴露給 JSP 視圖對象,所以在 JSP 中能夠獲取錯誤信息
在 JSP 頁面上可經過 <form:errors path=「userName」> 顯示錯誤消息
<form:form action="${ ctp}/emp/${employee.id }" method="post" modelAttribute="employee" > birthDay:<form:input path="birthDay"/><form:errors path="birthDay"/><br/> email:<form:input path="email"/><form:errors path="email"/><br> 男:<form:radiobutton path="gender" value="1"/> 女:<form:radiobutton path="gender" value="0"/><br/> <!-- SpringMvc習慣於直接用參數,而不是經過類。參數獲取 --> department:<form:select path="department.id" items="${depts}" itemLabel="departmentName" itemValue="id" ></form:select><br/> <!-- 瀏覽器 form 表單只支持 GET 與 POST 請求,而DELETE、PUT 等 method 並不支持, Spring3.0 添加了一個過濾器,能夠將這些請求轉換爲標準的 http 方法,使得支持 GET、POST、PUT 與 DELETE 請求。 因此要添加name="_method" value="PUT",過濾器根據這個進行區分 --> <input type="hidden" name="_method" value="PUT" > <input type="hidden" name="id" value="${employee.id}"> <input type="submit" value="更新"> </form:form>
每一個屬性在數據綁定和數據校驗發生錯誤時,都會生成一個對應的 FieldError 對象。
當一個屬性校驗失敗後,校驗框架會爲該屬性生成 4 個消息代碼,這些代碼以校驗註解類名爲前綴,結合 modleAttribute、屬性名及屬性類型名生成多個對應的消息代碼:例如 User 類中的 password 屬性標註了一個 @Pattern 註解,當該屬性值不知足 @Pattern 所定義的規則時, 就會產生如下 4 個錯誤代碼:
Pattern.user.password
Pattern.password
Pattern.java.lang.String
Pattern
當使用 Spring MVC 標籤顯示錯誤消息時, Spring MVC 會查看 WEB 上下文是否裝配了對應的國際化消息,若是沒有,則顯示默認的錯誤消息,不然使用國際化消息。
若數據類型轉換或數據格式轉換時發生錯誤,或該有的參數不存在,或調用處理方法時發生錯誤,都會在隱含模型中建立錯誤消息。其錯誤代碼前綴說明以下:
required:必要的參數不存在。如 @RequiredParam(「param1」) 標註了一個入參,可是該參數不存在
typeMismatch:在數據綁定時,發生數據類型不匹配的問題
methodInvocation:Spring MVC 在調用處理方法時發生了錯誤
Field error in object 'employee' on field 'lastName': rejected value [E-AA];
codes
[
Length.employee.lastName,//校驗註解類名.modleAttribute(保存隱含模型)的key.屬性
Length.lastName,//校驗註解類名.屬性
Length.java.lang.String,//校驗註解類名.屬性類型
Length//校驗註解類名
];//4種錯誤代碼;任何字段錯誤都會有他的錯誤代碼;國際化文件中的key就是要寫這個錯誤代碼;
arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [employee.lastName,lastName]; arguments []; default message [lastName],15,5]; default message [length must be between 5 and 15]
<!-- SpringMVC管理國際化資源文件 --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="error"></property> </bean>
3)、SpringMVC:<form:errors path="fieldName">自動的按照國際化要求取出錯誤信息;