SpringMVC Silicon Valley Notes + Some Understanding Combined Notes

Keywords: Java JavaEE Spring Back-end mvc

1. Introduction to Spring MVC

1. What is MVC

MVC is the idea of a software architecture that divides software into models, views, and controllers

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

JavaBean s fall into two categories:

  • A class called entity class Bean: Stores business data specifically, such as Student, User, and so on
  • One type is called a business processing Bean: a Service or Dao object designed to handle business logic and data access.

V:View, the view layer, refers to pages such as html or jsp in a project that interact with users and display data

C:Controller, the control layer, refers to a servlet in a project that receives requests and responds to browsers

MVC Workflow:
The user sends a request to the server through the view layer, and the request is received by the Controller in the server. The Controller calls the corresponding Model layer to process the request, returns the result to the Controller after processing, and the Controller finds the corresponding View view based on the result of the request processing, renders the data, and finally responds to the browser.

2. What is Spring MVC

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

SpringMVC is Spring's complete set of solutions for presentation layer development. After the evolution of the Representation Layer Framework from Strust, WebWork, Strust2 and many other products, SpringMVC is currently the preferred solution for the development of Representation Layer in Java EE projects.

Note: The three-tier architecture is divided into Representation Layer (or Representation Layer), Business Logic Layer, Data Access Layer, Representation Layer represents foreground page and background servlet

3. Features of Spring MVC

  • Spring family originals, seamless docking with infrastructure such as IOC containers
  • Based on native Servlet, request and response are handled uniformly through the powerful front-end controller Dispatcher Servlet
  • The problems that need to be solved in each subdivision of the expression layer are covered in an all-round way to provide a comprehensive solution
  • Fresh and concise code, greatly improving development efficiency
  • High degree of internal componentization, plug and play pluggable components, what functions you want to configure the corresponding components
  • Excellent performance, especially for modern large, super large Internet projects

2. HelloWorld

1. Development environment

IDE: idea 2021.1

Building tools: maven3.6.4

Server: tomcat9

Spring version: 5.3.1

2. Create a maven project

A>Add a web module
B>Packaging method: war
C>Introducing dependencies
<dependencies>
    <!-- SpringMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.1</version>
    </dependency>

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

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

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

Note: Due to Maven's transitivity, we do not have to configure all the packages we need to rely on, but instead configure the top-most dependencies and the others rely on transitive import.

3. Configure web.xml

Register the front-end controller Dispatcher Servlet for SpringMVC

A>Default configuration

With this configuration, SpringMVC's configuration file defaults to WEB-INF with the default name <servlet-name>-servlet.xml. For example, the configuration file for SpringMVC corresponding to the following configuration is located under WEB-INF with the file name springMVC-servlet.xml

<!-- To configure SpringMVC Front-end controller that handles browser-sent requests uniformly -->
<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 Request path for requests that the core controller can handle
        /The matched request can be/login or.html or.js or.css Request path of mode
        however/Unmatched.jsp Request Path
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>
B>Extended configuration

The location and name of the SpringMVC configuration file can be set through the init-param tag, and the initialization time of the SpringMVC front-end controller Dispatcher Servlet can be set through the load-on-startup tag.

<!-- To configure SpringMVC Front-end controller that handles browser-sent requests uniformly -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- Specify by initialization parameters SpringMVC Location and name of profile -->
    <init-param>
        <!-- contextConfigLocation Is Fixed Value -->
        <param-name>contextConfigLocation</param-name>
        <!-- Use classpath:Represents finding a configuration file from a class path, for example maven In the project src/main/resources -->
        <param-value>classpath:springMVC.xml</param-value>
    </init-param>
    <!-- 
 		As a core component of the framework, there is a lot of initialization to do during startup
		These operations, performed on the first request, can seriously affect access speed
		So this tag will start the control DispatcherServlet Initialization time is advanced to server startup
	-->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <!--
        Set up springMVC Request path for requests that the core controller can handle
        /The matched request can be/login or.html or.js or.css Request path of mode
        however/Unmatched.jsp Request Path
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

Note:

Differences between/and/* used in <url-pattern>tags:

/The matched request can be a request path in the form of/login or.html or.js or.css, but/cannot match the request in the.jsp request path

This prevents the request from being processed by Dispatcher Servlet when accessing a jsp page and the corresponding page from being found

/* will be able to match all requests, for example, when using filters, if all requests need to be filtered, the /* notation will be used

4. Create Request Controller

Since the front-end controller handles requests sent by the browser uniformly, but the specific requests are handled differently, it is necessary to create a class that handles the specific requests, that is, the request controller

Request each method in the controller that handles the request to become the controller method

Because SpringMVC's controller is a POJO (common Java class), it needs to be identified as a control layer component through the @Controller annotation and managed by Spring's IoC container before SpringMVC can recognize the existence of the controller

@Controller
public class HelloController {
    
}

5. Create a configuration file for springMVC

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

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

<!-- 
   Processing static resources, such as html,js,css,jpg
  If only this label is set, only static resources can be accessed, other requests cannot.
  This must be set<mvc:annotation-driven/>Solve the problem
 -->
<mvc:default-servlet-handler/>

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

6. Test HelloWorld

A>Implement access to the home page

Create a method to process requests in the request controller

// @RequestMapping Note: Mapping relationship between processing requests and controller methods
// The value property of the @RequestMapping annotation can match the request by the request address, /representing the context path of the current project
// localhost:80/springMVC/
@RequestMapping("/")
public String index() {
    //Set View Name
    return "index";
}
B>Jump to a specified page through a hyperlink

Set up hyperlinks in homepage index.html

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

Create a method to process requests in the request controller

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

7. Summary

The browser sends a request that is processed by the front-end controller Dispatcher Servlet if the request address matches the url-pattern of the front-end controller. The front-end controller reads the core configuration file of SpringMVC, finds the controller by scanning the components, matches the request address with the value attribute value of the @RequestMapping annotation in the controller, and if the match is successful, the controller method identified by the annotation is the one that handles the request. The method that handles the request needs to return a string-type view name that will be parsed by the view parser, rendered by Thymeleaf, and then forwarded to the page on which the view corresponds, along with a path that consists of a view with a prefix and suffix

3. @RequestMapping Notes

1. @RequestMapping annotation function

As you can see from the annotation name, the @RequestMapping annotation is used to associate the request with the controller method that handles the request and establish a mapping relationship.

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

2. @RequestMapping annotation location

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

@RequestMapping identifies a method for setting specific information about the path of a map request request

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

	//The request path for the request mapped by the request mapping is: /test/testRequestMapping
    @RequestMapping("/testRequestMapping")
    public String testRequestMapping(){
        return "success";
    }

}

3. @RequestMapping annotation value property

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

The value property of the @RequestMapping annotation is an array of string types indicating that the request mapping can match requests corresponding to multiple request addresses

The value property of the @RequestMapping annotation must be set, at least by request address matching request mapping

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

4. @RequestMapping annotation method property

The method property of the @RequestMapping annotation matches the request mapping by the way the request is requested (get or post)

The method property of the @RequestMapping annotation is an array of RequestMethod types, indicating that the request mapping can match requests of multiple request modes

If the request address of the current request satisfies the value attribute of the request mapping, but the request method does not satisfy the method attribute, the browser 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. Derived annotations for @RequestMapping are provided in SpringMVC for controller methods that handle specified requests

Mapping for processing get requests -->@GetMapping

Mapping for processing post requests -->@PostMapping

Mapping for processing put requests -->@PutMapping

Mapping for handling delete requests -->@DeleteMapping

2. Common requests are get, post, put, delete

However, browsers currently only support get and post. When a form form submission is made, a string (put or delete) with other request modes is set for the method, the default request mode for get processing is followed.

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

5. @RequestMapping annotation params property (understand)

The @RequestMapping annotation's params property matches the request mapping by the request parameter

The params property of the @RequestMapping annotation is an array of string types that allow you to set the matching relationship between request parameters and request mappings in four expressions

"Param": Requires that requests matching the request mapping must carry param request parameters

'!Param': Request mapping matches a request that must not carry param request parameters

"Param=value": Requires that requests matching the request mapping must carry a param request parameter and param=value

"param!=value": Requests that the request mapping matches must carry a param request parameter but param!= Value

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

Note:

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

6. @RequestMapping annotation headers property (understand)

The headers property of the @RequestMapping annotation matches the request mapping with the request header information of the request

The headers property of the @RequestMapping annotation is an array of string types that allows you to set the matching relationship between the request header information and the request map in four expressions

"Header": Requires that requests matching the request map must carry header request header information

'!Header': Request mapping matches a request that must not carry header request header information

"Header=value": Require that requests matching the request map must carry header request header information and header=value

"header!=value": Requests that the request mapping match must carry header request header information and header!= Value

If the current request satisfies the value and method properties of the @RequestMapping annotation, but the headers property is not, the page displays a 404 error, that is, the resource was not found

7. SpringMVC supports ant style paths

?: Represents any single character

*: Represents any zero or more characters

**: Indicates any one or more levels of directory

Note: When using **, you can only use /**/xxx

