Spring MVC learning notes

Posted by mephistoo on Sun, 21 Nov 2021 07:03:23 +0100

Learning route:

JavaSE: learn object-oriented concepts and characteristics, classes, interface methods and other basic knowledge, as well as relational database, the use of JDBC and the simple encapsulation of JDBC

JavaWeb: Learn browser and server related technologies, follow HTTP protocol to complete the interaction between browser and server, and use three-tier architecture to complete the function implementation process in WEB Engineering, namely presentation layer, business layer and persistence layer.

SSM: in the process of implementing the specified functions, these functions have the same patterns and processes. Therefore, it is necessary to consider function expansion, encapsulate the fixed patterns and processes, provide code reuse, and use the framework. SSM framework integration is the most popular framework structure at present. Spring MVC is an important part of SSM framework.

Main contents of this course:

IDE :IDEA
Construction tool: Maven
Thymeleaf: view rendering
Core technology: spring mvc5.3.1

catalogue

1, Introduction to spring MVC

1. What is MVC

  2. What is spring MVC

3. Characteristics of spring MVC

2, Build spring MVC framework

1. Development environment

2. Create maven project

3. Configure web.xml

4. Create request controller

5. Create a configuration file for spring MVC

6. Test HelloWorld

7. Summary

3, @ RequestMapping annotation

1. Function of @ RequestMapping annotation

2. @ RequestMapping annotation location

3. value attribute of @ RequestMapping annotation

4. method attribute of @ RequestMapping annotation

5. params attribute of @ RequestMapping annotation (understand)

6. headers attribute of @ RequestMapping annotation (understand)

7. Spring MVC supports ant style paths

8. Placeholder in spring MVC support path (emphasis)

4, Spring MVC get request parameters

1. Get through servlet API

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

3,@RequestParam

4,@RequestHeader

5,@CookieValue

6. Get request parameters through POJO

7. Solve the garbled problem of obtaining request parameters

5, Domain objects share data

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

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

3. Using Model to share data with rqequest domain objects

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

5. Use ModelMap to share data with request domain objects

6. Relationship between Model, ModelMap and Map

  7. Share data to the session domain

8. Share data with the application domain

  6, View of spring MVC

1,ThymeleafView

2. Forwarding view

3. Redirect view

4. View controller

7, RESTful

1. Introduction to RESTful

2. RESTful implementation

3. Use RESTFul to simulate the operation of user resources

Simulate get and post requests

HiddenHttpMethodFilter handles put and delete requests

Simulate PUT and DELETE requests

8, RESTful case

1. Preparatory work

Function list

2. Specific functions: visit the home page

3. Specific function: query all employee data

4. Specific function: delete

  5. Specific function: jump to the add data page

Specific function: execute save

6. Specific function: jump to the update data page

9. Specific function: execute update

8, HttpMessageConverter

1,@RequestBody

2,RequestEntity

3,@ResponseBody

  4. Spring MVC handles json

5. Spring MVC handles ajax

6. @ RestController annotation

7,ResponseEntity

9, File upload and download

1. File download

2. File upload

10, Interceptor

1. Interceptor configuration

2. Three abstract methods of interceptor

3. Execution sequence of multiple interceptors

11, Exception handler

1. Configuration based exception handling

  2. Annotation based exception handling

12, Annotation configuration spring MVC

1. Create an initialization class instead of web.xml

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

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

13, Spring MVC execution process

1. Spring MVC common components

2. Dispatcher servlet initialization process

3. DispatcherServlet calls the component to process the request

4. Execution process of spring MVC

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(service+dao+entity) in the project, which is used to process data and complete business logic
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, call models 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 Call the corresponding Model layer to process the request (service and dao), and return the result to the Controller after processing , Controller Then find the corresponding View according to the request processing results, render the data, and finally respond to the browser.

  2. What is spring MVC

Spring MVC is spring A follow-up product of is Spring A subproject of
Spring MVC is a complete set of solutions provided by spring for presentation layer development.
Note: the three-tier architecture is divided into presentation layer (or presentation layer), business logic layer and data access layer (persistence layer).
The presentation layer represents the foreground page and the background servlet. The foreground page sends a request to the server, and the server uses the servlet to receive the request, process it and respond to the browser.
SpringMVC For the encapsulation of the above function implementation, we only need to use the function code provided by spring MVC to complete the request processing.
In the presentation layer framework Strust After the successive changes of many products such as, WebWork and strut2, the industry has generally chosen SpringMVC As Java EE The preferred scheme for project presentation layer development.

3. Characteristics of spring MVC

