SpringMVC-10-SpringMVC全部笔记总结

初识SpringMvc

什么是MVC

  • MVC是用来分层解耦的。

  • Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写。

  • 一个请求进来,会先经过展示层(控制器 和 视图 servlet) ---- 业务逻辑层(spring) ---- 数据访问层(jdbc mybatis) ---- 数据库

  • 一个请求进行,会先经过控制器(Controller SpringMVC) ---- 模型(Model spring [实体Bean 业务Bean]) ------数据访问层(Mybatis) ---数据库

SpringMVC基础概念

  • SpringMVC是基于spring的,是spring的一个模块,做web开发使用。使用spring核心技术做web开发,springMVC内部使用的是 MVC架构。

  • SpringMVC也是一个容器,用来管理对象,使用的是IOC技术,SpringMVC管理界面层中的控制器对象。

  • SpringMVC底层是Servlet,接受请求,处理请求,显示处理结果给用户。

  • SpringMVC处理请求笼统过程描述: 用户发起请求 --- SpringMVC --- 调用Spring托管的dao service----Mybatis --- 数据库

  • SpringMVC中的核心Servlet 叫做: DisPatcherServlet,负责接收请求,响应请求处理结果,它的父类是HttpServlet。

  • DisPatchServlet也叫做前端控制器(front controller)。

  • SpringMVC管理控制器对象,原来在没有springMVC之前,会将Servlet作为控制器对象使用。现在通过SpringMVC创建一种叫做控制器的对象,代替Servlet
    行使控制器的角色和功能。

  • SpringMVC是基于Spring的,是Spring中的一个模块,也叫做SpringWeb MVC,使用Spring的核心技术,做WEB开发。

  • SpringMVC 也是一个容器,使用IOC技术管理对象,SpringMVC属于界面层,用于管理界面层的控制器对象,底层是Servlet,接收请求,处理请求,返回请求结果。

  • 用户发起请求给SpringMVC--Spring--Mybatis--数据库

SpringMVC使用方式

  • SpringMVC主要使用注解的方式创建控制器对象,处理请求。

