Shang Silicon Valley's most complete spring MVC notes

Java Web three-tier architecture: presentation layer, business layer, persistence layer uses HTTP protocol to complete the interaction between browser and server
Next step: consider the problem of function expansion, encapsulate the pattern and process, and improve the reuse rate of code

1, Introduction to spring MVC

1. What is MVC

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

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

JavaBean s fall into two categories:

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

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

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

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

2. What is spring MVC

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

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

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

Login success: redirection
Login failure: request forwarding

3. Characteristics of spring MVC

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

2, HelloWorld

1. Development environment

IDE: idea 2019.2

Build tool: maven 3.5.4

Server: tomcat7

Spring version: 5.3.1. It is not recommended to use the version before 5

2. Create maven project (introduce dependency)

maven has three packaging methods:
Default packaging method: jar
If you want to convert the current project to a web project: war package, and add a web module

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

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

   <!-- Tomcat Bring your own SetvletAPI and jsAPI jar package-->
    <!-- ServletAPI -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope> 
    </dependency>
  <!--scope Dependency range provide Description already provided,No need to package into the project Web-Info/lib in-->

    <!-- Spring5 and Thymeleaf Integration package -->
    <!-- Thymeleaf Control the content displayed on the page through view technology. If necessary, it will be displayed Thymeleaf analysis,th:-->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.12.RELEASE</version>
    </dependency>
</dependencies>

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

3. Configure web.xml (register front-end controller)

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

Why register? Because the browser cannot access a class, you need to set a matching path to access it

a> Default configuration method

Under this configuration, the configuration file of spring MVC is located under WEB-INF by default, and the default name is - servlet.xml. For example, the configuration file of spring MVC corresponding to the following configuration is located under WEB-INF, and the file name is springMVC-servlet.xml

<!-- to configure SpringMVC The front-end controller of the browser uniformly processes the requests sent by the browser -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>springMVC</servlet-name>
     <!--
            set up springMVC The request path of the request that can be processed by the core controller of
            Because it is to be handled uniformly——>Set to/    
            
        -->
    <url-pattern>/</url-pattern>
