zoukankan      html  css  js  c++  java
  • 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 子节点来规定只能扫描的注解。

        

     

     

  • 相关阅读:
    尾递归优化
    EOS Dawn 3.0 智能合约 -- 新格式
    以太坊钱包初探
    理解以太坊的椭圆曲线签名-校验签名
    以太坊交易字段
    以太坊的账户和交易
    以太坊源码探究之交易与签名
    以太坊交易签名
    L05 Laravel 教程
    thinkphp3.2配置redis缓存和文件缓存
  • 原文地址:https://www.cnblogs.com/zhuxiang1029/p/13046558.html
Copyright © 2011-2022 走看看