數據綁定流程分析

1.    數據綁定流程原理★

①   Spring MVC 主框架將 ServletRequest  對象及目標方法的入參實例傳遞給 WebDataBinderFactory 實例,以建立 DataBinder 實例對象前端

②   DataBinder 調用裝配在 Spring MVC 上下文中的 ConversionService 組件進行數據類型轉換、數據格式化工做。將 Servlet 中的請求信息填充到入參對象中java

③   調用 Validator 組件對已經綁定了請求消息的入參對象進行數據合法性校驗,並最終生成數據綁定結果 BindingData 對象jquery

④   Spring MVC 抽取 BindingResult 中的入參對象和校驗錯誤對象,將它們賦給處理方法的響應入參spring

Spring MVC 經過反射機制對目標處理方法進行解析,將請求消息綁定處處理方法的入參中。數據綁定的核心部件是 DataBinder,運行機制以下:後端

 

原理:SpringMVC如何肯定POJO參數的值,以及將頁面的值正確的賦值給POJO
一、使用數據綁定器來負責將頁面帶來的參數綁定到pojo中
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());
                }
            }
        }
二、DataBinder中有幾個組件負責完成這幾項工做;
三、ConversionService負責進行類型轉換以及格式化工做

 

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...
四、若是是數據校驗使用校驗器進行  validators
五、處理校驗成功仍是失敗信息?BindingResult負責處理校驗錯誤的信息

 

應用:
1)、自定義的類型轉換器;
 

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>

1)     Spring 支持的轉換器類型

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;
    }
JSR303數據校驗;
之前沒有數據校驗;
          數據輸錯:400頁面;
          咱們但願:回到本頁面,提示哪一項出錯便可;
之後校驗,在關鍵位置,咱們都應該使用雙端校驗;前端+後端;
JSR303數據校驗流程:
一、導包
導入校驗框架的jar包; Hibernate Validator標準5個包
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
 Tomcat7.0如下(不包括7)須要把下面el相關的三個包的包導入到tomcat的lib裏面,覆蓋以前的el表達式

 

二、加註解

給須要校驗的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"; }

4     在頁面上顯示錯誤

 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>

 

5.    提示消息的國際化

每一個屬性在數據綁定和數據校驗發生錯誤時,都會生成一個對應的 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 在調用處理方法時發生了錯誤

 

 1)、建立全部錯誤消息提示的國際化文件

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]

 

  2)、配置使用SpringMVC管理國際化資源文件
<!-- SpringMVC管理國際化資源文件 -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="error"></property>
    </bean>

3)、SpringMVC:<form:errors path="fieldName">自動的按照國際化要求取出錯誤信息;

相關文章
相關標籤/搜索