</servlet-mapping>
  • /The matching request can be a request path in the form of / login or. html or. js or. css, excluding. jsp
  • /*All, including. jsp

  • /A request that cannot match the. jsp request path
  • . jsp is essentially a Servlet, which needs to be processed by a specially specified Servlet in the server. It does not need the dispatcher Servlet, but only from the server
  • If the dispatcher servlet is used for processing, it will be treated as normal processing, and the corresponding jsp page cannot be found
Common b > extended configuration mode (common)

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

  • The Servlet is initialized on the first access
  • As the core component of the framework, DispatcherServlet has a large number of initialization operations to do during startup, and these operations are executed only when the first request is made, which will seriously affect the access speed. Therefore, it is necessary to raise the initialization time of the startup control DispatcherServlet to the server startup through the tag.
<!-- to configure SpringMVC The front-end controller of the browser uniformly processes the requests sent by the browser -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- Specified by initialization parameters SpringMVC Location and name of the configuration file -->
    <init-param>
        <!-- contextConfigLocation Is a fixed value -->
        <param-name>contextConfigLocation</param-name>
        <!-- use classpath:Represents the path from the class(.class)Find profile
        for example maven In Engineering src/main/resources and java-->
        <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>

*Differences between / and / used in labels:

  • /The matched request can be a request path in the form of / login or. html or. js or. css, but / cannot match the request path of. jsp
  • Therefore, it can be avoided that when accessing the jsp page, the request is processed by the dispatcher servlet, so that the corresponding page cannot be found
  • /*All requests can be matched. For example, when using a filter, if you need to filter all requests, you need to use the writing method of / *

4. Create request controller

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

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

Because the Controller of Spring MVC is a POJO (Plain Ordinary Java Object ordinary Java class) and does not need to be inherited, it needs to be identified as a control layer component through the @ Controller annotation. After scanning, this class can be used as a bean and managed by Spring's IoC container. At this time, Spring MVC can recognize the existence of the Controller

  1. @Component common component
  2. @Controller control layer component
  3. @Service business layer components
  4. @Repository persistence layer component
@Controller
public class HelloController {
    
}

5. Create a configuration file for spring MVC

<!-- Scanning components: automatic scanning of packages -->
<context:component-scan base-package="com.atguigu.mvc.controller"/>

<!-- to configure Thymeleaf view resolver  -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    <property name="order" value="1"/>
    <property name="characterEncoding" value="UTF-8"/>
    <property name="templateEngine">
        <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
            <property name="templateResolver">
                <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                    <!-- Thymeleaf When parsing, you must set the view prefix and view suffix
                      View name+The prefix and suffix can finally jump to the specified page-->
                    <!-- View prefix -->
                    <property name="prefix" value="/WEB-INF/templates/"/>
                    <!-- View suffix -->
                    <property name="suffix" value=".html"/>
                    <!-- Template model -->
                    <property name="templateMode" value="HTML5"/>
                    <!-- Code in page -->
                    <property name="characterEncoding" value="UTF-8" />
                    <!-- Whenever page Jump is realized,If the view name meets the criteria, it will be parsed by the current view parser
                     Find the page and realize page Jump-->
              </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>
  • Note that if the current page to be accessed is under WEB-INF, the browser cannot access it directly or redirect it. It can only be accessed through forwarding
  • If the page is placed directly under the Webapp, it cannot be accessed directly, because thymeleaf is currently used. Thymeleaf syntax is likely to exist in the page and needs to be parsed by thymeleaf. The view must be parsed through the currently configured view parser

6. Test HelloWorld

The web access context path can automatically access index.html/index.jsp
Currently, index.html is placed under WEB-INF and cannot be accessed,

a> Realize the access to the home page

Tomcat configuration

Try to start in debug mode

Create a method in the request controller to process the request

//Request path "/ - > access path" / WEB-INF/templates/index.html
//The method in the controller is the way to process the request
//There can be many methods in a controller (a class)
// You need to use @ RequestMapping to process the mapping relationship between the request (request address, request method, request parameters...) and the controller method
// @The value attribute of the RequestMapping annotation can match the request through the request address
//  /Context path of the current project - > localhost: 8080 / springmvc/
//When only value is assigned, value may not be written

public class HelloController {
    @RequestMapping(value="/")
    public String index(){
        //When the view name is returned, it will be parsed by the configured view parser (+ prefix + suffix), which is the final page to be accessed
        return "index";
    }
}

Log file:

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">
<head>
    <meta charset="UTF-8">
    <title>home page</title>
</head>
<body>
    <h1>home page</h1>
    <a th:href="@{/hello}">HelloWorld</a><br/>
   <!--Hypertext links, parsed by the browser-->
</body>
</html>
<a th:href="/target">Access target page</a><br/>

Is a hypertext link, which is parsed by the browser

  • The / slash is an absolute path in the web.
  1. /If the slash is parsed by the browser, the resulting address is: http://ip:port/
  1. /If the slash is parsed by the server, the resulting address is: http://ip:port/ Engineering path
    1. /servlet1
    2. servletContext.getRealPath("/");
    3. request.getRequestDispatcher("/");

Therefore, the resolution result of the browser is http://ip:port/target incorrect
The correct path should be http://ip:port/springMVC/target
Context path: it can be modified, so it is recommended not to write the context path when writing the jump path

So it is not recommended to write it

<a th:href="/springMVC/target">Access target page</a><br/>

Therefore, it is recommended to use the thymeleaf namespace in the html page and add:

<html lang="en" xmlns:th="http://www.thymeleaf.org">

You can use thymeleaf syntax
Before the attribute + th:, the attribute can be parsed by thymeleaf

<a th:href="@{/target}">HelloWorld</a><br/>

When an absolute path is detected, the context path is automatically added

Create a method in the request controller to process the request

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

7. Summary

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

3, @ RequestMapping annotation (request mapping)

public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

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. There are multiple controllers, and the request address matched by the method must be unique.

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

2. @ RequestMapping annotation location

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

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

You can add a layer of directory to the request directory to distinguish controllers and represent different modules at present

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

}
<a th:href="@{/test/testRequestMapping}">test@RequestMapping of value attribute-->/testRequestMapping</a><br>

3. value attribute (404)

@The value attribute of the RequestMapping annotation matches the request mapping through the request address of the request, and only one is satisfied

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

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

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

4. method attribute (405)

@The method attribute of the RequestMapping annotation matches the request mapping through the request method (get or post). If it is not set, any request method can be matched, and only one is satisfied

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

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

<a th:href="@{/test}">test@RequestMapping of value attribute-->/test</a><br>
<form th:action="@{/test}" method="post">
    <input type="submit">
</form>
@RequestMapping(
        value = {"/testRequestMapping", "/test"},//If only one address is satisfied, the request mapping can match the request
        method = {RequestMethod.GET, RequestMethod.POST}
)
public String testRequestMapping(){
    return "success";
}

Note:

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

Mapping for handling get requests – > @GetMapping

Mapping for handling post requests – > @PostMapping

Mapping for processing put requests – > @PutMapping

Mapping for handling delete requests – > @DeleteMapping

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

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

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

Difference between get and post:

  • get submits the request parameters, and the request parameters will be spliced after the address (? Key = value) (fast, limited data)
  • post will put the request parameters in the request body (safe and large amount of data)
  • Only post has a request body, and get has no request body
  • File upload can only use post < input type = "file" >

5. params attribute (400)

@The params attribute of the RequestMapping annotation matches the request mapping through the request parameters of the request, which must be met at the same time

@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

  1. "Param": the request matching the request mapping must carry param request parameters
  2. '! Param': the request matching the request mapping must not carry param request parameters
  3. "param=value": the request matching the request mapping must carry param request parameters and param=value
  4. "param!=value": the request matching the request mapping must carry param request parameters, but param!=value
<a th:href="@{/test(username='admin',password=123456)">
  <!--test@RequestMapping of params attribute-->/test</a><br>-->
@RequestMapping(
        value = {"/testRequestMapping", "/test"}
        ,method = {RequestMethod.GET, RequestMethod.POST}
        ,params = {"username","password=123456"}
    
)
public String testRequestMapping(){
    return "success";
}
@RequestMapping(
        value = {"/testRequestMapping", "/test"}
        ,method = {RequestMethod.GET, RequestMethod.POST}
        ,params = {"!username","password!=123456"}
         //There must be no username parameter
)
public String testRequestMapping(){
    return "success";
}

Note:

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

6. headers attribute (404)

@The headers attribute of the RequestMapping annotation matches the request mapping through the request header information of the request, which must be met at the same time

@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

  1. "Header": the request matching the request mapping must carry the header request header information
  2. '! Header': the request matched by the request mapping must not carry header request header information
  3. "header=value": the request matching the request mapping must carry header request header information and header=value
  4. "header!=value": the request matching the request mapping must carry header request header information and header!=value

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

7. Spring MVC supports ant style paths

  1. ?: represents an arbitrary single character and cannot match an empty character
  2. *****: represents any 0 or more characters
  3. ******: indicates any 0-tier or multi-tier directory, which can match an empty directory

be careful:

  • Replace? * with / and?
  • When using, you can only use / / xxx

8. Placeholder in spring MVC support path (emphasis)

REST: Representational State Transfer
The same access address, request path and different request methods - > correspond to different functions

The request address represents the current resource to be operated, and the request mode represents the current mode of operating the resource
All parameters to be transmitted are transmitted by path

  • Original method: / deleteUser?id=1
  • rest mode: / deleteUser/1

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

<a th:href="@{/testRest/1/admin}">Placeholder in test path-->/testRest</a><br>
@RequestMapping("/testRest/{id}/{username}")//{id} is a placeholder
//The annotation is written in the parameter position to modify the formal parameter. The value of placeholder {id} can be automatically assigned to the formal parameter
public String testRest(@PathVariable("id") String id, @PathVariable("username") String username){
    System.out.println("id:"+id+",username:"+username);
    return "success";
}
//The final output is -- > ID: 1, username: admin

4, Spring MVC get request parameters

1. Obtained through Servlet API (Servlet native interface, rarely used)

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

request.getParameter("");
request.getParameterValues("");//Get string array
<a th:href="@{/testParam(username='admin',password=123456)}">Test get request parameters-->/testParam</a><br>
@RequestMapping("/testParam")
//Different values are injected according to the formal parameters of the controller method. The formal parameter request 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";
}

Note: if the browser's request address adopts placeholder mode and only has value, request and getparameter cannot be used

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

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

<a th:href="@{/testParam(username='admin',password=123456)}">Test get request parameters-->/testParam</a><br>
@RequestMapping("/testParam")
public String testParam(String username, String password,String []hobbies){
    System.out.println("username:"+username+",password:"+password);
  
    for(int i=0;i<hobbies.length();i++){
        System.out.println(hobbies[i]);
    }
    return "success";
}
  • String hobbies returns a string that is spliced together
  • String []hobbies loop or Arrays.toString(hobbies) [a,b,c]

be careful:

  • The parameter name of the formal parameter must be consistent with the parameter name of the request parameter. If it is inconsistent, it cannot be obtained
  • If there are multiple request parameters with the same name in the request parameters transmitted by the request, you can set string array or string type formal parameters in the formal parameters of the controller method to receive the request parameters
  • If you use a formal parameter of string array type, the array of this parameter contains each data
  • If a string type parameter is used, the value of this parameter is the result of concatenation of commas in the middle of each data

3,@RequestParam

In order to prevent mismatch caused by the change of request parameters / controller method formal parameters, annotations are used for mapping
@RequestParam is to create a mapping relationship between the request parameters and the formal parameters of the controller method

@RequestMapping("/testParam")
public String testParam(
    @RequestPararm("username")String username, 
    String password,
    String []hobbies){
    System.out.println("username:"+username+",password:"+password);
  
    for(int i=0;i<hobbies.length();i++){
        System.out.println(hobbies[i]);
    }
    return "success";
}

@The RequestParam annotation has three attributes:

public @interface RequestParam {
    @AliasFor("name")//@AliasFor is an alias
    String value() default "";

    @AliasFor("value")
    String name() default "";

    boolean required() default true;

    String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
  1. value:

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

  1. Required: / / is required
  • **xml based auto assembly: * * the default value of xml auto assembly is null
  • **Annotation based automatic assembly: * * it must be assembled automatically. If the assembly fails, no bean in the IOC can automatically assign a value to this attribute, and an error is reported (400)

Set 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

  1. defaultValue:

Regardless of whether the required attribute value is true or false, when the request parameter specified by value is not transmitted or the transmitted value is' ', the default value is used to assign value to the formal parameter

4,@RequestHeader

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

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

5,@CookieValue

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

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

  • When the user requests a servlet, the servlet will first check whether there is a sessionID in the client cookie. If so, it will prove that it is an old session. Then it will send the sessionID to the server through the cookie, and the server will find the session object in the memory of the server according to the sessionID (because each session will have a sessionID to identify the session object), Find it and use it.
  • If there is no sessionid in the cookie, this proves to be a new session. The server will create a new session object, store the sessionid in the cookie, and send the sessionid to the client through the cookie. The next time the client accesses, it will send the sessionid to the server to find the session object again and complete session tracking. Therefore, if the user closes the cookie, the session will also become invalid. Session is dependent on cookies.
  • The difference and connection with cookies: cookies save the user's information on the client, while session s save the customer's information on the server
  • Session depends on cookies. If the user closes the cookie, the session becomes invalid because the sessionID cannot be passed from the client to the server or from the server to the client
  • Session technology life cycle: browser on to browser off

6. Get request parameters through POJO

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

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

7. Solve the garbled problem of obtaining request parameters

To solve the garbled problem of obtaining request parameters, you can use the encoding filter characterencoding filter provided by spring MVC, but it must be registered in web.xml
be careful:

  • The garbled code of get request is caused by Tomcat - > modifying Tomcat configuration file conf - > server.xml can be solved at one time

  • request.setEncoding refers to the garbled code of the post request. The encoding method must be set before obtaining the request parameters
  • The dispatcher servlet obtains the request parameters first, so it is useless to set the encoding method later
  • Therefore, it is necessary to find the component that starts earlier than the Servlet, listener - > filter - > 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><!--Set request code-->
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceResponseEncoding</param-name><!--Set response code-->
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
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

Processing request:

  1. Set encoding
  2. Get request parameters (IV)
  3. Take the request parameter as a condition and call the service to process the business logic (the service calls the DAO to access the database, returns the result to the service, and then returns the service to the control layer)
  4. If the data is to be sent in the page, share the data in the domain object

Domain object:

  1. ServletContext (the entire application range, from server on to server off, represents the context object, which is created only once)
  2. Session (one session, browser open to close, not related to the server, related to whether the browser is closed, 30min, passivation and activation)

Passivation: when the server is closed but the browser is not closed, the Session continues, and the data in the Session will be serialized to the disk
**Activation: * * if the browser is still not closed but the server is restarted, the contents of the passivated file will be read into the Session

  1. Request (one request)
  2. PageContext(jsp page)

Principle of selecting domain objects - > domain objects with the smallest range of functions

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

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p th:text="${testRequestScope}"></p>
</body>
</html>
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
    request.setAttribute("testScope", "hello,servletAPI");
    return "success";
}

2. Spring MVC shares data with the request domain object

2.1. Use ModelAndView (recommended)

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

2.2. Using Model

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

2.3. Use map

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

2.4. Using ModelMap

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

3. Relationship between Model, ModelMap and Map

toString:

{testScope=hello,Model}
{testScope=hello,Map}
{testScope=hello,ModelMap}

Use reflection xxx.getClass().getName();
It is found that these three classes are instantiated through the same class

The parameters of Model, ModelMap and Map types are essentially instantiated by BindingAwareModelMap type

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

toString:
{testScope=hello,Model}
{testScope=hello,Map}
{testScope=hello,ModelMap}

No matter what method is used, the data should eventually be encapsulated in ModelAndView

4. Share data to the session domain

The Servlet native API is recommended

@RequestMapping("/testSession")
public String testSession(HttpSession session){
    session.setAttribute("testSessionScope", "hello,session");
    return "success";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p th:text="${session.testRequestScope}"></p>
</body>
</html>

5. Share data with the application domain (ServletContext)

@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
	ServletContext application = session.getServletContext();
    application.setAttribute("testApplicationScope", "hello,application");
    return "success";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p th:text="${application.testRequestScope}"></p>
</body>
</html>

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
  • Video p44, the source code is not understood here. If you have the opportunity to continue, orz fool biscuits will finally interrupt




return the name of the View completely determines the type of the View (you can see the corresponding type of the View by viewing the View details)

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 SpringResourceResolver configured in the spring MVC configuration file. The final path obtained by splicing the view prefix and view suffix will jump through forwarding

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

2. Forwarding view

The default forwarding view in spring MVC is internal resource view. If Thymeleaf is not configured, this view is used by default

Create forwarding view in spring MVC:

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

For example, "forward: /", "forward"** 😗*/ employee”
themeleaf itself is accessed through forwarding, so it is basically unnecessary

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

