Spring MVC detailed summary

1, Introduction to spring MVC

1. What is MVC

MVC is an idea of software architecture, which divides software according to model, view and controller

M: Model, the model layer, refers to the JavaBean in the project, which is used to process data

JavaBean s fall into two categories:

  • One class is called entity class beans: beans that specifically store business data, such as Student, User, etc
  • One is called business processing Bean: it refers to Service or Dao objects, which are specially used to handle business logic and data access.

5: V iew, the View layer, refers to pages such as html or jsp in the project. It is used to interact with users and display data

C: Controller, the control layer, refers to the servlet in the project, which is used to receive requests and respond to browsers

MVC workflow:
The user sends a request to the server through the View layer, and the request is received by the Controller in the server. The Controller calls the corresponding Model layer to process the request, and returns the result to the Controller after processing. The Controller finds the corresponding View according to the request processing result, and finally responds to the browser after configuring the data

2. What is spring MVC

Spring MVC is a follow-up product of spring and a subproject of spring

Spring MVC is a complete set of solutions provided by spring for presentation layer development. After the evolution of many products such as struts, WebWork and strut2, the presentation layer framework has generally chosen spring MVC as the preferred solution for the presentation layer development of Java EE Projects.

Note: the three-tier architecture is divided into presentation layer (or presentation layer), business logic layer and data access layer. The presentation layer represents the foreground page and background servlet

3. Characteristics of spring MVC

  • The native products of Spring family are seamlessly connected with infrastructure such as IOC container
  • Based on the native Servlet, the powerful front-end controller dispatcher Servlet is used to process the request and response uniformly
  • The problems to be solved in each subdivided field of the presentation layer are covered in an all-round way to provide comprehensive solutions
  • The code is fresh and concise, which greatly improves the development efficiency
  • High degree of internal componentization, pluggable components plug and play, and you can configure the corresponding components according to the functions you want
  • Outstanding performance, especially suitable for modern large and super large Internet projects

2, HelloWorld

1. Development environment

IDE: idea 2019.2

Build tool: Maven 3 five point four

Server: tomcat7

Spring version: 5.3 one

2. Create maven project

a> Add web module
b> Packing method: war
c> Introduce dependency
<dependencies>
    <!-- SpringMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.1</version>
    </dependency>

    <!-- journal -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>

    <!-- ServletAPI -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

    <!-- Spring5 and Thymeleaf Integration package -->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.12.RELEASE</version>
    </dependency>
</dependencies>

Note: due to Maven's transitivity, we do not need to configure all the required packages, but configure the top dependency, and others rely on transitive import.

3. Configure web xml

Register the DispatcherServlet of the front-end controller of spring MVC

a> Default configuration method

Under this configuration, the configuration file of spring MVC is located under WEB-INF by default, and the default name is < servlet name > - servlet XML, for example, the configuration file of spring MVC corresponding to the following configuration is located under WEB-INF, and the file name is SpringMVC-servlet xml

<!-- to configure SpringMVC The front-end controller of the browser uniformly processes the requests sent by the browser -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <!--
        set up springMVC The request path of the request that can be processed by the core controller of
        /The matching request can be/login or.html or.js or.css Mode request path
        however/Cannot match.jsp Request for request path
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>
b> Extended configuration mode

The location and name of the spring MVC configuration file can be set through the init param tag, and the initialization time of the spring MVC front-end controller DispatcherServlet can be set through the load on startup tag

<!-- to configure SpringMVC The front-end controller of the browser uniformly processes the requests sent by the browser -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- Specified by initialization parameters SpringMVC Location and name of the configuration file -->
    <init-param>
        <!-- contextConfigLocation Is a fixed value -->
        <param-name>contextConfigLocation</param-name>
        <!-- use classpath:Indicates finding a configuration file from a classpath, for example maven In Engineering src/main/resources -->
        <param-value>classpath:springMVC.xml</param-value>
    </init-param>
    <!-- 
 		As the core component of the framework, there are a lot of initialization operations to be done during startup
		These operations are performed only when the first request is made, which will seriously affect the access speed
		Therefore, it is necessary to start the control through this label DispatcherServlet The initialization time of is advanced until the server starts
	-->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <!--
        set up springMVC The request path of the request that can be processed by the core controller of
        /The matching request can be/login or.html or.js or.css Mode request path
        however/Cannot match.jsp Request for request path
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

Note:

Differences between / and / * used in < URL pattern > Tags:

/The matching request can be / login or html or js or css request path, but / cannot match jsp request path

Therefore, it can be avoided that when accessing the jsp page, the request is processed by the dispatcher servlet, so that the corresponding page cannot be found