Spring Family native products , and IOC Seamless connection of container and other infrastructure
Native based Servlet , through powerful Front end controller DispatcherServlet , unified processing of requests and responses. Encapsulate many current processes, such as obtaining request parameters, page Jump, domain object access value, etc
Problems to be solved in each subdivided field of presentation layer Omnidirectional coverage , provide Comprehensive solution
The code is fresh and concise And greatly improve 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 It is especially suitable for modern large and super large Internet projects

2, Build spring MVC framework

1. Development environment

IDE: idea 2019.2
Build tool: maven 3.5.4  
Server: tomcat7
Spring version: 5.3.1

2. Create maven project

new module--maven -- select archetype and let idea automatically create maven projects. The following demonstrates the manual creation steps

a> Packing method: war
maven project has three packaging methods. The default method is jar package. To convert the current project into a web project, you need to set the packaging method to war package

b> Introduce dependency
The core configuration file pom.xml of the current maven project
<dependencies>
    <!-- SpringMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <!--The transitivity of a dependency automatically adds its own dependency jar package-->
        <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>
        <!--It is referenced at compile time and does not need to be added at publish time.Otherwise, it will be published with tomcat Bring your own servlet of jar Package conflict. An error will be reported when compiling without this package-->
        <scope>provided</scope>
    </dependency>

    <!--Spring5 and Thymeleaf The consolidation package controls the content to be displayed in the page through view technology-->
    <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.

  Problems encountered during maven package Guide Cannot resolve plugin org.apache.maven.plugins:maven-war-plugin:2.2

c> add to web modular  
Add a web module, the webapp resource path. Create a new webapp folder under the main directory

The path added by webapp has small blue dots. After the above steps are completed, there is web.xml in the folder. Web.xml is the configuration file of the web project entry, including registered servlet s, filters, listeners, etc. After that, the XML configuration file is replaced by annotation configuration class.

After the web project is made into a war package, the dependent jar package will be placed in lib under WEB-INFO in webapp directory

3. Configure web.xml

Reason for configuration: register the front-end controller of spring MVC DispatcherServlet is registered in xml.
During configuration, org.springframework.web.servlet.DispatcherServlet is popular. It is observed that there is only JDK in External Libraries and no jar package downloaded by maven

  Solution: there may be no dependent information in the. iml file of the project. You only need to execute the following command in the project directory to regenerate the. iml file:

mvn idea:module 

Right click the corresponding Module name in Maven projects on the right side of the IDEA and select Reimport to update the related dependencies.

  a> Default configuration method

Profile location name default

<!-- 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
        /*Represents matching all requests, including jsp
        however/Cannot match.jsp Request path.(jsp The essence of is servlet,You need to go through a special in the current server servlet Processing, not required DispatcherServlet Processing, if matched jsp,Requests will also be rejected SpringMVC Processing, processing error)
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

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.

maven project configuration files are uniformly placed under resources and implemented through extended configuration. (optimal)

b> Extended configuration mode
It can be accessed through init param Label (initialization parameter) setting SpringMVC The location and name of the configuration file, via load-on-startup Tag sets the initialization time of the DispatcherServlet of the spring MVC front-end controller
<!-- 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>

Create a configuration file under resource

resources ---- right click ----- new ----- XML configure file ----- spring config to create a new springMVC.xml

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. Currently, the required data has been obtained in the front-end controller. We only need to create a method to match this method in spring MVC.

Generally, the servlet that handles the request needs to implement the servlet interface or inherit the HTTP servlet. The Controller that handles the request in spring MVC is a POJO(Plain Ordinary Java Object). Because the Controller of spring MVC is served by a POJO (ordinary Java class), it needs to be identified as a control layer component through the @ Controller annotation, Spring MVC can recognize the existence of the Controller only when it is managed by spring's IoC container

package com.atguigu.controller;//The package name can be controller or handler (processor)

import org.springframework.stereotype.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">
    <!-- Set view parser priority(Multiple view parsers can be configured) -->
    <property name="order" value="1"/>
    <!-- The encoding used to parse the view -->
    <property name="characterEncoding" value="UTF-8"/>
    <!-- inside bean to templateEngine Template attribute assignment -->
    <property name="templateEngine">
        <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
            <property name="templateResolver">
                <!--inside bean-->
                <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    
                    <!-- View prefix -The view location accessed is/WEB-INF/templates/lower-->
                    <property name="prefix" value="/WEB-INF/templates/"/>
    
                    <!-- The page accessed by the view suffix is H5 of html-->
                    <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>
We will create a new templates directory under the WEB-INF directory and index.html under this directory. We write a request to access this page. You can't jump directly when accessing this page, because the content under WEB-INF can't be accessed directly through browser and redirection, but can only be accessed through forwarding. We need to parse the current view through the view parser. If the view name meets the conditions, it will be parsed by the view parser to find the corresponding page to jump. The view will be prefixed (access path) in front of the view and suffix (file type) after the view through the parser.

6. Test HelloWorld

a> Realize the access to the home page
The web stage access context path will automatically access the index page. To achieve the same effect, you need to configure spring MVC  
Create a method in the request controller to process the request
// localhost:8080/springMVC/
@Controller
public class HelloController {
    //"/"-->/WEB-INF/templates/index.html
    //The request mapping annotation handles the mapping relationship between the request and the controller method
    //The value attribute of the annotation can match the context path of the current project represented by / through the request address
    @RequestMapping(value = "/") //When the request sent by the browser is a context path, the method represented by the annotation will be executed
    public String index(){//The method that the request matches is independent of the method name

        /**Returns the view name, which determines the final page to jump to. The name of the view we returned
        It will be parsed by the configured view parser, prefix + view name + suffix
        */
        return  "index";
    }
}