3. Redirect view

The default redirection view in spring MVC is RedirectView

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

For example, "redirect: /", "redirect"** 😗*/ employee”

@RequestMapping("/testRedirect")
public String testRedirect(){
    return "redirect:/testHello";
}
  • Redirection cannot access the content under WEB-INF, so if you want to access it, you must forward it to the request, not a specific page

Note:

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

Difference between forwarding and redirection:
forward:

  1. The browser address bar has not changed
  2. The browser sends a request
  3. They share data in the request field
  4. It can be forwarded to the WEB-INF directory, and the browser cannot access / WEB-INF/form.html
  5. You cannot access resources outside the project
    eg. you can't jump to Baidu

Redirect:

  1. The browser address bar changes
  2. The browser sends the request twice
  3. Do not share data in the Request field. Two requests obtain different Request objects
  4. The resources under WEB-INF cannot be accessed, and the WEB-INF browser cannot access them directly
  5. You can access resources outside the project

4. View controller

When there is no processing of other request processes in the controller method, which is only used to realize page Jump, that is, only the view name needs to be set, the processor method can be represented by the view controller tag

 @RequestMapping("/testView")
public String index(){
        //When the view name is returned, it will be parsed by the configured view parser (+ prefix + suffix), which is the final page to be accessed
        return "success";
 }
