Spring MVC learning notes

preface

Recently, I learned spring MVC from shangsilicon Valley at station B. I felt that it was very good and easy to understand, so I partially modified and added the notes provided by the teacher according to my own understanding for future review

1, Introduction to spring MVC

Framework = configuration file + jar package

1. What is MVC

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

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

JavaBean s fall into two categories:

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

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

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

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

2. What is spring MVC

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

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

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

3. Characteristics of spring MVC

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

2, HelloWorld

1. Development environment

IDE: idea 2019.2

Build tool: Maven 3 five point four

Server: tomcat7

Spring version: 5.3.1

2. Create maven project

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

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

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

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

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

3. Configure web xml

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

a> Default configuration method

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

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

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

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

Note:

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

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

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

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

4. Create request controller

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

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

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

@Controller
public class HelloController {
    
}

5. Create a configuration file for spring MVC

<!-- Auto scan package -->
<context:component-scan base-package="controller"></context:component-scan>

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

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

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

6. Test HelloWorld

a> Realize the access to the home page

Create a method in the request controller to process the request

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

On the homepage index Set hyperlink in HTML

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

Create a method in the request controller to process the request

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

7. Summary

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

3, @ RequestMapping annotation

Difference between 0, get and post

get: whenever the request parameters are submitted, the request parameters will be spliced and displayed directly on the request address (spliced with a question mark); No requestor; Limited data transmission

post: put the request parameters in the request body; Safe but slower than get; The amount of data transmitted is large, which can be regarded as infinite

1. Function of @ RequestMapping annotation

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

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

2. @ RequestMapping annotation location

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

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

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

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

}

3. value attribute of @ RequestMapping annotation

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

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

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

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

4. method attribute of @ RequestMapping annotation

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

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

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

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

Note:

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

Mapping for processing get requests – > @ getmapping

Mapping for handling post requests – > @ postmapping

Mapping for processing put requests – > @ putmapping

Mapping for handling delete requests – > @ deletemapping

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

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

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

5. params attribute of @ RequestMapping annotation (understand)

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

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

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

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

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

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

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

Note:

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

6. headers attribute of @ RequestMapping annotation (understand)

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

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

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

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

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

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

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

7. Spring MVC supports ant style paths

?: Represents any single character

*: represents any 0 or more characters

**: indicates any one or more levels of directories

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

8. Placeholder in spring MVC support path (emphasis)

Original method: / deleteUser?id=1

rest mode: / deleteUser/1

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

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

4, Spring MVC get request parameters

1. Get through servlet API

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

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

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

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

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

Note:

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

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

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

3,@RequestParam

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

@The RequestParam annotation has three attributes:

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

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

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

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

4,@RequestHeader

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

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

5,@CookieValue

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

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

6. Get request parameters through POJO

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

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

7. Solve the problem of garbled code in obtaining request parameters - configure coding filter

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

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

Note:

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

5, Domain objects share data

In the view layer, the request parameters are sent to the control layer. The control layer takes the request parameters as conditions to call the model layer service to process business logic. The service calls dao to access the database. After obtaining the results (data), the results are returned to the service, and the service is returned to the control layer

In this process, if data needs to be sent to the page, it needs to be shared in the domain object

0. Classification of domain objects

Request: one request

Session: a session, that is, the process from browser opening to browser closing (only related to browser opening and closing, not related to server opening and closing)

Passivation and activation of session

Passivation: when the server shuts down normally, the surviving sessions (not destroyed within the set time) will be stored in the work directory of tomcat in the form of a file ("SESSIONS.ser") with the server shutting down. This process is called Session passivation.

That is, the server (normally) is closed, the browser is not closed, the current session is still continuing, and the data stored in the session will be serialized and stored on the disk

Activation: when the server is turned on normally again (the browser is not closed), the server will find the previous "SESSIONS.ser" file and recover the previously saved Session object from it. This process is called Session activation.

Application (ServletContext): the scope of the whole application, from server on to server off (independent of browser on and off)

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

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

2. Use ModelAndView to share data with request domain objects (important)

Note: in themeleaf, @ {} is used for url address

${} for text data

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

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

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

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

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

5. Use ModelMap to share data with request domain objects

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

6. Relationship between Model, ModelMap and Map

The parameters of Model, ModelMap and Map are essentially BindingAwareModelMap

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

7. Share data to the session domain

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

8. Share data with the application domain

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

6, View of spring MVC

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

There are many kinds of spring MVC views. By default, there are internal resource view and redirect view

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

0. Difference between forwarding and redirection

forward:

  1. The browser sends a request, and the second request is sent inside the server based on the first request
  2. The address in the address bar has not changed
  3. Forwarding can obtain the data in the request domain, because it is a request and is the same request domain object
  4. Forwarding can access the resources in the web-inf. reason: the resources in the WEB-INF folder are secure and can only be accessed inside the server, but not directly by the browser

Redirect:

  1. The browser sends two requests, the first to access the servlet and the second to access the redirected address
  2. The address in the address bar has changed
  3. Redirection can cross domain, but forwarding cannot cross domain
  4. Only one request can be redirected, not to a specific page (the resources in the WEB-INF folder are secure)

1,ThymeleafView

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

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

2. Forwarding view

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

Create forwarding view in spring MVC:

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

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

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

3. Redirect view

The default redirection view in spring MVC is RedirectView

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

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

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

Note:

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

4. View controller

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

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

Note:

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

<mvc:annotation-driven />

When using the view controller, the original controller method must be commented out

After configuring the spring mvc configuration file, you can directly write (1. Turn on component scanning) (2. Turn on mvc annotation driver) (3. Turn on the default servlet processor) as a fixed step

7, RESTful

1. Introduction to RESTful

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