/*All requests can be matched. For example, when using a filter, if you need to filter all requests, you need to use the writing method of / *

4. Create request controller

Because the front-end controller uniformly processes the requests sent by the browser, but the specific requests have different processing processes, it is necessary to create a class to process the specific requests, that is, the request controller

Each method in the request controller that processes the request becomes a controller method

Because the Controller of Spring MVC is a POJO (ordinary Java class), it needs to be identified as a control layer component through the @ Controller annotation and managed by Spring's IoC container. At this time, Spring MVC can recognize the existence of the Controller

@Controller
public class HelloController {
    
}

5. Create a configuration file for spring MVC

<!-- Auto scan package -->
<context:component-scan base-package="com.atguigu.mvc.controller"/>

<!-- to configure Thymeleaf view resolver  -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    <property name="order" value="1"/>
    <property name="characterEncoding" value="UTF-8"/>
    <property name="templateEngine">
        <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
            <property name="templateResolver">
                <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    
                    <!-- View prefix -->
                    <property name="prefix" value="/WEB-INF/templates/"/>
    
                    <!-- View suffix -->
                    <property name="suffix" value=".html"/>
                    <property name="templateMode" value="HTML5"/>
                    <property name="characterEncoding" value="UTF-8" />
                </bean>
            </property>
        </bean>
    </property>
</bean>

<!-- 
   Processing static resources, such as html,js,css,jpg
  If only this tag is set, only static resources can be accessed, and other requests cannot be accessed
  Must be set at this time<mvc:annotation-driven/>solve the problem
 -->
<mvc:default-servlet-handler/>

<!-- open mvc Annotation driven -->
<mvc:annotation-driven>
    <mvc:message-converters>
        <!-- Processing response Chinese content garbled -->
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="defaultCharset" value="UTF-8" />
            <property name="supportedMediaTypes">
                <list>
                    <value>text/html</value>
                    <value>application/json</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

6. Test HelloWorld

a> Realize the access to the home page

Create a method in the request controller to process the request

// @RequestMapping annotation: handles the mapping relationship between the request and the controller method
// @The value attribute of the RequestMapping annotation can match the context path of the current project represented by / through the request address
// localhost:8080/springMVC/
@RequestMapping("/")
public String index() {
    //Set view name
    return "index";
}
b> Jump to the specified page through hyperlink

On the homepage index Set hyperlink in HTML

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>home page</title>
</head>
<body>
    <h1>home page</h1>
    <a th:href="@{/hello}">HelloWorld</a><br/>
</body>
</html>

Create a method in the request controller to process the request

@RequestMapping("/hello")
public String HelloWorld() {
    return "target";
}

7. Summary

The browser sends a request. If the request address matches the URL pattern of the front-end controller, the request will be processed by the front-end controller DispatcherServlet. The front-end controller will read the core configuration file of spring MVC, find the controller by scanning the component, and match the request address with the value attribute value of the @ RequestMapping annotation in the controller. If the matching is successful, the controller method identified by the annotation is the method of processing the request. The method of processing the request needs to return a view name of string type. The view name will be parsed by the view parser, plus prefix and suffix to form the path of the view. The view will be rendered through Thymeleaf, and finally forwarded to the page corresponding to the view

3, @ RequestMapping annotation

1. Function of @ RequestMapping annotation

From the annotation name, we can see that the @ RequestMapping annotation is used to associate the request with the controller method processing the request and establish a mapping relationship.

When spring MVC receives the specified request, it will find the corresponding controller method in the mapping relationship to process the request.

2. @ RequestMapping annotation location

@RequestMapping identifies a class that sets the initial information of the request path of the mapping request

@RequestMapping identifies a method: set the specific information of the request path of the mapping request

@Controller
@RequestMapping("/test")
public class RequestMappingController {

	//At this time, the request path of the request mapped by the request mapping is: / test/testRequestMapping
    @RequestMapping("/testRequestMapping")
    public String testRequestMapping(){
        return "success";
    }

}

3. value attribute of @ RequestMapping annotation

@The value attribute of the RequestMapping annotation matches the request mapping by the request address of the request

@The value attribute of the RequestMapping annotation is a string type array, indicating that the request mapping can match the requests corresponding to multiple request addresses

@The value attribute of the RequestMapping annotation must be set to match the request mapping at least through the request address

<a th:href="@{/testRequestMapping}">test@RequestMapping of value attribute-->/testRequestMapping</a><br>
<a th:href="@{/test}">test@RequestMapping of value attribute-->/test</a><br>
@RequestMapping(
        value = {"/testRequestMapping", "/test"}
)
public String testRequestMapping(){
    return "success";
}

4. method attribute of @ RequestMapping annotation

@The method attribute of the RequestMapping annotation matches the request mapping by the request method (get or post) of the request

@The method attribute of the RequestMapping annotation is an array of RequestMethod type, indicating that the request mapping can match requests of multiple request methods

If the request address of the current request meets the value attribute of the request mapping, but the Request method does not meet the method attribute, the browser will report an error 405: Request method 'POST' not supported

<a th:href="@{/test}">test@RequestMapping of value attribute-->/test</a><br>
<form th:action="@{/test}" method="post">
    <input type="submit">
</form>
@RequestMapping(
        value = {"/testRequestMapping", "/test"},
        method = {RequestMethod.GET, RequestMethod.POST}
)
public String testRequestMapping(){
    return "success";
}

Note:

1. Spring MVC provides a derived annotation of @ RequestMapping for the controller method that handles the specified request mode

Mapping for processing get requests – > @ getmapping

Mapping for handling post requests – > @ postmapping

Mapping for processing put requests – > @ putmapping

Mapping for handling delete requests – > @ deletemapping

2. The common request methods are get, post, put and delete

However, at present, the browser only supports get and post. If a string of other request methods (put or delete) is set for the method when the form form is submitted, it will be processed according to the default request method get

To send put and delete requests, you need to use the spring provided filter HiddenHttpMethodFilter, which will be described in the RESTful section

5. params attribute of @ RequestMapping annotation (understand)

@The params attribute of the RequestMapping annotation matches the request mapping through the request parameters of the request

@The params property of the RequestMapping annotation is an array of string types. You can set the matching relationship between request parameters and request mapping through four expressions

"Param": the request matching the request mapping must carry param request parameters

'! Param': the request matching the request mapping must not carry param request parameters

"param=value": the request matching the request mapping must carry param request parameters and param=value

"param!=value": the request matching the request mapping must carry param request parameters, but param= value

<a th:href="@{/test(username='admin',password=123456)">test@RequestMapping of params attribute-->/test</a><br>
@RequestMapping(
        value = {"/testRequestMapping", "/test"}
        ,method = {RequestMethod.GET, RequestMethod.POST}
        ,params = {"username","password!=123456"}
)
public String testRequestMapping(){
    return "success";
}

Note:

If the current request satisfies the value and method attributes of the @ RequestMapping annotation, but does not satisfy the parameters attribute, the page returns an error of 400: Parameter conditions "username, password!=123456" not method for actual request parameters: username = {admin}, password = {123456}

6. headers attribute of @ RequestMapping annotation (understand)

@The headers attribute of the RequestMapping annotation matches the request mapping through the request header information of the request

@The headers attribute of the RequestMapping annotation is an array of string types. You can set the matching relationship between the request header information and the request mapping through four expressions

"Header": the request matching the request mapping must carry the header request header information

'! Header': the request matched by the request mapping must not carry header request header information

"header=value": the request matching the request mapping must carry header request header information and header=value

"header!=value": the request matched by the request mapping must carry header request header information and header= value

If the current request meets the value and method attributes of the @ RequestMapping annotation, but does not meet the headers attribute, the page displays 404 error, that is, the resource is not found

7. Spring MVC supports ant style paths

?: Represents any single character

*: represents any 0 or more characters

**: indicates any one or more levels of directories

Note: when * * is used, only / * * / xxx can be used

8. Placeholder in spring MVC support path (emphasis)

Original method: / deleteUser?id=1

rest mode: / deleteUser/1

Placeholders in the spring MVC path are often used in the RESTful style. When some data in the request path is transmitted to the server through the path, the transmitted data can be represented by the placeholder {xxx} in the value attribute of the corresponding @ RequestMapping annotation, and the data represented by the placeholder can be assigned to the formal parameters of the controller method through the @ PathVariable annotation

<a th:href="@{/testRest/1/admin}">Placeholder in test path-->/testRest</a><br>
@RequestMapping("/testRest/{id}/{username}")
public String testRest(@PathVariable("id") String id, @PathVariable("username") String username){
    System.out.println("id:"+id+",username:"+username);
    return "success";
}
//The final output is -- > ID: 1, username: admin

4, Spring MVC get request parameters

1. Get through servlet API

Take HttpServletRequest as the formal parameter of the controller method. At this time, the parameter of HttpServletRequest type represents the object encapsulating the request message of the current request

@RequestMapping("/testParam")
public String testParam(HttpServletRequest request){
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    System.out.println("username:"+username+",password:"+password);
    return "success";
}

2. Obtain the request parameters through the formal parameters of the controller method

Set the formal parameter with the same name as the request parameter at the formal parameter position of the controller method. When the browser sends a request and matches the request mapping, the request parameter will be assigned to the corresponding formal parameter in the dispatcher servlet

<a th:href="@{/testParam(username='admin',password=123456)}">Test get request parameters-->/testParam</a><br>
@RequestMapping("/testParam")
public String testParam(String username, String password){
    System.out.println("username:"+username+",password:"+password);
    return "success";
}

Note:

If there are multiple request parameters with the same name in the request parameters transmitted by the request, you can set string array or string type formal parameters in the formal parameters of the controller method to receive the request parameters

If you use a formal parameter of string array type, the array of this parameter contains each data

If a string type parameter is used, the value of this parameter is the result of concatenation of commas in the middle of each data

3,@RequestParam

@RequestParam is to create a mapping relationship between the request parameters and the formal parameters of the controller method

@The RequestParam annotation has three attributes:

value: Specifies the parameter name of the request parameter assigned to the formal parameter

required: sets whether this request parameter must be transmitted. The default value is true

If it is set to true, the current request must transmit the request parameter specified by value. If the request parameter is not transmitted and the defaultValue property is not set, the page will report an error 400: Required String parameter 'xxx' is not present; If it is set to false, the current request does not have to transmit the request parameter specified by value. If there is no transmission, the value of the formal parameter identified by the annotation is null

defaultValue: whether the required property value is true or false, when the request parameter specified by value is not transmitted or the transmitted value is' ', the default value is used to assign value to the formal parameter

4,@RequestHeader

@The RequestHeader creates a mapping relationship between the request header information and the formal parameters of the controller method

@The RequestHeader annotation has three attributes: value, required and defaultValue. The usage is the same as @ RequestParam

5,@CookieValue

@Cookie value is to create a mapping relationship between cookie data and formal parameters of the controller method

@The CookieValue annotation has three attributes: value, required and defaultValue. The usage is the same as @ RequestParam

6. Get request parameters through POJO

You can set a formal parameter of entity class type at the formal parameter position of the controller method. At this time, if the parameter name of the request parameter transmitted by the browser is consistent with the attribute name in the entity class, the request parameter will assign a value to this attribute

<form th:action="@{/testpojo}" method="post">
    user name:<input type="text" name="username"><br>
    password:<input type="password" name="password"><br>
    Gender:<input type="radio" name="sex" value="male">male<input type="radio" name="sex" value="female">female<br>
    Age:<input type="text" name="age"><br>
    Email:<input type="text" name="email"><br>
    <input type="submit">
</form>
@RequestMapping("/testpojo")
public String testPOJO(User user){
    System.out.println(user);
    return "success";
}
//Final result -- > user {id = null, username = 'Zhang San', password='123', age=23, sex =' male ', email='123@qq.com '}

7. Solve the garbled problem of obtaining request parameters

To solve the garbled problem of obtaining request parameters, you can use the encoding filter characterencoding filter provided by spring MVC, but it must be on the web Register in XML

<!--to configure springMVC Coding filter for-->
<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>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Note:

The encoding filter in spring MVC must be configured before other filters, otherwise it will be invalid

5, Domain objects share data

1. Use the servlet API to share data with the request domain object

@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
    request.setAttribute("testScope", "hello,servletAPI");
    return "success";
}

2. Use ModelAndView to share data with the request domain object

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
    /**
     * ModelAndView It has the functions of Model and View
     * Model It is mainly used to share data with the requesting domain
     * View It is mainly used to set the view and realize page Jump
     */
    ModelAndView mav = new ModelAndView();
    //Share data with the requesting domain
    mav.addObject("testScope", "hello,ModelAndView");
    //Set the view to realize page Jump
    mav.setViewName("success");
    return mav;
}

