05-springMVC(下)

解决问题:

 1.数据类型转换 (页面提交的所有数据都是字符串 。如String age=request.getParameter("age");

 2.数据格式(如 提交的日期进行转换 birth=2017-12-15-----> Date  格式是2017/12/15 还是 2017.12.15还是。。。)

 3.数据校验(我们提交的数据必须是合法的?前端:js+正则表达式。后端:也是必要的。 )

数据绑定流程原理(debug看源码可以结合尚硅谷雷丰阳老师的视频,这里不分析源码)

Spring MVC 通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。

数据绑定的核心部件是 DataBinder(数据绑定器),运行机制如下:

Spring MVC 抽取 BindingResult (绑定期间,效验的结果保存)中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

自定义类型转换器

  ConversionService  Spring 类型转换体系的核心接口。

  Spring 定义了 3 种类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到 ConversionServiceFactoryBean 中:

  Converter<S,T>:将 S 类型对象转为 T 类型对象(就用这个,不管其他2

一.数据类型转换

步骤:

1)ConversionService;是一个接口;

里面有converter(转换器)进行工作;

(动手操作粗体

实现converter接口,写一个自定义的类型转化器

Converter是ConversionService中的组件

你的converter得放进ConversionService中

2 将webDataBinder中的conversionservice设置成我们这个加了自定义类型转换器的conversionservice

配置出ConversionService,让springmvc用我们的ConversionService

4 源码上webDataBinder上的conversionservice组件就替换了,虽然替换了,但是默认的类型转换(比如string-->int之类的)还在,只是增加了刚刚定义的那一个。

例子1,在上次crud的基础上增加一个快速添加的功能。

    思路:

      1,编辑页面,点击快速添加。

      2,去到控制层,获取参数,希望转数据类型(string-->employee)。

      3,自定义一个数据类型转换器类(继承Converter,把 string 转为 employee)。

      4,去springmvc配置文件里注册一个自定义数据类型转换类。

<!--list.jsp里加上-->
<form:form action="${ctp}/quickAdd">
    <!--将员工的所有信息都写上,自动封装对象-->
    <input name="empinfo" value="empAdmin-admin@qq.com-1-101">
    <input type="submit" value="快速添加">
</form:form>
package com.atguigu.control;

import com.atguigu.bean.Employee;
import com.atguigu.dao.DepartmentDao;
import com.atguigu.dao.EmployeeDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * Created by Zhuxiang on 2020/6/5.
 */
@Controller
public class EmployeeController {
    @Autowired
    EmployeeDao employeeDao;
    @Autowired
    DepartmentDao departmentDao;
    /**
     * list传过来是 quickAdd?empinfo=empAdmin-admin@qq.com-1-101
     * @RequestParam("empinfo") Employee employee 意思是
     *     ===>  Employee employee=request.getParameter("empinfo")(转不了!)
     *     必须要自己写一个自定义类型的转换器。
     *      去到component包,编写mystringToEmployeeConverter
     */
    @RequestMapping("/quickAdd")
    public String quickAdd(@RequestParam("empinfo") Employee employee){
        System.out.println("最后结果是   "+employee);
        employeeDao.save(employee);
        return "redirect:/emps";
    }
}
控制层

自定义一个数据类型转换器

package com.atguigu.component;

import com.atguigu.bean.Department;
import com.atguigu.bean.Employee;
import com.atguigu.dao.DepartmentDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;

/**
 * Created by Zhuxiang on 2020/6/5.
 *  Converter<S,T>
 *  s:source
 *  T:target
 */
public class MyStringToEmployeeConverter implements Converter<String, Employee> {
@Autowired
DepartmentDao departmentDao;
    @Override
    public Employee convert(String s) {
        System.out.println("页面提交的要转的字符串"+s);
        if(s!=null){
            String[] strs = s.split("-");
                String lastName = strs[0];
                String email = strs[1];
                Integer gender = Integer.parseInt(strs[2]);
                Integer deptId = Integer.parseInt(strs[3]);
                Department dept = departmentDao.getDepartment(deptId);
                Employee employee = new Employee(null,lastName,email,gender,dept);
                System.out.println(s+"--converter--"+employee);
                return employee;
        }else{
            return null;
        }
    }
}
MyStringToEmployeeConverter

在springmvc配置文件里注册。

    <!--使用自己配置的conversionservice类型转换组件,而不是默认的-->
    <mvc:annotation-driven conversion-service="myConversionService"/>

    <!--告诉springmvc别用默认的conversionservice,用我们自定义的实现了convert接口的类-->
<!--    <bean id="myConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">-->
    <!--以后写自定义类型转换器的时候,就使用 FormattingConversionServiceFactoryBean 来注册
        既具有类型转换又具有格式化功能(如日期格式化)-->
    <bean id="myConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!--converters转换器中添加我们自定义的类型转换器-->
        <property name="converters">
            <set>
                <bean class="com.atguigu.component.MyStringToEmployeeConverter"></bean>
            </set>
        </property>
    </bean>
dispatcher-servlet.xml

二,数据格式

 

 

  1. 关于 <mvc:annotation-driven /> 作用

l <mvc:annotation-driven /> 会自动注册:

RequestMappingHandlerMapping RequestMappingHandlerAdapter 

ExceptionHandlerExceptionResolver  三个bean

还将提供以下支持:

支持使用 ConversionService 实例对表单参数进行类型转换

支持使用 @NumberFormat@DateTimeFormat 注解完成数据类型的格式化

支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证

支持使用 @RequestBody @ResponseBody 注解

1) 日期格式化概述

1) 实验代码(格式化日期)

 

格式化:页面提交的数据格式如果不正确,就报400

日期格式2017-12-19

