zoukankan      html  css  js  c++  java
  • springmvc学习第四天

    数据类型的转换、格式化、校验

    1、数据绑定流程

    1. Spring MVC 主框架将 ServletRequest 对象及目标方
    法的入参实例传递给 WebDataBinderFactory 实例,以创
    建 DataBinder 实例对象
    2. DataBinder 调用装配在 Spring MVC 上下文中的 
    ConversionService 组件进行数据类型转换、数据格式
    化工作。将 Servlet 中的请求信息填充到入参对象中
    3. 调用 Validator 组件对已经绑定了请求消息的入参对象
    进行数据合法性校验,并最终生成数据绑定结果
    BindingData 对象
    4. Spring MVC 抽取 BindingResult 中的入参对象和校验
    错误对象,将它们赋给处理方法的响应入参

    自定义类型转换器(了解)

    前台页面

    <form action="testConversionServiceConverer" method="post">
    Employee:<input type="text" name="employee" />
    <input type="submit" value="Submit" />
    </form>

    转换器类(要实现converter接口)

    package com.oracle.converters;

    import org.springframework.core.convert.converter.Converter;
    import org.springframework.stereotype.Component;

    import com.oracle.entities.Department;
    import com.oracle.entities.Employee;

    @Component
    public class MyConverter implements Converter<String, Employee> {

    @Override
    public Employee convert(String source) {
    if(source != null){
    String[] vals = source.split("-");
    if(vals != null&&vals.length==3){
    String lastName = vals[0];
    Integer gender = Integer.parseInt(vals[1]);
    Department department = new Department();
    department.setId(Integer.parseInt(vals[2]));
    Employee employee = new Employee(null, lastName, gender, department);
    return employee;
    }
    }
    return null;
    }

    }

    spring mvc配置文件中配置

    <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
    <!-- 配置自定义拦截器 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
    <set>
    <ref bean="myConverter"/>
    </set>
    </property>
    </bean>

    在控制类中使用

    @RequestMapping("testConversionServiceConverer")
    public String test(@RequestParam("employee") Employee employee){
    employeeDao.save(employee);
    return "redirect:/springmvc/listall";
    }

    关于 mvc:annotation-driven

    <mvc:annotation-driven /> 会自动注
    册RequestMappingHandlerMapping
    、RequestMappingHandlerAdapter 与
    ExceptionHandlerExceptionResolver 三个bean。
    还将提供以下支持:
    支持使用 ConversionService 实例对表单参数进行类型转换 –
    支持使用 @NumberFormat annotation、@DateTimeFormat –
    注解完成数据类型的格式化
    支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证 –
    支持使用 @RequestBody 和 @ResponseBody 注解

    InitBinder注解

    注解的作用:

    由 @InitBinder 标识的方法,可以对 WebDataBinder 对
    象进行初始化

    WebDataBinder的作用 

    ①WebDataBinder 是 DataBinder 的子类,用
    于完成由表单字段到 JavaBean 属性的绑定

    ②完成数据类型的转换,数据校验

    ③如果在数据转换和校验的过程中,出现错误信息,通过返回BindingResult,显示错误信息

    实例:

    @InitBinder
    public void initBinder(WebDataBinder binder){
    binder.setDisallowedFields("lastName");
    }

    数据格式化

    操作步骤

    ①在spring mvc 的配置文件中配置<mvc:annotation-driven></mvc:annotation-driven>

    ②在对应的实体类的属性上加上注解,例如

    @DateTimeFormat(pattern="yyyy-MM-dd")
    private Date birth;
    @NumberFormat(pattern="#,###,#.#")
    private float salary;

    格式化原理

    对属性对象的输入/输出进行格式化,从其本质上讲依然
    属于 “类型转换” 的范畴。
    Spring 在格式化模块中定义了一个实现
    ConversionService 接口的
    FormattingConversionService 实现类,该实现类扩展
    了 GenericConversionService,因此它既具有类型转换的
    功能,又具有格式化的功能
    FormattingConversionService 拥有一个
    FormattingConversionServiceFactroyBean 工厂类,
    后者用于在 Spring 上下文中构造前者

    FormattingConversionServiceFactroyBean  内部已经注册了 :
    NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性 –
    使用 @NumberFormat 注解
    JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期– 类型
    的属性使用 @DateTimeFormat 注解
    装配了 FormattingConversionServiceFactroyBean 后,就可
    以在 Spring MVC 入参绑定及模型数据输出时使用注解驱动
    了。<mvc:annotation-driven/> 默认创建的
    ConversionService 实例即为
    FormattingConversionServiceFactroyBean

    BindingResult 

    BindingResult中存放了处理的异常信息,可以通过入参是获取到BindingResult,进而获取到异常信息

    @RequestMapping(value="/add",method=RequestMethod.POST)
    public String save(Employee employee,BindingResult result){
    System.out.println(employee);
    if(result.getErrorCount()>0){
    for(FieldError error:result.getFieldErrors()){
    System.out.println(error.getField() + ":" + error.getDefaultMessage());
    }
    }
    employeeDao.save(employee);
    return "redirect:/springmvc/listall";
    }

    数据校验

    ①. 使用 JSR 303 验证标准

    JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,
    它已经包含在 JavaEE 6.0 中


    ②. 加入 hibernate validator 验证框架的 jar 包

    在官网下载hibernate validator的jar包

    加入以下六个jar包

    classmate-1.1.0.jar
    hibernate-validator-5.2.1.Final.jar
    hibernate-validator-annotation-processor-5.2.1.Final.jar
    hibernate-validator-cdi-5.2.1.Final.jar
    jboss-logging-3.2.1.Final.jar
    validation-api-1.1.0.Final.jar


    ③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />
    ④. 需要在 bean 的属性上添加对应的注解

    @NotEmpty
    private String lastName;

    @Email
    private String email;

    ⑤. 在目标方法 bean 类型的前面添加 @Valid 注解

    通过在处理方法的入参上标
    注 @valid 注解即可让 Spring MVC 在完成数据绑定后执行
    数据校验的工作


    2). 验证出错转向到哪一个页面 ?
    注意: 需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参

    错误消息的显示和国际化

    jsp页面显示

    显示全部错误消息

    <form:errors path="*"></form:errors>

    显示在对应的记录位置

    LastName:<form:input path="lastName"/><br>
    <form:errors path="lastName"></form:errors>

    国际化错误消息

    当使用 Spring MVC 标签显示错误消息时, Spring MVC 会查看
    WEB 上下文是否装配了对应的国际化消息,如果没有,则显示默认
    的错误消息,否则使用国际化消息。

    ①i18n.properties

    当一个属性校验失败后,校验框架会为该属性生成 4 个消 
    息代码,这些代码以校验注解类名为前缀,结合
    modleAttribute、属性名及属性类型名生成多个对应的消
    息代码

    例如

    NotEmpty.employee.lastName=u540Du5B57u4E0Du80FDu4E3Au7A7A
    Past.employee.birth = u751Fu65E5u5FC5u987Bu662Fu4E00u4E2Au8FC7u53BBu7684u65F6u95F4

    ②配置国际化消息

    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename" value="i18n"></property>
    </bean>

    ③补充

    若数据类型转换或数据格式转换时发生错误,或该有的参
    数不存在,或调用处理方法时发生错误,都会在隐含模型
    中创建错误消息。其错误代码前缀说明如下:
    required:必要的参数不存在。如 @RequiredParam(“param1”) –
    标注了一个入参,但是该参数不存在
    typeMismatch:在数据绑定时,发生数据类型不匹配的问题 –
    methodInvocation:Spring MVC 在调用处理方法时发生了错误

    ajax

    ①加入jackson的jar包

    jackson-annotations-2.4.0.jar
    jackson-core-2.4.5.jar
    jackson-databind-2.4.6.1.jar

    ②前台发送ajax请求

    $(function(){
    $("#id").click(function(){
    var url = this.href;
    var args={};
    $.post(url,args,function(data){
    for(var i=0;i<data.length;i++){
    var id = data[i].id
    var lastName = data[i].lastName
    alert(id+":"+lastName);
    }
    });
    return false;
    });
    })

    ③后台通过配置@ResponseBody和方法的返回值类型返回json数据

    @ResponseBody
    @RequestMapping("ajax")
    public Collection<Employee> testJson(){
    return employeeDao.getEmployees();
    }

    实现原理

    通过HttpMessageConverter<T>

    上传下载

    ①添加jar包

    commons-fileupload-1.2.1.jar
    commons-io-2.0.jar

    ②配置springmvc 的配置文件

    <!-- 配置 MultipartResolver -->
    <bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8"></property>
    <property name="maxUploadSize" value="1024000"></property>
    </bean>

    上传的页面

    <form action="testFileUpload" method="POST" enctype="multipart/form-data">
    File: <input type="file" name="file"/>
    Desc: <input type="text" name="desc"/>
    <input type="submit" value="Submit"/>
    </form>

    后台处理

    @RequestMapping("/testFileUpload")
    public String testFileUpload(@RequestParam("desc") String desc,
    @RequestParam("file") MultipartFile file) throws IOException{
    System.out.println("desc: " + desc);
    System.out.println("OriginalFilename: " + file.getOriginalFilename());
    System.out.println("InputStream: " + file.getInputStream());
    return "success";
    }

    下载的页面

    <a href="testResponseEntity">Test ResponseEntity</a>

    后台处理

    @RequestMapping("/testResponseEntity")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException{
    byte [] body = null;
    ServletContext servletContext = session.getServletContext();
    InputStream in = servletContext.getResourceAsStream("/files/abc.txt");
    body = new byte[in.available()];
    in.read(body);

    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "attachment;filename=abc.txt");

    HttpStatus statusCode = HttpStatus.OK;

    ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(body, headers, statusCode);
    return response;
    }

    国际化

    关于国际化:
    1. 在页面上能够根据浏览器语言设置的情况对文本(不是内容), 时间, 数值进行本地化处理
    2. 可以在 bean 中获取国际化资源文件 Locale 对应的消息
    3. 可以通过超链接切换 Locale, 而不再依赖于浏览器的语言设置情况

    解决:
    1. 使用 JSTL 的 fmt 标签
    2. 在 bean 中注入 ResourceBundleMessageSource 的示例, 使用其对应的 getMessage 方法即可
    3. 配置 LocalResolver 和 LocaleChangeInterceptor

    拦截器

    ①实现HandlerInterceptor接口

    package com.atguigu.springmvc.interceptors;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;

    public class FirstInterceptor implements HandlerInterceptor{

    /**
    * 该方法在目标方法之前被调用.
    * 若返回值为 true, 则继续调用后续的拦截器和目标方法.
    * 若返回值为 false, 则不会再调用后续的拦截器和目标方法.
    *
    * 可以考虑做权限. 日志, 事务等.
    */
    @Override
    public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception {
    System.out.println("[FirstInterceptor] preHandle");
    return true;
    }

    /**
    * 调用目标方法之后, 但渲染视图之前.
    * 可以对请求域中的属性或视图做出修改.
    */
    @Override
    public void postHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler,
    ModelAndView modelAndView) throws Exception {
    System.out.println("[FirstInterceptor] postHandle");
    }

    /**
    * 渲染视图之后被调用. 释放资源
    */
    @Override
    public void afterCompletion(HttpServletRequest request,
    HttpServletResponse response, Object handler, Exception ex)
    throws Exception {
    System.out.println("[FirstInterceptor] afterCompletion");
    }

    }

    ②配置文件中配置

    <mvc:interceptors>
      <!-- 配置自定义的拦截器 -->
      <bean class="com.atguigu.springmvc.interceptors.FirstInterceptor"></bean>
    </mvc:interceptors>

    拦截器补充

    <mvc:interceptors>
    <!-- 配置自定义的拦截器 -->

      <!-- <mvc:mapping path="/emps"/>配置拦截器作用的路径,<mvc:exclude-mapping path="/emps"/>配置拦截器不作用的路径 -->
      <mvc:interceptor>
        <mvc:mapping path="/emps"/>
        <bean class="com.atguigu.springmvc.interceptors.SecondInterceptor"></bean>
      </mvc:interceptor>

    </mvc:interceptors>

    多个拦截器的执行顺序

    preHandle正序

    postHandle和afterCompletion倒序

    异常处理

    Spring MVC 通过 HandlerExceptionResolver 处理程序
    的异常,包括 Handler 映射、数据绑定以及目标方法执行
    时发生的异常。

    ExceptionHandlerExceptionResolver

    主要处理 Handler 中用 @ExceptionHandler 注解定义的
    方法。用ModelAndView返回异常信息

    /**
    * 1. 在 @ExceptionHandler 方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象
    * 2. @ExceptionHandler 方法的入参中不能传入 Map. 若希望把异常信息传导页面上, 需要使用 ModelAndView 作为返回值
    * 3. @ExceptionHandler 方法标记的异常有优先级的问题. 越接近发生的异常的优先级越高
    * 4. @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常,
    * 则将去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常.
    */

    @ExceptionHandler({ArithmeticException.class})
    public ModelAndView handleArithmeticException(Exception ex){
    System.out.println("----> 出异常了: " + ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);
    return mv;
    }

    去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常. 

    package com.atguigu.springmvc.test;

    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.servlet.ModelAndView;

    @ControllerAdvice
    public class SpringMVCTestExceptionHandler {

    @ExceptionHandler({ArithmeticException.class})
    public ModelAndView handleArithmeticException(Exception ex){
    System.out.println("----> 出异常了: " + ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);
    return mv;
    }

    }

    ResponseStatusExceptionResolver

    自定义一个返回的页面

    可以作用在类上,也可以是方法上

    ①注册

    @ResponseStatus(value=HttpStatus.FORBIDDEN, reason="用户名和密码不匹配!")
    public class UserNameNotMatchPasswordException extends RuntimeException{

    /**
    *
    */
    private static final long serialVersionUID = 1L;


    }

    ②使用

    @RequestMapping("/testResponseStatusExceptionResolver")
    public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
    if(i == 13){
    throw new UserNameNotMatchPasswordException();
    }
    System.out.println("testResponseStatusExceptionResolver...");

    return "success";
    }

    也可以直接放在方法上,当调用此方法时,返回异常的页面

    @ResponseStatus(reason="测试",value=HttpStatus.NOT_FOUND)
    @RequestMapping("/testResponseStatusExceptionResolver")
    public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
    if(i == 13){
    throw new UserNameNotMatchPasswordException();
    }
    System.out.println("testResponseStatusExceptionResolver...");

    return "success";
    }

    DefaultHandlerExceptionResolver

    对一些特殊的异常进行处理,比
    如NoSuchRequestHandlingMethodException、HttpReques
    tMethodNotSupportedException、HttpMediaTypeNotSuppo
    rtedException、HttpMediaTypeNotAcceptableException
    等。

    SimpleMappingExceptionResolver

    如果希望对所有异常进行统一处理,可以使用 
    SimpleMappingExceptionResolver,它将异常类名映射为
    视图名,即发生异常时使用对应的视图报告异常

    <!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionAttribute" value="ex"></property>
    <property name="exceptionMappings">
    <props>
    <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
    </props>
    </property>
    </bean>

  • 相关阅读:
    [程序员代码面试指南]数组和矩阵问题-未排序正数数组中累加和为给定值的最长子数组长度
    [Mysql]知识点
    [SSM项目]一-Eclipse 搭建marven-web项目 hello world!
    [BZOJ2252]矩阵距离(BFS)
    [Spring实战笔记]4面向切面编程的Spring-代理
    [程序员代码面试指南]数组和矩阵问题-找到无序数组中最小的k个数(堆排序)
    [Java]刷题中的Java基础
    MySql的大小写问题
    MySql密码丢失
    MySql的rpm安装
  • 原文地址:https://www.cnblogs.com/yydeyi/p/4724106.html
Copyright © 2011-2022 走看看