框架学习——springMVC(5)

一、创建 springMVC 的项目

  1. 创建一个新的 maven 项目;

  2. 添加依赖:

    • <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.zhong</groupId>
          <artifactId>springMVCdemo</artifactId>
          <version>1.0-SNAPSHOT</version>
          <modules>
              <module>deno1</module>
          </modules>
          <packaging>pom</packaging>
      
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.3.7</version>
              </dependency>
      
          </dependencies>
      
          <!--    采用tomcat的maven插件,它提供了tomcat的功能    -->
      <build>
          <plugins>
              <plugin>
                  <groupId>org.apache.tomcat.maven</groupId>
                  <artifactId>tomcat7-maven-plugin</artifactId>
                  <version>2.2</version>
                  <configuration>
                      <port>8080</port>
                      <path>/</path>
                      <uriEncoding>UTF-8</uriEncoding>
                      <server>tomcat7</server>
                  </configuration>
              </plugin>
          </plugins>
      </build>
      
      </project>
      
  3. 项目类型改为 war;

  4. 添加 web 的主目录;webapp/WEB-INF/web.xml;

  5. 建立 web 包:com.zhong.web;

  6. 添加 springMVC 的配置文件(如果使用了默认的配置文件作为springMVC的配置文件,可以不用在resources下面创建配置文件,命名规则:xxx-servlet.xml,xxx就是<servlet-name>xxx</servlet-name>):

    • <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
          <!--  指定包及子包下的类都会被扫描,关注类中是否使用了DI方面的注解,另外有了该配置DI的注解才能使用  -->
          <context:component-scan base-package="com.zhong.web"/>
          <!--  springMVC的注解,也就是注解驱动,它用来指定需要使用的三大器。这三大器与在控制器上使用的注解有关系  -->
          <mvc:annotation-driven/>
      </beans>
      
  7. 在 web.xml 中配置中央调度器(servlet):

    • <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
      
          <servlet>
              <servlet-name>springMVC</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <init-param>
                  <!--      指定springMVC配置文件所在的路径      -->
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:springMVC.xml</param-value>
              </init-param>
              <!--     保证中央调度器在容器启动时第一个启动   -->
              <load-on-startup>1</load-on-startup>
          </servlet>
          <servlet-mapping>
              <!--     让中央调度器处理所有以 .action 结尾的请求   -->
              <servlet-name>springMVC</servlet-name>
              <url-pattern>*.action</url-pattern>
          </servlet-mapping>
      </web-app>
      
  8. 创建处理器(控制器);控制器就像 Servlet 的作用,能够处理请求。

    • package com.zhong.web;
      
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.servlet.ModelAndView;
      
      /**
       * @author 华韵流风
       *
       * 所有的控制器都需要spring容器管理(但是它属于子容器,因为是在springmvc的配置文件中进行扫描的)
       */
      @Controller
      public class MyController {
              
              
      
          @RequestMapping("/hello")
          public ModelAndView hello(){
              
              
              ModelAndView mav = new ModelAndView();
              //指定实用的视图的逻辑名称和需要渲染的数据
              mav.setViewName("/hello.jsp");
              mav.addObject("hello", "hello springMVC");
      
              return mav;
          }
      }
      
  9. 使用 jsp 页面作为视图,使用 EL 表达式来展示数据。

  10. 添加启动命令:tomcat7.run(指定工作目录,就是当前模组的根目录)。