Conversionservicefactorybean:创建的conversionservice组件是没有格式化器存在的。

所以如果要用自定义的conversionservice

(类型转换器)。

 

@RequestMapping("/haha")
public ResponseEntity<String> haha(){

 

 

 springMVC提供了拦截器机制;允许运行目标方法之前进行一些拦截工作,或者目标方法运行之后进行一些其他处理;

 filter;是javaweb提供的拦截器。

拦截器(HandlerInterceptor):是springMVC提供的拦截器。

    preHandle(httpservletrequest,httpservletresponse):在目标方法运行之前调用,返回boolean; return· true,(chain.doFilter())放行;return false,不放行。

    postHandle(httpservletrequest,httpservletresponse,modelandview):在目标方法运行之后调用 ;目标方法调用之后。

    afterCompletion(httpservletrequest,httpservletresponse,exception):请求整个完成之后,来到目标页面之后;chain.doFilter()放行;资源响应之后。

  1)拦截器是一个接口

  2)实现HandlerInterceptor接口。

  3)配置拦截器

  4)拦截器的正常运行流程

  拦截器的preHandle方法--->目标方法--->拦截器postHandle--->页面--->拦截器的afterCompletion

  MyFirstInterceptor...preHandle...
  test01...
  MyFirstInterceptor...postHandle...
  success.jsp...
  MyFirstInterceptor...afterCompletion...

  其他流程:

  1,只要preHandle不放行就没有以后的流程了。

  2,只要放行了,afterCompletion就都会执行。

  多个拦截器

  正常流程:

  MySecondInterceptor...preHandle...
  MyFirstInterceptor...preHandle...
  test01...
  MyFirstInterceptor...postHandle...
  MySecondInterceptor...postHandle...
  success.jsp...
  MyFirstInterceptor...afterCompletion...
  MySecondInterceptor...afterCompletion...

  异常流程:

  1.不放行;

    1)如果MyFirstInterceptor...preHandle...不放行,那么它前面已经放行了的拦截器的afterCompletion还是会执行。

    MySecondInterceptor...preHandle...
    MyFirstInterceptor...preHandle...

    MySecondInterceptor...afterCompletion...

  流程:filter的流程;

    拦截器的 preHandle 按顺序执行

    拦截器的 postHandle 按逆序执行

    拦截器的 afterCompletion 按逆序执行

    前面已经放行了的拦截器的afterCompletion还是会执行

    

 

 

问题:什么时候用filter,什么时候用拦截器?

  filter是javaweb3大组件之一,由tomcat执行,随着tomcat的启动而启动,

  而拦截器是在ioc容器里的,由springMVC执行。

如果某些功能需要其他组件配合完成,我们就使用拦截器。

其他简单的情况,就用filter,它就一个dofilter方法。

 springmvc配置国际化就不写了,可以去看尚硅谷springmvc的视频。

异常处理  springmvc里自带3个异常解析器。

解析是按顺序来的,1 2 3,如果都不能处理就抛出给tomcat。

1   ExceptionHandlerExceptionResolver

主要处理 Handler 中用 @ExceptionHandler 注解定义的方法

2   ResponseStatusExceptionResolver

在异常及异常父类中找到 @ResponseStatus 注解,然后使用这个注解的属性进行处理。

3   DefaultHandlerExceptionResolver

判断是否springmvc自带的异常

springmvc自己的异常,如HttpRequestMethodNotSupportedException,1,2异常解析器都没管的话。

springmvc运行流程。

 

 1,所有请求,前端控制器(DispatcherServlet)收到请求,调用doDispatch进行处理

      DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI):

      判断请求URI对应的映射

        1)不存在:

          a)再判断是否配置了mvc:default-servlet-handler

          b)如果没配置,则控制台报映射查找不到,客户端展示404错误

          c)如果有配置,则执行目标资源(一般为静态资源,如:JSP,HTML

        2)存在:继续

 2,根据HandlerMapping中保存的请求映射信息找到,处理当前请求的,处理器执行链(包含拦截器)

 3,根据当前处理器找到他的HandlerAdapter(适配器)

 4,拦截器的preHandle先执行

 5,适配器执行目标方法,并返回ModelAndView。

     1),ModelAttribute注解标注的方法提前运行

     2),执行目标方法的时候(确定目标方法用的参数)

         1),有注解

         2),没注解:

            1)看是否Model,map以及其他的

            2)如果是自定义类型

                1)从隐含模型中看有没有,如果有就从隐含模型中拿

                2)如果没有,再看是否SessionAttribute标注的属性,如果是从session中拿,如果拿不到会抛异常。

                3)都不是,就利用反射创建对象。

6,拦截器的postHandle执行

7,处理结果;(页面渲染流程)

    1),如果有异常使用异常解析器处理异常;处理完后还会返回ModelAndView

    2),调用render进行页面渲染

         1),视图解析器根据视图名得到视图对象

         2),视图对象调用render方法;

    3),执行拦截器的afterCompletion;

 springMVC和spring整合

 springMVC和spring整合的目的,分工明确。

 springMVC的配置文件就来配置和网站转发逻辑以及网站功能有关的(视图解析器,文件上传解析器,支持ajax。。。);

 spring的配置文件来配置和业务有关的(事务控制,数据源。。。);

问题:bean被创建两次。

     方式一(不推荐),springMVC配置文件里加上<import resource="spring.xml">

     再分别进行springmvc和spring的文件配置,虽然分开写配置文件了,但是还是在同一个ioc容器里。

     方式二(推荐),使用exclude-filter 和 include-filter 子节点来规定只能扫描的注解。

    

 

 

原文地址:https://www.cnblogs.com/zhuxiang1029/p/13046558.html