Configure tomcat for the project

There is a problem with the operation

  After successful operation

   b> Jump to the specified page through hyperlink

Set up hyperlinks in index.html on the home page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://Www.thymeleaf. Org "> <! -- namespace, you can use thymeleaf syntax -- >
<head>
    <meta charset="UTF-8">
    <title>home page</title>
</head>
<body>
    <h1>home page</h1>
    <!--@{}When an absolute path is detected, the context path is automatically added, i.e/springMVC-->
    <!--Write only<a href = "/hello">There is no context path,Because the browser parses/Indicates from localhot:8080 Next access, one less context path-->
    <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 to the server. If the request address matches the URL pattern ("/") of the front-end controller, the request will be processed by the DispatcherServlet of the front-end controller. The front-end controller will read the core configuration file of spring MVC, find the controller through scanning components, and compare the request address with the value of the @ RequestMapping annotation in the controller The attribute values are matched. If the matching is successful, the controller method identified by the annotation is the method to process the request. The method to process the request needs to return a view name of string type, which will be parsed by the view parser, plus prefix and suffix to form the path of the view, render the view through Thymeleaf, and finally forward it to the page corresponding to the view
Project construction process:
Create maven project ----- package and introduce dependencies in pom ----- (add web module and create web.xml) --- register front-end controller in web.xml ----- create spring MVC configuration file and configure (scan and view analysis) under resource ------ create controller ----- create template folder and web page content

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.

If there are multiple request controllers and the processed request addresses are the same, spring MVC will report a conflict error. Ensure that the address matched by requestmapping in all controllers is unique.

2. @ RequestMapping annotation location

@RequestMapping identifies a class: sets the initial information of the request path of the mapping request (first access to the initial information, and then access to the specific information), which is often used to distinguish controllers of different modules

@RequestMapping identifies a method: set the specific information of the request path of the mapping request (associated with the request sent by the browser)

@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";
    }

}

Modify the request path of the request mapped in index.html as: / test/testRequestMapping  

<body>
<h1>home page</h1>
<a th:href="@{/test/testRequestMapping}">test RequestMapping annotation</a>
</body>

  Application scenarios: such as user list and order list   / user/list   / order/list

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

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