3. Use the Model to share data with the request domain object

@RequestMapping("/testModel")
public String testModel(Model model){
    model.addAttribute("testScope", "hello,Model");
    return "success";
}

4. Use map to share data with the request domain object

@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
    map.put("testScope", "hello,Map");
    return "success";
}

5. Use ModelMap to share data with request domain objects

@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
    modelMap.addAttribute("testScope", "hello,ModelMap");
    return "success";
}

6. Relationship between Model, ModelMap and Map

The parameters of Model, ModelMap and Map are essentially BindingAwareModelMap

public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}

7. Share data to the session domain

@RequestMapping("/testSession")
public String testSession(HttpSession session){
    session.setAttribute("testSessionScope", "hello,session");
    return "success";
}

8. Share data with the application domain

@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
	ServletContext application = session.getServletContext();
    application.setAttribute("testApplicationScope", "hello,application");
    return "success";
}

6, View of spring MVC

The View in spring MVC is the View interface. The function of the View is to render data and display the data in the Model to the user

There are many kinds of spring MVC views, including forwarding view and redirection view by default

When the project introduces jstl dependency, the forwarding view will be automatically converted to JstlView

If the view technology used is Thymeleaf, the view parser of Thymeleaf is configured in the configuration file of spring MVC. After the view parser parses, the ThymeleafView is obtained

1,ThymeleafView

When the view name set in the controller method does not have any prefix, the view name will be parsed by the view parser configured in the spring MVC configuration file. The final path obtained by splicing the view prefix and view suffix will jump through forwarding