二、全面了解 spring 的处理器适配器可适配的处理器的类型

  1. 三大器(DispatcherServlet.properties 文件):

    • 处理器映射器:把请求的 URL 与处理请求的控制器进行匹配,从而找到并实例化对请求进行处理的控制器对象。getHandler 方法传入 Request 对象,因此该方法可以知道当前请求的方法(get,post等)以及 url,通过以上两份数据可以匹配到处理器当前请求的控制器。控制器一般就是基于 springMVC 框架所定义的 bean。

      • org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
         org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
        
    • 处理器适配器:把原本不能结合在一起的接口让它们能够在一起协调工作。首先判断当前的适配器是否支持当前的控制器,如果支持就执行当前适配器的 handle 方法,该方法的作用就是调用控制器处理当前请求的方法,var3 就是当前的控制器。

      • org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
         org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
         org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
        
    • 视图解析器:ViewResolver 是视图解析器接口,View resolveViewName(String viewName, Locate locate) 方法可以依据给定的视图逻辑名返回对应的视图对象,视图对象可以结合 model 进行渲染,得到最终展现的内容。InternalResourceViewResolver 称为内部视图解析器。

      • org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
        
    • 以上的实现类就是 springMVC 三大器的默认 Bean 的类型,常用。

  2. 控制器实现 Controller 接口:

    • package com.zhong.web;
      
      import org.springframework.web.servlet.ModelAndView;
      import org.springframework.web.servlet.mvc.Controller;
      
      /**
       * @author 华韵流风
       * @ClassName MyController2
       * @Description TODO
       * @Date 2021/7/3 20:15
       * @packageName com.zhong.web
       */
      @org.springframework.stereotype.Controller
      public class MyController2 implements Controller {
              
              
      
          public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
              
              
              ModelAndView mav = new ModelAndView();
              //指定实用的视图的逻辑名称和需要渲染的数据
              mav.setViewName("/hello.jsp");
              mav.addObject("hello", "Hello springMVC!");
      
              return mav;
          }
      }
      
    • 给容器添加该控制器的 Bean,并指定与它匹配的请求的 URL(name 表示与它匹配的请求的 URL):

    • <bean id="myController2" name="/myController2" class="com.zhong.web.MyController2"/>
      
  3. 实现 HttpRequestHandler 的控制器:

    • package com.zhong.web;
      
      import org.springframework.web.HttpRequestHandler;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      
      /**
       * @author 华韵流风
       * @ClassName MyController3
       * @Description TODO
       * @Date 2021/7/3 20:30
       * @packageName com.zhong.web
       */
      public class MyController3 implements HttpRequestHandler {
              
              
          public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
              
              
              httpServletRequest.setAttribute("hello", "Hello springMVC3!");
              httpServletRequest.getRequestDispatcher("/hello.jsp").forward(httpServletRequest,httpServletResponse);
          }
      }
      
    • 没有返回值,参数是请求和响应对象,同样需要添加控制器的 Bean,并指定与它匹配的 URL。实现该接口的控制器由 HttpRequestHandlerAdapter 来执行。

三、视图解析器

  • InternalResourceViewResolver 是默认的视图解析器,基本作用根据逻辑视图名找到对应的视图,结合 Model 创建 View(视图)对象,再调用 View 对象的 render 方法去渲染视图。对于 springMVC 的项目,一般要求所有的静态资源及视图(jsp,模板,pdf 之类)都不要对外公开,因此它们一般都放在 WEB-INF 目录下。(通过请求转发的方式访问 WEB-INF 下的资源,不能使用重定向的方法。)

  • 在 springMVC 中,通过视图解析器把非公开的资源进行映射,映射为控制器可以访问的资源。

  • <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--     前缀   -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--      后缀  -->
        <property name="suffix" value=".jsp"/>
    </bean>
    
  • 指定可以作为视图使用的文件路径的前缀和后缀。未出现的资源的文件名是不确定的,在具体的控制器的处理方法中未确定。方法中出现的就是逻辑视图名。

四、不同类型控制器执行原理的总结

  1. springMVC 包含三种常用的不同类型的控制器,分别是实现 Controller 接口,实现 HttpRequestHandler 接口,添加 @RequestMapping 注解。
  2. 前两种控制器是 springMVC 早期使用的控制器
    • 实现 Controller 接口的控制器,内部需要使用请求和响应对象来实现对请求的处理,返回 ModelAndView,与 Servlet 的原生处理方法比较相似,是一种原始的方式,不建议使用。
    • 实现 HttpRequestHandler 接口的控制器:内部需要使用请求和响应对象来实现对请求的处理,没有返回值,它更原始,需要通过请求或响应对象经过请求转发或重定向来实现结果,因此没有渲染的过程,不建议使用。
    • 添加了 @RequestMapping 注解的控制器:方法自定义,可以有多个,好处在于一个控制器可以有多个处理方法,方法的参数可以有多种组合(模型对象,请求响应会话对象都可以作为参数),也可以有自定义的各种参数包括基本类型,包括 vo 这种 javaBean 及其它的引用类型,返回值也可以有多种,比如返回字符串,返回 mav,也可以没有返回值;在方法,参数,返回值上还可以添加其它的各种注解来丰富增强方法的功能,是现在推荐的方式。