If the request address does not match the request mapping, a 404 error is reported  

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 (enumeration 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 the derived annotation of @ RequestMapping for the controller method that handles the specified request method
Mapping for processing get requests -- > @ getmapping
Mapping for handling post requests -- > @ postmapping
Mapping for processing put requests -- > @ putmapping
Mapping for processing delete requests -- > @ deletemapping

@GetMapping("/testRequestMapping")
public String testGetMapping(){
    return "success";
}

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 matched by 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>

You can also use the "pass parameter" method. This writing idea will prompt an error and will not affect the operation  

@RequestMapping(
        value = {"/testRequestMapping", "/test"}
        ,method = {RequestMethod.GET, RequestMethod.POST}
        ,params = {"username","password!=123456"}
)
public String testRequestMapping(){
    return "success";
}

Note: if the current request meets the value and method attributes of the @ RequestMapping annotation, but does not meet the parameters attribute, the page returns an error of 400: parameter conditions "username, password= 123456" not met 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

@RequestMapping(value = {"/test","/testRequestMapping"},
                method = {RequestMethod.POST,RequestMethod.GET},
                headers = {"Host=localhost: 8081"}              
)
   //headers are new types of key value pairs
public String mapTest(){
   return "success";
}

7. Spring MVC supports ant style paths

Fuzzy matching function. Applied to the value attribute of requestMapping

?: represents any single character (except?, and / or)
*: indicates any 0 or more characters (? And / excluded)
**: represents any one or more levels of directories. Note: when * * is used, only / * * / xxx can be used

 @RequestMapping("/a?a/testAnt")
public String testAnt(){
    return "success";
 }


@RequestMapping("/**/testAnt")
//springMVC/a1/a/testAnt or springMVC/testAnt or springMVC/a1/testAnt can be accessed
public String testAnt(){
    return "success";
}

8. Placeholder in spring MVC support path (emphasis)

value attribute applied to requestMapping

Original method: / deleteUser?id=1
restful mode: / deleteUser/1/admin

Which directory corresponds to which value? How do I get these values?  

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 value represented by {id} is automatically assigned to the formal parameter id, and the final output content is -- > id: 1, username: admin

In this way, the parameter name will not be exposed to the front end

4, Spring MVC get request parameters

1. Get through servlet API

The request sent by the browser is first processed by the front-end controller, which indirectly calls the controller method. 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. (the current request in the controller is assigned to the formal parameter as an argument)

@RequestMapping("/testParam")
//The request of the formal parameter position represents the current request
public String testParam(HttpServletRequest request){
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    System.out.println("username:"+username+",password:"+password);
    return "success";
}
<a th:href="@{/testServletAPI(username='admin',password=123)}">test</a>

This method is rarely used in general, and it can be used without the native API, because spring MVC helps us simplify a lot.  

  Episode: HTTP status 500 - servlet. Init() for servlet dispatcherservlet thread exception occurs during project operation. Direct rebuild project solution

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. (if the match is inconsistent, it cannot be obtained)

<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

<form th:action="@{/testParam}" method="post">
    user name:<input type="text" name="password"><br>
    password:<input type="password" name="username"><br>
    Hobbies:<input type="checkbox" name="hobby" value="a">a
    <input type="checkbox" name="hobby" value="b">b
    <input type="checkbox" name="hobby" value="c">c<br>
    <input type="submit" value="Submit">
</form>
@RequestMapping("/testParam")
    public String testParam(String username,String password,String hobby){
        //username:12,password:yu,hobby:a,b
        System.out.println("username:"+username+",password:"+password+",hobby:"+hobby);
        return "success";
    }

@RequestMapping("/testParam")
   public String testParam(String username,String password,String[] hobby){
        //username:12,password:yu,hobby:[a, b, c]
       System.out.println("username:"+username+",password:"+password+",hobby:"+hobby);
       return "success";
   }

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

@RequestMapping("/testParam")
    public String testParam(
        @RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username,
        String password,
        String[] hobby){
        System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobby));
        return "success";
    }

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 @ RequestParam

public String testParam(
            @RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username,
            @RequestHeader("Host" )String host)
            {
        System.out.println("username:"+username);
        //Host:localhost:8080
        System.out.println("Host:"+host);

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

    @RequestMapping("/testParam")
    public String testParam(
            @RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username,
            @RequestHeader("Host" )String host,
            @CookieValue("JSESSIONID") String JSESSIONID)
            {
        System.out.println("username:"+username);
        //Host:localhost:8080
        System.out.println("Host:"+host);
        System.out.println("JSESSIONID:"+JSESSIONID);
        return "success";
    }

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 ='? ', email='123@qq.com '} character codes are inconsistent and garbled

7. Solve the garbled problem of obtaining request parameters

The reason why the get request is garbled is caused by tomcat. The tomcat configuration file conf/server.xml needs to be changed. (it needs to be changed before version 8). post needs to set the encoding method before obtaining the request parameters to be effective (request.setCharacterEconding()).

Because the dispatcher servlet has obtained the request parameters, it is invalid to set the encoding method. To solve the problem of garbled code in obtaining request parameters, you can use the encoding filter characterencoding filter provided by spring MVC before obtaining request parameters, but it must be registered in web.xml. (the loading order of the three components is Listen, filter and servlet. Because Listen listens to the creation and destruction of servletConText only once, it is set in the filter. The request code is only set through the filter. Each time a request is sent, it is processed by the filter and then forwarded to the dispatcher Servlet.)

<!--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>

Manual code source:

 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String encoding = this.getEncoding();
        if (encoding != null) {
            if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
                request.setCharacterEncoding(encoding);
            }

            if (this.isForceResponseEncoding()) {
                response.setCharacterEncoding(encoding);
            }
        }

        filterChain.doFilter(request, response);
    }

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

5, Domain objects share data

Four domain objects: page, request, session and application

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

@RequestMapping("/testRequestByServletAPI")
public String testServletAPI(HttpServletRequest request){
    request.setAttribute("testScope", "hello,servletAPI");
    return "success";
}
<!--index-->
<a th:href="@{/testRequestByServletAPI}">test</a>

<!--success-->
<p th:text="${testScope}"></p> //Get the data in the request field, Hello, servlet API