stay springMVC.xml Add to profile
<!--
	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 />

p47 7:40 other functions

Before the appearance of themeleaf viewresolver, if the view used jsp, how did spring MVC parse the jsp view?
If you do not add / use forward:, use internalresourceviewresolver

<!-- to configure InternalResoureView view resolver  -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/templates/"></property>
        <property name="suffix" value=".jsp"/>
    </bean>

jsp can be accessed directly outside the WEB-INF, so there is no need to set the request mapping for accessing the home page,
Tomcat accesses index.jsp by default. It is available in Tomcat's web.xml. It is effective for all projects deployed to Tomcat
The web.xml of the current project is only valid for the current project

<welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
 @RequestMapping("/success")
public String index(){
        //When the view name is returned, it will be parsed by the configured view parser (+ prefix + suffix), which is the final page to be accessed
        return "success";
 }
<%--jsp Command to set some information in the current page--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--EL Expression, accessed through methods that access properties--%>
  <a href="${pageContext.request.contextPath}/success">success.jsp</a>
</body>
</html>

forward:redirect: it is generally used when the prefix and suffix do not match

7, RESTful

1. Introduction to RESTful

Is a style of software architecture
REST: Representational State Transfer, presentation layer (front-end view page + back-end control layer) resource (the project is deployed to the server, the contents in the project are called resources, and the resource state is different from the representation of resources) state transfer (send the resources on the server to the client).

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