SpringMVC中的核心Servlet-----中央调度器(DispatcherServlet)

  • DispatcherServlet是框架中的一个Servlet对象,他负责去接收请求,响应处理结果。它的父类是HttpServlet。

  • DispatcherServlet也叫做前端控制器(front controller)。

  • SpringMVC可以管理控制器对象,原来没有SpringMVC的时候使用的是Servlet来管理控制器对象,现在通过SpringMVC容器创建一种叫做控制器对象,代替Servlet行使
    控制器的功能。

  • 新建SpringMVC的步骤

    • 新建WEB应用

    • 加入所需依赖

    • 声明SpringMVC核心对象DispatcherServlet(web.xml)
      DispatcherServlet的作用:(1) 在Servlet的init()方法中,创建SpringMVC中的容器对象,创建所有java对象,也就是Controller对象。
      (2) 作为Servlet接收请求。

      DispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:Dispatcher-Servlet.xml 1 DispatcherServlet *.do
      • 创建一个JSP页面 发起请求

      • 创建一个普通的类作为控制器使用,代替之前的Servlet。
        在该类上边要加入一个@Controller注解或者实现Controller接口
        在该类中定义方法,方法的上边要加入一个@RequestMapping()注解。该方法是处理请求的,相当于doGet()、doPost()。
        该注解中写请求名,@RequestMapping(value = {"/some.do","/first.do"}),可以写多个。

      • 可以写多个Controller类,每一个Controller类中可以写多个方法(增删改查)。

      • 创建一个作为结果的JSP页面。

      • 创建SpringMVC的配置文件。
        声明组件扫描器,指定@Controller所在的包
        视图解析器
        逻辑视图名称

  • SpringMVC 请求过程

    用户发起请求some.do --- TomCat接收了请求(Tomcat根据Web.xml文件中的*.do)
    Tomcat发现扩展名是.do结尾的,所以将some.do请求交给了当前DispatcherServlet对象处理(中央调度器),中央控制器中收集了所有请求。并将这些请求存储在一个Map中
    例如:Map(类名key,请求名Value)。DispatcherServlet对象(中央调度器)根据springMVC的配置文件,解析注解,将这个请求分配给了Controller类(后端控制器)根据注解@RequestMapping注解,
    将请求分配给Controller类下的方法,doSome()方法,doSome()方法处理请求,返回ModelAndView对象给前端页面。

    首先,SpringMVC框架在启动的时候会遍历Spring容器中的所有bean,对标注了@Controller或@RequestMapping注解的类中方法进行遍历,
    将类和方法上的@RequestMapping注解值进行合并,(@RequestMapping注解的相关参数值 如value、method等等)封装一个RequestMappingInfo对象中,
    然后将这个Controller实例、方法及方法参数信息(类型、注解等等)封装到一个HandlerMethod对象中。
    然后以RequestMappingInfo对象为key,HandlerMethod对象为value封装到一个以Map为结构的handlerMethods对象中。
    接着,将@RequestMapping注解中的value(即请求路径)值取出,即url,然后以url为key,以RequestMappingInfo为value,存到一个以Map为结构的urlMap对象属性中。

    客户端发起请求的时候,根据请求的URL到urlMap中查找,找到RequestMappingInfo,然后根据RequestMappingInfo到handlerMethods中查找,找到对应的HandlerMethod,
    接着将HandlerMethod封装到HandlerExecutionChain对象中;接着遍历容器中所有HandlerAdapter实现类,找到支持这次请求的HandlerAdapter,
    如RequestMappingHandlerAdapter,然后执行SpringMVC拦截器的前置方法(preHandle方法),然后对请求参数解析及转换,
    然后(使用反射)调用具体Controller的对应方法返回一个ModelAndView对象,执行拦截器的后置方法(postHandle方法),然后对返回的结果进行处理,最后执行afterCompletion方法。

SpringMVC注解式开发

  • @RequestMapping注解

    • 该注解可以放在类上使用,也可以放在类下的方法上使用。

    • 在同一个Controller类中存在多个方法,那么该类下的方法上 @RequestMapping注解值,都会有一个公用的请求路径,那么就可以把/test/这个请求路径提取出来,放在类上边

           @RequestMapping(value = {"/test/some.do","/test/first.do"})
           @RequestMapping(value = {"/test/other.do","/test/second.do"})
      
    • @RequestMapping(value(),method) 有两个属性,一个Value中填写请求地址,另一个是method,填写请求方式。
      例如: @RequestMapping(value = ("/test"), method = RequestMethod.GET)

    • @RequestParam(value="",required=true/false) 该注解用来指定form表单请求参数的参数名。require表示是否允许为空。

各个配置文件说明

  • web.xml 部署描述符文件 该文件是给服务器用的,给Tomcat用的,TomCat在启动的时候,读取web.xml,根据文件中的各种声明,创建各种对象 和 通过web.xml的各种声明描述
    知道 各种请求和Servlet的对应关系。

  • 框架配置文件,ApplicationContext.xml、spring-servlet.xml,beans.xml,声明框架创建的项目中的各种对象,主要是创建Controller对象。

  • 配置文件加载的顺序: Tomcat服务器启动,首先要读取的是 web.xml文件,根据web.xml文件中的声明,首先会创建一个DispatcherServlet对象,
    在创建DispatcherServlet对象的过程中会在init()方法中进行SpringMVC容器对象的创建

    contextConfigLocation
    classpath:springmvc-servlet.xml

    相等于 WebApplicationContext context = newClassPathXmlApplicationContext("spring-servlet.xml");
    SpringMVC容器对象创建的时候读取SpringMVC配置文件 spring-servlet.xml。

    • 读取SpringMVC配置文件,会解析到配置文件中声明的组件扫描器,然后遍历com.shi.controller包中的所有类,
      将controller包中的类上带有@Controller注解的类使用IOC控制反转创建对象,统一管理。也会扫描到@RequestMapping注解,也就知道了请求路径,知道了/some.do请求
      执行哪个方法。

    • 用户发起请求some.do,请求首先进过DisPatcherServlet,DisPatcherServlet根据初始化时候读取配置文件获取到的信息,
      会将该请求分发给对应的Controller对象,执行所对应的方法

