SpringMVC preliminary detailed explanation

Introduction to MVC pattern and SpringMVC

MVC : It is a pattern for designing and creating the presentation layer of web applications. Its main function is to separate the view display from the business control code

MVC uses three roles to handle different functions:

  • Model (model): data model (encapsulation object)

  • View (view): responsible for the display of data (html, jsp)

  • Controller (controller): responsible for scheduling, for program business logic processing


The relationship between the MVC architecture and the three-tier architecture:

  • MVC divides the presentation layer in the three-tier architecture into controllers, views, and models.
  • The purpose of the three-tier architecture is decoupling, and the purpose of MVC is to realize the division of responsibilities of the web system.

The position diagram of the MVC architecture in the three-tier architecture:

insert image description here


Introduction to Spring MVC

SpringMVC is a specific implementation of the MVC pattern by Spring products, and it belongs to a lightweight WEB framework. It allows an ordinary Java class to become a controller through a set of simple annotations without implementing any interface. At the same time, he also supports the RestFul-style programming style.

The function of SpringMVC is to encapsulate the common functions in the original Servlet, such as request parameter parsing and processing, request result encapsulation and return, etc.

In SpringMVC, like Spring, there is also the concept of containers (supporting spring annotations).


SpringMVC entry case (xml)

SpringMVC dependencies

  <dependencies>
    <!--springmvc-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.6.RELEASE</version>
    </dependency>
    <!--前端控制器 servlet-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
  </dependencies>

Enable SpringMVC annotation support

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 包扫描 -->
    <context:component-scan base-package="cn.test"></context:component-scan>
    
    <!-- 配置springmvc的注解驱动。内置了处理器映射器和处理器适配器 -->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 视图解析器 -->
    <!-- 
		 配置返回页面的前缀和后缀。当需要返回一个视图的时候,只需写视图的名称,视图解析器会自动在该名称上拼接前后缀。
         	前缀 + 控制器返回值  + 后缀
         	/WEB-INF/jsps/ + 控制器返回值 + .jsp
    -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsps/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>

Configure the front controller in web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<!-- 配置SpringMVC的前端控制器 DispatcherServlet -->
	<servlet>
		<servlet-name>mvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!--自动加载Springmvc的配置文件-->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>mvc</servlet-name>
		<!-- 处理所有请求,不处理.jsp为后缀的请求 -->
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

Controller

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 控制器:需要交给容器管理
 *    方法:接受请求,调用service,完成响应和页面跳转
 */
@Controller
public class HelloController {
    
    

    /**
     * 控制器方法:
     *     接受请求,调用service,完成响应和页面跳转
     *     1、返回值String (跳转的页面路径)
     *     2、需要在方法上通过注解@RequestMapping配置进入此方法的url
     *
     */
    @RequestMapping(value="/hello")
    public String hello() {
    
    
        System.out.println("hello heima23");
        return "success";   //    /WEB-INF/jsps/ + 控制器返回值 + .jsp
    }
}

Principle of Spring MVC

web engineering execution process

insert image description here

  1. The browser makes a requesthttp://localhost/hello
  2. Tomcat receives the request, parses the request and encapsulates the Request and Response objects, and then transfers them to the application
  3. The configured DispatcherServlet will intercept the requested path
  4. After some analysis and processing, DispatcherServlet will forward the request to the custom Controller (@RequestMapping)
  5. The Controller is processed and given a return path
  6. DispatcherServlet gets this path and will find the corresponding JSP for view rendering.

SpringMVC execution process

insert image description here

  1. The user sends a request to DispatcherServlet through the browser
  2. DispatcherServlet receives a request to call HandlerMapping
  3. HandlerMapping finds the specific processor chain and returns it to DispatcherServlet
  4. DispatcherServlet will call HandlerAdapter according to the returned processor chain
  5. HandlerAdapter is adapted to call the specific Handler (controller)
  6. Controller execution completes and returns an execution result
  7. HandlerAdapter returns the result ModelAndView object of Handler to DispatcherServlet
  8. DispatcherServlet passes the ModelAndView object to ViewReslover
  9. ViewResolver gets the specific View after parsing and returns it to DispatcherServlet
  10. DispatcherServlet renders the view according to the View (that is, fills the model data into the view)
  11. DispatcherServlet will respond the rendered view to the browser