The same request address (the current resource to be operated) and different request methods (the current resource operation method)

3, 8. Spring MVC supports placeholders in the path: instead of passing parameters with question marks, they are spliced in the request address with slashes

2. RESTful implementation

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

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

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

operationTraditional wayREST style
Query operationgetUserById?id=1user/1 – > get request method
Save operationsaveUseruser – > post request mode
Delete operationdeleteUser?id=1user/1 – > delete request method
update operationupdateUseruser – > put request mode
@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";
}


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <a th:href="@{/user}">Query all user information</a>
  <a th:href="@{/user/1}">according to id Query user information</a>
 
</body>
</html>

3,HiddenHttpMethodFilter

Since the browser only supports sending requests in the get and post modes (not the get method by default), how do you send put and delete requests?

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

HiddenHttpMethodFilter conditions for processing put and delete requests:

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

b> The current request must transmit the request parameters_ method

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

Register HiddenHttpMethodFilter in web.xml
When there are multiple filters, the filter execution order is determined by the filter mapping order. The coding filter should be written to the front. You can't get any request parameters before setting the coding. As long as you get it, setting the coding will have no effect

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

Filter is divided into three processes: creating doFilter and destroying. Filter chain performs filtering

@RequestMapping(value="/user",method=RequestMethod.PUT)
public String UpdateUser(){
    System.out.println("Modify user information");
    return "success";
}
@RequestMapping(value="/user",method=RequestMethod.DELETE)
public String DeleteUser(){
    System.out.println("Delete user information");
    return "success";
}


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <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>
  <!--
1.Request method must be post
2.Parameters must be transferred_method"
-->
  <a th:href="@{/user}" method="post">Delete user information</a>
  <input type="hidden" name="_method" value="DELETE"><br>
  
 <!--  
How do you control hyperlinks when deleting them form Form?
Hyperlink through vue Bind a click event, first block the default jump of the hyperlink, and obtain a current form,
adopt submit Let the form submit and then cancel the default behavior of hyperlinks
-->
</body>
</html>

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 the characterencoding filter, use the request.setCharacterEncoding(encoding) method to set the value of the character set
  • The request.setCharacterEncoding(encoding) method requires that there must be no previous operation to obtain the request parameters
  • HiddenHttpMethodFilter has exactly one operation to obtain the request method:
String paramValue = request.getParameter(this.methodParam);

8, RESTful case

1. Preparatory work

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

  • Build environment
  • Prepare entity class
package com.atguigu.mvc.bean;

public class Employee {

   private Integer id;
   private String lastName;

   private String email;
   //1 male, 0 female
   private Integer gender;
   
   public Integer getId() {
      return id;
   }