如何在Controller类中接收请求参数

 - 如果需要 HttpServletRequest,HttpServletResponse, HttpSession 可以在形参中直接定义,就可以使用了。

 - 接收请求中的参数又分为两大类,逐个接收  和  对象接收

 1.逐个接收参数(表单中的参数名 和 Controller形参名称一致的情况)
        - 使用框架的时候,只要保证form表单中所提交的参数的参数名,和Controller类形参中的参数名一致,类型一致,就可以直接接收表单数据。
          相当于  request.getParameter(String name);
     
        - 当允许表单所提交数据为空的时候,Controller类的形参类型,应该为包装类型,这样允许为空,才能够提交NULL
  
 2.逐个接收参数(表单中的参数名 和 Controller形参名称不一致的情况)
     
         - 使用@RequestParam注解:  解决表单中的参数名 和 Controller形参参数名不一致的情况
 
         - 该注解有两个属性 value 和 required,
            
           value 用来表示请求中的参数名,放在形参定义的前面。
           public ModelAndView getParam(@RequestParam(value = "username") String name, int age);
 
           required 默认值是true,true表示请求中必须有此参数,不能为空,没有就报错;false表示请求中可以没有此参数,可以为空。

 3. 对象接收
 
        - 后台控制器方法的形参是java对象,使用java对象的属性接收请中的参数值。

        - java对象的属性名要是形式参数名保持一致