a> Resources

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

b> Representation of resources

The description of resources is a description of the state of resources at a specific time. It can be transferred (exchanged) between client and server. The expression of resources can be in 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.

2. RESTful implementation

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

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

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

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

3,HiddenHttpMethodFilter

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

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

HiddenHttpMethodFilter conditions for processing put and delete requests:

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

b> The current request must transmit the request parameters_ method

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

On the web Register HiddenHttpMethodFilter in XML

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

Note:

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

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

reason:

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

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

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

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

8, RESTful case

1. Preparatory work

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

  • Build environment

  • Prepare entity class

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

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

2. Function list

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

3. Specific functions: visit the home page

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

4. Specific function: query all employee data

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

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

5. Specific function: delete

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

Introduce Vue js

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

Delete hyperlink

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

Handling click events through vue

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

6. Specific function: jump to the add data page

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

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

</body>
</html>

7. Specific function: execute save

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

8. Specific function: jump to the update data page

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

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

</body>
</html>

9. Specific function: execute update

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

8, HttpMessageConverter

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

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

Among them, two request s use less

Note: @ RequestBody and @ ResponseBody use different positions

0. Review json

json: a data interaction format with simple parsing and less generated data

It is divided into json object * * {} * * and json array [], which parse data in different ways. The former uses object Attribute, which is parsed with a for loop

After the entity class is converted to json, it is a json object

After the map collection is converted to json, it is a json array

1. @ RequestBody (identity parameter)

Convert the request body in the request message into a Java object

@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 (identifies the controller parameter type)

Receive the whole request message

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

After adding this annotation, the return value of the controller method is no longer the view name, but directly responds to the browser as a response body

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

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

Result: the browser page displays success

4. Spring MVC handles json

@Steps for processing json by ResponseBody:

a> Import jackson dependencies

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

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

<mvc:annotation-driven />

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

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

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

Results displayed in the browser's page:

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

5. Spring MVC handles ajax

a> Request hyperlink:

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

b> Handle click events through vue and axios:

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

c> Controller method:

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

6. @ RestController annotation (easy to use)

@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 (return value type of controller method)

The response message type can be customized

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

9, File upload and download

1. File download

Use ResponseEntity to download files

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

2. File upload

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

enctype = "multipart / form data": the file is divided into multiple segments and transmitted in the form of stream

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

Upload steps:

a> Add dependency:

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

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

<!--
Profile upload parser
 The file must be parsed by the file parser to convert the file to MultipartFile object
 It must be set here id,Otherwise Spring Unable to get
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

c> Controller method:

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

10, Interceptor

The request is sent from the browser to the server. ① it is filtered by the filter, ② it is received by the front-end Controller (dispatcher servlet) after filtering, and ③ the front-end Controller calls the request Controller (Controller)

There are three abstract methods before and after the interceptor acts on the execution of the controller

1. Interceptor configuration

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

Interceptors in spring MVC need to implement HandlerInterceptor

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

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

2. Three abstract methods of interceptor

Interceptors in spring MVC have three abstract methods:

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

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

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

3. Execution sequence of multiple interceptors

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

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

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

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

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

11, Exception handler

1. Configuration based exception handling

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

The implementation classes of the HandlerExceptionResolver interface include DefaultHandlerExceptionResolver and SimpleMappingExceptionResolver

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

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

2. Annotation based exception handling

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

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

}

I wrote one with ModelAndView

//@ControllerAdvice identifies the current class as an exception handling component
@ControllerAdvice
public class ExceptionController {
    /**
     * If the specified exception of value value in the annotation occurs, directly execute the controller method under the annotation
     * Put the Exception class directly as a formal parameter to get Exception information
     */
    @ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
    public ModelAndView goToError(Exception ex){
        ModelAndView mav = new ModelAndView();
        //Here, the attribute name needs to be consistent with ${ex} on the error page
        mav.addObject("ex", ex);
        mav.setViewName("error");
        return mav;
    }
}

12, Annotation configuration spring MVC

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

1. Create an initialization class instead of web xml

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

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

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

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

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

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

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

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

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

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

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

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

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


}

4. Test function

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

13, Spring MVC execution process

1. Spring MVC common components

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

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

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

Function: find the Handler according to the requested url, method and other information (@ RequestMapping annotation), that is, the controller method

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

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

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

Function: execute the processor (controller method) through the HandlerAdapter. The processor mapper is responsible for finding and the processor adapter is responsible for calling the corresponding controller method

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

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

  • View: View

Function: display model data to users through pages

2. Dispatcher servlet initialization process

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

a> Initialize WebApplicationContext

Category: org springframework. web. servlet. FrameworkServlet

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

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

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

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

    return wac;
}
b> Create WebApplicationContext

Category: org springframework. web. servlet. FrameworkServlet

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

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

    return wac;
}
c> Dispatcher servlet initialization policy

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

Category: org springframework. web. servlet. DispatcherServlet

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

3. DispatcherServlet calls the component to process the request

a>processRequest()

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

Category: org springframework. web. servlet. FrameworkServlet

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

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

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

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

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

    initContextHolders(request, localeContext, requestAttributes);

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

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

Category: org springframework. web. servlet. DispatcherServlet

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

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

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

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

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

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

Category: org springframework. web. servlet. DispatcherServlet

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

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

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

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

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

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

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

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

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

    boolean errorView = false;

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

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

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

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

4. Execution process of spring MVC

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

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

a) Does not exist

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

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

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

b) If it exists, execute the following process

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

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

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

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

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

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

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

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

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

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

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

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

  5. Returns the rendering results to the client.

Keywords: Java Spring mvc

Added by woodsy2k on Thu, 06 Jan 2022 12:16:17 +0200