   public void setId(Integer id) {
      this.id = id;
   }

   public String getLastName() {
      return lastName;
   }

   public void setLastName(String lastName) {
      this.lastName = lastName;
   }

   public String getEmail() {
      return email;
   }

   public void setEmail(String email) {
      this.email = email;
   }

   public Integer getGender() {
      return gender;
   }

   public void setGender(Integer gender) {
      this.gender = gender;
   }

   public Employee(Integer id, String lastName, String email, Integer gender) {
      super();
      this.id = id;
      this.lastName = lastName;
      this.email = email;
      this.gender = gender;
   }

   public Employee() {
   }
}
  • Prepare dao simulation data persistence layer
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;
   //Add and modify
   public void save(Employee employee){
      if(employee.getId() == null){
         employee.setId(initId++);
      }
      employees.put(employee.getId(), employee);
   }
   
   public Collection<Employee> getAll(){
      return employees.values();
   }
   
   public Employee get(Integer id){
      return employees.get(id);
   }
   
   public void delete(Integer id){
      employees.remove(id);
   }
}

2. Function list

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

3. Specific functions: visit the home page

Spring MVC adds a scan of the persistence layer

<!--      <!-- The scan component scans the packages of the control layer and the persistence layer,It is managed as a component-->
       <context:component-scan base-package="com.test.mvc.controller,com.test.mvc.controller.dao"/>
       <!--Or-->
       <context:component-scan base-package="com.test.mvc"/>
a> Configure the view controller and set the main page
<!--Configure view controller-->
<mvc:view-controller path="/" view-name="index"/>
<!--open mvc Annotation driven-->
<mvc:annotation-driven/>
b> Create page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" >
    <title>Title</title>
</head>
<body>
<h1>home page</h1>
<a th:href="@{/employee}">Access employee information</a>
</body>
</html>

4. Specific function: query all employee data

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

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

5. Specific function: delete

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

Introduce vue.js

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

Delete hyperlink

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

Handling click events through vue

<script type="text/javascript">
    var vue = new Vue({
        el:"#dataTable",
        methods:{
            //Event indicates the current event
            deleteEmployee:function (event) {
                     // Get form elements by id
                     var deleteForm=document.getElementById("deleteForm");
                     //The form is submitted to the hyperlink that triggers the event. If it is not set, the form will only be submitted to the current page
                     // Event represents the currently triggered event, and target only the elements triggered by the current event, that is, the hyperlink href represents the href attribute of the element of the current event
                     //Assign the href attribute of the hyperlink that triggers the click event to the action of the form
                     deleteForm.action=event.target.href;
                     //Submit Form 
                     deleteForm.submit();
                     //The default behavior of canceling the hyperlink is to click to bind the form, jump from the page to the submission event of completing the form, and send the / employee/id request
                     //At the same time, there is a href request address in the form
                     event.preventDefault();
                  }
        }
    });
</script>
c> Controller method
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE)
public String deleteEmployee(@PathVariable("id") Integer id){
    employeeDao.delete(id);
    return "redirect:/employee";
}

6. Specific function: jump to the add data page

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

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

</body>
</html>

7. Specific function: execute save

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

8. Specific function: jump to the update data page

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

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

</body>
</html>

9. Specific function: execute update

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


405 appears because vue.js cannot be found

It also reports an error that no static resource is found. At this time, the request path is processed by the front-end controller, but the static resource cannot be processed by spring MVC, but should be processed by the default Servlet - defaultServlet

Add in springMVC.xml

<!--    Open access to static resources-->
<!--    First cause springMVC If the corresponding request mapping cannot be found, the default is used defaultServlet handle-->
<!--    If the default Servlet If it cannot be handled, it will be reported to 404-->
    <mvc:default-servlet-handler/>

The selection of web.xml in the project and web.xml in Tomcat shall be based on the principle of proximity. In case of conflict, the one in the current project shall prevail

8, HttpMessageConverter

  • HttpMessageConverter
  • The browser sends a request to the server: convert the request message into a Java object
  • The server sends a response to the browser: convert the Java object into a response message

HttpMessageConverter provides two annotations and two types:

  1. **@RequestBody * * converts the request body in the request message into a Java object
  2. **@ResponseBody * * converts a Java object to a response body
  3. **RequestEntity * * request entity - can be used to receive the entire request message (either the request header or the request body can be accepted)
  4. **ResponseEntity * * response entity

The two responses are commonly used. Before using Response.getWriter.write(), the contents can be sent to the browser as a response body
This method is very convenient to convert Java data into response body. As long as * * @ ResponseBody is used to identify the controller method, the return value of the song method is the response body of the response message
Request message is divided into request header, blank line and request body * * (only POST request has request body)

1,@RequestBody (identify formal parameters and obtain the request body)

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

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

Output results:

requestBody:username=admin&password=123456

2. RequestEntity (type of controller parameter)

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 (method of identifying controller)