@RequestMapping("/testHello")
public String testHello(){
    return "hello";
}

2. Forwarding view

The default forwarding view in spring MVC is the internal resource view

Create forwarding view in spring MVC:

When the view name set in the controller method is prefixed with "forward:", the InternalResourceView view is created. At this time, the view name will not be resolved by the view parser configured in the spring MVC configuration file, but the prefix "forward:" will be removed, and the rest will be used as the final path to jump through forwarding

For example, "forward: /", "forward:/employee"

@RequestMapping("/testForward")
public String testForward(){
    return "forward:/testHello";
}

[external link picture transfer failed, and the source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-57S2dwAL-1628318642802)(img/img003.png)]

3. Redirect view

The default redirection view in spring MVC is RedirectView

When the view name set in the controller method is prefixed with "redirect:" to create a RedirectView, the view name will not be resolved by the view parser configured in the spring MVC configuration file, but the prefix "redirect:" will be removed, and the rest will be used as the final path to jump through redirection

For example, "redirect: /", "redirect:/employee"

@RequestMapping("/testRedirect")
public String testRedirect(){
    return "redirect:/testHello";
}

Note:

When the redirect view is parsed, the redirect: prefix will be removed first, and then whether the remaining part starts with /. If so, the context path will be spliced automatically

4. View controller

When the controller method is only used to realize page Jump, that is, only the view name needs to be set, the processor method can be represented by the view controller tag

<!--
	path: Set the address of the request to be processed
	view-name: Set the view name corresponding to the request address
-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>

Note:

When any view controller is set in spring mvc, all request mappings in other controllers will fail. At this time, you need to set the label to enable mvc annotation driven in the core configuration file of spring mvc:

<mvc:annotation-driven />

7, RESTful

1. Introduction to RESTful

REST: Representational State Transfer, the state transfer of presentation layer resources.

a> Resources

Resource is a way of looking at the server, that is, the server is regarded as composed of many discrete resources. Each resource is a named abstraction on the server. Because resource is an abstract concept, it can not only represent a file in the server file system, a table in the database and other specific things, but also design resources as abstract as possible, as long as imagination allows and client application developers can understand. Similar to object-oriented design, resources are organized with nouns as the core, and nouns are the first concern. A resource can be identified by one or more URIs. A URI is not only the name of a resource, but also the address of the resource on the Web. Client applications interested in a resource can interact with it through the URI of the resource.

b> Representation of resources

The description of resources is a description of the state of resources at a specific time. It can be transferred (exchanged) between client and server. The expression of resources can be in a variety of formats, such as HTML/XML/JSON / plain text / picture / video / audio, etc. the expression format of resources can be determined through negotiation mechanism. The expression of request response direction usually uses different formats.

c> State transition

State transfer refers to the expression that transfer represents the state of resources between the client and the server. Through the expression of transfer and operation resources, the purpose of operating resources can be achieved indirectly.

2. RESTful implementation

Specifically, in the HTTP protocol, there are four verbs representing the operation mode: GET, POST, PUT and DELETE.

They correspond to four basic operations: GET is used to obtain resources, POST is used to create new resources, PUT is used to update resources, and DELETE is used to DELETE resources.

REST style advocates the uniform style design of URL address. Each word from front to back is separated by slash. The request parameters are not carried by question mark key value pair, but the data to be sent to the server is taken as a part of the URL address to ensure the consistency of the overall style.

operationTraditional wayREST style
Query operationgetUserById?id=1user/1 – > get request method
Save operationsaveUseruser – > post request mode
Delete operationdeleteUser?id=1user/1 – > delete request method
update operationupdateUseruser – > put request mode

3,HiddenHttpMethodFilter

Since the browser only supports sending get and post requests, how to send put and delete requests?

Spring MVC provides HiddenHttpMethodFilter to help us convert POST requests into DELETE or PUT requests

HiddenHttpMethodFilter conditions for processing put and delete requests:

a> The request mode of the current request must be post

b> The current request must transmit the request parameters_ method

If the above conditions are met, the HiddenHttpMethodFilter filter will convert the request mode of the current request into request parameters_ Method, so the request parameter_ The method value is the final request method

On the web Register HiddenHttpMethodFilter in XML

<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Note:

So far, spring MVC has provided two filters: characterencoding filter and HiddenHttpMethodFilter

On the web When registering in XML, you must first register CharacterEncodingFilter and then HiddenHttpMethodFilter

reason:

  • Pass request. In characterencoding filter The SetCharacterEncoding (encoding) method sets the encoding of the character set

  • request. The SetCharacterEncoding (encoding) method requires that there must be no previous operation to obtain the request parameters

  • HiddenHttpMethodFilter has exactly one operation to obtain the request method:

  • String paramValue = request.getParameter(this.methodParam);
    

8, RESTful case

1. Preparatory work

Like traditional CRUD, it can add, delete, modify and query employee information.

  • Build environment

  • Prepare entity class

    package com.atguigu.mvc.bean;
    
    public class Employee {
    
       private Integer id;
       private String lastName;
    
       private String email;
       //1 male, 0 female
       private Integer gender;
       
       public Integer getId() {
          return id;
       }
    
       public void setId(Integer id) {
          this.id = id;
       }
    
       public String getLastName() {
          return lastName;
       }
    
       public void setLastName(String lastName) {
          this.lastName = lastName;
       }
    
       public String getEmail() {
          return email;
       }
    
       public void setEmail(String email) {
          this.email = email;
       }
    
       public Integer getGender() {
          return gender;
       }
    
       public void setGender(Integer gender) {
          this.gender = gender;
       }
    
       public Employee(Integer id, String lastName, String email, Integer gender) {
          super();
          this.id = id;
          this.lastName = lastName;
          this.email = email;
          this.gender = gender;
       }
    
       public Employee() {
       }
    }
    
  • Prepare dao simulation data

    package com.atguigu.mvc.dao;
    
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    
    import com.atguigu.mvc.bean.Employee;
    import org.springframework.stereotype.Repository;
    
    
    @Repository
    public class EmployeeDao {
    
       private static Map<Integer, Employee> employees = null;
       
       static{
          employees = new HashMap<Integer, Employee>();
    
          employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1));
          employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1));
          employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0));
          employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0));
          employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1));
       }
       
       private static Integer initId = 1006;
       
       public void save(Employee employee){
          if(employee.getId() == null){
             employee.setId(initId++);
          }
          employees.put(employee.getId(), employee);
       }
       
       public Collection<Employee> getAll(){
          return employees.values();
       }
       
       public Employee get(Integer id){
          return employees.get(id);
       }
       
       public void delete(Integer id){
          employees.remove(id);
       }
    }
    

