GVKun编程网logo

Spring MVC 数据绑定流程分析(简述springmvc数据绑定流程)

19

关于SpringMVC数据绑定流程分析和简述springmvc数据绑定流程的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于4:springmvc数据绑定、JavaEE_Mybatis_Sp

关于Spring MVC 数据绑定流程分析简述springmvc数据绑定流程的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于4:spring mvc 数据绑定、JavaEE_Mybatis_SpringMVC__Spring MVC中数据绑定之日期类型、Spring MVC 执行流程分析、spring mvc 的数据绑定,数据验证等相关知识的信息别忘了在本站进行查找喔。

本文目录一览:

Spring MVC 数据绑定流程分析(简述springmvc数据绑定流程)

Spring MVC 数据绑定流程分析(简述springmvc数据绑定流程)

1.    数据绑定流程原理★

①   Spring MVC 主框架将 ServletRequest  对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象

②   DataBinder 调用装配在 Spring MVC 上下文中的 ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中

③   调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果 BindingData 对象

④   Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

Spring MVC 通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是 DataBinder,运行机制如下:


 

 

 

原理:SpringMVC 如何确定 POJO 参数的值,以及将页面的值正确的赋值给 POJO
1、使用数据绑定器来负责将页面带来的参数绑定到 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());
                }
            }
        }
复制代码
2、DataBinder 中有几个组件负责完成这几项工作;
3、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...
复制代码
4、如果是数据校验使用校验器进行  validators
5、处理校验成功还是失败信息?BindingResult 负责处理校验错误的信息

 

应用:
1)、自定义的类型转换器;
 

ConversionService 是 Spring 类型转换体系的核心接口。
可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC 容器中定义一个 ConversionService. 
Spring 将自动识别出 IOC 容器中的 ConversionService,并在 Bean 属性配置及 
Spring MVC 处理方法入参绑定等场合使用它进行数据的转换
可通过 ConversionServiceFactoryBean 的 converters 属性注册自定义的类型转换器

复制代码
</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 等)对象)可使用该转换器工厂类

GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换

复制代码
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 数据校验流程:
1、导包
导入校验框架的 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 表达式

 

2、加注解

给需要校验的 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;
复制代码

 

3、告诉 SpringMVC 这个 javaBean 需要校验;@Valid

一定注意:所有的 ModelAttribute 要全部统一;

 

* 在员工更新操作之前;在点击提交之前,提前运行查出数据
* 校验成功失败的信息,以及校验失败后怎么做?
* 给参数后面紧跟一个 Errors、或者 BindingResult

 

 