@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")
public String testResponseBody(HttpServlet response)throws IOException{
    response.getWriter().write("hello");//The printed content is directly returned to the browser as the response body of the response message
    return "success";
}



@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
    return "success";//Instead of the view name, the body of the current response is returned
}

Result: the browser page displays success

4. Spring MVC handles json (json is a data interaction format in Javascript, and so is xml)

HTTP specifies the method of transmitting information between the browser and the server, but the format of the information is not specified
The browser cannot directly receive Java objects, but can only accept strings. You can use json as a data exchange format, and you need to convert the current Java object into json
json data format is simple, parsing is simple, and the amount of generated data is small. xml is mainly used as a configuration file
Microservice: json+HTTP @ ResponseBody should be added to each controller
@The steps of ResponseBody processing json, that is, the Java object returned by the current controller is transformed into json conversion process:
a> Import json dependencies
pom.xml

<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 (1. View control 2. Static resources 3. Convert the Java object returned by the current controller into JSON). At this time, a message converter, MappingJackson2HttpMessageConverter, will be automatically assembled in the HandlerAdaptor to convert the Java object responding to the browser into a string in JSON format

<mvc:annotation-driven />

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

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

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

json has two formats: 1. Object {} (key value pair) 2. Array []
Entity class object and map into json are json objects
list to json array

5. Spring MVC handles ajax

ajax sends requests in different ways. The page does not jump, interacts with the server, cannot forward and redirect, and can only respond to browser data
a> Request hyperlink:
Binding ajax through hyperlinks cancels the default behavior of hyperlinks

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

b> Handle click events through vue and axios:

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

c> Controller method:

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

6. @ RestController annotation

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

7. ResponseEntity (response entity, customized response message)

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

9, File upload and download

static store picture files and pack them
The actual server deployment path is springMVC-demo1-1.0-SNAPSHOT above


The previous web phase was placed under the output path out

1. File download

Use ResponseEntity to download files
When downloading from the server to the client, you can only change the default file and file name

@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
    //Get ServletContext object
    ServletContext servletContext = session.getServletContext();
    //Get the real path of the file corresponding to the string in the server (the path where the project is deployed to the Tomcat server)
    String realPath = servletContext.getRealPath("/static/img/1.jpg");
    //Create an input stream and copy files through the IO stream
    InputStream is = new FileInputStream(realPath);
    //Create a byte array. is.available() is the number of bytes in the current input stream file
    byte[] bytes = new byte[is.available()];
    //Read stream into byte array
    is.read(bytes);
    //Create HttpHeaders object, set response header information, MultiValueMap interface extendsMap, and implement class HttpHeaders
    MultiValueMap<String, String> headers = new HttpHeaders();
    //Set the download method and the name of the file to be downloaded. Attachment is downloaded as an attachment
    headers.add("Content-Disposition", "attachment;filename=1.jpg");
    //Set response status code
    HttpStatus statusCode = HttpStatus.OK;
    //Create a ResponseEntity object. bytes is the response body, headers is the response header, statusCode is the response status code
    ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
    //Close input stream
    is.close();
    return responseEntity;//As the return value of the controller method, it represents the response message currently responding to the browser
}

2. File upload

File upload requirements:

  1. The request method of the form must be post,
  2. And add the attribute enctype = "multipart / form data" (not uploaded to the server in the form of name=vlaue, but uploaded to the server in binary mode)

Finally, upload to the corresponding location of the target

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

Upload steps:

a> Add dependency: cannot be less

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

<!--Encapsulate uploaded files into MultipartFile,The file must be parsed by the file parser to convert the file to MultipartFile object-->
<!--from springMVC of IOC The container is accessed automatically to realize a conversion process-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

How to get bean s:

  1. Get by id (spring MVC)
  2. Get by type

c> Controller method:

@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
    //The uploaded file cannot be directly converted to MultipartFile
    //getOriginalFilename(); get the file name of the uploaded file "1.jpg"“
    //getName();"photo" gets the name attribute value of the form element
    String fileName = photo.getOriginalFilename();
    //Handle the problem of duplicate file names, which will overwrite the contents of the file rather than the file
    String hzName = fileName.substring(fileName.lastIndexOf("."));
    fileName = UUID.randomUUID().toString().replaceAll("-","") + hzName;
    //Gets the path to the photo directory in the server
    ServletContext servletContext = session.getServletContext();
    String photoPath = servletContext.getRealPath("photo");
    //Path does not exist, created automatically
    File file = new File(photoPath);
    if(!file.exists()){
        file.mkdir();
    }
    String finalPath = photoPath + File.separator + fileName;
    //Realize the upload function
    photo.transferTo(new File(finalPath));
    return "success";
}
<a th:href="@{/testDown}">Download 1.jpg</a>
<form th:action="@{/testUp}" method="post" enctype="multipart/form-data">
<!--    Select a file-->
    head portrait:<input type="file" name="photo"><br>
    <input type="submit" value="upload">
</form>

10, Interceptor

1. Interceptor configuration

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