2. Function list

functionURL addressRequest mode
Visit home page √/GET
Query all data √/employeeGET
Delete √/employee/2DELETE
Jump to add data page √/toAddGET
Execute save √/employeePOST
Jump to update data page √/employee/2GET
Execute update √/employeePUT

3. Specific functions: visit the home page

a> Configure view controller
<mvc:view-controller path="/" view-name="index"/>
b> Create page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" >
    <title>Title</title>
</head>
<body>
<h1>home page</h1>
<a th:href="@{/employee}">Access employee information</a>
</body>
</html>

4. Specific function: query all employee data

a> Controller method
@RequestMapping(value = "/employee", method = RequestMethod.GET)
public String getEmployeeList(Model model){
    Collection<Employee> employeeList = employeeDao.getAll();
    model.addAttribute("employeeList", employeeList);
    return "employee_list";
}
b> Create employee_list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Employee Info</title>
    <script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
</head>
<body>

    <table border="1" cellpadding="0" cellspacing="0" style="text-align: center;" id="dataTable">
        <tr>
            <th colspan="5">Employee Info</th>
        </tr>
        <tr>
            <th>id</th>
            <th>lastName</th>
            <th>email</th>
            <th>gender</th>
            <th>options(<a th:href="@{/toAdd}">add</a>)</th>
        </tr>
        <tr th:each="employee : ${employeeList}">
            <td th:text="${employee.id}"></td>
            <td th:text="${employee.lastName}"></td>
            <td th:text="${employee.email}"></td>
            <td th:text="${employee.gender}"></td>
            <td>
                <a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>
                <a th:href="@{'/employee/'+${employee.id}}">update</a>
            </td>
        </tr>
    </table>
</body>
</html>

5. Specific function: delete

a> Create a form that handles the delete request
<!-- Function: control the submission of forms through hyperlinks post Request converted to delete request -->
<form id="delete_form" method="post">
    <!-- HiddenHttpMethodFilter Requirement: must be transmitted_method Request parameters, and the value is the final request method -->
    <input type="hidden" name="_method" value="delete"/>
</form>
b> Delete hyperlink binding click event

Introduce Vue js

<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>

Delete hyperlink

<a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>

Handling click events through vue

<script type="text/javascript">
    var vue = new Vue({
        el:"#dataTable",
        methods:{
            //Event indicates the current event
            deleteEmployee:function (event) {
                //Get form label by id
                var delete_form = document.getElementById("delete_form");
                //Assign the href attribute of the hyperlink that triggers the event to the action attribute of the form
                delete_form.action = event.target.href;
                //Submit Form 
                delete_form.submit();
                //Block default jump behavior of hyperlinks
                event.preventDefault();
            }
        }
    });
</script>
c> Controller method
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE)
public String deleteEmployee(@PathVariable("id") Integer id){
    employeeDao.delete(id);
    return "redirect:/employee";
}

6. Specific function: jump to the add data page

a> Configure view controller
<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
b> Create employee_add.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Add Employee</title>
</head>
<body>

<form th:action="@{/employee}" method="post">
    lastName:<input type="text" name="lastName"><br>
    email:<input type="text" name="email"><br>
    gender:<input type="radio" name="gender" value="1">male
    <input type="radio" name="gender" value="0">female<br>
    <input type="submit" value="add"><br>
</form>

</body>
</html>

7. Specific function: execute save

a> Controller method
@RequestMapping(value = "/employee", method = RequestMethod.POST)
public String addEmployee(Employee employee){
    employeeDao.save(employee);
    return "redirect:/employee";
}

8. Specific function: jump to the update data page

a> Modify hyperlink
<a th:href="@{'/employee/'+${employee.id}}">update</a>
b> Controller method
@RequestMapping(value = "/employee/{id}", method = RequestMethod.GET)
public String getEmployeeById(@PathVariable("id") Integer id, Model model){
    Employee employee = employeeDao.get(id);
    model.addAttribute("employee", employee);
    return "employee_update";
}
c> Create employee_update.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Update Employee</title>
</head>
<body>

<form th:action="@{/employee}" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="hidden" name="id" th:value="${employee.id}">
    lastName:<input type="text" name="lastName" th:value="${employee.lastName}"><br>
    email:<input type="text" name="email" th:value="${employee.email}"><br>
    <!--
        th:field="${employee.gender}"Can be used for echo of radio boxes or check boxes
        If the radio box is value and employee.gender If the values are consistent, add checked="checked"attribute
    -->
    gender:<input type="radio" name="gender" value="1" th:field="${employee.gender}">male
    <input type="radio" name="gender" value="0" th:field="${employee.gender}">female<br>
    <input type="submit" value="update"><br>
</form>

</body>
</html>

9. Specific function: execute update

a> Controller method
@RequestMapping(value = "/employee", method = RequestMethod.PUT)
public String updateEmployee(Employee employee){
    employeeDao.save(employee);
    return "redirect:/employee";
}

8, HttpMessageConverter

HttpMessageConverter, message information converter, converts request message into Java object or Java object into response message

HttpMessageConverter provides two annotations and two types: @ RequestBody, @ ResponseBody, RequestEntity,

ResponseEntity

1,@RequestBody

@RequestBody can obtain the request body. You need to set a formal parameter in the controller method and identify it with @ RequestBody. The request body of the current request will assign a value to the formal parameter identified by the current annotation

<form th:action="@{/testRequestBody}" method="post">
    user name:<input type="text" name="username"><br>
    password:<input type="password" name="password"><br>
    <input type="submit">
</form>
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String requestBody){
    System.out.println("requestBody:"+requestBody);
    return "success";
}

Output results:

requestBody:username=admin&password=123456

2,RequestEntity

RequestEntity encapsulates a type of request message. This type of parameter needs to be set in the formal parameter of the controller method, and the request message of the current request will be assigned to this formal parameter. You can obtain the request header information through getHeaders() and the request body information through getBody()

@RequestMapping("/testRequestEntity")
public String testRequestEntity(RequestEntity<String> requestEntity){
    System.out.println("requestHeader:"+requestEntity.getHeaders());
    System.out.println("requestBody:"+requestEntity.getBody());
    return "success";
}