Four major components of SpringMVC

insert image description here

  • Front controller (DispatcherServlet):

    The core component of SpringMVC (DispathcherServlet), coordinates the operation of all components

  • Processor Mapper (HandlerMapping):

    Responsible for finding the corresponding processor (method in the Controller) according to the URL request

  • Processor Adapter (HandlerAdapter):

    The unified adapter interface encapsulates the processor and can be called uniformly. Really call the processing method (execute the method in the Controller)

  • View resolver (ViewReslover):

    Match the logical view to the real physical view

    Physical view: the full path of the jsp page


@RequestMapping annotation

The @RequestMapping annotation is used to establish the correspondence between the request URL and the processing method, and can also make various restrictions on the request through its attributes

  • value / path attribute: Limit the request path. The value and path attributes are exactly the same, they are the request path for configuring the current method. default option
  • method attribute: used to limit the request type. Configure the request type of the current request:
    • RequestMethod.post
    • RequestMethod.get
    • RequestMethod.delete
    • RequestMethod.put
  • params attribute: conditions used to limit request parameters. Configure the request parameters that this method must carry. If the request does not carry the specified parameters, an exception will be thrown

This annotation can be marked on the method or on the class. Marking on the class means that all methods in the class can share a URL


Receiving and processing request parameters

Receive request parameters

Multiple types can be used in SpringMVC to receive address bar parameters passed in from the front end

  • Simple types (8 basic types \ wrapper types for 8 basic types \ strings)

    How to use: You only need to ensure that the parameter name passed by the front end is consistent with the formal parameter name of the method

    //处理器中属性名必须和请求参数名一致
    @RequestMapping("/simpleParam")
    public String simpleParam(Integer id, String name){
          
          
        System.out.println(id);
        System.out.println(name);
        return "success";
    }
    
  • Object (pojo) type

    How to use: You only need to ensure that the parameter name passed by the front end is consistent with the pojo attribute name (set method), and all request parameters are automatically encapsulated into java objects

    @RequestMapping("/dtoParam")
    public String voParam(UserDTO dto){
          
          
        System.out.println(dto);
        return "success";
    }
    
  • array type

    How to use: Just make sure that the parameter name passed by the front end is consistent with the name of the array formal parameter in the method

    Parameters with the same name are passed, and the request parameters are automatically encapsulated into an array

  • collection type

    Just wrap the collection into an object, and automatically encapsulate the data passed in from the front end into the collection properties in the object

  • date type

    A series of type converters are built in springmvc, which can automatically convert the String type of the request parameter into a certain format (Integer)

    For some common types, SpringMVC has built-in type converters, but for some parameters with more flexible formats (date and time), SpringMVC cannot complete the type conversion, so a custom type converter is required


Handle request parameters

@RequestParam annotation

The @RequestParam annotation is annotated before the method parameters, used to make some restrictions on the incoming parameters, and supports three attributes:

  • value / name attribute: default attribute, used to bind the parameter name passed in by the request. Generally, it is used when the request parameter is inconsistent with the controller method input parameter
  • required attribute: used to specify whether this parameter must be passed
    • The parameter modified by @RequestParam must pass a value by default, and you can use required = false to specify an optional value
  • defaultValue attribute: specify the default value of the parameter (when the parameter is not required and the request does not pass in the parameter, the default value is used)

Accept request header information