Generally, we do not use the native method. We often use the spring MVC encapsulation method.  

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

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){//Be sure to return the ModelAndView object
    /**
     * 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();
    //Process model data and share data with the requesting domain
    mav.addObject("testScope", "hello,ModelAndView");
    //Set the view to realize page Jump
    mav.setViewName("success");
    return mav;
}

  The front-end controller parses the encapsulated model data and view information according to the returned object.

3. Using Model to share data with rqequest domain objects

@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){//The data stored in the map set is the data stored in the domain object
    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> {} //modelmap is the implementation class of map
public class ExtendedModelMap extends ModelMap implements Model {}//Class can instantiate modelmap and model
public class BindingAwareModelMap extends ExtendedModelMap {}

In any way, the model data and current view information will eventually be encapsulated in the modelandview object. (through breakpoints combined with source code analysis)

7. Share data to the session domain

@RequestMapping("/testSession")
public String testSession(HttpSession session){
    session.setAttribute("testSessionScope", "hello,session");
    return "success";
}
<p th:text="${session.testSessionScope}></p>

It is often used to save the login status of users. It is recommended to use the native API  

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";
}
<p th:text="${application.testApplicationScope}></p>

  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";
}

Source code: (debug and jump to the render () method in processDispatchResult). mv.getModelInternal returns the model object, that is, the model data encapsulated by ModelAndView.

resolveViewName() creates a view object based on the view name. Create ThymeleafView without any prefix

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:", a view of InternalResourceView type 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

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

    @RequestMapping("/testForward")
    public String testForward(){
        return "forward:/testThymeleafView";//Forward request to / testThymeleafView
    }

  1. Forward the testThymeleafView request that can jump to the success page. 2. Create a ThymeleafView view to access success

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

@RequestMapping("/testRedirect")
public String testRedirect(){
    return "redirect:/testHello";//Redirect to a request, not a page (the page under web_info cannot be redirected. All pages must be parsed by thymeleaf, and the thymeleaf view can be accessed through forwarding)
}

 

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

Review the differences between forwarding and redirection:
1. Forwarding is one request (one request from the browser), and redirection is two requests from the browser. The first is to access the Servlet and the second is to access the redirection address
2. The forwarding address bar address remains unchanged, and the redirection address bar address becomes the redirection address
3. Forwarding can obtain request domain data, but redirection cannot (two requests).
4. Forwarding can access the web_ The resource under info cannot be redirected. web_info resources are secure and can only be accessed through the server, not through the browser.
5. Forwarding cannot cross domain, and redirection can (for example, visit Baidu under the project)

4. View controller

When the controller method is only used to realize page Jump without other process processing, 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, which refers to the state transfer of presentation (description) layer resources. A style of software architecture.

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 many formats, such as HTML/XML/JSON / plain text / picture / video / audio, etc. The expression format of resources can be determined through negotiation mechanism. The request response direction is usually expressed in different formats.

c> State transition

State transfer refers to the transfer between the client and the server, which represents the expression of resource state. Through the expression of transfer and operation resources, the purpose of operating resources can be realized 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.

3. Use RESTFul to simulate the operation of user resources

Simulate get and post requests

<a th:href="@{/user}">Query all user information</a><br>
<a th:href="@{/user/1}">"according to id Query user information"</a><br>
<form th:action="@{/user}" method="post">
    user name<input type="text" name="username"><br>
    password<input type="password" name="password"><br>
    <input type="submit" value="Add user information"><br>
</form>
@Controller
public class UserController {
    /**
     * Use RESTFul to simulate the addition, deletion, modification and query of user resources
     * /user GET Query all user information
     * /user/1 GET Query user information according to user id
     * /user POST Add user information
     * /user/1 DELETE Delete user information
     * /user PUT Update user information
     */
    @RequestMapping(value = "/user",method = RequestMethod.GET )
    public String getAllUser(){
        System.out.println("Query all user information");
        return "success";
    }

    @RequestMapping(value = "/user/{id}",method = RequestMethod.GET )
    public String getUserById(){
        System.out.println("according to id Query user information");
        return "success";
    }

    @RequestMapping(value = "/user",method = RequestMethod.POST)
    public String insertUser(String username,String password){
        System.out.println("Add user information:"+username+","+password);
        return "success";
    }
}

HiddenHttpMethodFilter handles put and delete requests

<form th:action="@{/user}" method="put">
    user name<input type="text" name="username"><br>
    password<input type="password" name="password"><br>
    <input type="submit" value="modify"><br>
</form>
    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    public String updateUser(String username,String password){
        System.out.println("Modify user information:"+username+","+password);
        return "success";
    }

Because the browser does not support put, the access method is still get, and the query controller method is executed.

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

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