8. SpringMVC supports placeholders in paths (emphasis)

Original way: /deleteUser?id=1

rest method: /deleteUser/1

Placeholders in SpringMVC paths are commonly used in the RESTful style. When certain data is routed to the server in the request path, the data transferred can be represented by the placeholder {xxx} in the value property of the corresponding @RequestMapping annotation, and the data represented by the placeholder can be assigned to the parameter of the controller method in the @PathVariable annotation.

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

4. SpringMVC Get Request Parameters

1. Obtained through the Servlet API

HttpServletRequest is used as a parameter to the controller method, where a parameter of type HttpServletRequest represents the object encapsulating the request message of the current request

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

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

In the parameter location of the controller method, set the parameter with the same name as the request parameter, and when the browser sends the request and matches the request mapping, the request parameter is assigned to the corresponding parameter in the Dispatcher Servlet

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

Note:

If the request is transmitted with more than one request parameter with the same name, then a string array or a string type parameter can be set in the parameter of the controller method to receive the request parameter.

If a parameter of type string array is used, the array of this parameter contains each data

If a string type parameter is used, the value of this parameter is the result of using a comma stitch in the middle of each data

3,@RequestParam

@RequestParam creates a mapping relationship between the request parameters and the parameters of the controller method

The @RequestParam annotation has three properties:

value: The parameter name of the request parameter specified as a parameter assignment

required: Sets whether this request parameter must be transferred, defaulting to true

If set to true, the current request must transfer the request parameter specified by value. If the request parameter is not transferred and the defaultValue property is not set, the page error is 400:Required String parameter'xxx'is not present; If set to false, the current request does not have to transfer the request parameters specified by value. If not, the value of the parameter identified by the comment is null

Default Value: 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 parameter assignment is made using the default value

4,@RequestHeader

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

The @RequestHeader annotation has three properties: value, required, defaultValue, and is used in the same way as @RequestParam

5,@CookieValue

@CookieValue creates a mapping relationship between cookie data and the parameters of the controller method

The @CookieValue annotation has three properties: value, required, defaultValue, and is used in the same way as @RequestParam

6. Obtain request parameters through POJO

An entity class type parameter can be set at the parameter location of the controller method, and if the parameter name of the request parameter transmitted by the browser is the same as the property name in the entity class, the request parameter will be assigned a value for this property

<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>
    Mailbox:<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='man', email='123@qq.com '}

7. Solve the problem of scrambling to get request parameters

7.1. Resolve Chinese scrambling in GET requests by adjusting server configuration

The following code can be found directly in service.xml under the conf folder of tomcat:

   <Connector port="80"  protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

Then add a URLEncoding="UTF-8" to the code

give the result as follows

          <Connector port="80" URLEncoding="UTF-8"  protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

7.2 Adjust all encoding formats through java

To resolve the scrambling problem of getting request parameters, you can use the encoding filter CharacterEncoding Filter provided by SpringMVC, but it must be registered in web.xml

<!--To configure springMVC Coding filters for-->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Note:

Filters that process codes in SpringMVC must be configured before other filters, otherwise they are invalid

5. Domain Object Sharing Data

1. Use the Servlet API to share data with the request domain object------- scope of one request

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