The way to get the request header of the current request in the controller:

  • The @RequestHeader annotation is configured on the method parameter: the front controller automatically obtains the header information
    •  @RequestHeader Map map : 获取所有的请求头
      
    •  @RequestHeader("cookie") String cookie : 根据key从所有头信息中获取指定头信息
      
  • @CookieValue("key") : Get the specified value data from the cookie according to the key
  	/**
     * 在控制器中获取,当前请求的请求头
     */
    @RequestMapping(value="/demo12")
    public String demo12(@RequestHeader Map map,
                         @RequestHeader("cookie") String cookie,
                         @CookieValue("JSESSIONID") String sessionId) {
    
    
        System.out.println(map);
        System.out.println(cookie);
        System.out.println(sessionId);
        return "success";
    }

File Upload

Three elements of client file upload

  • The method of the form form = post
  • enctype="multipart/form-data" of the form form
  • The type of input in the from form = file

The server in springmvc

  • file upload dependencies

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
    </dependency>
    
  • It is necessary to configure the file upload parser in the SpringMVC configuration file (automatically convert the uploaded content into a MultipartFile object)

    <!--
        文件解析器
            id:固定值(multipartResolver)
            property:其中指定上传文件的大小规则
    -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--文件的大小规则  5M = 1024 * 1024 * 5 -->
        <property name="maxUploadSize" value="5242880"></property>
    </bean>
    
  • On the controller method, directly use the MultipartFile object parameter to encapsulate the uploaded file

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.multipart.MultipartFile;
    import java.io.File;
    import java.io.IOException;
    
    @Controller
    public class FileUploadController {
          
          
    
        /**
         * 上传文件到服务端。服务端将文件转存到E:\file
         *  MultipartFile :封装上传的文件
         *      参数名 :和上传文件的input的name属性一致
         */
        @RequestMapping("/upload")
        public String upload(MultipartFile myFile, String name) throws IOException {
          
          
            System.out.println("name=" + name);
            System.out.println(myFile.getOriginalFilename()); //获取上传文件名
            System.out.println(myFile.getSize()); //获取上传文件大小
    
            File file = new File(new File("E:\\file"), myFile.getOriginalFilename());
            myFile.transferTo(file);  //写入文件内容
    
            return "success";
        }
    }
    

@RequestBody, @ResponseBody annotations

Ajax + json realizes asynchronous interaction

insert image description here

For ajax data interaction in SpringMVC, it is necessary to simplify development through two annotations

  • @RequestBody : Automatically convert the requested json string into a specified java object (processing the request)

  • @ResponseBody : Automatically convert the java object to the specified format (usually json string) through the converter and respond (processing the response)

        @RequestMapping("/testAjax")
        @ResponseBody
        public  User testAjax(@RequestBody User user) {
          
          
            System.out.println("ajax请求的数据对象=" + user);
            //调用业务逻辑
            User user2 = new User();
            user2.setUsername("张三");
            return user2;
        }
    

Note: Springmvc uses MappingJackson2HttpMessageConverter to convert json data by default, and needs to add the jackson package

    <dependency>
    	<groupId>com.fasterxml.jackson.core</groupId>
    	<artifactId>jackson-databind</artifactId>
    	<version>2.9.8</version>
    </dependency>

page jump

SpringMVC obtains Servlet native API

Servlet native API objects: HttpServletRequest, HttpSevletResponse, HttpSession

Grammar rules:

  • Method 1 (recommended): configure the object in the controller method as a method parameter

    	/**
         * 获取Servlet原生API对象(request,response,session)
         */
        @RequestMapping("/demo2")
        public String demo2(HttpServletRequest request, HttpServletResponse response, 
                            HttpSession session) {
          
          
            request.setAttribute("user", "1");
            System.out.println(request);
            System.out.println(response);
            System.out.println(session);
            return "success";
        }
    
  • Method 2: Inject the required API objects through @Autowired


Forwarding of page jump