解决乱码问题

  • request.setCharacterEncoding("utf-8"); 该方式需要在接收参数之前设置有效,设置动态文字(参数,数据库)

  • response.setContentType("text/xml;charset=GBK") 设置页面静态文字 ,作用是让浏览器用utf-8来解析返回的数据

  • response.setCharacterEncoding() 告诉servlet用utf-8转码,而不是默认的iso8859-1,是设置从request中取得的值或从数据库中取出的值

  • 设置过滤器,在web.xml中,框架提供了一个过滤器. 使用框架自带过滤器。

    characterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter
    <!--属性1. 项目所使用的的字符编码-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
    
    <!--属性2. 强制请求对象 request,使用encoding编码方式-->
    <init-param>
        <param-name>forceRequestEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    
    <!--属性3. 强制响应对象 response ,使用encoding编码方式 -->
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    
    characterEncodingFilter /*

后台控制器的返回值类型

  • 返回值类型包括: ModelAndView、Model、String、void、Object。
  1. ModelAndView

    • ModelAndView 包括数据和视图两部分,其中数据存放在request作用域; 视图执行forward转发操作。
  2. Model

    • Model 只是用来传输数据的,不能存放视图,不能进行业务寻址。
  3. String

    • String 只是用来传输视图(静态页面地址,完整视图路径/逻辑名称),框架对于返回值为String的操作,会执行forward转发操作。

    • 使用String不能存放数据,但是可以使用HttpServletRequest对象,将数据存放在request域中。

    • 返回String字符串的视图地址,字符串表示完整视图路径的时候(不能配置视图解析器,要不然前缀和后缀地址就重复了)

    • 返回String字符串视图地址, 逻辑路径(是指已配置了视图解析器,只需要返回一个视图名就可以了)

  4. void

    • void 既不返回数据,也不返回视图。主要做ajax请求处理。

    • 可以使用HttpServletResponse输出数据,响应ajax请求。

    • 这里遇到一个问题,引入js文件报错404,是因为servlet-mapping中使用了'/',这样静态文件直接给过滤了。

    • 在pom.xml中引入了新的依赖以后,需要去项目结构中更新一下当前工程的lib文件夹。

  5. Object

    • 返回数据Object,可以使集合、Student、User,String,这些都是数据,而Ajax请求需要的就是数据,所以后台控制器返回对象的时候一般都是响应ajax请求。

    • 在ajax请求中,一般需要从服务器端返回的是json格式的数据,所以我们需要处理java对象到json字符串的转换,而且还需要将json数据输出,去响应ajax的请求。

    • 框架提供了java对象到json转换,还有将json字符串输出的工作。

    • HttpMessageConverter接口 消息转换器,作用:
      1) 实现将前台页面发过来的请求所携带的数据转换为java对象
      2) 将后台控制器方法返回的对象转换为json,xml,text,二进制等不同格式的数据。

    • 视图页面(html,jsp等)发起请求并携带数据(name=zhangsan;password=123),后端控制器接收到请求和数据,
      并使用HttpMessageConverter接口将前台页面发过来的请求所携带的数据转换为java对象,给Controller使用。
      Controller处理完成返回给前端页面一个对象,但是Ajax需要json字符串,此时继续使用HttpMessageConverter接口
      将对象转换为json字符串,返回给前端页面。

  6. String 类型的数据 不是视图

    • 当一个后台控制器方法上加了@RequestBody注解以后,那么该方法如果返回String类型对象,该String类型对象将不是一个视图,而是一个String类型的数据。

    • 返回该字符串响应给浏览器会发现出现了乱码,因为ajax请求不会经过过滤器,所以配置的过滤器没有起作用。

      • 解决该乱码: 需要使用@RequestMapping注解中的一个属性produces。
      • produces属性: 可以指定本次请求content-type的值。
        @RequestMapping(value = "return-StringData-ajax.do", produces = "text/plain;charset=utf-8")

HttpMessageConverter接口

  • HttpMessageConverter接口下的方法(这四个方法不用程序员手动调用,框架会自动调用)

    • boolean canRead(Class<?> clazz,@Nullable MediaType mediaType);
      MediaType: MediaType表示媒体类型,是指在互联网中所传输的数据格式,例如:application/json、text/html、 image/gif
      作用: 检查clazz这个类能否转换成mediaType所表示的数据格式,如果能转换为mediaType那么就返回true,就会调用read()方法; 如果不能转换为mediaType那么就返回false。

    • T read(Class<? extends T>clazz,HttpInputMessage inputMessage);
      作用:接收请求中携带过来的数据,将数据转换为clazz所表示的对象。

    • boolean canWrite(Class<?> clazz,@Nullable MediaType mediaType);
      作用: 检查clazz这个类型能否转为 mediaType所表示的数据格式。如果能就返回true,就会调用write()方法。

    • void write(T t,@Nullable MediaType mediaType, HttpOutputMessage);
      作用: 把T对象,按照mediaType所说明的格式,将Object转换为mediaType所对应的格式(json,xml...)

HttpMessageConverter接口的实现类

  • 该接口下有很多实现类,主要掌握两个实现类就可以。

    • MappingJackson2HttpMessageConverter
      作用: 使用Jackson工具库中的ObjectMapper,把java对象转换成json的数据格式

    • StringHttpMessageConverter
      作用: 把字符串类型的数据,进行格式的转换和编码。

  • 怎么使用实现类呢?

    • 框架根据后端控制器方法的返回值类型,自动查找使用实现类。

    • 默认情况下,SpringMVC使用了HttpMessageConverter接口下的四个实现类,包括了StringHttpMessageConverter,
      但是不包括MappingJackson2HttpMessageConverter,所以需要在SpringMVC的配置文件中,加入一个注解驱动的标签,mvc:annotation-driven。
      加入了这个注解驱动标签后,SpringMVC项目启动后会创建HttpMessageConverter接口下的八个实现类对象,包括了MappingJackson2HttpMessageConverter实现类。

      mvc:annotation-driven/

      相等于:
      //把对象转换为json格式并赋值
      ObjectMapper objectMapper = new ObjectMapper();
      String json = objectMapper.writeValueAsString(user);
      System.out.println("服务器端的对象转为的json字符串"+json);

注解 @RequestBody注解 自动输出

  • 作用: @RequestBody注解 把HttpMessageConverter接口转换后的数据通过HttpServletResponse对象输出给浏览器。

    相等于:
    //输出Json到前端页面响应ajax
    response.setContentType("application/json;charset=utf-8");
    PrintWriter out = response.getWriter();
    out.println(json);
    out.flush();
    out.close();

后台控制器返回对象(Object) 转换为json的步骤

  1. 在pom.xml中加入jackson的依赖,SpringMVC框架,默认处理json字符串就是使用的jackson。

  2. 在SpringMVC的配置文件中,加入注解驱动的标签mvc:annotation-driven/

  3. 在控制器方法上加 @RequestBody注解,表示将转换后的Object数据,响应给浏览器。

  • 框架是怎么做到自动将返回值类型(Object)转换为各种字符格式的呢?

    1.框架会根据控制器方法的返回值类型(ModelAndView、String、Void、Object),找到HttpMessageConverter接口,然后在该接口中找到8中实现类中的对应的实现类。

    2.找到实现类MappingJackson2HttpMessageConverter以后,执行该类的Write()方法,将返回的user对象转换为json格式的数据。

    3.框架提供@ResponseBody注解,通过HttpServletResponse对象,将第二步中转换好的json数据,输出给了浏览器。

后台控制器返回String类型数据的过程

  1. 框架会根据控制器方法的返回值类型(ModelAndView、String、Void、Object),找到HttpMessageConverter接口,然后在该接口中找到8中实现类中的对应的实现类。

  2. 处理String类型数据的实现类是 StringHttpMessageConverter类。StringHttpMessageConverter使用的编码方式是 text/plain;charset=ISO-8859-1。

  3. 该类返回的不是json字符串,而是text文本。

中央调度器(front controller) 中的

  • *.do .do表示所有以.do结尾的请求,都交给当前DispatcherServlet来处理分发。

    • 那么.do以外的请求是谁处理的呢? 由Tomcat自带的一个DefaultServlet处理的,在Tomcat文件夹中有一个自带的web.xml,该文件中配置了DefaultServlet,

    • 作用: 该Servlet处理所有未被映射到其他Servlet的请求,和静态资源的处理。

    • 位置: Tomcat安装目录--->conf---->web.xml

  • / / 表示所有请求都交给当前DispatcherServlet来处理分发包括静态资源,但是当前DispatcherServlet处理不了静态资源。

    • 当我们自己配置的DispatcherServlet的url-pattern使用了 / 以后,就代表着当前DispatcherServlet取代了defaultServlet,
      所有请求都交给当前DispatcherServlet来处理分发包括静态资源,但是当前DispatcherServlet处理不了静态资源。

    • 为什么当前DispatcherServlet处理不了静态资源?
      因为DispatcherServlet,会将请求分发给后台控制器(Controller),但是并没有相应的处理静态资源的后台控制器对象,所以会报错404.

如何解决静态资源不能处理的情况呢?

  • 方式一

    • 在SpringMVC配置文件中创建DefaultServletHttpRequestHandler对象,它会像一个检查员一样,对DispatcherServlet的请求URL进行筛查
      如果发现是静态资源请求,就将该请求转由Tomcat自带的默认Servlet,DefaultServlet处理。

    • 创建DefaultServletHttpRequestHandler对象的方式?

      1. 注解方式: mvc:default-servlet-handler/

        但是该注解和@RequestMapping注解有冲突,会导致动态资源(some.do)无法访问,所以要使用mvc:default-servlet-handler/,必须先声明 mvc:annotation-driven/

  • 方式二

    • 在SpringMVC配置文件中创建ResourceHttpRequestHandler控制器对象,它会去处理静态资源的访问,这种方式不依赖Tomcat服务器。是框架来处理的。

    • 如何创建ResourceHttpRequestHandler对象?

posted @ 2021-07-22 16:55  失昼  阅读(91)  评论(0编辑  收藏  举报