2. Use ModelAndView to share data to request domain objects

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
    /**
     * ModelAndView With Model and View capabilities
     * Model Primarily used to share data to request domains
     * View Mainly used to set up views for page jumps
     */
    ModelAndView mav = new ModelAndView();
    //Share data to request domain
    mav.addObject("testScope", "hello,ModelAndView");
    //Set up views to jump pages
    mav.setViewName("success");
    return mav;
}

3. Use Model to share data to request domain objects

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

4. Use map to share data to request domain objects

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

5. Use ModelMap to share data to request domain objects

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

6. Relationship among Model, ModelMap, Map

Parameters of type Model, ModelMap, Map are essentially of type BindingAwareModelMap

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

7. Sharing data to session domain--------------------- scope of a session

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

8. Sharing data to the application domain------------------------------- The scope of the entire application (server on to off)

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

6. View of Spring MVC

Views in SpringMVC are the View interface, which renders data and displays data from Model Models to users

There are many types of SpringMVC views, with forwarded and redirected views by default

When a project introduces a jstl dependency, the forward view is automatically converted to a JstlView

If the view technology used is Thymeleaf, Thymeleaf's view resolver is configured in the Spring MVC configuration file, and the resolver resolves the view to ThymeleafView

1,ThymeleafView

When the view name set in the controller method does not have any prefix, the view name will be resolved by the view resolver configured in the SpringMVC configuration file. The final path resulting from the view name splicing the view prefix and view suffix will be forwarded to jump

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

2. Forward View

The default forward view in SpringMVC is InternalResourceView

When creating forwarded views in SpringMVC:

InternalResourceView views are created when the view name set in the controller method is prefixed with "forward:". Instead of being resolved by the view resolver configured in the SpringMVC configuration file, the prefix "forward:" is removed and the rest is forwarded as the final path to jump.

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

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

3. Redirected View

The default redirected view in SpringMVC is RedirectView

A RedirectView view is created when the view name set in the controller method is prefixed with "redirect:". The view name is not resolved by the view resolver configured in the SpringMVC configuration file, but the prefix "redirect:" is removed and the rest is redirected as the final path to jump.

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

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

Note:

The redirect view parses by removing the redirect: prefix and then deciding if the rest begins with/or splices the context path automatically if so

4. View controller view-controller

Processor methods can be represented using the view-controller tag when the controller method is used only for page jumps, that is, when only the view name needs to be set

<!--
	path: Set processing request address
	view-name: Set the view name for the request address
-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>

Note:

When any view-controller is set in SpringMVC, all request mappings from other controllers will fail, requiring the tag to turn on MVC annotation-driven in the core configuration file of SpringMVC: <mvc:annotation-driven />

7. RESTful

1. Introduction to RESTful

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

A>Resources

Resources are a way of looking at servers, that is, they are composed of many discrete resources. Each resource is a named abstraction on the server. Because resources are an abstract concept, they can not only represent a file in the server's file system, a table in the database, and so on. They can also represent how abstract a resource's design is, provided the imagination allows it and the client application developer understands it. Like object-oriented design, resources are organized around nouns, with nouns as the primary concern. A resource can be identified by one or more URIs. The URI is both the name of the resource and the address of the resource on the Web. Client applications interested in a resource can interact with it through its URI.

B>Description of the resource

A description of a resource is a description of its state at a particular time. You can transfer (exchange) between client and server. Resources can be represented in a variety of formats, such as HTML/XML/JSON/plain text/pictures/video/audio, and so on. The format of a resource's presentation can be determined through a negotiation mechanism. Request-response directions are usually expressed in different formats.

C>State Transition

State transitions refer to transfers between the client and server representing the state of a resource. Indirectly achieve the purpose of operating resources by transferring and manipulating the representation of resources.

2. Implementation of RESTful

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

They correspond to four basic operations: GET to get resources, POST to create new resources, PUT to update resources, and DELETE to delete resources.

The REST style advocates a uniform style design for URL addresses, using slashes to separate the words from front to back, and not using question mark key pairs to carry request parameters. Instead, the data sent to the server is used as part of the URL address to ensure overall style consistency.