Output results:
requestHeader:[host:"localhost:8080", connection:"keep-alive", content-length:"27", cache-control:"max-age=0", sec-ch-ua:"" Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"", sec-ch-ua-mobile:"?0", upgrade-insecure-requests:"1", origin:"http://localhost:8080", user-agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"]
requestBody:username=admin&password=123

3,@ResponseBody

@ResponseBody is used to identify a controller method. The return value of this method can be directly used as the response body of the response message to respond to the browser

@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
    return "success";
}

Result: the browser page displays success

4. Spring MVC handles json

@Steps for processing json by ResponseBody:

a> Import jackson dependencies

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

b> Open the mvc annotation driver in the spring mvc core configuration file. At this time, a message converter, MappingJackson2HttpMessageConverter, will be automatically installed in the HandlerAdaptor, which can convert the Java object responding to the browser into a string in Json format

<mvc:annotation-driven />

c> Use the @ ResponseBody annotation on the processor method for identification

d> If the Java object is returned directly as the return value of the controller method, it will be automatically converted to a string in Json format

@RequestMapping("/testResponseUser")
@ResponseBody
public User testResponseUser(){
    return new User(1001,"admin","123456",23,"male");
}

Results displayed in the browser's page:

{"id": 1001, "username": "admin", "password": "123456", "age": 23, "sex": "male"}

5. Spring MVC handles ajax

a> Request hyperlink:

<div id="app">
	<a th:href="@{/testAjax}" @click="testAjax">testAjax</a><br>
</div>

b> Handle click events through vue and axios:

<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script>
<script type="text/javascript">
    var vue = new Vue({
        el:"#app",
        methods:{
            testAjax:function (event) {
                axios({
                    method:"post",
                    url:event.target.href,
                    params:{
                        username:"admin",
                        password:"123456"
                    }
                }).then(function (response) {
                    alert(response.data);
                });
                event.preventDefault();
            }
        }
    });
</script>

c> Controller method:

@RequestMapping("/testAjax")
@ResponseBody
public String testAjax(String username, String password){
    System.out.println("username:"+username+",password:"+password);
    return "hello,ajax";
}

6. @ RestController annotation

@The RestController annotation is a composite annotation provided by spring MVC. Identifying it on the Controller class is equivalent to adding the @ Controller annotation to the class and the @ ResponseBody annotation to each method

7,ResponseEntity

ResponseEntity is used for the return value type of the controller method. The return value of the controller method is the response message in response to the browser

9, File upload and download

1. File download

Use ResponseEntity to download files

@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
    //Get ServletContext object
    ServletContext servletContext = session.getServletContext();
    //Gets the real path of the file in the server
    String realPath = servletContext.getRealPath("/static/img/1.jpg");
    //Create input stream
    InputStream is = new FileInputStream(realPath);
    //Create byte array
    byte[] bytes = new byte[is.available()];
    //Read stream into byte array
    is.read(bytes);
    //Create an HttpHeaders object and set the response header information
    MultiValueMap<String, String> headers = new HttpHeaders();
    //Set the method to download and the name of the file to download
    headers.add("Content-Disposition", "attachment;filename=1.jpg");
    //Set response status code
    HttpStatus statusCode = HttpStatus.OK;
    //Create ResponseEntity object
    ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
    //Close input stream
    is.close();
    return responseEntity;
}

2. File upload

File upload requires that the form request method must be post, and the attribute enctype = "multipart / form data" is added

Spring MVC encapsulates the uploaded file into a MultipartFile object, through which you can obtain file related information

Upload steps:

a> Add dependency:

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>

b> Add configuration in the configuration file of spring MVC:

<!--The file must be parsed by the file parser to convert the file to MultipartFile object-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

c> Controller method:

@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
    //Gets the file name of the uploaded file
    String fileName = photo.getOriginalFilename();
    //Handling file name duplication
    String hzName = fileName.substring(fileName.lastIndexOf("."));
    fileName = UUID.randomUUID().toString() + hzName;
    //Gets the path to the photo directory in the server
    ServletContext servletContext = session.getServletContext();
    String photoPath = servletContext.getRealPath("photo");
    File file = new File(photoPath);
    if(!file.exists()){
        file.mkdir();
    }
    String finalPath = photoPath + File.separator + fileName;
    //Realize the upload function
    photo.transferTo(new File(finalPath));
    return "success";
}

10, Interceptor

1. Interceptor configuration

Interceptors in spring MVC are used to intercept the execution of controller methods

Interceptors in spring MVC need to implement HandlerInterceptor

The interceptor of spring MVC must be configured in the configuration file of spring MVC:

<bean class="com.atguigu.interceptor.FirstInterceptor"></bean>
<ref bean="firstInterceptor"></ref>
<!-- The above two configurations are correct DispatcherServlet All requests processed are intercepted -->
<mvc:interceptor>
    <mvc:mapping path="/**"/>
    <mvc:exclude-mapping path="/testRequestEntity"/>
    <ref bean="firstInterceptor"></ref>
</mvc:interceptor>
<!-- 
	The above configuration methods can be ref or bean Tag set interceptor, through mvc:mapping Set the request to be intercepted through mvc:exclude-mapping Set the requests that need to be excluded, that is, the requests that do not need to be intercepted
-->

2. Three abstract methods of interceptor

Interceptors in spring MVC have three abstract methods:

preHandle: execute preHandle() before the controller method is executed. The return value of boolean type indicates whether to intercept or release. Return true is release, that is, call the controller method; Returning false indicates interception, that is, the controller method is not called

postHandle: execute postHandle() after the controller method is executed

After compilation: after processing the view and model data, execute after compilation () after rendering the view

3. Execution sequence of multiple interceptors

a> If each interceptor's preHandle() returns true

At this time, the execution order of multiple interceptors is related to the configuration order of interceptors in the spring MVC configuration file:

preHandle() will execute in the order configured, while postHandle() and aftercompilation () will execute in the reverse order configured

b> If the preHandle() of an interceptor returns false

preHandle() returns false and the preHandle() of the interceptor before it will be executed, postHandle() will not be executed, and aftercompilation() of the interceptor before the interceptor returns false will be executed

11, Exception handler

1. Configuration based exception handling