复制代码
public String empUpdate(@Valid @ModelAttribute("employee") Employee employee,Errors errors){
      //后端把错误显示出来 if(errors.getFieldErrorCount()>0){ System.out.println("类型转换出错误了"); //1、获取产生的所有的错误 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"> 自动的按照国际化要求取出错误信息;

 https://www.cnblogs.com/limingxian537423/p/7277538.html

 

https://www.jianshu.com/p/a707acd7eb3a

http://www.imooc.com/article/263093

 

 

 

 

4:spring mvc 数据绑定

4:spring mvc 数据绑定



  1. 如何绑定数据

     

  2. API方式绑定数据

     

    我们还可以通过如HttpServletRequest 等API 得到请求数据,但推荐使用注解方式,因为使用起来更简单。我们需要首先看看功能处理方法支持哪些类型的形式参数,以及他们的具体含义。
    一、ServletRequest/HttpServletRequest 和ServletResponse/HttpServletResponse

    二、InputStream/OutputStream 和Reader/Writer

    requestBodyIn:等价于request.getInputStream();
    responseBodyOut:等价于response.getOutputStream() 。

    三、WebRequest/NativeWebRequest
    WebRequest 是Spring Web MVC 提供的统一请求访问接口,不仅仅可以访问请求相关数据(如参数区数据、请求头数据,但访问不到Cookie 区数据),还可以访问会话和上下文中的数据;NativeWebRequest 继承了WebRequest,并提供访问本地Servlet API 的方法。

    四、HttpSession

    session 访问不是线程安全的,如果需要线程安全,需要设置AnnotationMethodHandlerAdapter 或RequestMappingHandlerAdapter 的synchronizeOnSession 属性为true,即可线程安全的访问session。

    五、命令/表单对象
    Spring Web MVC 能够自动将请求参数绑定到功能处理方法的命令/表单对象上。

    六、Model、Map、ModelMapSpring Web MVC 提供Model、Map 或ModelMap 让我们能去暴露渲染视图需要的模型数据。

    虽然此处注入的是三个不同的类型(Model model, Map model2, ModelMap model3),但三者是同一个对象

    AnnotationMethodHandlerAdapter 和RequestMappingHandlerAdapter 将使用BindingAwareModelMap 作为模型对象的实现,即此处我们的参数(Model model, Map model2, ModelMap model3)都是同一个BindingAwareModelMap 实例。

    七、Errors/BindingResult



     
  3. 注解方式绑定数据

    1、@RequestParam绑定单个请求参数值;

    2、@PathVariable绑定URI 模板变量值;

    3、@CookieValue绑定Cookie 数据值

    4、@RequestHeader绑定请求头数据;

    5、@ModelAttribute绑定参数到命令对象;

    6、@SessionAttributes绑定命令对象到session;


    @RequestParam绑定单个请求参数值
    public String requestparam(@RequestParam("username") String username)

    @RequestParam注解主要有哪些参数
    value:参数名字,即入参的请求参数名字,如username 表示请求的参数区中的名字为username 的参数的值将传入;
    required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报404 错误码;
    defaultValue:默认值,表示如果请求中没有同名参数时的默认值

    public String requestparam(@RequestParam(value="username“,required=false) String username)
    表示请求中可以没有名字为username 的参数,如果没有默认为null,此处需要注意如下几点:原子类型:必须有值,否则抛出异常,如果允许空值请使用包装类代替。Boolean 包装类型类型:默认Boolean.FALSE,其他引用类型默认为null。

    对于多个同名请求参数的处理,
    例如:url?role=admin&role=user
    public String requestparam(@RequestParam(value=“role”) String roles)
    实际得到的值是roles=“admin,user”。多个值以逗号的方式隔开
    或者把方法参数定义为字符串数组(String[] roles)或集合(List<String> roles)

    @PathVariable绑定URI 模板变量值
    @RequestMapping(value="/users/{userId}/topics/{topicId}")public String test(@PathVariable(value="userId") intuserId, @PathVariable(value="topicId") inttopicId)
    如请求的URL 为“控制器URL/users/123/topics/456”,则自动将URL 中模板变量{userId}和{topicId} 绑定到通过@PathVariable注解的同名参数上,即入参后userId=123、topicId=456。

    @CookieValue绑定Cookie 数据值
    public String test(@CookieValue(value="JSESSIONID", defaultValue="") String sessionId)
    传入参数类型也可以是javax.servlet.http.Cookie类型。public String test2(@CookieValue(value="JSESSIONID", defaultValue="") Cookie sessionId)

    @RequestHeader绑定请求头数据
    @RequestMapping(value="/header")public String test(@RequestHeader("User-Agent") String userAgent,@RequestHeader(value="Accept") String[] accepts)

    @ModelAttribute绑定请求参数到Model
    @ModelAttribute一个具有如下三种使用方式:
    作用在方法参数里面:用于将多个请求参数绑定到一个命令对象,从而简化绑定流程,而且自动暴露为模型数据用于视图页面展示时使用;
    作用在一般方法上面:该Controller的所有方法在调用前,先执行此@ModelAttribute方法;
    作用于方法的返回值上面:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为模型数据,用于视图页面展示时使

    public String findUser(@ModelAttribute("user") UserModel user) @ModelAttribute("cityList")public List<String> cityList() {
    
        return Arrays. asList("北京", "山东");
    
    }
    
    public @ModelAttribute(“user”) UserModel findUser(@ModelAttribute(“user2”) UserModel user)   


    注:返回值上的user会覆盖方法参数上的user2作为视图的模型名

    匿名绑定
    public String findUser(@ModelAttribute UserModel user)
    Spring Web MVC 会自动将简单类名(首字母小写)作为名字暴露对于集合类型(Collection 接口的实现者们,包括数组),生成的模型对象属性名为“简单类名(首字母小写)”+“ List”

    @SessionAttributes绑定对象到session
    在控制器上加入@SessionAttributes(value = { “user”}) @SessionAttributes(value = { “user”}) public class SessionAttributeController调用SessionStatus对象的setComplete()销毁当前控制器上使用的Session
    @RequestMapping("/session2") public String session(@ModelAttribute("user") UserModeluser, SessionStatusstatus) {status.setComplete();return "success";}

JavaEE_Mybatis_SpringMVC__Spring MVC中数据绑定之日期类型

JavaEE_Mybatis_SpringMVC__Spring MVC中数据绑定之日期类型

数据绑定应该算是Spring MVC的特点之一吧~简单易用且功能强大,极大地简化了我们编程人员对于用户输入数据的接收及转换。

早先版本的Spring中的数据绑定完全都是基于PropertyEditor的。而Spring3中引入了Converter,用来替代PropertyEditor完成类型转换。

那么我们也依照这个顺序,先来讲讲基于传统的PropertyEditor来实现日期类型的数据绑定。


在Spring MVC中,我们可以通过WebDataBinder来注册自定义的PropertyEditor,从而添加对应的请求参数绑定。有两种方式:

1、使用@InitBinder注解@Controller中的方法 2、自定义WebBindingInitializer来提供一个全局的数据绑定规则。


1、使用@InitBinder注解

@InitBinder
  • public void initBinder(WebDataBinder binder){
  • binder.registerCustomEditor(Date.class, new DateEditor());
  • }

    1. public class DateEditor extends PropertyEditorSupport {
    2. @Override
    3. public void setAsText(String text) throws IllegalArgumentException {
    4. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    5. Date date = null;
    6. try {
    7. date = format.parse(text);
    8. } catch (ParseException e) {
    9. format = new SimpleDateFormat("yyyy-MM-dd");
    10. try {
    11. date = format.parse(text);
    12. } catch (ParseException e1) {
    13. e1.printStackTrace();
    14. }
    15. }
    16. setValue(date);
    17. }
    18. }

    这里我们将DateEditor提出来封装成一个类方便重用。

    另外这里有个try...catch的小妙用,就是首先以"yyyy-MM-dd HH:mm:ss"的形式来解析用户输入的参数,若解析失败则转以"yyyy-MM-dd"的形式来解析。这样的逻辑就可以同时处理"yyyy-MM-dd HH:mm:ss"和"yyyy-MM-dd"形式的日期数据,我想在一般的中文系统中,这两种形式应该是最常用的了吧。

    添加如上代码之后,@InitBinder所在的Controller就可以自动绑定日期类型的数据了,不过这仅仅是在该Controller中生效,若想在全局范围内生效的话,可以将@InitBinder注解所在的Controller定义为一个BaseController,其余Controller都继承这个Controller。当然还有另外的方法,若你有兴趣的话,请看2。


    2、自定义WebBindingInitializer

    1. public class MyWebBindingInitializer implements WebBindingInitializer {
    2. @Override
    3. public void initBinder(WebDataBinder binder, WebRequest request) {
    4. binder.registerCustomEditor(Date.class, new DateEditor());
    5. }
    6. }

    还是前面写的DateEditor,这么快又见面了,只不过注册的位置改变了,在WebBindingInitializer中注册的PropertyEditor是在全局范围内共享的。

    不过光这样还不够,还要将WebBindingInitializer注入到AnnotationMethodHandlerAdapter中。

    1. <bean
    2. class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    3. <property name="webBindingInitializer">
    4. <bean
    5. class="org.springframework.samples.petclinic.web.ClinicBindingInitializer" />
    6. </property>
    7. </bean>


    如果是用<mvc:annotation-driven />的童鞋,上面的配置就没效果了,而mvc命名空间也没提供如此细粒度的配置,怎么办呢?

    别怕,方法还是有的,我们可以通过一个自定义PostBeanProcessor来处理:

    1. @Override
    2. public Object postProcessBeforeInitialization(Object bean, String beanName)
    3. throws BeansException {
    4. if (bean instanceof RequestMappingHandlerAdapter) {
    5. RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
    6. adapter.setWebBindingInitializer(new MyWebBindingInitializer());
    7. }
    8. return bean;
    9. }

    不过实际上<mvc:annotation-driven />默认就为我们提供了一个WebBindingInitializer——ConfigurableWebBindingInitializer

    而上面的方法则会覆盖默认的ConfigurableWebBindingInitializer,其实我们可以直接使用这个Bean来注册我们的PropertyEditor:

    1. @Override
    2. public Object postProcessBeforeInitialization(Object bean, String beanName)
    3. throws BeansException {
    4. if(bean instanceof ConfigurableWebBindingInitializer){
    5. ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) bean;
    6. initializer.setPropertyEditorRegistrar(new PropertyEditorRegistrar() {
    7. @Override
    8. public void registerCustomEditors(PropertyEditorRegistry registry) {
    9. registry.registerCustomEditor(Date.class, new DateEditor());
    10. }
    11. });
    12. }
    13. return bean;
    14. }

    这里需要说明一下,WebBindingInitializer中不仅仅能注册PropertyEditor,还能注册Converter,也就是下面的3


    3、使用ConverstionService

    Spring3新引入了Converter系统,而ConversionService则是一个Facade类,用来封装底层实现而对外提供便捷的类型转换。所以这里不能重用之间的DateEditor了,不过大致逻辑还是一样的。另外补充说明一下,Converter是处理任意两类型间的转换,而Formatter是处理字符串和另一类型之间的转换的。可以看出来,Formatter是一类特殊的Converter,并且在处理数据绑定时,Formatter比Converter更加合适。所以我们这里就用Formatter来做:

    1. public class DateFormatter implements Formatter<Date> {
    2. @Override
    3. public String print(Date object, Locale locale) {
    4. return null;
    5. }
    6. @Override
    7. public Date parse(String text, Locale locale) throws ParseException {
    8. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    9. Date date = null;
    10. try {
    11. date = format.parse(text);
    12. } catch (Exception e) {
    13. format = new SimpleDateFormat("yyyy-MM-dd");
    14. date = format.parse(text);
    15. }
    16. return date;
    17. }
    18. }

    这里我们只写String到Date的逻辑。然后需要将DateFormatter注册到一个ConversionService中,最后再将ConversionService注册到Spring MVC中。

    1. <bean id="conversionService"
    2. class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    3. <property name="formatters">
    4. <set>
    5. <bean class="com.test.common.core.DateFormatter"></bean>
    6. </set>
    7. </property>
    8. </bean>


    如果是用<mvc:annotation-driven />的童鞋,那么很简单,只需要:

    <mvc:annotation-driven conversion-service="conversionService"/>


    而未使用<mvc:annotation-driven />的童鞋,需要定义一个WebBindingInitializer(或者使用ConfigurableWebBindingInitializer),然后注入到RequestMappingHandlerAdapter中去:

    1. <bean
    2. class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    3. <property name="webBindingInitializer" ref="webBindingInitializer">
    4. </property>
    5. </bean>
    6. <bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
    7. <property name="conversionService" ref="conversionService"></property>
    8. </bean>

    此时可能有人会问,如果同时使用PropertyEditor和ConversionService,执行顺序是什么呢?内部首先查找PropertyEditor进行类型转换,如果没有找到相应的PropertyEditor再通过ConversionService进行转换。


    4、PropertyEditor的自动注册

    对了,这里再稍带提一下自动注册PropertyEditor,只需要将JavaBean和JavaBean名称+Editor这两个类放在同一包下,那么JavaBeans的基础结构会自动发现PropertyEditor的类,而无需你手动注册~

    Spring MVC 执行流程分析

    Spring MVC 执行流程分析

    从刚才的Spring MVC入门程序中,我们大致明白了代码的书写过程,但是对Spring MVC每个元素的执行过程不太清楚,接下来我们分析Spring MVC的执行流程。

    1 Spring MVC执行流程图

    file

    1. 用户发送出请求到前端控制器DispatcherServlet。
    2. DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。
    3. HandlerMapping找到具体的处理器(可查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
    4. DispatcherServlet调用HandlerAdapter(处理器适配器)。
    5. HandlerAdapter经过适配调用具体的处理器(Handler/Controller)。
    6. Controller执行完成返回ModelAndView对象。
    7. HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
    8. DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。
    9. ViewReslover解析后返回具体View(视图)。
    10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
    11. DispatcherServlet响应用户。

    2 关键组件分析

    1. 前端控制器:DispatcherServlet(不需要程序员开发),由框架提供,在web.xml中配置。 作用:接收请求,响应结果,相当于转发器,中央处理器。
    2. 处理器映射器:HandlerMapping(不需要程序员开发),由框架提供。 作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。
    3. 处理器适配器:HandlerAdapter(不需要程序员开发),由框架提供。 作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler。
    4. 处理器:Handler(也称之为Controller,需要工程师开发)。 注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。 作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。
    5. 视图解析器:ViewResolver(不需要程序员开发),由框架提供。 作用:进行视图解析,把逻辑视图名解析成真正的物理视图。
    6. 视图:View(需要前端工程师开发)。 作用:把数据展现给用户的页面,View是一个接口,实现类支持不同的View技术(Jsp、Freemarker、Pdf等)

    原文地址:http://www.yiidian.com/springmvc/process-analysis.html

    欢迎关注我的公众号:一点教程,获得高质量的IT学习资源和干货推送。 如果您对我的专题内容感兴趣,也可以关注我的网站:yiidian.com

    spring mvc 的数据绑定,数据验证

    spring mvc 的数据绑定,数据验证

    正在学习 spring (3.0.5) mvc, 有个问题想请教一下:如何处理在数据绑定时候出的错呢?如何自定义出错的信息呢?

    比如说:Object 中要求是 Integer, 但是前台用户输入了字母 A, 这种情况,在 Spring Binder Data,进行数据绑定的时候就会进行类型的转换,然后就会 throw exception, 如何处理这种情况?如何自定义错误信息呢?

    我们今天的关于Spring MVC 数据绑定流程分析简述springmvc数据绑定流程的分享就到这里,谢谢您的阅读,如果想了解更多关于4:spring mvc 数据绑定、JavaEE_Mybatis_SpringMVC__Spring MVC中数据绑定之日期类型、Spring MVC 执行流程分析、spring mvc 的数据绑定,数据验证的相关信息,可以在本站进行搜索。

    本文标签:

    上一篇SpringMVC 内置的精准数据绑定 2(springmvc数据绑定方式)

    下一篇spring-boot-mybatis(springbootmybatis配置详解)