operationTraditional wayREST Style
Query operationgetUserById?id=1user/1 ->get request mode
Save OperationsaveUseruser-post request method
Delete operationdeleteUser?id=1user/1 ->delete request mode
update operationupdateUseruser-put request method

3,HiddenHttpMethodFilter

Since browsers only support requests sent as get and post, how do I send put and delete requests?

SpringMVC provides HiddenHttpMethodFilter to help us convert POST requests to DELETE or PUT requests

The conditions under which HiddenHttpMethodFilter handles put and delete requests:

A>The current request must be requested in the form of post

B>Current request must transfer request parameter_ method

If the above condition is met, the HiddenHttpMethodFilter filter will convert the request mode of the current request to the request parameter_ Value of method, so request parameter_ The value of the method is the final request

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>

Note:

So far, two filters have been provided in Spring MVC: CharacterEncodingFilter and HiddenHttpMethodFilter

When registering in web.xml, you must register CharacterEncodingFilter before registering HiddenHttpMethodFilter

Reason:

  • Setting the character set in the CharacterEncoding Filter by the request.setCharacterEncoding(encoding) method

  • The request.setCharacterEncoding(encoding) method requires that there must be no preceding action to get the request parameters

  • HiddenHttpMethodFilter, on the other hand, has exactly one operation to get the request mode:

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

8. RESTful Cases

1. Preparations

As with traditional CRUD, it achieves the addition, deletion and alteration of employee information.

  • Set up environment

  • Prepare entity classes

    package com.ziop.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() {
       }
    }
    
  • Preparing dao simulation data

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

2. Functional List

functionURL AddressRequest Method
Visit Home Page/GET
Query all data/employeeGET
Delete/employee/2DELETE
Jump to Add Data Page_/toAddGET
Execute Save_/employeePOST
Jump to Update Data Page/employee/2GET
Perform Updates/employeePUT

3. Specific functions: Visit the home page

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

4. Specific functions: Query all employee data

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

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

5. Specific functions: Delete

A>Create a form to handle delete requests
<!-- Role: Controls the submission of forms through hyperlinks, which will post Request Conversion to delete request -->
<form id="delete_form" method="post">
    <!-- HiddenHttpMethodFilter Requirements: Must transfer_method Request parameter with value as final request mode -->
    <input type="hidden" name="_method" value="delete"/>
</form>
B>Remove hyperlink binding click events

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

Handle click events via vue

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

6. Specific functions: jump to add data page

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

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

</body>
</html>

7. Specific functions: perform save

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

8. Specific functions: jump to update data page

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

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

</body>
</html>

9. Specific Functions: Perform Updates

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

8. HttpMessageConverter

HttpMessageConverter, Message Information Converter, Converts a request message into a Java object or a Java object into a response message

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

ResponseEntity

1,@RequestBody

The @RequestBody can get the request body, which requires a parameter to be set in the controller method and identified with @RequestBody. The current request body assigns values to the parameters identified by the current comment.

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

Output results:

requestBody:username=admin&password=123456

2,RequestEntity

RequestEntity encapsulates a type of request message that needs to be set in the parameters of the controller method. The request message of the current request is assigned to this parameter. Request header information can be obtained through getHeaders(), and request body information can be obtained 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:80", 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:80", user-agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"]
requestBody:username=admin&password=123

3,@ResponseBody

@ResponseBody identifies a controller method that can respond directly to the browser as the response body of the response message

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

Result: Browser page shows success

4. SpringMVC Processing json

Steps for @ResponseBody to process json:

A>Importing jackson's dependencies

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

B>Turn on mvc's annotation driver in the core profile of Spring MVC, where a message converter is automatically assembled in the Handler Adaptor: MappingJackson2HttpMessageConverter, which converts Java objects responding to the browser into Json-formatted strings

<mvc:annotation-driven />

C>Identify processor methods using the @ResponseBody annotation

D>Returning a Java object directly as a return value from a controller method automatically converts it to a Json-formatted string

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

Results shown on the browser's page:

