SpringMVC——數據轉換 & 數據格式化 & 數據校驗
阿新 • • 發佈:2017-12-31
gpo new open util tro -m 註解 構造 param
一、數據綁定流程
- 1. Spring MVC 主框架將 ServletRequest 對象及目標方 法的入參實例傳遞給 WebDataBinderFactory 實例,以創 建 DataBinder 實例對象
- 2. DataBinder 調用裝配在 Spring MVC 上下文中的 ConversionService 組件進行數據類型轉換、數據格式 化工作。將 Servlet 中的請求信息填充到入參對象中
- 3. 調用 Validator 組件對已經綁定了請求消息的入參對象 進行數據合法性校驗,並最終生成數據綁定結果 BindingData 對象
- 4. Spring MVC 抽取 BindingResult 中的入參對象和校驗 錯誤對象,將它們賦給處理方法的響應入參
Spring MVC 通過反射機制對目標處理方法進行解析,將請 求消息綁定到處理方法的入參中。數據綁定的核心部件是 DataBinder,運行機制如下:
源碼分析
- 在JavaBean對象的屬性setter方法處打斷點調試
- 在調試頁面進入org.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgument
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest request, WebDataBinderFactory binderFactory) throwsException { String name = ModelFactory.getNameForParameter(parameter); Object attribute = mavContainer.containsAttribute(name)?mavContainer.getModel().get(name):this.createAttribute(name, parameter, binderFactory, request); //創建binderd對象 WebDataBinder binder = binderFactory.createBinder(request, attribute, name);if(binder.getTarget() != null) { //數據的綁定 this.bindRequestParameters(binder, request); //完成數據的校驗 this.validateIfApplicable(binder, parameter); if(binder.getBindingResult().hasErrors()
&& this.isBindExceptionRequired(binder, parameter)) { throw new BindException(binder.getBindingResult()); } } Map bindingResultModel = binder.getBindingResult().getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return binder.getTarget(); }
- 查看Binder對象的屬性
- 可以看到binder包含了ConversionService和validators屬性,它們分別處理類型轉換和數據校驗
二、數據轉換
- Spring MVC 上下文中內建了很多轉換器,可完成大多數 Java 類型的轉換工作。
- ConversionService converters =
自定義類型轉換器
ConversionService 是 Spring 類型轉換體系的核心接口。
- 可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC 容器中定義一個 ConversionService。Spring 將自動識別出 IOC 容器中的 ConversionService,並在 Bean 屬性配置及 Spring MVC 處理方法入參綁定等場合使用它進行數據的轉換
- 可通過 ConversionServiceFactoryBean 的 converters 屬性 註冊自定義的類型轉換器
三、數據格式化
- 在表單添加birthday(生日)輸入框,同時在Javabean中天機brith屬性,屬性的類型為Java.util.Date
- 提交表單時,頁面報400錯誤,數據無法提交到目標方法
- 原因:輸入框的birthday沒有進行格式化
解決方法:
在Javabean對象的birth屬性上加註解
@DateTimeFormat(pattern = "yy-mm-dd") private Date birth;
①、日期格式化
@DateTimeFormat 註解可對 java.util.Date、java.util.Calendar、java.long.Long 時間 類型進行標註:
- pattern 屬性:類型為字符串。指定解析/格式化字段數據的模式, 如:”yyyy-MM-dd hh:mm:ss”
- iso 屬性:類型為 DateTimeFormat.ISO。指定解析/格式化字段數據 的ISO模式,包括四種:ISO.NONE(不使用) -- 默 認、ISO.DATE(yyyy-MM-dd) 、ISO.TIME(hh:mm:ss.SSSZ)、 ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)
- style 屬性:字符串類型。通過樣式指定日期時間的格式,由兩位字 符組成,第一位表示日期的格式,第二位表示時間的格式:S:短日 期/時間格式、M:中日期/時間格式、L:長日期/時間格式、F:完整 日期/時間格式、-:忽略日期或時間格式
②、數值格式化
@NumberFormat 可對類似數字類型的屬性進行標 註,它擁有兩個互斥的屬性:
- style:類型為 NumberFormat.Style。用於指定樣式類 型,包括三種:Style.NUMBER(正常數字類型)、 Style.CURRENCY(貨幣類型)、 Style.PERCENT( 百分數類型)
- pattern:類型為 String,自定義樣式, 如patter="#,###";
③、源碼分析
- Spring MVC 上下文中內建了很多格式化處理器,可完成大多數 Java數據類型的格式化。
- ConversionService converters =
- 對屬性對象的輸入/輸出進行格式化,從其本質上講依然 屬於 “類型轉換” 的範疇。
- Spring 在格式化模塊中定義了一個實現 ConversionService 接口的 FormattingConversionService 實現類,該實現類擴展 了 GenericConversionService,因此它既具有類型轉換的功能,又具有格式化的功能
- FormattingConversionService 擁有一個 FormattingConversionServiceFactroyBean 工廠類, 後者用於在 Spring 上下文中構造前者
FormattingConversionServiceFactroyBean 內部已經註冊了 :
- NumberFormatAnnotationFormatterFactroy:支持對數字類型的屬性 使用 @NumberFormat 註解
- DateTimeFormatAnnotationFormatterFactroy:支持對日期類型 的屬性使用 @DateTimeFormat 註解
- 裝配了 FormattingConversionServiceFactroyBean 後,就可 以在 Spring MVC 入參綁定及模型數據輸出時使用註解了。
- 默認創建的 ConversionService 實例即為 FormattingConversionServiceFactroyBean
④、自定義數據類型格式化&數據轉換
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven> <!-- 配置 ConversionService --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <ref bean="自定義類型格式化&轉換實現類"/> </set> </property> </bean>
四、數據校驗
JSR 303 是 Java 為 Bean 數據合法性校驗提供的標準框架, 它已經包含在 JavaEE 6.0 中 .JSR 303 通過在 Bean 屬性上標註類似於 @NotNull、@Max 等標準的註解指定校驗規則,並通過標準的驗證接口對 Bean 進行驗證
Hibernate Validator 擴展註解:
- Hibernate Validator 是 JSR 303 的一個實現,除支持 所有標準的校驗註解外,它還支持以下的擴展註解
校驗流程
①. 使用 JSR 303 驗證標準
②. 加入 hibernate validator 驗證框架的 jar 包
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
③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />
④. 需要在 bean 的屬性上添加對應的註解
package com.nchu.mybatis.bean; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.NotEmpty; import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; /** * Created by yangshijing on 2017/12/4 0004. */ public class Employee { private Integer id; private String lastName; @Email private String email; private String gender; private Integer deptId; @DateTimeFormat(pattern = "yy-mm-dd") private Date birth; public Employee() { } public Employee(String email, String gender, Integer id, String lastName,Integer deptId) { this.email = email; this.gender = gender; this.id = id; this.lastName = lastName; this.deptId = deptId; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public Integer getDeptId() { return deptId; } public void setDeptId(Integer deptId) { this.deptId = deptId; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Override public String toString() { return "Employee{" + "id=" + id + ", lastName=‘" + lastName + ‘\‘‘ + ", email=‘" + email + ‘\‘‘ + ", gender=‘" + gender + ‘\‘‘ + ",birth="+ birth + ‘}‘; } }View Code
⑤. 在目標方法 bean 類型的前面添加 @Valid 註解
/** *添加employee接口 * @param employee * @return */ @RequestMapping(value = "/emp" ,method= RequestMethod.POST) public String save(@Valid Employee employee, Map<String,Object> map){ try{ employeeService.saveEmp(employee); }catch (Exception e){ e.printStackTrace(); } return "redirect:/employee/getemps"; }
⑥、表單email項未輸入email格式時,無法訪問到目標方法,並在控制臺打印出錯誤信息
SpringMVC——數據轉換 & 數據格式化 & 數據校驗