Request forwarding: only send one request without data loss (SpringMVC's default page jump form)

  • Method 1: Directly return to the logical view

    • The underlying request is forwarded through the view parser, and the prefix and suffix are added to form the physical view (the completion path of the page) to render and jump
  • Method 2: Use forward to forward

    • Syntax rules (return value): forward: physical view
    • forward: The path after the keyword indicates that it will no longer go through the view resolver
        @RequestMapping("/demo3")
        public String demo3() {
          
          
            System.out.println("forward转发");
            return "forward:/WEB-INF/jsps/success.jsp";
        }
    
  • Method 3: Use servlet native api

    • Note: controller method return value: void
    	@RequestMapping("/demo3")
        public void demo3(HttpServletRequest request, HttpServletResponse response) throws Exception {
          
          
            System.out.println("servlet原生API对象");
            request.getRequestDispatcher("/WEB-INF/jsps/success.jsp").forward(request, response);
        }
    

Carry data when requesting forwarding

  • Carry data when forwarding: return response data.

  • Method 1 (recommended): Bind data to the request field

    	@RequestMapping("/demo4")
        public String demo4(HttpServletRequest request){
          
          
            // 将数据绑定到request域
            request.setAttribute("username", "张三")
            return "result"
        }
    

    The page gets the response data through the el expression and displays it

  • Method 2: Bind to the Model object

    Model: The Model in SpringMVC is configured on parameters, and the underlying layer is implemented through Request. Can be used to replace the request to complete the data response

    	@RequestMapping("/demo4")
        public String demo4(Model model){
          
          
            // 将数据绑定到Model对象
            model。addAttribute("username", "张三")
            return "result"
        }
    
  • Method 3 (official): return via ModelAndView

    ModelAndView : model view object, through which you can specify the returned view address and data binding

    Grammar rules:

    • The return value of the method: ModelAndView
    • In the method, specify the page to jump to through the setViewName method of ModelAndView
    • In the method, specify the data that needs to be stored in the request field through the addObject method of ModelAndView
    	@RequestMapping("/demo4")
        public ModelAndView demo4() {
          
          
            ModelAndView mv = new ModelAndView();
            // 指定响应数据
            mv.addObject("username", "传智播客");
            // 配置返回页面视图地址
            mv.setViewName("result"); 	// 支持逻辑视图,支持forward:物理视图
            return mv;
        }
    

Redirection of page jump

Redirection: Redirect various network requests to other locations through various methods (such as: webpage redirection, domain name redirection, and route selection changes are also a redirection of the path through which data packets are routed).

Implementation principle:

  • The client browser sends an http request, and the web server sends a 302 status code response and the corresponding new location to the client after receiving the request. When the client finds that it is a 302 request, it automatically sends a new http request. The requested url is the new location, and the server responds to the client according to the new http request.

  • The location here can be defined to any url. Since the browser resends the request, there is no concept of request delivery. The redirected path is displayed in the path bar of the client browser, and the client can observe the change of the path.

Features:

  • is the behavior of the client
  • It is the browser that made at least two access requests
  • The address of the browser changes
  • The data transmitted between the two jumps is lost (request range), that is, the value of the form cannot be obtained from the redirected page
  • Can redirect to any url

How to redirect:

  • Method 1 (recommended): use redirect to redirect

        @RequestMapping("/demo5")
        public void demo5(HttpServletRequest request, HttpServletResponse response) throws IOException {
          
          
            System.out.println("第一次请求");
            return "redirect:/demo6";
        }
    
    	@RequestMapping("/demo6")
        public String demo6() {
          
          
            System.out.println("重定向到demo6");
            return "success";
        }
    
  • Method 2: Use servlet native API

        @RequestMapping("/demo5")
        public void demo5(HttpServletRequest request, HttpServletResponse response) throws IOException {
          
          
            System.out.println("第一次请求");
            response.sendRedirect("/demo6");
        }
    
    	@RequestMapping("/demo6")
        public String demo6() {
          
          
            System.out.println("重定向到demo6");
            return "success";
        }
    

SpringMVC operates session domain

Operate the session domain in the traditional way

@RequestMapping("/hello13.action")
public String hello13(HttpSession session){
    
    
    session.setAttribute("prod", "电视机");
    return "hello";
}

@RequestMapping("/hello14.action")
public String hello14(HttpSession session){
    
    
    String prod = (String) session.getAttribute("prod");
    System.out.println(prod);
    return "hello";
}

Use @SessionAttribute("name") to get the value of the corresponding parameter from the session according to the name

@GetMapping("/test-mvc-get-session")
public String testMvcGetSession(@SessionAttribute("girl") String girl) {
    
    
    System.out.println("testMvcGetSession -----> girl in session is " + girl);
    return "success";
}

Use the ModelMap object to get the value from the session field

@RequestMapping("/getValue")
public String getValue(ModelMap modelMap){
    
    
    System.out.println(modelMap.get("value"));
    return "success";
}

Clear the session field

@RequestMapping("/delValue")
public String delValue(SessionStatus sessionStatus){
    
    
    //清空session
    sessionStatus.setComplete();
    return "success";
}


Release static resources (not handed over to SpringMVC for processing)

When there are static resources that need to be loaded, such as jquery.js, the reason why it is not loaded into jquery.js is found by capturing the package through Google Developer Tools:

  • Now the url-pattern configuration of SpringMVC's front-end controller DispatcherServlet is / (default), which means that all requests except jsp requests will be intercepted, including some static files (js, html, css, jpg, etc.), and after interception, it cannot find the corresponding processor method to process, so an error is reported

How to release static resources

  • Method 1 (recommended): Configure and release all static resource files uniformly in the Springmvc configuration file

    • When SpringMVC processes static resources, it delegates to the default Servlet for processing
    • Default Servlet: The default Servlet in tomcat
    <mvc:default-servlet-handler/>
    
  • Method 2: Configure the release of static resources in the SpringMVC configuration file

    • mvc:resources tag
      • mapping tag: URL mapping rules for the request path
      • location tag: the physical directory of the static resource

    When static resources are requested to SpringMVC's front controller, according to the configuration of releasing resources

    1. No longer look for specific controller processing
    2. Find matching resources from the location path
        <mvc:resources mapping="/js/*" location="/js/"></mvc:resources>
        <mvc:resources mapping="/image/*" location="/image/"></mvc:resources>
        <mvc:resources mapping="/css/*" location="/css/"></mvc:resources>
    
  • Method 3: Modify web.xmlthe URL mapping rules of the front-end controller, and the request ending with a special string is handed over to the front-end controller for processing

    • servlet-mapping tag
      • url-pattern tag:
        • /* : Valid for all requests (including jsp pages)
        • / : Valid for all requests (excluding jsp pages)
    • All requests that need to enter SpringMVC need to end with .do
    • In the controller method, @RequestMapping does not need to do additional configuration
        <servlet-mapping>
            <servlet-name>mvc</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    

Unified exception handling of SpringMVC

There are generally two ways to handle exceptions:

  • One is the current method processing (try-catch), which will cause the coupling of business code and exception handling code.

  • One is that the current method does not handle it, and throws it directly to the caller for processing after an exception occurs.

    Using the Spring framework, the code is ultimately called by the framework, that is to say, the exception will eventually be thrown to the framework, and then the framework will specify an exception handler to handle the exception uniformly.


Method 1: Custom exception handler

Customize a class to implement the HandlerExceptionResolver interface, rewrite the resolveException method, and hand over the exception handler to the spring container for management

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义异常处理器
 * 跳转到一个美化的页面,携带错误信息
 */
@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    
    
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
    
    
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg","运行报错!");
        mv.setViewName("forward:error.jsp");
        return mv;
    }
}