{id': 1001,'username':'admin','password':'123456','age': 23,'sex':'man'}

5. SpringMVC Processing ajax

A>Request hyperlinks:

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

B>Handle click events with vue and axios:

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

C>Controller method:

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

6. @RestController comment

The @RestController annotation is a composite annotation provided by springMVC that identifies on the controller's class as adding the @Controller annotation to the class and @ResponseBody annotation to each of its methods

7,ResponseEntity

ResponseEntity is used for the return value type of a controller method whose return value is the response message to the browser

9. File upload and download

1. File Download

Use ResponseEntity to download files

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

2. File upload

File upload requires the form form form to be requested in a post manner, and adds the attribute enctype="multipart/form-data"

The uploaded file is encapsulated in the MultipartFile object in SpringMVC, through which you can get information about the file

Upload steps:

A>Add dependencies:

<!-- 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 a configuration to the Spring MVC configuration file:

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

C>Controller method:

@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
    //Get the file name of the uploaded file
    String fileName = photo.getOriginalFilename();
    //Handle file renames
    String hzName = fileName.substring(fileName.lastIndexOf("."));
    fileName = UUID.randomUUID().toString() + hzName;
    //Get the path to the photo directory on the server
    ServletContext servletContext = session.getServletContext();
    String photoPath = servletContext.getRealPath("photo");
    File file = new File(photoPath);
    if(!file.exists()){
        file.mkdir();
    }
    String finalPath = photoPath + File.separator + fileName;
    //Implement Upload Function
    photo.transferTo(new File(finalPath));
    return "success";
}

10. Interceptors

1. Interceptor configuration

Interceptors in SpringMVC are used to intercept the execution of controller methods

Interceptors in SpringMVC need to implement HandlerInterceptor

Interceptors for SpringMVC must be configured in the SpringMVC configuration file:

<bean class="com.ziop.interceptor.FirstInterceptor"></bean>
<ref bean="firstInterceptor"></ref>
<!-- Both configurations are correct DispatcherServlet Intercept all requests processed -->
<mvc:interceptor>
    <mvc:mapping path="/**"/>
    <mvc:exclude-mapping path="/testRequestEntity"/>
    <ref bean="firstInterceptor"></ref>
</mvc:interceptor>
<!-- 
	The above configurations can be ref or bean Label set interceptor, via mvc:mapping Set requests that need to be intercepted by mvc:exclude-mapping Set requests that need to be excluded, that is, requests that do not need to be intercepted
-->

2. Three abstract methods of interceptor

Interceptors in SpringMVC have three abstract methods:

PreHandle: Executes preHandle() before the controller method executes. The return value of boolean type indicates whether to intercept or release. Return true is release, that is, calls the controller method. Returning false indicates interception, i.e. no controller method call

PostHandle: Execute postHandle() after the controller method executes

AfterComplation: After processing view and model data, after rendering the view, afterComplation()

3. Execution order of multiple interceptors

  • If each interceptor's preHandle() returns true

    • The order in which multiple interceptors are executed at this time is related to the order in which the interceptors are configured in the Spring MVC configuration file:
    • preHandle() executes in the order configured, while postHandle() and afterComplation() execute in the reverse order configured
  • If preHandle() of an interceptor returns false

    • PreHandle() returns false and preHandle() of the interceptor before it executes, postHandle() does not execute, afterComplation() of the interceptor before returning false executes
      • Explanation:
        1. When preHandler is executed, if an interceptor returns false, interceptorIndex is equal to the sum of the number of interceptors previously executed, and because it returns false, 149 lines of code in the following figure are called to execute the call attempting to intercept.
        2. Because view interceptors are invoked in reverse order and depend on interceptor index, only view interceptors in those entities passed by the previous Pre-interceptor will be executed

4. Interceptor Execution Process

A>Pre-interceptor

  • Method to invoke preinterceptor

  • Sequential execution of multiple pre-interceptors
    • Positive execution because it is i ++

B>Rear Interceptor

  • Method to invoke a rear interceptor

  • Sequential execution of multiple rear interceptors

    • Executing is i - - so it's a retrospective execution

C>View Interceptor

  • Method to invoke view interceptor
  • Execution of multiple view interceptors
    • Execute i - - procedure, so it's a retrospective execution