HiddenHttpMethodFilter conditions for processing put and delete requests (analyze the source code and draw a conclusion):

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

Register HiddenHttpMethodFilter in web.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>

Hand tearing source code:

 private static final List<String> ALLOWED_METHODS;
 public static final String DEFAULT_METHOD_PARAM = "_method";
 private String methodParam = "_method";
 static {
   ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));}

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//Request the request intercepted by the current filter
        HttpServletRequest requestToUse = request;
        if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {//The request method of the current request must be post to execute the following contents
            //Request parameters of the current request, (private String methodParam = "_method";)
            String paramValue = request.getParameter(this.methodParam);obtain_method The value of the request parameter
            //If there is a length (not empty)
            if (StringUtils.hasLength(paramValue)) {
                //_ The value of the method parameter is capitalized
                String method = paramValue.toUpperCase(Locale.ENGLISH);
                if (ALLOWED_METHODS.contains(method)) {//The parameter values are one of the three constants, put, delete and patch
                    requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
                }
            }
        }

        filterChain.doFilter((ServletRequest)requestToUse, response);
    }

//Replace the request mode of request with POST_ The value represented by the method parameter (DELETE/PUT/PATCH)
 private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
        private final String method;
        //method (DELETE/PUT/PATCH)
        public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
            super(request);
            this.method = method;
        }

        public String getMethod() {
            return this.method;//Rewrite the getMethod method of the request object and return the method
        }
    }

Simulate PUT and DELETE requests

<form th:action="@{/user}" method="post">
    <input type="hidden" name="_method" value="PUT">
    user name<input type="text" name="username"><br>
    password<input type="password" name="password"><br>
    <input type="submit" value="modify"><br>
</form>

<!--Delete the following examples-->

Note: so far, spring MVC has provided two filters: characterencoding filter and HiddenHttpMethodFilter
When registering in web.xml, you must first register CharacterEncodingFilter and then HiddenHttpMethodFilter

reason:
In CharacterEncodingFilter, set the request.setCharacterEncoding(encoding) method of the character set through the request.setCharacterEncoding(encoding) method. The request.setCharacterEncoding(encoding) method requires that there must be no previous operation to obtain the request parameters, while 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

Create a new maven project and configure pom.xml,web.xml and springMVC.xml.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>springMVC_rest</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <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>

</project>

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <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>

    <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>

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

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

    <context:component-scan base-package="com.atguigu.rest"></context:component-scan>
    <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>

    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
    <mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
    <!--Open access to static resources-->
    <mvc:default-servlet-handler/>
    <mvc:annotation-driven />
</beans>
  • 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++);//Assign first and then increase automatically
      }
      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);
   }
}

Function list

2. 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>

3. 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"><!--id Attribute to vue Binding container-->
        <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>

4. Specific function: delete

Deleting is usually a hyperlink method, but the hyperlink cannot send a delete request. Therefore, the form submission is controlled by hyperlink. The form mehtod is post and the request parameter is_ method

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

Create a new static folder under webapp folder, create JS, and 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>
<!--Bind stand-alone events-->

Handling click events through vue

<script type="text/javascript">
    var vue = new Vue({
        el:"#dataTable ", / / the current vue container uses the attribute datatabel (used in the scope containing hyperlinks)
        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 currently 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";
}

Running result report 404 reason: static resources cannot be accessed by spring MVC. Add the following configuration in spring MVC

   <!--Open access to static resources-->
    <mvc:default-servlet-handler/>

If the current request dispatchsetvlet cannot handle it, it will be handed over to the default servlet (web.xml configuration in tomcat)

5. 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>

Specific function: execute save

a> Controller method

@RequestMapping(value = "/employee", method = RequestMethod.POST)
public String addEmployee(Employee employee){//Saving data with entity class objects
    employeeDao.save(employee);
    return "redirect:/employee";
}

6. Specific function: jump to the update data page

Find out the data to be queried and return to the display page after modifying the page to be modified

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}"><!--id Echo of-->
    lastName:<input type="text" name="lastName" th:value="${employee.lastName}"><br><!--Echo-->
    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>

Specific function: execute update

a> Controller method

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

9, HttpMessageConverter

HttpMessageConverter, message information converter, converts request message into Java object or Java object into response message. (request message: browser sends request to server and Java receives request message. Response message: server responds to request to browser and Java object converts response message to server)

HttpMessageConverter provides two annotations and two types: @ RequestBody, @ ResponseBody, RequestEntity and responseentity (two commonly used responses)

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"><!--post The request has a request body-->
    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

You can use the return value of the method as the browser's response body, and json is required to respond to the object (introduce dependency, open mvc annotation driver, and add responseBody annotation)

@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