五、在 web.xml 中针对中央调度器的 url-pattern 的配置形式

  1. *.action 把以 action 作为后缀的 url 请求交给中央调度器来进行处理,要求对所有控制器的访问必须带上 .action,针对静态资源或 .jsp 文件的访问不会交给中央调度器处理。因此,在传统的开发过程中,没有采用 restful 风格的请求。

    • restful 含义是表示层状态转化,是 web 技术刚出现时制定者所确定的规范,前提在于 http 的请求是无状态的,为了让请求变得有状态,才制定了 restful 的请求规范。
    • restful 风格的请求就要求用户请求的资源必须使用名词,请求的方法必须使用动词(get,post,put,delete 等),请求的参数必须是 url 的一部分,资源名称必须是 url 中的一部分。
    • 现在的基于 web 技术的实现,基本上要求使用 restful 风格的请求方式。采用 *.action 这种形式的请求 url 与 restful 的风格是不匹配的。
  2. 采用 /,在 tomcat 的核心配置文件中,把 / 表示的请求交给默认的 servlet 处理,含义是所有没有对应的 servlet 的请求都交给 defaultServlet 处理,说明所有针对静态资源(html,img,css,js 文件)的请求都交给默认的 Servlet 处理。

    • 在 springMVC 中,/ 表示把所有的请求都要交给中央调度器处理,那么所有的资源也就由中央调度器处理,而静态资源应该由 defaultServlet 处理,而中央调度器是没有义务处理静态资源同时也没有能力处理,这种情况下会造成静态资源无法访问。

    • springMVC 的处理方式:

      1. 仍然把静态资源交给容器提供的 defaultServlet 处理,这种方案采用的是底层的技术,实现方式是添加一个配置:<mvc:default-servlet-handler/>。此时,静态资源仍然交给中央调度器处理,springMVC 就提供了 DefaultServletHttpRequestHandler 处理器来处理静态资源,对应适配器是 HttpRequestHandlerAdaptor。
      2. 由 springMVC 自己来处理静态资源,采用资源映射的方式,把静态资源映射为 springMVC 可以自己处理的资源。添加配置项 <mvc:resources mapping="/static/**" location="/static/"/>。location 表示静态资源所在的位置,mapping 表示静态资源的映射名称,**表示任意的目录(虚拟)层级。此时内部的处理器是 ResourceHttpRequestHandler,适配器仍然是 HttpRequestHandlerAdaptor。
      • 以上建议使用第二种。项目中所用到的所有的静态资源都要进行映射配置。这种方案直接访问 jsp,中央调度器不处理。
  3. 采用 /*:在 javaweb 原始应用中,如果 servlet 的 url-pattern 配置成 /* 表示所有的请求交给 servlet 处理。这种情形,中央调度器会拦截对所有 jsp 的请求也包括对 jsp 的转发处理,从而造成流程中断。

  • 总结:springMVC 是 web 层的框架,肯定需要与 javaEE 及容器打交道,仅就解决中央调度器应该处理什么类型的请求的问题就是一个复杂的问题。在项目中应该把中央调度器的请求映射配置为 /,原因在于满足 restful 风格的要求,也符合 springMVC 内部的设计要求。

六、控制器方法的返回值

  • 控制器也就是我们一直在讲的 handler (处理器),handler 是使用 springMVC 时程序员主要的设计对象,现在都采用 @RequestMapping 注解来映射客户的请求,这样可以在控制器中出现多个处理请求的方法。无论是 Servlet 还是 struct2 中的控制器,基本结构都是一个类处理一个请求,而 springMVC 的控制器做到了一个控制器可以处理多个不同的请求,这样程序的结构更加紧凑,代码的模块化也更好。
  1. 作为 springMVC 控制器的基本要求

    • 控制器的作用就是处理用户的请求,当前框架的控制器属于处理器执行链的一个重要部分,需要框架处理的请求首先会被中央调度器所接收并处理,依据请求的 URL 的值映射出需要进行处理的处理器执行链,执行链是一个有确定顺序的拦截器(多个)和处理器的链条,拦截器的执行位置有多个,主要在处理器执行的前和后,其中的核心是处理器,处理器的核心功能就是对请求进行处理的处理方法,这些方法的功能就决定了请求如何被处理及返回什么结果。
    • 控制器必须要被 spring 的容器管理,所以必须要作为容器中的 Bean 所存在。
  2. 控制器中处理请求的方法的基本设计内容

    • 方法的返回值:处理请求的方法可以有多种类型的返回值,不同的返回值对应不同的返回结果。

    • 返回 ModelAndView:这是 springMVC 控制器处理方法最基本的要求,当进行视图渲染时,两个基本要素分别是模型数据和视图对象。渲染视图是请求处理中后续一个重要步骤,此步骤不是必须的,比如用请求和响应对象进行转发和重定向,但这不是框架建议的方式。基本使用要求就是创建 ModelAndView 对象,并向对象中设置模型数据和逻辑视图名,最后返回该对象。返回的该对象作为视图渲染的入参对象。

      • @RequestMapping("/hello")
        public ModelAndView hello(){
                  
                  
            ModelAndView mav = new ModelAndView();
            //指定实用的视图的逻辑名称和需要渲染的数据
            //这就是逻辑视图名
            mav.setViewName("result");
            mav.addObject("hello", "Hello springMVC!");
            return mav;
        }
        
        
    • 返回 String:这种方式更体现出 springMVC 处理方法的一种灵活性:

      ①返回的字符串就是需要渲染的逻辑视图名,如果需要模型数据,可在入参中添加 Model 类型的参数,对应的对象由框架自动创建并传递进来;

      • @RequestMapping("/toString1")
        public String toString1(Model model){
                  
                  
            model.addAttribute("name","springMVC");
            //返回值就是需要渲染的逻辑视图
            return "result";
        }
        
        

      ②返回的字符串就是要返回的内容,需要给方法添加 @ResponseBody 注解,它的作用表示返回值作为响应内容的主体(响应体,响应正文)。

      • @RequestMapping("/toString2")
        public @ResponseBody String toString2(){
                  
                  
            //返回值就是需要返回的内容
            return "string result";
        }
        
        
    • 没有返回值:如果需要采用原生 Servlet 的方式来处理请求,可以不需要返回值,测试必须在请求参数中添加请求和响应对象,否则该方法不会起作用。

      • @RequestMapping("/toString3")
        public void toString3(HttpServletRequest request, HttpServletResponse response){
                  
                  
            //无返回值,按照以前写Servlet的方式
        }
        
        
    • 返回字符串:返回的字符串需要带有前缀,可以是 redirect 表示请求重定向,也可以是 forward 表示请求转发。如果是转发可以在请求等对象中设置属性数据并参入渲染,如果是重定向可以带请求参数。重定向的情况下,视图不能放在安全目录下,此种方式 springMVC 不建议这样用。请求和重定向的视图针对视图解析器所配置的前缀和后缀是无效的。

      • @RequestMapping("/toString4")
        public String toString4(){
                  
                  
         
            return "redirect:/toString1";
        }
        
        
    • 返回对象:最重要的一种。

      • 使用 springMVC 框架设计项目目前主要有两种方式,一是前端的视图与后端的 java 代码或控制器放在同一个工程中。这是一种较传统的方式,并未实现前后端分离。此时要求方法返回字符串或 ModelAndView。另一种就是前后端分离的情况。

      • 基本的使用要求:必须引入 jackson 的依赖。

        • <!--    添加 springMVC处理json数据的依赖    -->
                  <dependency>
                      <groupId>com.fasterxml.jackson.core</groupId>
                      <artifactId>jackson-annotations</artifactId>
                      <version>2.12.3</version>
                  </dependency>
          
                  <dependency>
                      <groupId>com.fasterxml.jackson.core</groupId>
                      <artifactId>jackson-core</artifactId>
                      <version>2.12.3</version>
                  </dependency>
          
                  <dependency>
                      <groupId>com.fasterxml.jackson.core</groupId>
                      <artifactId>jackson-databind</artifactId>
                      <version>2.12.3</version>
                  </dependency>
          
          
      • 在项目中,如果需要返回 json 对象,一般都会先创建一个对应的 pojo,把 pojo 转换为 json。方法上需要添加 @ResponseBody 注解。

        • @RequestMapping("/toString5")
          @ResponseBody
          public Object toString5(){
                      
                      
          
              return new Person("张三",20, Arrays.asList(new String[]{
                      
                      "李四","王五"}));
          }
          
          

七、@RequestMapping 注解的使用

  1. 主要作用:把请求的 url 映射到一个处理器的方法上,RequestMappingHandlerMapping 处理器映射器针对该注解来完成 url 到处理器方法的映射,它返回的是方法对象,因此对应的处理器适配器就知道去执行哪个方法。

  2. 在方法上使用该注解,处理器适配器不需要按照某种接口类型去执行接口的方法,因此使用该注解给编程带来了灵活性。

  3. 该注解的主要属性取值:

    • value:映射的 url,不需要带上主机名、接口和项目名,它是从项目名(/)开始表示的。
    • method:表示请求的方式(get,post,put,delete),它的取值决定了当前方法只能处理什么方式的请求。默认是 GET 请求。
    • produces:规定了请求头中所指定的内容类型,content-type 的值。
    • paramers:规定了请求中必须有指定的参数。
  4. 该注解可以用在控制器类上,如果一个控制器中有多个处理方法,这些方法可以规定一个统一的 url 前缀,那么可以使用该注解把前缀在该类上进行指定。这是一种常用的做法。

    • @RequestMapping(value = "/toString6",method = RequestMethod.POST)
      public String toString6(){
              
              
      
          return "result";
      }
      
      

八、请求处理方法的参数

  1. 可以使用 springMVC 内定的一些参数类型,如果需要使用一些内定的类型,可以把该类型作为入参来使用。只要指定了规定可使用的类型,框架结汇把相应的参数传递到方法中。比如请求、响应、会话、Model 等。

  2. 按照实际的请求参数(可有多个),可以在方法中定义对应的参数类型。如果需要接收表单的请求或 get 请求中带有请求参数的情况,

    • 各个参数都是单一的值。如果请求的参数名与方法的参数名不一样,控制器接收不到参数,此时需要给方法的参数添加 @RequestParam 注解,以指定请求参数的名称。required 表示该参数是否必须有。

      • @RequestMapping(value = "/toString7")
        public String toString7(@RequestParam(value = "name1",required = true) String name, int age,Model model){
                  
                  
            model.addAttribute("name",name);
            //取单一值
            System.out.println(name+" "+age);
            return "result";
        }
        
        
    • 请求参数对应 pojo 中的属性。这是项目中常用的方式。

      • @RequestMapping(value = "/toString8")
        public String toString8(Person person){
                  
                  
            //取pojo
            System.out.println(person);
            return "result";
        }
        
        
      • 以上两种方式参数的类型都可以自动转换。springMVC 的内部提供了转换器,所有转换器都实现了 Convert 接口,也可以自定义项目中需要使用的特殊类型的转换器。

    • restful 请求的 url 中所带有的参数。restful 的请求有两个特点:

      • 第一:请求的参数不使用 ?,而是作为 url 中的一个部分。

      • 第二:请求的方法不仅是 get 和 post,还包括其他方法。

      • @RequestMapping(value = "/toString9/{name}/{age}",method = RequestMethod.GET)
        public String toString9(@PathVariable("name") String name, @PathVariable("age") int age) {
                  
                  
            System.out.println(name + " " + age);
            return "result";
        }
        
        
    • 通过 ajax 发出的请求,如果参数是一个 json 数据:

      • <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        
            <script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
            <script>
                let test = () => {
                   
                   
                    $.ajax({
                   
                   
                        url: "/before/toString10",  //请求的url,后台的servlet
                        async: true,  //指定是否是异步请求
                        type: 'POST',  //请求类型
                        data: '{"name": "xyz", "age": 99}', //请求的数据
                        dataType: 'json',  //返回的数据类型
                        contentType: 'application/json;charset=utf-8',
                        cache: false,  //是否缓存
                        success: function (data) {
                   
                    //回调函数,把data渲染到页面中
                            $("#age").text(data.age);
                        }
                    });
        
        
                };
            </script>
        </head>
        <body>
        
        <h2 id="age">Hello World!</h2>
        <button onclick="test()">查询</button>
        
        </body>
        </html>
        
        
  •     @RequestMapping(value = "/toString10",method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
            @ResponseBody
            public Object toString10(@RequestBody Person person) {
          
          
                System.out.println(person);
                return person;
            }
    
    
    • 注意:@RequestBody 表示参数是通过请求正文或请求体传来的。请求方式不能是 GET,GET 没有请求体。produces = MediaType.APPLICATION_JSON_UTF8_VALUE 表示 ajax 的请求头必须指定为 application/json。
    • 使用 springMVC 实现文件上传:
      • 引用的依赖:commons-fileupload,commons-io。
      • 把 springMVC 的文件上传解析器在容器中进行注册,并指定相应的属性。强调 bean 的 id 必须为 multipartResolver。
      • 在请求处理方法的参数中,必须添加 MultipartFile 类型的参数用来接收上传文件。如果表单中有其它的普通字段也可以添加相应的参数。为了能够得到 ServletContxt 对象,参数再添加 HttpServletRequest 参数。
      • 在项目中添加上传文件的目录。
      • 利用 MultipartFile 对象把上传的文件保存到服务器上。
  • 关于响应结果乱码的问题:

    • 如果请求处理方法的返回值是响应体的内容,可能会出现乱码,解决方式:

    • @RequestMapping(value = "/toString11",method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
      
      
    • 也就是在 @RequestMapping 注解上添加属性:produces = MediaType.APPLICATION_JSON_UTF8_VALUE。

  • 关于请求结果乱码的问题,可以在 web.xml 中添加配置:

    • <!--  全局的编码转换过滤器  -->
      <filter>
          <filter-name>characterEncoding</filter-name>
          <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
          <init-param>
              <param-name>encoding</param-name>
              <param-value>utf-8</param-value>
          </init-param>
      </filter>
      <filter-mapping>
          <filter-name>characterEncoding</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
      

九、自定义拦截器

  • javaWeb 中有 Filter 过滤器,它的作用就是在 servlet 执行的前后分别完成一些功能。首先要实现 Filter 接口创建过滤器,另外要进行配置,指定它所过滤的请求。执行的主要方法是 doFilter(请求、响应、过滤链),主要的处理逻辑都在该方法中完成,包括 servlet 执行的前和后两个部分。

  • springMVC 提供了中央调度器,中央调度器是 servlet,因此它提供的过滤器基本上都是针对调度器。

  • 如果设计者需要在控制器的执行前后或视图渲染后执行一些功能,此时就可以通过拦截器来完成,拦截器在项目中主要用来书写日志,现在项目中用的比较多的就是对用户的登录情况进行拦截,以确定用户是否合法。

  • 拦截器的使用:

    1. 实现 HandlerInterceptor 接口。接口中三个方法的执行时机和顺序:

      • preHandle(请求处理前)
      • postHandle(请求处理后)
      • afterCompletion(视图渲染后)
    2. 配置拦截器:

      • <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/before/toString7"/>
                <bean class="com.zhong.interceptor.MyInterceptor1"/>
            </mvc:interceptor>
        
            <mvc:interceptor>
                <mvc:mapping path="/before/toString7"/>
                <bean class="com.zhong.interceptor.MyInterceptor2"/>
            </mvc:interceptor>
        </mvc:interceptors>
        
        
    3. 执行过程:

      • 注意,如果有多个拦截器,在控制器处理的前后,拦截器的执行顺序是相反的。这说明多个拦截器处于一种特殊的数据结构中,前面是队列,后面是堆栈。
    4. preHandle 方法的返回值:

      • 返回 true,拦截器按顺序执行。
      • 返回false:
        • 第一个返回 false,所有的都不执行(包括控制器)。
        • 第二个返回 false,两个 preHandler 都执行,第一个渲染后的方法执行,没有响应,其他都不执行。都是 false 同第一种情况。
        • 结论:无论有多少个拦截器,所有的 preHandle 都可以决定控制器是否执行,任何一个拦截器返回 false 都会拦截控制器的执行。一般在第一个方法中 preHandle 来判断执行条件是否符合,在第二个方法中对处理后的环境进行恢复,在第三个方法中对模型数据进行回收等。在项目中一般只用到第一个方法。
        • springMVC 考虑到多半只使用其中的某个方法,所以提供了针对三个方法的适配器,在设计时,如果需要使用哪个方法,就继承哪个适配器。适配器名称:HandlerInterceptorAdapter。

十、统一异常处理

  • 在项目中,控制层,业务逻辑层,数据访问层中都可能对产生异常。
  • springMVC 提供了统一的异常处理方案,它主要针对两种异常,一种是用户自定义的异常,另一种就是系统的异常。这种方案的好处是不用再任何层去处理异常,另外也可以提供有效的异常信息给用户查看,还可以把不需要特别处理的异常放在一个类中进行集中处理。
  1. 创建自定义的异常类型;

    • public class CustomException extends RuntimeException {
              
              
      
          public CustomException(String msg) {
              
              
              super(msg);
          }
      }
      
      
  2. 创建能够统一处理异常的异常处理类,实现 HandlerExceptionResolver(异常解析器),针对两种异常进行处理,返回统一的异常信息的视图。

    • import com.wang.pojo.CustomException;
      import org.springframework.web.servlet.HandlerExceptionResolver;
      import org.springframework.web.servlet.ModelAndView;
      
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      public class CustomHandlerException implements HandlerExceptionResolver {
              
              
          //该方法执行后会进行视图的渲染,该视图可以作为展现异常信息的视图,也可以用原始视图作为结果视图
          public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
              
              
              ModelAndView mv = new ModelAndView();
              if(e instanceof CustomException){
              
              //是自定义异常
                  mv.addObject("exp", e.getMessage());
               }else{
              
              //系统异常
                  mv.addObject("exp","未知的错误,请找陶宇处理!");
              }
              mv.setViewName("exception");
      
              return mv;
          }
      }
      
      
      
  3. 对异常处理类进行配置。

    • <bean class="com.zhong.utils.CustomHandlerException"/>
      
      

十一、数据校验

  • 分为客户端和服务端两种校验方法,这里利用 hibernate 提供的校验工具来实现服务器端数据校验。
  1. 引入依赖:hibernate-validator;

  2. 在需要校验的属性上添加校验注解;

    • @NotNull(message = "用户名不能为空!")
      @Size(min = 4,max = 6,message = "长度不符合要求(4-6)")
      
      
  3. 在控制器的方法的入参添加开始校验的注解,@Valid,紧跟后面添加一个校验结果参数 BindingResult 类型;

  4. 在方法的开始添加判断,判断是否有校验未通过的情形发生;

    • @RequestMapping(value = "/toString8")
      public String toString8(@Valid Person person, BindingResult result) {
              
              
          if(result.hasErrors()){
              
              
              List<ObjectError> allErrors = result.getAllErrors();
              for (ObjectError allError : allErrors) {
              
              
                  System.out.println(allError.getDefaultMessage());
              }
          }
          //取pojo
          System.out.println(person);
          return "result";
      }
      
      
  5. 可以将错误信息转发到原始页面进行展示。

  • //约束注解	详细信息
    @Null	被注释的元素必须为 null
    @NotNull	被注释的元素必须不为 null
    @AssertTrue	被注释的元素必须为 true
    @AssertFalse	被注释的元素必须为 false
    @Min(value)	被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    @Max(value)	被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    @DecimalMin(value)	被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    @DecimalMax(value)	被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    @Size(max, min)	被注释的元素的大小必须在指定的范围内
    @Digits (integer, fraction)	被注释的元素必须是一个数字,其值必须在可接受的范围内
    @Past	被注释的元素必须是一个过去的日期
    @Future	被注释的元素必须是一个将来的日期
    @Pattern(value)	被注释的元素必须符合指定的正则表达式
    @Email	被注释的元素必须是电子邮箱地址
    @Length	被注释的字符串的大小必须在指定的范围内
    @NotEmpty	被注释的字符串的必须非空
    @Range	被注释的元素必须在合适的范围内
    
    

项目地址:
ssm项目——药品管理

猜你喜欢

转载自blog.csdn.net/qq_44628734/article/details/118657946
今日推荐