Spring MVC provides an interface to handle exceptions during the execution of controller methods: HandlerExceptionResolver

The implementation classes of the HandlerExceptionResolver interface include DefaultHandlerExceptionResolver and SimpleMappingExceptionResolver

Spring MVC provides a custom exception handler, SimpleMappingExceptionResolver, which can be used as follows:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
        	<!--
        		properties The key of represents an exception that occurs during the execution of the processor method
        		properties The value of indicates that if a specified exception occurs, set a new view name and jump to the specified page
        	-->
            <prop key="java.lang.ArithmeticException">error</prop>
        </props>
    </property>
    <!--
    	exceptionAttribute Property to set a property name and share the exception information in the request domain
    -->
    <property name="exceptionAttribute" value="ex"></property>
</bean>

2. Annotation based exception handling

//@ControllerAdvice identifies the current class as an exception handling component
@ControllerAdvice
public class ExceptionController {

    //@ExceptionHandler is used to set the exceptions handled by the identified method
    @ExceptionHandler(ArithmeticException.class)
    //ex represents the exception object in the current request processing
    public String handleArithmeticException(Exception ex, Model model){
        model.addAttribute("ex", ex);
        return "error";
    }

}

12, Annotation configuration spring MVC

Use configuration classes and annotations instead of web Functions of XML and spring MVC configuration files

1. Create an initialization class instead of web xml

In Servlet3 0 environment, the container will find the implementation javax. 0 in the classpath Servlet. The class of servletcontainerinitializer interface. If found, use it to configure the Servlet container.
Spring provides an implementation of this interface, called SpringServletContainerInitializer. In turn, this class will find the classes that implement WebApplicationInitializer and entrust them with the task of configuration. Spring3.2 introduces a convenient basic implementation of WebApplicationInitializer called AbstractAnnotationConfigDispatcherServletInitializer. When our class extends AbstractAnnotationConfigDispatcherServletInitializer and deploys it to Servlet3 0 container, the container will automatically discover it and use it to configure the Servlet context.

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {

    /**
     * Specifies the configuration class for spring
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    /**
     * Specifies the configuration class for spring MVC
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    /**
     * Specify the mapping rule of DispatcherServlet, i.e. URL pattern
     * @return
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    /**
     * Add filter
     * @return
     */
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceRequestEncoding(true);
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        return new Filter[]{encodingFilter, hiddenHttpMethodFilter};
    }
}

2. Create a SpringConfig configuration class to replace the spring configuration file

@Configuration
public class SpringConfig {
	//After ssm integration, spring configuration information is written in this class
}

3. Create a WebConfig configuration class to replace the spring MVC configuration file

@Configuration
//Scan component
@ComponentScan("com.atguigu.mvc.controller")
//Enable MVC annotation driver
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    //Use the default servlet to handle static resources
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    //Profile upload parser
    @Bean
    public CommonsMultipartResolver multipartResolver(){
        return new CommonsMultipartResolver();
    }

    //Configuring Interceptors 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        FirstInterceptor firstInterceptor = new FirstInterceptor();
        registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
    }
    
    //Configure view control
    
    /*@Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }*/
    
    //Configure exception mapping
    /*@Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
        Properties prop = new Properties();
        prop.setProperty("java.lang.ArithmeticException", "error");
        //Set exception mapping
        exceptionResolver.setExceptionMappings(prop);
        //Set the key to share exception information
        exceptionResolver.setExceptionAttribute("ex");
        resolvers.add(exceptionResolver);
    }*/

    //Configure build template parser
    @Bean
    public ITemplateResolver templateResolver() {
        WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver requires a ServletContext as a construction parameter, which can be obtained through the WebApplicationContext method
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
                webApplicationContext.getServletContext());
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }

    //Generate a template engine and inject a template parser into the template engine
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    //The generated view parser is not injected into the template engine
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }


}

4. Test function

@RequestMapping("/")
public String index(){
    return "index";
}

13, Spring MVC execution process

1. Spring MVC common components

  • Dispatcher servlet: front-end controller, which does not need to be developed by engineers and is provided by the framework

Function: handle the request and response in a unified way. It is the center of the whole process control, and it calls other components to process the user's request

  • Handler mapping: processor mapper, which does not need to be developed by engineers and is provided by the framework

Function: find the Handler according to the requested url, method and other information, that is, the controller method

  • Handler: processor, which needs to be developed by engineers

Function: under the control of dispatcher servlet, the Handler handles specific user requests

  • HandlerAdapter: processor adapter. It does not need to be developed by engineers. It is provided by the framework

Function: execute the processor (controller method) through the HandlerAdapter

  • ViewResolver: View resolver, which does not need to be developed by engineers and is provided by the framework

Function: analyze the view to get the corresponding view, such as ThymeleafView, InternalResourceView and RedirectView

  • View: View

Function: display model data to users through pages

2. Dispatcher servlet initialization process

Dispatcher Servlet is essentially a Servlet, so it naturally follows the Servlet life cycle. Therefore, it is the Servlet life cycle to schedule.

a> Initialize WebApplicationContext

Category: org springframework. web. servlet. FrameworkServlet

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    if (this.webApplicationContext != null) {
        // A context instance was injected at construction time -> use it
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            if (!cwac.isActive()) {
                // The context has not yet been refreshed -> provide services such as
                // setting the parent context, setting the application context id, etc
                if (cwac.getParent() == null) {
                    // The context instance was injected without an explicit parent -> set
                    // the root application context (if any; may be null) as the parent
                    cwac.setParent(rootContext);
                }
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    if (wac == null) {
        // No context instance was injected at construction time -> see if one
        // has been registered in the servlet context. If one exists, it is assumed
        // that the parent context (if any) has already been set and that the
        // user has performed any initialization such as setting the context id
        wac = findWebApplicationContext();
    }
    if (wac == null) {
        // No context instance is defined for this servlet -> create a local one
        // Create WebApplicationContext
        wac = createWebApplicationContext(rootContext);
    }

    if (!this.refreshEventReceived) {
        // Either the context is not a ConfigurableApplicationContext with refresh
        // support or the context injected at construction time had already been
        // refreshed -> trigger initial onRefresh manually here.
        synchronized (this.onRefreshMonitor) {
            // Refresh WebApplicationContext
            onRefresh(wac);
        }
    }

    if (this.publishContext) {
        // Publish the context as a servlet context attribute.
        // Share IOC container in application domain
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}
b> Create WebApplicationContext

Category: org springframework. web. servlet. FrameworkServlet

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
    Class<?> contextClass = getContextClass();
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
        throw new ApplicationContextException(
            "Fatal initialization error in servlet with name '" + getServletName() +
            "': custom WebApplicationContext class [" + contextClass.getName() +
            "] is not of type ConfigurableWebApplicationContext");
    }
    // Create IOC container objects through reflection
    ConfigurableWebApplicationContext wac =
        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    wac.setEnvironment(getEnvironment());
    // Set parent container
    wac.setParent(parent);
    String configLocation = getContextConfigLocation();
    if (configLocation != null) {
        wac.setConfigLocation(configLocation);
    }
    configureAndRefreshWebApplicationContext(wac);

    return wac;
}
c> Dispatcher servlet initialization policy