The browser cannot receive the response object. You need to convert the object to 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

<!-- 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>

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 ", / / container id
        methods:{
            testAjax:function (event) {
                axios({
                    method:"post",
                    url:event.target.href,
                    params:{
                        username:"admin",
                        password:"123456"
                    }
                }).then(function (response) {//ajax handles the to be executed successfully
                    alert(response.data);
                });
                event.preventDefault();//Cancels the default behavior of hyperlinks
            }
        }
    });
</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 (derived) 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. (because the @ ResponseBody annotation is quite common)

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

10, File upload and download

1. File download

Download resources from the server to the browser

Use ResponseEntity to download files

Response header, response body, response status code

@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
    //Get ServletContext object
    ServletContext servletContext = session.getServletContext();
    //Get the real path of the file in the server (the path of the current project deployed to tomcat)
    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()];//Gets all bytes of the file corresponding to the input stream
    //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");//The download method is attachment. The default file name is 1.jpg
    //Set response status code
    HttpStatus statusCode = HttpStatus.OK;
    //Create ResponseEntity object bytes response body headers response header
    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

At this time, the data in the form is transmitted to the server in binary mode

<form th:action="@{/testUp}" method="post" enctype="multipart/form-data">
    head portrait:<input type="file" name="photo"></br>
    <input type="submit" value="upload">
</form>

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:

Configure the file upload parser to package the uploaded file as MultipartFile

<!--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:

session get server path

@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
    //Gets the file name of the uploaded file
    String fileName = photo.getOriginalFilename();
    //Handle the problem of file name duplication and obtain the suffix of the uploaded file
    String hzName = fileName.substring(fileName.lastIndexOf("."));//Gets the location of the last occurrence of
    fileName = UUID.randomUUID().toString() + hzName;//The result of stitching UUID and suffix is taken as the final file name
    //Gets the path to the photo directory in the server
    ServletContext servletContext = session.getServletContext();
    String photoPath = servletContext.getRealPath("photo");//Get the path to the photo directory
    File file = new File(photoPath);
    //Determine whether the path corresponding to the photoPath exists
    if(!file.exists()){
        //If it does not exist, create a directory
        file.mkdir();
    }
    String finalPath = photoPath + File.separator + fileName;//path separator 
    //Realize the upload function
    photo.transferTo(new File(finalPath));
    return "success";
}

11, 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 (otherwise it has no effect):

<!-- The following two configuration methods are correct DispatcherServlet All requests processed are intercepted-->
<mvc:interceptors>
    <bean class="com.atguigu.interceptor.FirstInterceptor"></bean>
    <!--bean perhaps ref Two ways of writing-->
    <ref bean="firstInterceptor"></ref>
<mvc:interceptors/>

<!-- 
    The following 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