11. Exception Handler

1. Configuration-based exception handling

SpringMVC provides an interface to handle exceptions that occur during the execution of controller methods: HandlerExceptionResolver

The implementation classes of the HandlerExceptionResolver interface are DefaultHandlerExceptionResolver and SimpleMappingExceptionResolver

SpringMVC provides a custom exception handler, SimpleMappingExceptionResolver, which can be used in:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
        	<!--
        		properties The key of the processor represents an exception that occurs during the execution of the processor method
        		properties A value of
        	-->
            <prop key="java.lang.ArithmeticException">error</prop>
        </props>
    </property>
    <!--
    	exceptionAttribute Property sets a property name, and the exception information that appears is shared in the request domain
    -->
    <property name="exceptionAttribute" value="ex"></property>
</bean>

2. Annotation-based exception handling

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

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

}

12. Annotation Configuration SpringMVC

Replace web.xml and Spring MVC profiles with configuration classes and annotations

1. Create initialization classes instead of web.xml

In the Servlet3.0 environment, the container looks for classes in the class path that implement the javax.servlet.ServletContainerInitializer interface and, if found, configures the Servlet container.
Spring provides an implementation of this interface, called SpringServletContainerInitializer, which in turn looks for classes that implement WebApplicationInitializer and gives them the task of configuring it to complete. Spring 3.2 introduces a convenient basic implementation of WebApplicationInitializer called AbstractAnnotationConfigDispatcher ServletInitializer, which is automatically discovered and used to configure the Servlet context when our class extends AbstractAnnotationConfigDispatcher ServletInitializer and deploys it to the Servlet 3.0 container.

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {

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

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

    /**
     * Specify the mapping rule for Dispatcher Servlet, 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 instead of a spring configuration file

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

3. Create WebConfig configuration class instead of SpringMVC configuration file

@Configuration
//Scan Component
@ComponentScan("com.ziop.mvc.controller")
//Turn on MVC annotation driver
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

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

    //Profile Upload Parser
    @Bean
    public CommonsMultipartResolver multipartResolver(){
        return new CommonsMultipartResolver();
    }

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

    //Configure Generate Template Parser
    @Bean
    public ITemplateResolver templateResolver() {
        WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver requires a ServletContext as a construction parameter, which is available 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 it
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    //Generate View Parser does not inject parser into Template Engine
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }


}

4. Testing Functions

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

13. Spring MVC Execution Process

1. Common components of SpringMVC

  • Dispatcher Servlet: Front-end controller, not developed by engineers, provided by framework

Role: Unified processing of requests and responses, the center of overall process control, which calls other components to process user requests

  • HandlerMapping: Processor mapper, not developed by engineers, provided by framework

Role: Find the Handler, that is, the controller method, based on the requested url, method, and other information

  • Handler: Processor, engineer development required

Role: Handler handles specific user requests under the control of Dispatcher Servlet

  • HandlerAdapter: Processor adapter, not developed by engineer, provided by framework

Role: Processor (controller method) execution via HandlerAdapter

  • ViewResolver: View resolver, not developed by engineer, provided by framework

Role: Parse the view to get the appropriate view, such as ThymeleafView, Internal ResourceView, RedirectView

  • View: View

Role: Show model data to users through a page

2. Dispatcher Servlet initialization process

Dispatcher Servlet is essentially a Servlet, so it naturally follows the life cycle of a Servlet. So the macro is the Servlet lifecycle for scheduling.

A>Initialize WebApplicationContext

In the class: org.springframework.web.servlet.FrameworkServlet

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

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

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

    if (this.publishContext) {
        // Publish the context as a servlet context attribute.
        // Sharing IOC Containers in Application Domains
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}
B>Create a WebApplicationContext

In the 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 object by reflection
    ConfigurableWebApplicationContext wac =
        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

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

    return wac;
}
C>Dispatcher Servlet Initialization Policy

After the FrameworkServlet creates the WebApplicationContext, it refreshes the container and calls onRefresh(wac), which is overridden in the Dispatcher Servlet and invokes the initStrategies(context) method, which initializes the policy by initializing components of the Dispatcher Servlet

In the class: org.springframework.web.servlet.Dispatcher Servlet

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

3. Dispatcher Servlet Call Component Processing Request

a>processRequest()

FrameworkServlet overrides service() and doXxx() in HttpServlet, which calls processRequest(request, response)

In the class: org.springframework.web.servlet.FrameworkServlet

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

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

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

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

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

    initContextHolders(request, localeContext, requestAttributes);

    try {
		// Executing a service, doService() is an abstract method that is overridden in 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()

In the class: org.springframework.web.servlet.Dispatcher Servlet

@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()

In the class: org.springframework.web.servlet.Dispatcher Servlet

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
                Contains handler, interceptorList, interceptorIndex
            	handler: Controller method matching browser-sent request
            	interceptorList: Processing all interceptor collections for controller methods
            	interceptorIndex: Interceptor index to control 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 interceptor preHandle()
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Actually invoke the handler.
            // Specific controller methods are invoked by the processor adapter, resulting in a ModelAndView object
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            applyDefaultViewName(processedRequest, mv);
            // Call interceptor postHandle()
            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);
        }
        // Follow-up: Processing model data and rendering views
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}
d>processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {

    boolean errorView = false;

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

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

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

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

4. Execution process of SpringMVC

  1. The user sends a request to the server, which is captured by the SpringMVC front-end controller Dispatcher Servlet.

  2. Dispatcher Servlet parses the request URL, gets the request resource identifier (URI), and determines the mapping of the request URI:

a) does not exist

i. Determine if mvc:default-servlet-handler is configured

ii. If not configured, console report map lookup is not found, client shows 404 error

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-GMKkC2aa-1631444315465)(img/img006.png)]

iii.If configured, access the target resource (typically static resources, such as JS,CSS,HTML), and fail to find the client will also display 404 errors

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-iXF6BTdj-1631444315466)(img/img008.png)]

b) Execute the following process if it exists

  1. Based on this URI, call HandlerMapping to get all the related objects of the Handler configuration (including the Handler object and the corresponding interceptor for the Handler object), and finally return as the Handler ExecutionChain execution chain object.

  2. Dispatcher Servlet chooses an appropriate Handler Adapter based on the handler obtained.

  3. If the HandlerAdapter is successfully obtained, execution of the interceptor's preHandler(...) method will begin at this point [Forward]

  4. Extract the model data from Request, fill in the Handler input, start executing the Handler (Controller) method, and process the request. Spring will do some extra work for you during the fill Handler input process, depending on your configuration:

a) HttpMessageConveter: Converts the request message (such as Json, xml, etc.) into an object and the object into the specified response information

b) Data conversion: Data conversion of request messages. For example, String conversion to Integer, Double, etc.

c) Data formatting: Data formatting of the request message, such as converting a string to a formatted number or date, etc.

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

  1. When the Handler execution is complete, a ModelAndView object is returned to the Dispatcher Servlet.

  2. The interceptor's postHandle(...) method [Reverse] will now be executed.

  3. Based on the returned ModelAndView (which will determine if there are exceptions: if there are exceptions, execute HandlerExceptionResolver for exception handling), select an appropriate ViewResolver for view resolution and render the view according to Model and View.

  4. Rendering the view finishes executing the interceptor's afterCompletion(...) method [Reverse].

  5. Returns the rendering result to the client.

14. Summary of the Causes of Errors

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

  • 400:When passing parameters in a restful style, if the parameter type passed does not match the parameter type required by the server, a 400 error will pop out

    • Type Status Report

      Describes that the server cannot or will not process the current request because it is considered a client-to-client error (for example, malformed request syntax, invalid request information frames, or virtual request routing).

  • 404: If the current request does not match the value of any @RequestMapping comment, the page shows a 404 error, that is, the resource was not found

  • **404:**If the current request satisfies the value and method attributes of the @RequestMapping annotation, but does not satisfy the headers attribute, the page displays a 404 error where the resource was not found

  • **405:**Browser error 405:Request method'POST'not supported if the current request address satisfies the value attribute of the request mapping but the request method does not satisfy the method attribute

Posted by robert_gsfame on Fri, 19 Nov 2021 15:42:04 -0800