Method 2: Define global exception handling through @ControllerAdvice and @ExceptionHandler annotations

How to use:

  • @ControllerAdvice: Exception monitoring. standard on java class
  • Define an exception handling method
    • return value String (view)
    • Parameters: Model
    • @ExceptionHandler annotation: marked on the method
      • value attribute: specifies the exception type handled by the current exception handler
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

/**
 * 定义全局异常处理
 */
@ControllerAdvice
public class MyHandlerException2 {
    
    

    @ExceptionHandler(value=Exception.class)
    public String handlerException(Model model) {
    
    
        model.addAttribute("errorMsg", "运行报错!");
        return "forward:error.jsp";
    }
}

Method 3: Use the exception mechanism provided by the web

Provide exception handling configuration in web.xml

<!--处理403异常-->
<error-page>
    <error-code>403</error-code>
    <location>/403.jsp</location>
</error-page>
<!--处理404异常-->
<error-page>
    <error-code>404</error-code>
    <location>/404.jsp</location>
</error-page>

SpringMVC interceptor

Interceptor is a technology provided by SpringMVC. Its function is similar to Filter. It will intercept before entering the controller, after leaving the controller and after the page is rendered.

insert image description here

The difference between interceptors and filters

  • Filters are part of the Servlet specification and can be used by any java web project;

    The interceptor belongs to the SpringMVC framework and can only be used by projects that use the SpringMVC framework.

  • After the filter is configured with /* in url-pattern, it can intercept all resources to be accessed;

    The interceptor will only intercept the accessed controller method, if the access is jsp, js, html, css, image, etc., it will not intercept.


custom interceptor

  • Implement the HnadlerInterceptor interface

  • Implement three methods (three interception points)

    // 进入controller方法之前执行的内容(对请求拦截处理)
    	// 返回值 boolean。true :放行(继续向后执行,进入到controller),false :拦截过滤
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    
    // 执行了controller方法之后,执行的内容(对象响应进行拦截处理)
    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
                           Object handler, ModelAndView modelAndView)
    
    // 页面渲染完成之后,执行(一般不用)
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
                                Object handler, Exception ex)
    

Interceptor based on URL implementation

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义拦截器
 * 实现HnadlerInterceptor接口。实现其中的三个方法(三个拦截点)
 */