Interceptors in spring MVC need to implement the HandlerInterceptor interface

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

<bean class="com.atguigu.interceptor.FirstInterceptor"></bean>

<ref bean="firstInterceptor"></ref>
<!-- Configure the scanning component range to scan this class, and use this class as@Component identification -->


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

2. Three abstract methods of interceptor

Interceptors in spring MVC have three abstract methods:

  1. 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
  2. postHandle: execute postHandle() after the controller method is executed
  3. After compilation: after processing the view and model data, execute after compilation () after rendering the view



DispatcherServlet

DispatcherServlet->rocessDispatchResult

3. Execution sequence of multiple interceptors

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

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

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

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

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

package com.test.mvc.controller.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

11, Exception handler

1. Configuration based exception handling

Spring MVC provides an interface to handle exceptions during the execution of controller methods: HandlerExceptionResolver
Return a new ModelAndView and jump to the specified page

The implementation classes of HandlerExceptionResolver interface are:

  1. DefaultHandlerExceptionResolver
  2. SimpleMappingExceptionResolver

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

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
        	<!--
            properties Key value pair
        		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 error
        	-->
            <prop key="java.lang.ArithmeticException">error</prop>
        </props>
    </property>
    <!--
    	exceptionAttribute Property to set a property name and share the exception information in the request domain
    -->
    <property name="exceptionAttribute" value="ex"></property>
</bean>

2. Annotation based exception handling

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

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

}

12, Annotation configuration spring MVC

Use configuration classes and annotations instead of 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.

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

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

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

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

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

  1. Scan component
  2. view resolver
  3. view-controller
  4. Default servlet header static resource processing
  5. MVC annotation driven
  6. File upload parser
  7. Exception handling bean/configureHandlerExceptionResolvers
  8. ]
  9. Interceptor
@Configuration//Identifies the current class as a configuration class

@ComponentScan("com.atguigu.mvc.controller")//Scan component

@EnableWebMvc//Enable MVC annotation driver
//Web project initialization class, which is used to replace web.xml
public class WebConfig implements WebMvcConfigurer {

    //Use the default servlet to process static resources 4. Default servlet header static resource processing
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    //6. Configuration file upload parser
    @Bean
    public CommonsMultipartResolver multipartResolver(){
        return new CommonsMultipartResolver();
    }

    //8. Configure 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);
    }*/
    //Bean s are created from the inside out
    //1. Configure the generated template parser
    @Bean
    public ITemplateResolver templateResolver() {
        //Implementation of IOC container in spring
        //1. Application -- java project
        //2. Webapplication - Web Engineering
        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;
    }

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

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


}

4. Test function

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

13, Spring MVC execution process

1. Spring MVC common components

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

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

  • HandlerMapping: the processor mapper @ RequestMapping, which does not need to be developed by engineers, is provided by the framework

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

  • Handler: processor, i.e. controller @ Control, needs to be developed by engineers

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

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

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

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

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

  • View: View

Function: display model data to users through pages

2. Dispatcher servlet initialization process

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

a> Initialize WebApplicationContext

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.
        // Share IOC container in application domain
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    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 parent container
    wac.setParent(parent);
    String configLocation = getContextConfigLocation();
    if (configLocation != null) {
        wac.setConfigLocation(configLocation);
    }
    configureAndRefreshWebApplicationContext(wac);

    return wac;
}
c> Dispatcher servlet initialization policy

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

Class: org.springframework.web.servlet.DispatcherServlet

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

3. DispatcherServlet calls the component to process the request

a>processRequest()

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

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 {
		// 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) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

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

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

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

4. Execution process of spring MVC

  1. The user sends a request to the server, which is captured by the DispatcherServlet, the spring MVC front-end controller.
  2. DispatcherServlet parses the request URL, obtains the request resource identifier (URI), and judges the mapping corresponding to the request URI:

a) Does not exist

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

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

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

b) If it exists, execute the following process

  1. According to the URI, call HandlerMapping to obtain all relevant objects configured by the Handler (including the Handler object and the interceptor corresponding to the Handler object), and finally return in the form of HandlerExecutionChain object.
  2. DispatcherServlet selects an appropriate HandlerAdapter according to the obtained Handler.
  3. If the HandlerAdapter is successfully obtained, the pre handler (...) method [forward] of the interceptor will be executed
  4. Extract the model data in the Request, fill in the Handler input 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

  1. After the Handler is executed, a ModelAndView object is returned to the dispatcher servlet.
  2. At this time, the postHandle(...) method of the interceptor [reverse] will be executed.
  3. According to the returned ModelAndView (whether there is an exception will be judged at this time: if there is an exception, execute HandlerExceptionResolver for exception handling), select a suitable ViewResolver for View resolution, and render the View according to the Model and View.
  4. After rendering the view, execute the after completion (...) method of the interceptor [reverse].
  5. Returns the rendering results to the client.

Tags: JavaEE Framework

Posted on Wed, 01 Dec 2021 01:21:57 -0500 by statrat