Learning route:
JavaSE: learn object-oriented concepts and characteristics, classes, interface methods and other basic knowledge, as well as relational database, the use of JDBC and the simple encapsulation of JDBC
JavaWeb: Learn browser and server related technologies, follow HTTP protocol to complete the interaction between browser and server, and use three-tier architecture to complete the function implementation process in WEB Engineering, namely presentation layer, business layer and persistence layer.
SSM: in the process of implementing the specified functions, these functions have the same patterns and processes. Therefore, it is necessary to consider function expansion, encapsulate the fixed patterns and processes, provide code reuse, and use the framework. SSM framework integration is the most popular framework structure at present. Spring MVC is an important part of SSM framework.
Main contents of this course:
IDE :IDEA
Construction tool: Maven
Thymeleaf: view rendering
Core technology: spring mvc5.3.1
catalogue
3. Characteristics of spring MVC
5. Create a configuration file for spring MVC
3, @ RequestMapping annotation
1. Function of @ RequestMapping annotation
2. @ RequestMapping annotation location
3. value attribute of @ RequestMapping annotation
4. method attribute of @ RequestMapping annotation
5. params attribute of @ RequestMapping annotation (understand)
6. headers attribute of @ RequestMapping annotation (understand)
7. Spring MVC supports ant style paths
8. Placeholder in spring MVC support path (emphasis)
4, Spring MVC get request parameters
2. Obtain the request parameters through the formal parameters of the controller method
6. Get request parameters through POJO
7. Solve the garbled problem of obtaining request parameters
1. Use the servlet API to share data with the request domain object
2. Use ModelAndView to share data with the request domain object
3. Using Model to share data with rqequest domain objects
4. Use map to share data with the request domain object
5. Use ModelMap to share data with request domain objects
6. Relationship between Model, ModelMap and Map
7. Share data to the session domain
8. Share data with the application domain
3. Use RESTFul to simulate the operation of user resources
Simulate get and post requests
HiddenHttpMethodFilter handles put and delete requests
Simulate PUT and DELETE requests
2. Specific functions: visit the home page
3. Specific function: query all employee data
5. Specific function: jump to the add data page
Specific function: execute save
6. Specific function: jump to the update data page
9. Specific function: execute update
6. @ RestController annotation
2. Three abstract methods of interceptor
3. Execution sequence of multiple interceptors
1. Configuration based exception handling
2. Annotation based exception handling
12, Annotation configuration spring MVC
1. Create an initialization class instead of web.xml
2. Create a SpringConfig configuration class to replace the spring configuration file
3. Create a WebConfig configuration class to replace the spring MVC configuration file
13, Spring MVC execution process
1. Spring MVC common components
2. Dispatcher servlet initialization process
3. DispatcherServlet calls the component to process the request
1, Introduction to spring MVC
1. What is MVC
- 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
2. What is spring MVC
3. Characteristics of spring MVC
2, Build spring MVC framework
1. Development environment
Build tool: maven 3.5.4
Server: tomcat7
Spring version: 5.3.1
2. Create maven project
new module--maven -- select archetype and let idea automatically create maven projects. The following demonstrates the manual creation steps
<dependencies> <!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <!--The transitivity of a dependency automatically adds its own dependency jar package--> <artifactId>spring-webmvc</artifactId> <version>5.3.1</version> </dependency> <!-- journal --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!-- ServletAPI --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <!--It is referenced at compile time and does not need to be added at publish time.Otherwise, it will be published with tomcat Bring your own servlet of jar Package conflict. An error will be reported when compiling without this package--> <scope>provided</scope> </dependency> <!--Spring5 and Thymeleaf The consolidation package controls the content to be displayed in the page through view technology--> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.12.RELEASE</version> </dependency> </dependencies>
Note: due to Maven's transitivity, we do not need to configure all the required packages, but configure the top dependency, and others rely on transitive import.
Problems encountered during maven package Guide Cannot resolve plugin org.apache.maven.plugins:maven-war-plugin:2.2
The path added by webapp has small blue dots. After the above steps are completed, there is web.xml in the folder. Web.xml is the configuration file of the web project entry, including registered servlet s, filters, listeners, etc. After that, the XML configuration file is replaced by annotation configuration class.
After the web project is made into a war package, the dependent jar package will be placed in lib under WEB-INFO in webapp directory
3. Configure web.xml
Solution: there may be no dependent information in the. iml file of the project. You only need to execute the following command in the project directory to regenerate the. iml file:
mvn idea:module
Right click the corresponding Module name in Maven projects on the right side of the IDEA and select Reimport to update the related dependencies.
a> Default configuration method
Profile location name default
<!-- to configure SpringMVC The front-end controller of the browser uniformly processes the requests sent by the browser --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!-- set up springMVC The request path of the request that can be processed by the core controller of /The matching request can be/login or.html or.js or.css Mode request path /*Represents matching all requests, including jsp however/Cannot match.jsp Request path.(jsp The essence of is servlet,You need to go through a special in the current server servlet Processing, not required DispatcherServlet Processing, if matched jsp,Requests will also be rejected SpringMVC Processing, processing error) --> <url-pattern>/</url-pattern> </servlet-mapping>
Under this configuration, the configuration file of spring MVC is located under WEB-INF by default, and the default name is < servlet name > - servlet.xml. For example, the configuration file of spring MVC corresponding to the following configuration is located under WEB-INF, and the file name is springMVC-servlet.xml.
maven project configuration files are uniformly placed under resources and implemented through extended configuration. (optimal)
<!-- to configure SpringMVC The front-end controller of the browser uniformly processes the requests sent by the browser --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- Specified by initialization parameters SpringMVC Location and name of the configuration file --> <init-param> <!-- contextConfigLocation Is a fixed value --> <param-name>contextConfigLocation</param-name> <!-- use classpath:Indicates finding a configuration file from a classpath, for example maven In Engineering src/main/resources --> <param-value>classpath:springMVC.xml</param-value> </init-param> <!-- As the core component of the framework, there are a lot of initialization operations to be done during startup These operations are performed only when the first request is made, which will seriously affect the access speed Therefore, it is necessary to start the control through this label DispatcherServlet The initialization time of is advanced until the server starts --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!-- set up springMVC The request path of the request that can be processed by the core controller of /The matching request can be/login or.html or.js or.css Mode request path however/Cannot match.jsp Request for request path --> <url-pattern>/</url-pattern> </servlet-mapping>
Create a configuration file under resource
resources ---- right click ----- new ----- XML configure file ----- spring config to create a new springMVC.xml
4. Create request controller
Because the front-end controller uniformly processes the requests sent by the browser, but the specific requests have different processing processes, it is necessary to create a class to process the specific requests, that is, the request controller.
Each method in the request controller that processes the request becomes a controller method. Currently, the required data has been obtained in the front-end controller. We only need to create a method to match this method in spring MVC.
Generally, the servlet that handles the request needs to implement the servlet interface or inherit the HTTP servlet. The Controller that handles the request in spring MVC is a POJO(Plain Ordinary Java Object). Because the Controller of spring MVC is served by a POJO (ordinary Java class), it needs to be identified as a control layer component through the @ Controller annotation, Spring MVC can recognize the existence of the Controller only when it is managed by spring's IoC container
package com.atguigu.controller;//The package name can be controller or handler (processor) import org.springframework.stereotype.Controller; @Controller public class HelloController { }
5. Create a configuration file for spring MVC
<!-- Auto scan package --> <context:component-scan base-package="com.atguigu.mvc.controller"/> <!-- to configure Thymeleaf view resolver --> <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <!-- Set view parser priority(Multiple view parsers can be configured) --> <property name="order" value="1"/> <!-- The encoding used to parse the view --> <property name="characterEncoding" value="UTF-8"/> <!-- inside bean to templateEngine Template attribute assignment --> <property name="templateEngine"> <bean class="org.thymeleaf.spring5.SpringTemplateEngine"> <property name="templateResolver"> <!--inside bean--> <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"> <!-- View prefix -The view location accessed is/WEB-INF/templates/lower--> <property name="prefix" value="/WEB-INF/templates/"/> <!-- The page accessed by the view suffix is H5 of html--> <property name="suffix" value=".html"/> <property name="templateMode" value="HTML5"/> <property name="characterEncoding" value="UTF-8" /> </bean> </property> </bean> </property> </bean> <!-- Processing static resources, such as html,js,css,jpg If only this tag is set, only static resources can be accessed, and other requests cannot be accessed Must be set at this time<mvc:annotation-driven/>solve the problem --> <mvc:default-servlet-handler/> <!-- open mvc Annotation driven --> <mvc:annotation-driven> <mvc:message-converters> <!-- Processing response Chinese content garbled --> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="defaultCharset" value="UTF-8" /> <property name="supportedMediaTypes"> <list> <value>text/html</value> <value>application/json</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
6. Test HelloWorld
// localhost:8080/springMVC/ @Controller public class HelloController { //"/"-->/WEB-INF/templates/index.html //The request mapping annotation handles the mapping relationship between the request and the controller method //The value attribute of the annotation can match the context path of the current project represented by / through the request address @RequestMapping(value = "/") //When the request sent by the browser is a context path, the method represented by the annotation will be executed public String index(){//The method that the request matches is independent of the method name /**Returns the view name, which determines the final page to jump to. The name of the view we returned It will be parsed by the configured view parser, prefix + view name + suffix */ return "index"; } }
Configure tomcat for the project
There is a problem with the operation
After successful operation
b> Jump to the specified page through hyperlink
<!DOCTYPE html> <html lang="en" xmlns:th="http://Www.thymeleaf. Org "> <! -- namespace, you can use thymeleaf syntax -- > <head> <meta charset="UTF-8"> <title>home page</title> </head> <body> <h1>home page</h1> <!--@{}When an absolute path is detected, the context path is automatically added, i.e/springMVC--> <!--Write only<a href = "/hello">There is no context path,Because the browser parses/Indicates from localhot:8080 Next access, one less context path--> <a th:href="@{/hello}">HelloWorld</a><br/> </body> </html>
Create a method in the request controller to process the request
@RequestMapping("/hello") public String HelloWorld() { return "target"; }
7. Summary
3, @ RequestMapping annotation
1. Function of @ RequestMapping annotation
From the annotation name, we can see that the @ RequestMapping annotation is used to associate the request with the controller method processing the request and establish a mapping relationship.
When spring MVC receives the specified request, it will find the corresponding controller method in the mapping relationship to process the request.
If there are multiple request controllers and the processed request addresses are the same, spring MVC will report a conflict error. Ensure that the address matched by requestmapping in all controllers is unique.
2. @ RequestMapping annotation location
@RequestMapping identifies a class: sets the initial information of the request path of the mapping request (first access to the initial information, and then access to the specific information), which is often used to distinguish controllers of different modules
@RequestMapping identifies a method: set the specific information of the request path of the mapping request (associated with the request sent by the browser)
@Controller @RequestMapping("/test") public class RequestMappingController { //At this time, the request path of the request mapped by the request mapping is: / test/testRequestMapping @RequestMapping("/testRequestMapping") public String testRequestMapping(){ return "success"; } }
Modify the request path of the request mapped in index.html as: / test/testRequestMapping
<body> <h1>home page</h1> <a th:href="@{/test/testRequestMapping}">test RequestMapping annotation</a> </body>
Application scenarios: such as user list and order list / user/list / order/list
3. value attribute of @ RequestMapping annotation
@The value attribute of the RequestMapping annotation matches the request mapping by the request address of the request
@The value attribute of the RequestMapping annotation is a string type array, indicating that the request mapping can match the requests corresponding to multiple request addresses
@The value attribute of the RequestMapping annotation must be set to match the request mapping at least through the request address
@RequestMapping( value = {"/testRequestMapping", "/test"} ) public String testRequestMapping(){ return "success"; }
<a th:href="@{/testRequestMapping}">test@RequestMapping of value attribute-->/testRequestMapping</a><br> <a th:href="@{/test}">test@RequestMapping of value attribute-->/test</a><br>st</a><br>
If the request address does not match the request mapping, a 404 error is reported
4. method attribute of @ RequestMapping annotation
@The method attribute of the RequestMapping annotation matches the request mapping by the request method (get or post) of the request
@The method attribute of the RequestMapping annotation is an array of RequestMethod (enumeration type), indicating that the request mapping can match requests of multiple request methods
If the request address of the current request meets the value attribute of the request mapping, but the request method does not meet the method attribute, the browser will report an error 405: Request method 'POST' not supported
<a th:href="@{/test}">test@RequestMapping of value attribute-->/test</a><br> <form th:action="@{/test}" method="post"> <input type="submit"> </form>
@RequestMapping( value = {"/testRequestMapping", "/test"}, method = {RequestMethod.GET, RequestMethod.POST} ) public String testRequestMapping(){ return "success"; }
Note: 1. Spring MVC provides the derived annotation of @ RequestMapping for the controller method that handles the specified request method
Mapping for processing get requests -- > @ getmapping
Mapping for handling post requests -- > @ postmapping
Mapping for processing put requests -- > @ putmapping
Mapping for processing delete requests -- > @ deletemapping
@GetMapping("/testRequestMapping") public String testGetMapping(){ return "success"; }
2. The common request methods are get, post, put and delete
However, at present, the browser only supports get and post. If a string of other request methods (put or delete) is set for the method when the form form is submitted, it will be processed according to the default request method get
To send put and delete requests, you need to use the spring provided filter HiddenHttpMethodFilter, which will be described in the RESTful section
5. params attribute of @ RequestMapping annotation (understand)
@The params attribute of the RequestMapping annotation matches the request mapping through the request parameters of the request
@The params property of the RequestMapping annotation is an array of string types. You can set the matching relationship between request parameters and request mapping through four expressions
"Param": the request matching the request mapping must carry param request parameters
"! Param ": the request matching the request mapping must not carry param request parameters
"param=value": the request matching the request mapping must carry param request parameters and param=value
"param!=value ": the request matched by the request mapping must carry param request parameters, but param!=value
<a th:href="@{/test(username='admin',password=123456)">test@RequestMapping of params attribute-->/test</a><br>
You can also use the "pass parameter" method. This writing idea will prompt an error and will not affect the operation
@RequestMapping( value = {"/testRequestMapping", "/test"} ,method = {RequestMethod.GET, RequestMethod.POST} ,params = {"username","password!=123456"} ) public String testRequestMapping(){ return "success"; }
Note: if the current request meets the value and method attributes of the @ RequestMapping annotation, but does not meet the parameters attribute, the page returns an error of 400: parameter conditions "username, password= 123456" not met for actual request parameters: username={admin}, password={123456}
6. headers attribute of @ RequestMapping annotation (understand)
@The headers attribute of the RequestMapping annotation matches the request mapping through the request header information of the request
@The headers attribute of the RequestMapping annotation is an array of string types. You can set the matching relationship between the request header information and the request mapping through four expressions
"Header": the request matching the request mapping must carry the header request header information
"! Header ": the request matched by the request mapping must not carry header request header information
"header=value": the request matching the request mapping must carry header request header information and header=value
"header!=value ": the request matched by the request mapping must carry header request header information and header!=value
If the current request meets the value and method attributes of the @ RequestMapping annotation, but does not meet the headers attribute, the page displays 404 error, that is, the resource is not found
@RequestMapping(value = {"/test","/testRequestMapping"}, method = {RequestMethod.POST,RequestMethod.GET}, headers = {"Host=localhost: 8081"} ) //headers are new types of key value pairs public String mapTest(){ return "success"; }
7. Spring MVC supports ant style paths
Fuzzy matching function. Applied to the value attribute of requestMapping
?: represents any single character (except?, and / or)
*: indicates any 0 or more characters (? And / excluded)
**: represents any one or more levels of directories. Note: when * * is used, only / * * / xxx can be used
@RequestMapping("/a?a/testAnt") public String testAnt(){ return "success"; } @RequestMapping("/**/testAnt") //springMVC/a1/a/testAnt or springMVC/testAnt or springMVC/a1/testAnt can be accessed public String testAnt(){ return "success"; }
8. Placeholder in spring MVC support path (emphasis)
value attribute applied to requestMapping
Original method: / deleteUser?id=1
restful mode: / deleteUser/1/admin
Which directory corresponds to which value? How do I get these values?
Placeholders in the spring MVC path are often used in the RESTful style. When some data in the request path is transmitted to the server through the path, the transmitted data can be represented by the placeholder {xxx} in the value attribute of the corresponding @ RequestMapping annotation, and the data represented by the placeholder can be assigned to the formal parameters of the controller method through the @ PathVariable annotation
<a th:href="@{/testRest/1/admin}">Placeholder in test path-->/testRest</a><br>
@RequestMapping("/testRest/{id}/{username}") public String testRest(@PathVariable("id") String id, @PathVariable("username") String username){ System.out.println("id:"+id+",username:"+username); return "success"; } //The value represented by {id} is automatically assigned to the formal parameter id, and the final output content is -- > id: 1, username: admin
In this way, the parameter name will not be exposed to the front end
4, Spring MVC get request parameters
1. Get through servlet API
The request sent by the browser is first processed by the front-end controller, which indirectly calls the controller method. Take HttpServletRequest as the formal parameter of the controller method. At this time, the parameter of HttpServletRequest type represents the object encapsulating the request message of the current request. (the current request in the controller is assigned to the formal parameter as an argument)
@RequestMapping("/testParam") //The request of the formal parameter position represents the current request public String testParam(HttpServletRequest request){ String username = request.getParameter("username"); String password = request.getParameter("password"); System.out.println("username:"+username+",password:"+password); return "success"; }
<a th:href="@{/testServletAPI(username='admin',password=123)}">test</a>
This method is rarely used in general, and it can be used without the native API, because spring MVC helps us simplify a lot.
Episode: HTTP status 500 - servlet. Init() for servlet dispatcherservlet thread exception occurs during project operation. Direct rebuild project solution
2. Obtain the request parameters through the formal parameters of the controller method
Set the formal parameter with the same name as the request parameter at the formal parameter position of the controller method. When the browser sends a request and matches the request mapping, the request parameter will be assigned to the corresponding formal parameter in the dispatcher servlet. (if the match is inconsistent, it cannot be obtained)
<a th:href="@{/testParam(username='admin',password=123456)}">Test get request parameters-->/testParam</a><br>
@RequestMapping("/testParam") public String testParam(String username, String password){ System.out.println("username:"+username+",password:"+password); return "success"; }
Note:
If there are multiple request parameters with the same name in the request parameters transmitted by the request, you can set string array or string type formal parameters in the formal parameters of the controller method to receive the request parameters
If you use a formal parameter of string array type, the array of this parameter contains each data
If a string type parameter is used, the value of this parameter is the result of concatenation of commas in the middle of each data
<form th:action="@{/testParam}" method="post"> user name:<input type="text" name="password"><br> password:<input type="password" name="username"><br> Hobbies:<input type="checkbox" name="hobby" value="a">a <input type="checkbox" name="hobby" value="b">b <input type="checkbox" name="hobby" value="c">c<br> <input type="submit" value="Submit"> </form>
@RequestMapping("/testParam") public String testParam(String username,String password,String hobby){ //username:12,password:yu,hobby:a,b System.out.println("username:"+username+",password:"+password+",hobby:"+hobby); return "success"; } @RequestMapping("/testParam") public String testParam(String username,String password,String[] hobby){ //username:12,password:yu,hobby:[a, b, c] System.out.println("username:"+username+",password:"+password+",hobby:"+hobby); return "success"; }
3,@RequestParam
@RequestParam is to create a mapping relationship between the request parameters and the formal parameters of the controller method
@The RequestParam annotation has three attributes:
value: Specifies the parameter name of the request parameter assigned to the formal parameter
required: sets whether this request parameter must be transmitted. The default value is true
If it is set to true, the current request must transmit the request parameter specified by value. If the request parameter is not transmitted and the defaultValue property is not set, the page will report an error 400: Required String parameter 'xxx' is not present; If it is set to false, the current request does not have to transmit the request parameter specified by value. If there is no transmission, the value of the formal parameter identified by the annotation is null
defaultValue: whether the required property value is true or false, when the request parameter specified by value is not transmitted or the transmitted value is' ', the default value is used to assign value to the formal parameter
@RequestMapping("/testParam") public String testParam( @RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username, String password, String[] hobby){ System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobby)); return "success"; }
4,@RequestHeader
@The RequestHeader creates a mapping relationship between the request header information and the formal parameters of the controller method
@The RequestHeader annotation has three attributes: value, required, and defaultValue. The usage is @ RequestParam
public String testParam( @RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username, @RequestHeader("Host" )String host) { System.out.println("username:"+username); //Host:localhost:8080 System.out.println("Host:"+host);
5,@CookieValue
@Cookie value is to create a mapping relationship between cookie data and formal parameters of the controller method
@The CookieValue annotation has three attributes: value, required and defaultValue. The usage is the same as @ RequestParam
@RequestMapping("/testParam") public String testParam( @RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username, @RequestHeader("Host" )String host, @CookieValue("JSESSIONID") String JSESSIONID) { System.out.println("username:"+username); //Host:localhost:8080 System.out.println("Host:"+host); System.out.println("JSESSIONID:"+JSESSIONID); return "success"; }
6. Get request parameters through POJO
You can set a formal parameter of entity class type at the formal parameter position of the controller method. At this time, if the parameter name of the request parameter transmitted by the browser is consistent with the attribute name in the entity class, the request parameter will assign a value to this attribute
<form th:action="@{/testpojo}" method="post"> user name:<input type="text" name="username"><br> password:<input type="password" name="password"><br> Gender:<input type="radio" name="sex" value="male">male<input type="radio" name="sex" value="female">female<br> Age:<input type="text" name="age"><br> Email:<input type="text" name="email"><br> <input type="submit"> </form>
@RequestMapping("/testpojo") public String testPOJO(User user){ System.out.println(user); return "success"; } //Final result -- > user {id = null, username = 'Zhang San', password='123', age=23, sex ='? ', email='123@qq.com '} character codes are inconsistent and garbled
7. Solve the garbled problem of obtaining request parameters
The reason why the get request is garbled is caused by tomcat. The tomcat configuration file conf/server.xml needs to be changed. (it needs to be changed before version 8). post needs to set the encoding method before obtaining the request parameters to be effective (request.setCharacterEconding()).
Because the dispatcher servlet has obtained the request parameters, it is invalid to set the encoding method. To solve the problem of garbled code in obtaining request parameters, you can use the encoding filter characterencoding filter provided by spring MVC before obtaining request parameters, but it must be registered in web.xml. (the loading order of the three components is Listen, filter and servlet. Because Listen listens to the creation and destruction of servletConText only once, it is set in the filter. The request code is only set through the filter. Each time a request is sent, it is processed by the filter and then forwarded to the dispatcher Servlet.)
<!--to configure springMVC Coding filter for--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Manual code source:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String encoding = this.getEncoding(); if (encoding != null) { if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) { request.setCharacterEncoding(encoding); } if (this.isForceResponseEncoding()) { response.setCharacterEncoding(encoding); } } filterChain.doFilter(request, response); }
Note: the encoding filter in spring MVC must be configured before other filters, otherwise it will be invalid
5, Domain objects share data
Four domain objects: page, request, session and application
1. Use the servlet API to share data with the request domain object
@RequestMapping("/testRequestByServletAPI") public String testServletAPI(HttpServletRequest request){ request.setAttribute("testScope", "hello,servletAPI"); return "success"; }
<!--index--> <a th:href="@{/testRequestByServletAPI}">test</a> <!--success--> <p th:text="${testScope}"></p> //Get the data in the request field, Hello, servlet API
Generally, we do not use the native method. We often use the spring MVC encapsulation method.
2. Use ModelAndView to share data with the request domain object
@RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){//Be sure to return the ModelAndView object /** * ModelAndView It has the functions of Model and View * Model It is mainly used to share data with the requesting domain * View It is mainly used to set the view and realize page Jump */ ModelAndView mav = new ModelAndView(); //Process model data and share data with the requesting domain mav.addObject("testScope", "hello,ModelAndView"); //Set the view to realize page Jump mav.setViewName("success"); return mav; }
The front-end controller parses the encapsulated model data and view information according to the returned object.
3. Using Model to share data with rqequest domain objects
@RequestMapping("/testModel") public String testModel(Model model){ model.addAttribute("testScope", "hello,Model"); return "success"; }
4. Use map to share data with the request domain object
@RequestMapping("/testMap") public String testMap(Map<String, Object> map){//The data stored in the map set is the data stored in the domain object map.put("testScope", "hello,Map"); return "success"; }
5. Use ModelMap to share data with request domain objects
@RequestMapping("/testModelMap") public String testModelMap(ModelMap modelMap){ modelMap.addAttribute("testScope", "hello,ModelMap"); return "success"; }
6. Relationship between Model, ModelMap and Map
The parameters of Model, ModelMap and Map are essentially BindingAwareModelMap
public interface Model{} public class ModelMap extends LinkedHashMap<String, Object> {} //modelmap is the implementation class of map public class ExtendedModelMap extends ModelMap implements Model {}//Class can instantiate modelmap and model public class BindingAwareModelMap extends ExtendedModelMap {}
In any way, the model data and current view information will eventually be encapsulated in the modelandview object. (through breakpoints combined with source code analysis)
7. Share data to the session domain
@RequestMapping("/testSession") public String testSession(HttpSession session){ session.setAttribute("testSessionScope", "hello,session"); return "success"; }
<p th:text="${session.testSessionScope}></p>
It is often used to save the login status of users. It is recommended to use the native API
8. Share data with the application domain
@RequestMapping("/testApplication") public String testApplication(HttpSession session){ ServletContext application = session.getServletContext(); application.setAttribute("testApplicationScope", "hello,application"); return "success"; }
<p th:text="${application.testApplicationScope}></p>
6, View of spring MVC
The View in spring MVC is the View interface. The function of the View is to render data and display the data in the Model to the user
There are many kinds of spring MVC views, including forwarding view and redirection view by default
When the project introduces jstl dependency, the forwarding view will be automatically converted to JstlView
If the view technology used is Thymeleaf, the view parser of Thymeleaf is configured in the configuration file of spring MVC. After the view parser parses, the ThymeleafView is obtained
1,ThymeleafView
When the view name set in the controller method does not have any prefix, the view name will be parsed by the view parser configured in the spring MVC configuration file. The final path obtained by splicing the view prefix and view suffix will jump through forwarding
@RequestMapping("/testHello") public String testHello(){ return "hello"; }
Source code: (debug and jump to the render () method in processDispatchResult). mv.getModelInternal returns the model object, that is, the model data encapsulated by ModelAndView.
resolveViewName() creates a view object based on the view name. Create ThymeleafView without any prefix
2. Forwarding view
The default forwarding view in spring MVC is the internal resource view
Create forwarding view in spring MVC:
When the view name set in the controller method is prefixed with "forward:", a view of InternalResourceView type is created. At this time, the view name will not be resolved by the view parser configured in the spring MVC configuration file, but the prefix "forward:" will be removed, and the rest will be used as the final path to jump through forwarding
@RequestMapping("/testThymeleafView") public String testThymeleafView(){ return "success"; } @RequestMapping("/testForward") public String testForward(){ return "forward:/testThymeleafView";//Forward request to / testThymeleafView }
1. Forward the testThymeleafView request that can jump to the success page. 2. Create a ThymeleafView view to access success
3. Redirect view
The default redirection view in spring MVC is RedirectView
When the view name set in the controller method is prefixed with "redirect:" to create a RedirectView, the view name will not be resolved by the view parser configured in the spring MVC configuration file, but the prefix "redirect:" will be removed, and the rest will be used as the final path to jump through redirection
@RequestMapping("/testRedirect") public String testRedirect(){ return "redirect:/testHello";//Redirect to a request, not a page (the page under web_info cannot be redirected. All pages must be parsed by thymeleaf, and the thymeleaf view can be accessed through forwarding) }
Note: when the redirect view is parsed, the redirect: prefix will be removed first, and then whether the rest starts with /. If so, the context path will be spliced automatically
Review the differences between forwarding and redirection:
1. Forwarding is one request (one request from the browser), and redirection is two requests from the browser. The first is to access the Servlet and the second is to access the redirection address
2. The forwarding address bar address remains unchanged, and the redirection address bar address becomes the redirection address
3. Forwarding can obtain request domain data, but redirection cannot (two requests).
4. Forwarding can access the web_ The resource under info cannot be redirected. web_info resources are secure and can only be accessed through the server, not through the browser.
5. Forwarding cannot cross domain, and redirection can (for example, visit Baidu under the project)
4. View controller
When the controller method is only used to realize page Jump without other process processing, that is, only the view name needs to be set, the processor method can be represented by the view controller tag
<!-- path: Set the address of the request to be processed view-name: Set the view name corresponding to the request address --> <mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>
Note:
When any view controller is set in spring mvc, all request mappings in other controllers will fail. At this time, you need to set the label to enable mvc annotation driven in the core configuration file of spring mvc:
<mvc:annotation-driven />
7, RESTful
1. Introduction to RESTful
REST: Representational State Transfer, which refers to the state transfer of presentation (description) layer resources. A style of software architecture.
a> Resources
Resource is a way of looking at the server, that is, the server is regarded as composed of many discrete resources. Each resource is a named abstraction on the server. Because resource is an abstract concept, it can not only represent a file in the server file system, a table in the database and other specific things, but also design resources as abstract as possible, as long as imagination allows and client application developers can understand. Similar to object-oriented design, resources are organized with nouns as the core, and nouns are the first concern. A resource can be identified by one or more URIs. A URI is not only the name of a resource, but also the address of the resource on the Web. Client applications interested in a resource can interact with it through the URI of the resource.
b> Representation of resources
The description of resources is a description of the state of resources at a specific time. It can be transferred (exchanged) between client and server. The expression of resources can be in many formats, such as HTML/XML/JSON / plain text / picture / video / audio, etc. The expression format of resources can be determined through negotiation mechanism. The request response direction is usually expressed in different formats.
c> State transition
State transfer refers to the transfer between the client and the server, which represents the expression of resource state. Through the expression of transfer and operation resources, the purpose of operating resources can be realized indirectly.
2. RESTful implementation
Specifically, in the HTTP protocol, there are four verbs representing the operation mode: GET, POST, PUT and DELETE.
They correspond to four basic operations: GET is used to obtain resources, POST is used to create new resources, PUT is used to update resources, and DELETE is used to DELETE resources.
REST style advocates the uniform style design of URL address. Each word from front to back is separated by slash. The request parameters are not carried by question mark key value pair, but the data to be sent to the server is taken as a part of the URL address to ensure the consistency of the overall style.
3. Use RESTFul to simulate the operation of user resources
Simulate get and post requests
<a th:href="@{/user}">Query all user information</a><br> <a th:href="@{/user/1}">"according to id Query user information"</a><br> <form th:action="@{/user}" method="post"> user name<input type="text" name="username"><br> password<input type="password" name="password"><br> <input type="submit" value="Add user information"><br> </form>
@Controller public class UserController { /** * Use RESTFul to simulate the addition, deletion, modification and query of user resources * /user GET Query all user information * /user/1 GET Query user information according to user id * /user POST Add user information * /user/1 DELETE Delete user information * /user PUT Update user information */ @RequestMapping(value = "/user",method = RequestMethod.GET ) public String getAllUser(){ System.out.println("Query all user information"); return "success"; } @RequestMapping(value = "/user/{id}",method = RequestMethod.GET ) public String getUserById(){ System.out.println("according to id Query user information"); return "success"; } @RequestMapping(value = "/user",method = RequestMethod.POST) public String insertUser(String username,String password){ System.out.println("Add user information:"+username+","+password); return "success"; } }
HiddenHttpMethodFilter handles put and delete requests
<form th:action="@{/user}" method="put"> user name<input type="text" name="username"><br> password<input type="password" name="password"><br> <input type="submit" value="modify"><br> </form>
@RequestMapping(value = "/user",method = RequestMethod.PUT) public String updateUser(String username,String password){ System.out.println("Modify user information:"+username+","+password); return "success"; }
Because the browser does not support put, the access method is still get, and the query controller method is executed.
Since the browser only supports sending get and post requests, how to send put and delete requests?
Spring MVC provides HiddenHttpMethodFilter Filters help us convert POST requests to DELETE or PUT requests
HiddenHttpMethodFilter conditions for processing put and delete requests (analyze the source code and draw a conclusion):
a> The request mode of the current request must be post
b> The current request must transmit the request parameters_ method
If the above conditions are met, the HiddenHttpMethodFilter filter will convert the request mode of the current request into request parameters_ Method, so the request parameter_ The method value is the final request method
Register HiddenHttpMethodFilter in web.xml
<filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Hand tearing source code:
private static final List<String> ALLOWED_METHODS; public static final String DEFAULT_METHOD_PARAM = "_method"; private String methodParam = "_method"; static { ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));} protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//Request the request intercepted by the current filter HttpServletRequest requestToUse = request; if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {//The request method of the current request must be post to execute the following contents //Request parameters of the current request, (private String methodParam = "_method";) String paramValue = request.getParameter(this.methodParam);obtain_method The value of the request parameter //If there is a length (not empty) if (StringUtils.hasLength(paramValue)) { //_ The value of the method parameter is capitalized String method = paramValue.toUpperCase(Locale.ENGLISH); if (ALLOWED_METHODS.contains(method)) {//The parameter values are one of the three constants, put, delete and patch requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method); } } } filterChain.doFilter((ServletRequest)requestToUse, response); } //Replace the request mode of request with POST_ The value represented by the method parameter (DELETE/PUT/PATCH) private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper { private final String method; //method (DELETE/PUT/PATCH) public HttpMethodRequestWrapper(HttpServletRequest request, String method) { super(request); this.method = method; } public String getMethod() { return this.method;//Rewrite the getMethod method of the request object and return the method } }
Simulate PUT and DELETE requests
<form th:action="@{/user}" method="post"> <input type="hidden" name="_method" value="PUT"> user name<input type="text" name="username"><br> password<input type="password" name="password"><br> <input type="submit" value="modify"><br> </form> <!--Delete the following examples-->
Note: so far, spring MVC has provided two filters: characterencoding filter and HiddenHttpMethodFilter
When registering in web.xml, you must first register CharacterEncodingFilter and then HiddenHttpMethodFilter
reason:
In CharacterEncodingFilter, set the request.setCharacterEncoding(encoding) method of the character set through the request.setCharacterEncoding(encoding) method. The request.setCharacterEncoding(encoding) method requires that there must be no previous operation to obtain the request parameters, while HiddenHttpMethodFilter has exactly one operation to obtain the request method:
String paramValue = request.getParameter(this.methodParam);
8, RESTful case
1. Preparatory work
Like traditional CRUD, it can add, delete, modify and query employee information.
-
Build environment
Create a new maven project and configure pom.xml,web.xml and springMVC.xml.
pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>springMVC_rest</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.1</version> </dependency> <!-- journal --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!-- ServletAPI --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- Spring5 and Thymeleaf Integration package --> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.12.RELEASE</version> </dependency> </dependencies> </project> web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springMVC.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> springMVC <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.atguigu.rest"></context:component-scan> <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <property name="order" value="1"/> <property name="characterEncoding" value="UTF-8"/> <property name="templateEngine"> <bean class="org.thymeleaf.spring5.SpringTemplateEngine"> <property name="templateResolver"> <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"> <!-- View prefix --> <property name="prefix" value="/WEB-INF/templates/"/> <!-- View suffix --> <property name="suffix" value=".html"/> <property name="templateMode" value="HTML5"/> <property name="characterEncoding" value="UTF-8" /> </bean> </property> </bean> </property> </bean> <mvc:view-controller path="/" view-name="index"></mvc:view-controller> <mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller> <!--Open access to static resources--> <mvc:default-servlet-handler/> <mvc:annotation-driven /> </beans>
-
Prepare entity class
package com.atguigu.mvc.bean; public class Employee { private Integer id; private String lastName; private String email; //1 male, 0 female private Integer gender; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getGender() { return gender; } public void setGender(Integer gender) { this.gender = gender; } public Employee(Integer id, String lastName, String email, Integer gender) { super(); this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; } public Employee() { } }
-
Prepare dao simulation data
package com.atguigu.mvc.dao; import java.util.Collection; import java.util.HashMap; import java.util.Map; import com.atguigu.mvc.bean.Employee; import org.springframework.stereotype.Repository; @Repository public class EmployeeDao { private static Map<Integer, Employee> employees = null; static{ employees = new HashMap<Integer, Employee>(); employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1)); employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1)); employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0)); employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0)); employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1)); } private static Integer initId = 1006; public void save(Employee employee){ if(employee.getId() == null){ employee.setId(initId++);//Assign first and then increase automatically } employees.put(employee.getId(), employee); } public Collection<Employee> getAll(){ return employees.values(); } public Employee get(Integer id){ return employees.get(id); } public void delete(Integer id){ employees.remove(id); } }
Function list
2. Specific functions: visit the home page
a> Configure view controller
<mvc:view-controller path="/" view-name="index"/>
b> Create page
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" > <title>Title</title> </head> <body> <h1>home page</h1> <a th:href="@{/employee}">Access employee information</a> </body> </html>
3. Specific function: query all employee data
a> Controller method
@RequestMapping(value = "/employee", method = RequestMethod.GET) public String getEmployeeList(Model model){ Collection<Employee> employeeList = employeeDao.getAll(); model.addAttribute("employeeList", employeeList); return "employee_list"; }
b> Create employee_list.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Employee Info</title> <script type="text/javascript" th:src="@{/static/js/vue.js}"></script> </head> <body> <table border="1" cellpadding="0" cellspacing="0" style="text-align: center;" id="dataTable"><!--id Attribute to vue Binding container--> <tr> <th colspan="5">Employee Info</th> </tr> <tr> <th>id</th> <th>lastName</th> <th>email</th> <th>gender</th> <th>options(<a th:href="@{/toAdd}">add</a>)</th> </tr> <tr th:each="employee : ${employeeList}"> <td th:text="${employee.id}"></td> <td th:text="${employee.lastName}"></td> <td th:text="${employee.email}"></td> <td th:text="${employee.gender}"></td> <td> <a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a> <a th:href="@{'/employee/'+${employee.id}}">update</a> </td> </tr> </table> </body> </html>
4. Specific function: delete
Deleting is usually a hyperlink method, but the hyperlink cannot send a delete request. Therefore, the form submission is controlled by hyperlink. The form mehtod is post and the request parameter is_ method
a> Create a form that handles the delete request
<!-- Function: control the submission of forms through hyperlinks post Request converted to delete request --> <form id="delete_form" method="post"> <!-- HiddenHttpMethodFilter Requirement: must be transmitted_method Request parameters, and the value is the final request method --> <input type="hidden" name="_method" value="delete"/> </form>
b> Delete hyperlink binding click event
Introduce vue.js
Create a new static folder under webapp folder, create JS, and introduce vue.js
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
Delete hyperlink
<a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a> <!--Bind stand-alone events-->
Handling click events through vue
<script type="text/javascript"> var vue = new Vue({ el:"#dataTable ", / / the current vue container uses the attribute datatabel (used in the scope containing hyperlinks) methods:{ //Event indicates the current event deleteEmployee:function (event) { //Get form label by id var delete_form = document.getElementById("delete_form"); //Assign the href attribute of the hyperlink that currently triggers the event to the action attribute of the form delete_form.action = event.target.href; //Submit Form delete_form.submit(); //Block default jump behavior of hyperlinks event.preventDefault(); } } }); </script>
c> Controller method
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE) public String deleteEmployee(@PathVariable("id") Integer id){ employeeDao.delete(id); return "redirect:/employee"; }
Running result report 404 reason: static resources cannot be accessed by spring MVC. Add the following configuration in spring MVC
<!--Open access to static resources--> <mvc:default-servlet-handler/>
If the current request dispatchsetvlet cannot handle it, it will be handed over to the default servlet (web.xml configuration in tomcat)
5. Specific function: jump to the add data page
a> Configure view controller
<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
b> Create employee_add.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Add Employee</title> </head> <body> <form th:action="@{/employee}" method="post"> lastName:<input type="text" name="lastName"><br> email:<input type="text" name="email"><br> gender:<input type="radio" name="gender" value="1">male <input type="radio" name="gender" value="0">female<br> <input type="submit" value="add"><br> </form> </body> </html>
Specific function: execute save
a> Controller method
@RequestMapping(value = "/employee", method = RequestMethod.POST) public String addEmployee(Employee employee){//Saving data with entity class objects employeeDao.save(employee); return "redirect:/employee"; }
6. Specific function: jump to the update data page
Find out the data to be queried and return to the display page after modifying the page to be modified
a> Modify hyperlink
<a th:href="@{'/employee/'+${employee.id}}">update</a>
b> Controller method
@RequestMapping(value = "/employee/{id}", method = RequestMethod.GET) public String getEmployeeById(@PathVariable("id") Integer id, Model model){ Employee employee = employeeDao.get(id); model.addAttribute("employee", employee); return "employee_update"; }
c> Create employee_update.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Update Employee</title> </head> <body> <form th:action="@{/employee}" method="post"> <input type="hidden" name="_method" value="put"> <input type="hidden" name="id" th:value="${employee.id}"><!--id Echo of--> lastName:<input type="text" name="lastName" th:value="${employee.lastName}"><br><!--Echo--> email:<input type="text" name="email" th:value="${employee.email}"><br> <!-- th:field="${employee.gender}"Can be used for echo of radio boxes or check boxes If the radio box is value and employee.gender If the values are consistent, add checked="checked"attribute --> gender:<input type="radio" name="gender" value="1" th:field="${employee.gender}">male <input type="radio" name="gender" value="0" th:field="${employee.gender}">female<br> <input type="submit" value="update"><br> </form> </body> </html>
Specific function: execute update
a> Controller method
@RequestMapping(value = "/employee", method = RequestMethod.PUT) public String updateEmployee(Employee employee){ employeeDao.save(employee); return "redirect:/employee"; }
9, HttpMessageConverter
HttpMessageConverter, message information converter, converts request message into Java object or Java object into response message. (request message: browser sends request to server and Java receives request message. Response message: server responds to request to browser and Java object converts response message to server)
HttpMessageConverter provides two annotations and two types: @ RequestBody, @ ResponseBody, RequestEntity and responseentity (two commonly used responses)
1,@RequestBody
@RequestBody can obtain the request body. You need to set a formal parameter in the controller method and identify it with @ RequestBody. The request body of the current request will assign a value to the formal parameter identified by the current annotation
<form th:action="@{/testRequestBody}" method="post"><!--post The request has a request body--> user name:<input type="text" name="username"><br> password:<input type="password" name="password"><br> <input type="submit"> </form>
@RequestMapping("/testRequestBody") public String testRequestBody(@RequestBody String requestBody){ System.out.println("requestBody:"+requestBody); return "success"; }
Output results:
requestBody:username=admin&password=123456
2,RequestEntity
RequestEntity encapsulates a type of request message. This type of parameter needs to be set in the formal parameter of the controller method, and the request message of the current request will be assigned to this formal parameter. You can obtain the request header information through getHeaders() and the request body information through getBody()
@RequestMapping("/testRequestEntity") public String testRequestEntity(RequestEntity<String> requestEntity){ System.out.println("requestHeader:"+requestEntity.getHeaders()); System.out.println("requestBody:"+requestEntity.getBody()); return "success"; }
Output results:
requestHeader:[host:"localhost:8080", connection:"keep-alive", content-length:"27", cache-control:"max-age=0", sec-ch-ua:"" Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"", sec-ch-ua-mobile:"?0", upgrade-insecure-requests:"1", origin:"http://localhost:8080", user-agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"]
requestBody:username=admin&password=123
3,@ResponseBody
You can use the return value of the method as the browser's response body, and json is required to respond to the object (introduce dependency, open mvc annotation driver, and add responseBody annotation)
@ResponseBody is used to identify a controller method. The return value of this method can be directly used as the response body of the response message to respond to the browser
@RequestMapping("/testResponseBody") @ResponseBody public String testResponseBody(){ return "success"; }
Result: the browser page displays success
4. Spring MVC handles json
The browser cannot receive the response object. You need to convert the object to json.
@Steps for processing json by ResponseBody:
a> Import jackson dependencies
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.1</version> </dependency>
b> Open the mvc annotation driver in the spring mvc core configuration file. At this time, a message converter, MappingJackson2HttpMessageConverter, will be automatically installed in the HandlerAdaptor, which can convert the Java object responding to the browser into a string in Json format
<!-- open mvc Annotation driven --> <mvc:annotation-driven> <mvc:message-converters> <!-- Processing response Chinese content garbled --> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="defaultCharset" value="UTF-8" /> <property name="supportedMediaTypes"> <list> <value>text/html</value> <value>application/json</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
c> Use the @ ResponseBody annotation on the processor method for identification
d> If the Java object is returned directly as the return value of the controller method, it will be automatically converted to a string in Json format
@RequestMapping("/testResponseUser") @ResponseBody public User testResponseUser(){ return new User(1001,"admin","123456",23,"male"); }
Results displayed in the browser's page:
{"id":1001,"username":"admin","password":"123456","age":23,"sex": "male"}
5. Spring MVC handles ajax
a> Request hyperlink:
<div id="app"> <a th:href="@{/testAjax}" @click="testAjax">testAjax</a><br> </div>
b> Handle click events through vue and axios:
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script> <script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script> <script type="text/javascript"> var vue = new Vue({ el:"#app ", / / container id methods:{ testAjax:function (event) { axios({ method:"post", url:event.target.href, params:{ username:"admin", password:"123456" } }).then(function (response) {//ajax handles the to be executed successfully alert(response.data); }); event.preventDefault();//Cancels the default behavior of hyperlinks } } }); </script>
c> Controller method:
@RequestMapping("/testAjax") @ResponseBody public String testAjax(String username, String password){ System.out.println("username:"+username+",password:"+password); return "hello,ajax"; }
6. @ RestController annotation
@The RestController annotation is a composite (derived) annotation provided by spring MVC. Identifying it on the Controller class is equivalent to adding the @ Controller annotation to the class and the @ ResponseBody annotation to each method. (because the @ ResponseBody annotation is quite common)
7,ResponseEntity
ResponseEntity is used for the return value type of the controller method. The return value of the controller method is the response message in response to the browser
10, File upload and download
1. File download
Download resources from the server to the browser
Use ResponseEntity to download files
Response header, response body, response status code
@RequestMapping("/testDown") public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException { //Get ServletContext object ServletContext servletContext = session.getServletContext(); //Get the real path of the file in the server (the path of the current project deployed to tomcat) String realPath = servletContext.getRealPath("/static/img/1.jpg"); //Create input stream InputStream is = new FileInputStream(realPath); //Create byte array byte[] bytes = new byte[is.available()];//Gets all bytes of the file corresponding to the input stream //Read stream into byte array is.read(bytes); //Create an HttpHeaders object and set the response header information MultiValueMap<String, String> headers = new HttpHeaders(); //Set the method to download and the name of the file to download headers.add("Content-Disposition", "attachment;filename=1.jpg");//The download method is attachment. The default file name is 1.jpg //Set response status code HttpStatus statusCode = HttpStatus.OK; //Create ResponseEntity object bytes response body headers response header ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode); //Close input stream is.close(); return responseEntity; }
2. File upload
File upload requires that the form request method must be post, and the attribute enctype = "multipart / form data" is added
At this time, the data in the form is transmitted to the server in binary mode
<form th:action="@{/testUp}" method="post" enctype="multipart/form-data"> head portrait:<input type="file" name="photo"></br> <input type="submit" value="upload"> </form>
Spring MVC encapsulates the uploaded file into a MultipartFile object, through which you can obtain file related information
Upload steps:
a> Add dependency:
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
b> Add configuration in the configuration file of spring MVC:
Configure the file upload parser to package the uploaded file as MultipartFile
<!--The file must be parsed by the file parser to convert the file to MultipartFile object--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
c> Controller method:
session get server path
@RequestMapping("/testUp") public String testUp(MultipartFile photo, HttpSession session) throws IOException { //Gets the file name of the uploaded file String fileName = photo.getOriginalFilename(); //Handle the problem of file name duplication and obtain the suffix of the uploaded file String hzName = fileName.substring(fileName.lastIndexOf("."));//Gets the location of the last occurrence of fileName = UUID.randomUUID().toString() + hzName;//The result of stitching UUID and suffix is taken as the final file name //Gets the path to the photo directory in the server ServletContext servletContext = session.getServletContext(); String photoPath = servletContext.getRealPath("photo");//Get the path to the photo directory File file = new File(photoPath); //Determine whether the path corresponding to the photoPath exists if(!file.exists()){ //If it does not exist, create a directory file.mkdir(); } String finalPath = photoPath + File.separator + fileName;//path separator //Realize the upload function photo.transferTo(new File(finalPath)); return "success"; }
11, Interceptor
1. Interceptor configuration
Interceptors in spring MVC are used to intercept the execution of controller methods
Interceptors in spring MVC need to implement HandlerInterceptor
The interceptor of spring MVC must be configured in the configuration file of spring MVC (otherwise it has no effect):
<!-- The following two configuration methods are correct DispatcherServlet All requests processed are intercepted--> <mvc:interceptors> <bean class="com.atguigu.interceptor.FirstInterceptor"></bean> <!--bean perhaps ref Two ways of writing--> <ref bean="firstInterceptor"></ref> <mvc:interceptors/> <!-- The following configuration methods can be ref or bean Tag set interceptor, through mvc:mapping Set the request to be intercepted through mvc:exclude-mapping Set the requests that need to be excluded, that is, the requests that do not need to be intercepted --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/><!--/*It only represents the Interception under the directory of one layer, such as/a,/**Indicates the interception of all requests--> <mvc:exclude-mapping path="/testRequestEntity"/> <ref bean="firstInterceptor"></ref><!--ref Reference current IOC One of the containers bean of id,At this point, give the interceptor to ioc Administration,@component Identify components, you can also use bean Method of--> </mvc:interceptor> <mvc:interceptors>
2. Three abstract methods of interceptor
Interceptors in spring MVC have three abstract methods:
preHandle: execute preHandle() before the controller method is executed. The return value of boolean type indicates whether to intercept or release. Return true to release, that is, call the controller method; return false to intercept, that is, do not call the controller method
postHandle: execute postHandle() after the controller method is executed
After compilation: after processing the view and model data, execute after compilation () after rendering the view
@Component public class FirstInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("FirstInterceptor-->preHandle"); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("FirstInterceptor-->postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("FirstInterceptor-->afterCompletion"); } }
3. Execution sequence of multiple interceptors
a> If each interceptor's preHandle() returns true
At this time, the execution order of multiple interceptors is related to the configuration order of interceptors in the spring MVC configuration file: preHandle() will execute in the configured order, while postHandle() and aftercompilation() will execute in the reverse order of configuration
b> If the preHandle() of an interceptor returns false
preHandle() returns false. It and the preHandle() of the interceptor before it will execute, postHandle() will not execute, and aftercompilation() of the interceptor before the interceptor returns false will execute
Hand tear source code
if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //Controller method mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } mappedHandler.applyPostHandle(processedRequest, response, mv); if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, (Exception)null); } } //Enter the HandlerExecutionChain class of the above method boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { //Traverse the interceptor collection //interceptorIndex is the interceptor index before prehandle returns false for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {//The initial value of interceptorIndex is - 1 HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i); if (!interceptor.preHandle(request, response, this.handler)) { //After completion will be executed, and the interceptor order traversed during execution is the reverse order of interceptorIndex values at this time. //post is not executed this.triggerAfterCompletion(request, response, (Exception)null); return false; } } return true; } //Enter the above method void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { for(int i = this.interceptorList.size() - 1; i >= 0; --i) { HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i); interceptor.postHandle(request, response, this.handler, mv); } } void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) { for(int i = this.interceptorIndex; i >= 0; --i) {//interceptorIndex starts from the previous accumulation, so it is also executed in reverse order HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i); try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable var7) { logger.error("HandlerInterceptor.afterCompletion threw exception", var7); } } }
mappedHandler is the execution chain of the controller, including the currently matched controller method and the interceptor for processing the controller method (spring MVC comes with one)
12, Exception handler
1. Configuration based exception handling
Spring MVC provides an interface to handle exceptions during the execution of controller methods: HandlerExceptionResolver
The implementation classes of the HandlerExceptionResolver interface are defaulthandlerexceptionresolver (default) and SimpleMappingExceptionResolver
Spring MVC provides a custom exception handler, SimpleMappingExceptionResolver, which can be used as follows:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"><!--Anomaly mapping--> <props> <!-- properties The key of represents an exception that occurs during the execution of the processor method properties The value of indicates that if a specified exception occurs, set a new view name and jump to the specified page --> <prop key="java.lang.ArithmeticException">error</prop> </props> </property> <!-- exceptionAttribute Property sets a property name to share the exception information in the request field. It realizes the display of error information on the page --> <property name="exceptionAttribute" value="ex"></property> </bean>
@RequestMapping("/testException") public String testException(){ System.out.println(1/0); return "success"; }
<!--error.html--> <body> <h1>You're wrong</h1> <p th:text="${ex}"></p> </body>
2. Annotation based exception handling
//@ControllerAdvice identifies the current class as an exception handling component @ControllerAdvice public class ExceptionController { //@ExceptionHandler is used to set the exceptions handled by the identified method @ExceptionHandler(ArithmeticException.class) //ex represents the exception object in the current request processing public String handleArithmeticException(Exception ex, Model model){ model.addAttribute("ex", ex); return "error"; } }
13, Annotation configuration spring MVC
Use configuration classes and annotations instead of the functionality of web.xml and spring MVC configuration files
1. Create an initialization class instead of web.xml
In the Servlet 3.0 environment, the container will find the class that implements the javax.servlet.ServletContainerInitializer interface in the class path. If found, it will be used to configure the Servlet container. Spring provides an implementation of this interface, called SpringServletContainerInitializer. In turn, this class will find the classes that implement WebApplicationInitializer and entrust them with the task of configuration. Spring 3.2 introduces a convenient basic implementation of web application initializer called AbstractAnnotationConfigDispatcherServletInitializer. When our class extends AbstractAnnotationConfigDispatcherServletInitializer and deploys it to the Servlet 3.0 container, the container will automatically discover it and use it to configure the Servlet context.
Create a new module, a new webapp under the main folder, and a new WEB-INF folder under webapp
//Initialization class of Web project, which is used to replace web.xml public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer { /** * Specifies the configuration class for spring * @return */ @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } /** * Specifies the configuration class for spring MVC * @return */ @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; } /** * Specify the mapping rule of DispatcherServlet, i.e. URL pattern * @return */ @Override protected String[] getServletMappings() { return new String[]{"/"}; } /** * Add filter * @return */ @Override protected Filter[] getServletFilters() { CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); encodingFilter.setEncoding("UTF-8"); encodingFilter.setForceRequestEncoding(true); HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter(); return new Filter[]{encodingFilter, hiddenHttpMethodFilter}; } }
2. Create a SpringConfig configuration class to replace the spring configuration file
@Configuration//Identify as configuration class public class SpringConfig { //After ssm integration, spring configuration information is written in this class }
3. Create a WebConfig configuration class to replace the spring MVC configuration file
Replace the configuration file of spring MVC:
1. Scanning component 2. View parser 3. View controller 4. Default servlet handler 5. MVC driver annotation 6. File upload parser 7. Exception handling 8. Interceptor
//Identifies the current class as a configuration class @Configuration //Scan component @ComponentScan("com.atguigu.mvc.controller") //Enable MVC annotation driver @EnableWebMvc public class WebConfig implements WebMvcConfigurer {//Interface provides configuration methods for us to use //Use the default servlet to handle static resources @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } //Profile upload parser @Bean public CommonsMultipartResolver multipartResolver(){ return new CommonsMultipartResolver(); } //Configuring Interceptors @Override public void addInterceptors(InterceptorRegistry registry) { FirstInterceptor firstInterceptor = new FirstInterceptor();//Interceptor object registry.addInterceptor(firstInterceptor).addPathPatterns("/**");//Add interception path (multiple can be written) } //Configure view control @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); } //Configure exception mapping @Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver(); Properties prop = new Properties(); prop.setProperty("java.lang.ArithmeticException", "error"); //Set exception mapping exceptionResolver.setExceptionMappings(prop); //Set the key to share exception information exceptionResolver.setExceptionAttribute("ex"); resolvers.add(exceptionResolver); } //Configure the generation template parser (the view part of xml depends on memory beans, and the configuration starts from memory beans) @Bean //The return value of the method is a bean of ioc public ITemplateResolver templateResolver() { WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext(); // ServletContextTemplateResolver requires a ServletContext as a construction parameter, which can be obtained through the WebApplicationContext method ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext()); templateResolver.setPrefix("/WEB-INF/templates/"); templateResolver.setSuffix(".html"); templateResolver.setCharacterEncoding("UTF-8"); templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver; } //Generate a template engine and inject a template parser into the template engine @Bean //ioc automatic assembly assignment parameters public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver); return templateEngine; } //The generated view parser is not injected into the template engine @Bean public ViewResolver viewResolver(SpringTemplateEngine templateEngine) { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setCharacterEncoding("UTF-8"); viewResolver.setTemplateEngine(templateEngine); return viewResolver; } }
Test function
@RequestMapping("/") public String index(){ return "index"; }
14, Spring MVC execution process
1. Spring MVC common components
Dispatcher servlet: front-end controller, which does not need to be developed by engineers and is provided by the framework
Function: handle the request and response in a unified way. It is the center of the whole process control, and it calls other components to process the user's request
Handler mapping: processor mapper, which does not need to be developed by engineers and is provided by the framework
Function: find the handler (also known as controller) according to the requested url, method and other information, that is, the controller method
Handler: processor, which needs to be developed by engineers
Function: under the control of dispatcher servlet, the Handler handles specific user requests
HandlerAdapter: processor adapter. It does not need to be developed by engineers. It is provided by the framework
Function: execute the processor (controller method) through the HandlerAdapter (call the execution controller method)
ViewResolver: View resolver, which does not need to be developed by engineers and is provided by the framework
Function: analyze the view to get the corresponding view, such as ThymeleafView, InternalResourceView and RedirectView
View: View
Function: display model data to users through pages
2. Dispatcher servlet initialization process
Dispatcher Servlet is essentially a Servlet, so it naturally follows the Servlet life cycle. Therefore, it is the Servlet life cycle to schedule.
The description with gray up arrow after the method in the following figure is the rewritten method. If the method is empty, it indicates the specific implementation of the inherited subclass or subclass method
a> Initialize webapplicationcontext (initialize the IOC container of spring MVC)
Class: org.springframework.web.servlet.FrameworkServlet
protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());//Get WebApplicationContext through tool class WebApplicationContext wac = null; if (this.webApplicationContext != null) {//The first execution is null // A context instance was injected at construction time -> use it wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> set // the root application context (if any; may be null) as the parent cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { // No context instance was injected at construction time -> see if one // has been registered in the servlet context. If one exists, it is assumed // that the parent context (if any) has already been set and that the // user has performed any initialization such as setting the context id wac = findWebApplicationContext();//find } if (wac == null) { // No context instance is defined for this servlet -> create a local one // Creating WebApplicationContext is an important step wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { // Either the context is not a ConfigurableApplicationContext with refresh // support or the context injected at construction time had already been // refreshed -> trigger initial onRefresh manually here. synchronized (this.onRefreshMonitor) { // Refresh WebApplicationContext onRefresh(wac); } } if (this.publishContext) { // Publish the context as a servlet context attribute. // Share IOC container in application domain String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac);//Share in the application domain with attrname as the attribute name and wac as the attribute value } return wac; }
b> Create WebApplicationContext
Class: org.springframework.web.servlet.FrameworkServlet
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { Class<?> contextClass = getContextClass(); if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException( "Fatal initialization error in servlet with name '" + getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext"); } // Create IOC container objects through reflection ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); // Set the parent container (after the integration of spring and spring MVC (two configurations), the IOC container of spring MVC is the child container and the IOC container of spring is the parent container wac.setParent(parent);//Make spring's IOC container the parent of spring MVC's IOC container String configLocation = getContextConfigLocation(); if (configLocation != null) { wac.setConfigLocation(configLocation); } configureAndRefreshWebApplicationContext(wac); return wac; }
c> Dispatcher servlet initialization policy
After the FrameworkServlet creates the WebApplicationContext, refresh the container and call onRefresh(wac). This method is rewritten in the dispatcher servlet and calls the initStrategies(context) method to initialize the policy, that is, initialize each component of the dispatcher servlet
Class: org.springframework.web.servlet.DispatcherServlet
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context);//Initialize file upload parser initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
3. DispatcherServlet calls the component to process the request
a>processRequest()
FrameworkServlet rewrites service() and doXxx() in HttpServlet. These methods call processRequest(request, response). ProcessRequest method calls doDispatcher() in calling doService(), doService().
Class: org.springframework.web.servlet.FrameworkServlet
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod != HttpMethod.PATCH && httpMethod != null) { super.service(request, response);//The doXXX method in this method is overridden by the FrameworkServlet } else { this.processRequest(request, response); } } protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.processRequest(request, response); } protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.processRequest(request, response); } ... ...
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); try { // To execute a service, doService() is an abstract method that is rewritten in the dispatcher servlet doService(request, response); } catch (ServletException | IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException("Request processing failed", ex); } finally { resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } logResult(request, response, failureCause, asyncManager); publishRequestHandledEvent(request, response, startTime, failureCause); } }
b>doService()
Class: org.springframework.web.servlet.DispatcherServlet
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); if (this.flashMapManager != null) { FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } RequestPath requestPath = null; if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) { requestPath = ServletRequestPathUtils.parseAndCache(request); } try { // Processing requests and responses doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } if (requestPath != null) { ServletRequestPathUtils.clearParsedRequestPath(request); } } }
c>doDispatch()
Class: org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. /* mappedHandler: Call chain Including handler, interceptorList, interceptorIndex handler: The controller method that matches the request sent by the browser interceptorList: A collection of all interceptors that handle controller methods interceptorIndex: Interceptor index, which controls the execution of interceptor afterCompletion() */ mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. // Create the corresponding processor adapter through the controller method and call the corresponding controller method HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // Call the interceptor's preHandle() if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. // The processor adapter calls the specific controller method to obtain the ModelAndView object mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); // Call postHandle() of interceptor mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // Subsequent processing: processing model data and rendering views processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
d>processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; if (exception != null) {//Handling of exceptions if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { // Processing model data and rendering views render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled.. // Call the interceptor's afterCompletion() mappedHandler.triggerAfterCompletion(request, response, null); } }
4. Execution process of spring MVC
1) The user sends a request to the server, which is captured by the DispatcherServlet, the spring MVC front-end controller.
2) DispatcherServlet parses the request URL, obtains the request resource identifier (URI), and judges the mapping corresponding to the request URI:
a) Does not exist
i. Then judge whether MVC: default servlet handler is configured
ii. If it is not configured (the current request will only be processed by the dispatchservlet), the console will report that the mapping cannot be found, and the client will display a 404 error
iii. if it is configured, access the target resources (generally static resources, such as JS, CSS and HTML). If the client is not found, a 404 error will be displayed
b) If it exists, execute the following process
3) According to the URI, call HandlerMapping to obtain all relevant objects configured by the Handler (including the Handler object and the interceptor corresponding to the Handler object), and finally return in the form of HandlerExecutionChain object.
4) DispatcherServlet selects an appropriate HandlerAdapter according to the obtained Handler.
5) If the HandlerAdapter is successfully obtained, the pre handler (...) method [forward] of the interceptor will be executed
6) Extract the model data in the Request, fill in the Handler (controller method) input parameters, and start executing the Handler (Controller) method to process the Request. In the process of filling in the Handler input parameters, Spring will help you do some additional work according to your configuration:
a) Httpmessageconverter: converts the request message (such as Json, xml and other data) into an object, and converts the object into the specified response information
b) Data conversion: perform data conversion on the request message, such as converting String to Integer, Double, etc
c) Data format: data format the request message, such as converting a string into a formatted number or a formatted date
d) Data verification: verify the validity of data (length, format, etc.), and store the verification results in BindingResult or Error (now it is generally verified directly in the browser)
7) After the handler is executed, a ModelAndView object is returned to the dispatcher servlet.
8) At this time, the postHandle(...) method of the interceptor [reverse] will be executed.
9) According to the returned ModelAndView (whether there is an exception will be judged at this time: if there is an exception, execute HandlerExceptionResolver for exception handling), select a suitable ViewResolver for View resolution, and render the View according to the Model and View.
10) After rendering the view, execute the after completion (...) method of the interceptor [reverse].
11) Returns the rendering results to the client.