public class MyInterceptor01 implements HandlerInterceptor {
    
    

    /**
     * 进入controller方法之前执行的内容(对请求拦截处理)
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        String path = request.getServletPath();
        if (path.matches(Const.NO_INTERCEPTOR_PATH)) {
    
    
        	//不需要的拦截直接过
            return true;
        } else {
    
    
        	// 这写你拦截需要干的事儿,比如取缓存,SESSION,权限判断等
            System.out.println("====================================");
            return true;
        }
    }

    /**
     * 执行了controller方法之后,执行的内容(对象响应进行拦截处理)
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    
        System.out.println("执行MyInterceptor01的postHandle方法");
    }

    /**
     * 页面渲染完成之后,执行(不用)
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    
        System.out.println("执行MyInterceptor01的afterCompletion方法");
    }
}

Key code: path.matches(Const.NO_INTERCEPTOR_PATH is the url based on regular matching

/**
 * 常量类
 */
public class Const {
    
    

    public static final String SUCCESS = "SUCCESS";
    public static final String ERROR = "ERROR";
    public static final String FIALL = "FIALL";
    /**********************对象和个体****************************/
    public static final String SESSION_USER = "loginedAgent"; // 用户对象
    public static final String SESSION_LOGINID = "sessionLoginID"; // 登录ID
    public static final String SESSION_USERID = "sessionUserID"; // 当前用户对象ID编号

    public static final String SESSION_USERNAME = "sessionUserName"; // 当前用户对象ID编号
    public static final Integer PAGE = 10; // 默认分页数
    public static final String SESSION_URL = "sessionUrl"; // 被记录的url
    public static final String SESSION_SECURITY_CODE = "sessionVerifyCode"; // 登录页验证码
    // 时间 缓存时间
    public static final int TIMEOUT = 1800;// 秒
	public static final String ON_LOGIN = "/logout.htm";
	public static final String LOGIN_OUT = "/toLogout";
    // 不验证URL anon:不验证/authc:受控制的
    public static final String NO_INTERCEPTOR_PATH =".*/((.css)|(.js)|(images)|(login)|(anon)).*";
}

Annotation based interceptor

1. Create annotations:

/**
 * 在需要登录验证的Controller的方法上使用此注解
 */
@Target({
    
    ElementType.METHOD})	// 可用在方法名上
@Retention(RetentionPolicy.RUNTIME)	// 运行时有效
public @interface LoginRequired {
    
    
	
}

2. Create an interceptor:

public class MyInterceptor02 extends HandlerInterceptorAdapter{
    
    
	