After the FrameworkServlet creates the WebApplicationContext, refresh the container and call onRefresh(wac). This method is rewritten in the dispatcher servlet and calls the initStrategies(context) method to initialize the policy, that is, initialize each component of the dispatcher servlet

Category: org springframework. web. servlet. DispatcherServlet

protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);
   initLocaleResolver(context);
   initThemeResolver(context);
   initHandlerMappings(context);
   initHandlerAdapters(context);
   initHandlerExceptionResolvers(context);
   initRequestToViewNameTranslator(context);
   initViewResolvers(context);
   initFlashMapManager(context);
}

3. DispatcherServlet calls the component to process the request

a>processRequest()

FrameworkServlet rewrites service() and doXxx() in HttpServlet, which invoke processRequest(request, response).

Category: org springframework. web. servlet. FrameworkServlet

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;

    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = buildLocaleContext(request);

    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

    initContextHolders(request, localeContext, requestAttributes);

    try {
		// To execute a service, doService() is an abstract method that is rewritten in the dispatcher servlet
        doService(request, response);
    }
    catch (ServletException | IOException ex) {
        failureCause = ex;
        throw ex;
    }
    catch (Throwable ex) {
        failureCause = ex;
        throw new NestedServletException("Request processing failed", ex);
    }

    finally {
        resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) {
            requestAttributes.requestCompleted();
        }
        logResult(request, response, failureCause, asyncManager);
        publishRequestHandledEvent(request, response, startTime, failureCause);
    }
}
b>doService()

Category: org springframework. web. servlet. DispatcherServlet

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);

    // Keep a snapshot of the request attributes in case of an include,
    // to be able to restore the original attributes after the include.
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap<>();
        Enumeration<?> attrNames = request.getAttributeNames();
        while (attrNames.hasMoreElements()) {
            String attrName = (String) attrNames.nextElement();
            if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
    }

    // Make framework objects available to handlers and view objects.
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

    if (this.flashMapManager != null) {
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    RequestPath requestPath = null;
    if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
        requestPath = ServletRequestPathUtils.parseAndCache(request);
    }

    try {
        // Processing requests and responses
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
        if (requestPath != null) {
            ServletRequestPathUtils.clearParsedRequestPath(request);
        }
    }
}
c>doDispatch()

Category: org springframework. web. servlet. DispatcherServlet

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // Determine handler for the current request.
            /*
            	mappedHandler: Call chain
                Including handler, interceptorList, interceptorIndex
            	handler: The controller method that matches the request sent by the browser
            	interceptorList: A collection of all interceptors that handle controller methods
            	interceptorIndex: Interceptor index, which controls the execution of interceptor afterCompletion()
            */
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
           	// Create the corresponding processor adapter through the controller method and call the corresponding controller method
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
			
            // Call the interceptor's preHandle()
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Actually invoke the handler.
            // The processor adapter calls the specific controller method to obtain the ModelAndView object
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            // Call postHandle() of interceptor
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // Subsequent processing: processing model data and rendering views
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}
d>processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {

    boolean errorView = false;

    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // Did the handler return a view to render?
    if (mv != null && !mv.wasCleared()) {
        // Processing model data and rendering views
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        if (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // Concurrent handling started during a forward
        return;
    }

    if (mappedHandler != null) {
        // Exception (if any) is already handled..
        // Call the interceptor's afterCompletion()
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

4. Execution process of spring MVC

  1. The user sends a request to the server, which is captured by the DispatcherServlet, the spring MVC front-end controller.

  2. DispatcherServlet parses the request URL, obtains the request resource identifier (URI), and judges the mapping corresponding to the request URI:

a) Does not exist

i. Then judge whether MVC: default servlet handler is configured

ii. If it is not configured, the console report mapping cannot be found, and the client displays 404 error

iii. if it is configured, access the target resources (generally static resources, such as JS, CSS and HTML). If the client is not found, a 404 error will be displayed


b) If it exists, execute the following process

  1. According to the URI, call HandlerMapping to obtain all relevant objects configured by the Handler (including the Handler object and the interceptor corresponding to the Handler object), and finally return in the form of HandlerExecutionChain object.

  2. DispatcherServlet selects an appropriate HandlerAdapter according to the obtained Handler.

  3. If the HandlerAdapter is successfully obtained, the pre handler (...) method [forward] of the interceptor will be executed

  4. Extract the model data in the Request, fill in the Handler input parameter, and start executing the Handler (Controller) method to process the Request. In the process of filling in the parameters of the Handler, Spring will help you do some extra work according to your configuration:

a) Httpmessageconverter: converts the request message (such as Json, xml and other data) into an object, and converts the object into the specified response information

b) Data conversion: perform data conversion on the request message. Such as converting String to Integer, Double, etc

c) Data format: format the request message. Such as converting a string into a formatted number or a formatted date

d) Data verification: verify the validity of data (length, format, etc.), and store the verification results in BindingResult or Error

  1. After the Handler is executed, a ModelAndView object is returned to the dispatcher servlet.

  2. At this time, the postHandle(...) method of the interceptor [reverse] will be executed.

  3. According to the returned ModelAndView (whether there is an exception will be judged at this time: if there is an exception, execute HandlerExceptionResolver for exception handling), select a suitable ViewResolver for View resolution, and render the View according to the Model and View.

  4. After rendering the view, execute the after completion (...) method of the interceptor [reverse].

  5. Returns the rendering results to the client.

Keywords: Java Spring

Added by Toy on Tue, 28 Dec 2021 05:24:41 +0200