-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/><!--/*It only represents the Interception under the directory of one layer, such as/a,/**Indicates the interception of all requests-->
        <mvc:exclude-mapping path="/testRequestEntity"/>
        <ref bean="firstInterceptor"></ref><!--ref Reference current IOC One of the containers bean of id,At this point, give the interceptor to ioc Administration,@component Identify components, you can also use bean Method of-->
    </mvc:interceptor>
<mvc:interceptors>

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 to release, that is, call the controller method; return false to intercept, that is, do not call the controller method

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

@Component
public class FirstInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor-->preHandle");
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor-->postHandle");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor-->afterCompletion");
    }
}

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 configured order, while postHandle() and aftercompilation() will execute in the reverse order of configuration

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

         preHandle() returns false. It and the preHandle() of the interceptor before it will execute, postHandle() will not execute, and aftercompilation() of the interceptor before the interceptor returns false will execute

Hand tear source code

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
     return;
}

//Controller method
 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

mappedHandler.applyPostHandle(processedRequest, response, mv);

if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
            }

    }

//Enter the HandlerExecutionChain class of the above method
 boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //Traverse the interceptor collection
    //interceptorIndex is the interceptor index before prehandle returns false 
    for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {//The initial value of interceptorIndex is - 1
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            if (!interceptor.preHandle(request, response, this.handler)) {
                //After completion will be executed, and the interceptor order traversed during execution is the reverse order of interceptorIndex values at this time.                
                //post is not executed
                this.triggerAfterCompletion(request, response, (Exception)null);
                return false;
            }
        }

        return true;
}


//Enter the above method
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
        for(int i = this.interceptorList.size() - 1; i >= 0; --i) {
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            interceptor.postHandle(request, response, this.handler, mv);
        }

    }



void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
        for(int i = this.interceptorIndex; i >= 0; --i) {//interceptorIndex starts from the previous accumulation, so it is also executed in reverse order
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);

            try {
                interceptor.afterCompletion(request, response, this.handler, ex);
            } catch (Throwable var7) {
                logger.error("HandlerInterceptor.afterCompletion threw exception", var7);
            }
        }

    }

mappedHandler is the execution chain of the controller, including the currently matched controller method and the interceptor for processing the controller method (spring MVC comes with one)

12, 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 are defaulthandlerexceptionresolver (default) 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"><!--Anomaly mapping-->
        <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 sets a property name to share the exception information in the request field. It realizes the display of error information on the page
    -->
    <property name="exceptionAttribute" value="ex"></property>
</bean>
@RequestMapping("/testException")
    public String testException(){
        System.out.println(1/0);
        return "success";
    }
<!--error.html-->
<body>
<h1>You're wrong</h1>
<p th:text="${ex}"></p>
</body>

  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";
    }

}

13, Annotation configuration spring MVC

Use configuration classes and annotations instead of the functionality of web.xml and spring MVC configuration files

1. Create an initialization class instead of web.xml

In the Servlet 3.0 environment, the container will find the class that implements the javax.servlet.ServletContainerInitializer interface in the class path. If found, it will be used 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. Spring 3.2 introduces a convenient basic implementation of web application initializer called AbstractAnnotationConfigDispatcherServletInitializer. When our class extends AbstractAnnotationConfigDispatcherServletInitializer and deploys it to the Servlet 3.0 container, the container will automatically discover it and use it to configure the Servlet context.

Create a new module, a new webapp under the main folder, and a new WEB-INF folder under webapp

//Initialization class of Web project, which is used to replace web.xml
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//Identify as configuration class
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

Replace the configuration file of spring MVC:

1. Scanning component 2. View parser 3. View controller 4. Default servlet handler 5. MVC driver annotation 6. File upload parser 7. Exception handling 8. Interceptor

//Identifies the current class as a configuration class
@Configuration
//Scan component
@ComponentScan("com.atguigu.mvc.controller")
//Enable MVC annotation driver
@EnableWebMvc

public class WebConfig implements WebMvcConfigurer {//Interface provides configuration methods for us to use
    //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();//Interceptor object
        registry.addInterceptor(firstInterceptor).addPathPatterns("/**");//Add interception path (multiple can be written)
    }
    
    //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 the generation template parser (the view part of xml depends on memory beans, and the configuration starts from memory beans)
    @Bean    //The return value of the method is a bean of ioc
    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 //ioc automatic assembly assignment parameters
    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;
    }
}

Test function

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

14, 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 (also known as controller) 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 (call the execution controller method)

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.

The description with gray up arrow after the method in the following figure is the rewritten method. If the method is empty, it indicates the specific implementation of the inherited subclass or subclass method

a> Initialize webapplicationcontext (initialize the IOC container of spring MVC)

Class: org.springframework.web.servlet.FrameworkServlet

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());//Get WebApplicationContext through tool class
    WebApplicationContext wac = null;
​
    if (this.webApplicationContext != null) {//The first execution is 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();//find
    }
    if (wac == null) {
        // No context instance is defined for this servlet -> create a local one
        // Creating WebApplicationContext is an important step
        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);//Share in the application domain with attrname as the attribute name and wac as the attribute value
    }
​
    return wac;
}

b> Create WebApplicationContext

Class: 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 the parent container (after the integration of spring and spring MVC (two configurations), the IOC container of spring MVC is the child container and the IOC container of spring is the parent container
    wac.setParent(parent);//Make spring's IOC container the parent of spring MVC's IOC container
    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

Class: org.springframework.web.servlet.DispatcherServlet

protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);//Initialize file upload parser
   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. These methods call processRequest(request, response). ProcessRequest method calls doDispatcher() in calling doService(), doService().

Class: org.springframework.web.servlet.FrameworkServlet

  protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
            super.service(request, response);//The doXXX method in this method is overridden by the FrameworkServlet
        } else {
            this.processRequest(request, response);
        }
    }

 protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }

    protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }
... ...
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()

Class: 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()

Class: 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) {//Handling of exceptions
        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 current request will only be processed by the dispatchservlet), the console will report that the mapping cannot be found, and the client will display a 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
3) 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.

4) DispatcherServlet selects an appropriate HandlerAdapter according to the obtained Handler.

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

6) Extract the model data in the Request, fill in the Handler (controller method) input parameters, and start executing the Handler (Controller) method to process the Request. In the process of filling in the Handler input parameters, Spring will help you do some additional 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: data 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 (now it is generally verified directly in the browser)

7) After the handler is executed, a ModelAndView object is returned to the dispatcher servlet.

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

9) 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.

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

11) Returns the rendering results to the client.

 

Topics: Java RESTful Spring MVC