	 @Override
	 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
	 	// 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
    
    
            return true;
        }
        // 方法注解级拦截器
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        // 判断接口是否需要登录
        LoginRequired methodAnnotation = method.getAnnotation(LoginRequired.class);
        // 有 @LoginRequired 注解,需要认证
        if (methodAnnotation != null) {
    
    
            // 拦截需要干的事儿,比如取缓存,SESSION,权限判断等
            System.out.println("====================================");
            return true;
        }
        return true;
	}
}

Configure interceptors

  • config class method

    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import com.*.*.interceptor.AdminInterceptor;
    
    /**
     * 拦截器配置
     */
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
          
          
        
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
          
          
            //注册MyInterceptor01拦截器
            InterceptorRegistration registration = registry.addInterceptor(getMyInterceptor01());
            registration.addPathPatterns("/**");                      //所有路径都被拦截
            registration.excludePathPatterns(                         //添加不拦截路径
                                             "登陆路径",            	//登录
                                             "/**/*.html",            //html静态资源
                                             "/**/*.js",              //js静态资源
                                             "/**/*.css",             //css静态资源
                                             "/**/*.woff",
                                             "/**/*.ttf"
                                             );    
        
            // 注册MyInterceptor02拦截器。拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要拦截
            registry.addInterceptor(getMyInterceptor02()).addPathPatterns("/**");
        }
        
        @Bean
    	 public MyInterceptor01 getMyInterceptor01() {
          
          
    		 return new MyInterceptor01();
    	 }
    	 
    	 @Bean
    	 public MyInterceptor02 getMyInterceptor02() {
          
          
    		 return new MyInterceptor02();
    	 }
    }
    
  • xml way

    In the SpringMVC configuration file, add the interceptor configuration (the configuration interceptor corresponds to the URL and method rules that need to be intercepted)

        <!--配置SpringMVC的拦截器-->
        <mvc:interceptors>
            <!--配置具体的拦截器和拦截器的拦截规则-->
            <mvc:interceptor>
                <!-- mapping : 配置拦截规则。 /** 表示拦截所有  -->
                <mvc:mapping path="/**"/>
                <!-- exclude-mapping: 配置不拦截的规则 -->
                <mvc:exclude-mapping path="/hello/demo2"/>
                <!--创建对象:在当前拦截器中有效-->
                <bean class="cn.test.interceptors.MyInterceptor01"></bean>
            </mvc:interceptor>
        </mvc:interceptors>
    

Custom interceptor chain

During development, interceptors can be used alone, or multiple interceptors can be used at the same time to form an interceptor chain.

The development steps are the same as for a single interceptor, except that multiple ones are registered when registering. Note that the order of registration here represents the order in which interceptors are executed.

Configure interceptors : the execution order of multiple interceptor chains is related to the configuration order

    <!--配置SpringMVC的拦截器-->
    <mvc:interceptors>
        <!--配置具体的拦截器和拦截器的拦截规则-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/hello/demo2"/>
            <bean class="cn.test.interceptors.MyInterceptor01"></bean>
        </mvc:interceptor>

        <!--配置具体的拦截器和拦截器的拦截规则-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/hello/demo2"/>
            <bean class="cn.test.interceptors.MyInterceptor02"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

expand

custom type converter

1. Customize a type converter to implement the method of type conversion

import org.springframework.core.convert.converter.Converter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 自定义的类型转换器
 * 实现Converter接口,<原始类型,目标类型>
 */
public class StringToDateConverter implements Converter<String, Date> {
    
    

    /**
     * 日期转化
     *   参数:请求参数中的原始数据
     *   返回值:转换好的数据(目标类型)
     */
    public Date convert(String source) {
    
    
        Date date = null;
        try {
    
    
            date = new SimpleDateFormat("yyyy-MM-dd").parse(source);
        }catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return date;
    }
}

2. Register the custom type conversion to the conversion service of SpringMvc, and then register the service to the annotation driver of SpringMVC

  • xml way
    <!--将自定义的类型转化器加入Springmvc的转化器ConversionService的集合中-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <!--使用集合传入自定义的converter-->
        <property name="converters">
            <set>
                <!--一个bean对应一个类型转换器-->
                <bean class="cn.test.converter.StringToDateConverter"></bean>
            </set>
        </property>
    </bean>

    <!--将Springmvc的转化器注册到springmvc驱动中-->
    <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
  • configuration class
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;

@Configuration
public class ConvertConfig {
    
    
    @Bean
    public ConversionService genericConversionService(GenericConversionService genericConversionService){
    
    
        genericConversionService.addConverter(new StringToDateConverter());
        return genericConversionService;
    }
}

Restful style

Restful is referred to as REST, and its full name is Representational State Transfer.

REST is a software architectural style, which emphasizes that HTTP should be resource-centric (verbs should not appear in the URL as much as possible).

It formulates four actions for HTTP requests, which respectively represent CRUD operations on resources: GET (get), POST (new), PUT (update), DELETE (delete)

How to use restful:

  • The same URL, according to different request methods, do different business processing
  • Custom address parameter/PATH/{custom address parameter name}
  • Receive the value of the placeholder in the REST style request address: @PathVariable(value="Address parameter name") annotation
  • Request method: GET (get), POST (new), PUT (update), DELETE (delete)
turn out to be Restful
keep /saveUser POST /user
Revise /udpateUser?uid=1 PUT /user/1
delete /deleteUser?uid=1 DELETE /user/1
query a /findUserByUid?uid=1 GET /user/1
query all /findUser GET /user
@Controller
@RequestMapping("/user")
public class UserController {
    
    

    /**
     * 根据id查询
     *  请求地址:/user/5
     *  请求方式:GET
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String findById(@PathVariable(value="id") String id) {
    
    
        System.out.println("根据id查询,id=" + id);
        return "success";
    }

    /**
     * 根据id删除
     *  请求地址:/user/5
     *  请求方式:DELETE
     */
    @RequestMapping(value="/{id}", method = RequestMethod.DELETE)
    public String delete(@PathVariable(value="id") String id) {
    
    
        System.out.println("根据id删除,id=" + id);
        return "success";
    }

    /**
     * 根据id更新
     *  请求地址:/user/5
     *  请求方式:PUT
     */
    @RequestMapping(value="/{id}", method = RequestMethod.PUT)
    public String update(@PathVariable(value="id") String id) {
    
    
        System.out.println("根据id更新,id=" + id);
        return "success";
    }

    /**
     * 保存
     *  请求地址:/user
     *  请求方式:POST
     */
    @RequestMapping(value="/", method = RequestMethod.POST)
    public String save() {
    
    
        System.out.println("保存");
        return "success";
    }
}

@RestController annotation description

The restful style is mostly used in project development where the front and back ends are absolutely separated. At this time, synchronous requests will not be available, and all processors will become asynchronous requests that return data.

In this case, the @ResponseBody annotation on all handler methods can be extracted to the class.

Then, you can use the @RestController annotation to replace the @Controller and @ResponseBody annotations.

It is written as follows:

//@Controller
//@ResponseBody
@RestController
@RequestMapping("/day02")
public class Day02Controller {
    
    
    ...
}

Dealing with Chinese garbled characters

When SpringMVC uses post to submit requests, there is a problem of garbled characters for Chinese parameters. In this case, it provides a Chinese garbled filter, which only needs to be configured.

Configuring web.xmlthe SpringMVC Chinese garbled filter

	<!--在web.xml中配置过滤器,设置编码即可 CharacterEncodingFilter-->
	<filter>
		<filter-name>characterEncodingFilter</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>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
	</filter>
	<filter-mapping>
		<filter-name>characterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

Guess you like

Origin blog.csdn.net/footless_bird/article/details/124271101