1, an overview of the
Before learning about SpringMVC, we need to know the MVC architecture design pattern and the three-tier architecture design of J2EE, as shown in the following figure:
The three-layer structure is shown in the figure below:
SpringMVC is a Web framework based on MVC design concept, integrated into the SpringFramework. SpringMVC, also known as the ‘S’ in ‘SSM’, uses a set of MVC annotations to make POJOs the controller for handling requests without implementing any interfaces, supports REST-style urls, and has a loosely coupled, pluggable component structure that is more extensible and flexible than other MVC frameworks.
SpringMVC is implemented based on the Servlet specification, so projects based on SpringMVC need to be supported by Servlet container servers, such as the commonly used Tomcat.
2. Get started quickly
1) Environmental preparation
The first step is to import maven dependencies required by the project, including Spring-Web, spring-webMVC, servlet-API, JSP-related dependencies, and IoC -related dependencies. The basic environment is Spring5.1.3.RELEASE, Tomcat8.
2) Logical code
① Controller
First you need to create a Controller class that will distribute requests. In SpringMVC you just mark the class with the @Controller annotation to indicate that it is a Controller class. Then you use the @requestMapping annotation to specify the request path on the method. The return value of the method is the corresponding view page (in this case, JSP).
package top.jtszt.controller; @Controller public class HelloController { @RequestMapping("/hello") public String hello(){ return "/WEB-INF/pages/hello.jsp"; }}Copy the code
② Configuration related
With the Controller class annotated with the @Controller annotation, we also need to add component scans to the IoC container:
<! -- SpringMVC-config.xml --> <beans ... > <context:component-scan base-package="top.jtszt"/> </beans>Copy the code
The core controller of SpringMVC is a Servlet called DispatcherServlet. So we need to configure it in web.xml, and we need to configure the corresponding Spring configuration file pointing and startup levels:
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMVC-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Copy the code
Classpath :{servlet-name}-servlet. XML is the default path for the Spring configuration file. If the path is /, the JSP page will be blocked. And JSP is what we use to display, can’t intercept.
Next, configure the Tomcat and JSP pages
(3) test
Once configured, we can launch the project and view the effect in the browser.
View resolver
1) overview
The ViewResolver in SpringMVC is one of the nine components in the front controller that converts a logical view into a physical view. SpringMVC converts the return value of the String/ModelAndView/View type of the controller class to ModelAndView, which the View parser then parses into a View object of the specific View type.
The ViewResolver interface has several main implementation classes that implement view resolution:
- BeanNameViewResolver: Resolves the view name to a Bean
- InternalResourceViewResolver: the view name resolves to a URL files
- JasperReportsViewResolver: the view name resolves to report file corresponding to the URL
We can choose one view parser or mix multiple view parsers, and each view parser implements the Ordered interface and exposes an order attribute, which can be used to specify the priority of the parsers. The smaller the order, the higher the priority.
2) Parse prefixes and suffixes
In InternalResourceViewResolver are generally used on the interpretation of the JSP page, the most common is to configure the view resolution of prefixes and suffixes, for XML configuration configuration bean can directly:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
Copy the code
Prefix stands for the beginning of the parser string, suffix stands for the end of the parser string. After this configuration, we only need to return Hello in the controller class.
/WEB-INF/pages/hello.jsp ---> hello
Copy the code
3) String or not?
There is also the question of whether or not the return value is conjoined. Normally, the return value is conjoined with the specified prefix and suffix and then returned to the view. The view parser will not conjoin the prefix and suffix if either of the following conditions occurs:
- The return value to
forward:
At the beginning, it stands for direct forwarding - The return value to
redirect:
At the beginning, it represents a redirect
Except for the above two cases, all other cases will be pieced together.
4. Data transfer and parameter binding
Now that request distribution and response are available, what if the data on a page needs to be rendered on request? In other words, what about data transfer? You can then place the data in the Request field and retrieve the corresponding data on the page. The traditional way of introducing HttpServletRequest delivery is not introduced, but rather the data delivery functionality provided in SpringMVC.
1) ModelAndView
The ModelAndView encapsulates the data and returns the jump view information, where the data stored is actually stored in the Request domain. You can pass a ModelAndView object at the parameter location, then call setViewName to set the view name, and call addObject to set the data information (key-value pairs) to be placed.
@RequestMapping("/hello")
public ModelAndView hello(ModelAndView mv) {
mv.addObject("msg"."this is msg from modelAndView");
mv.setViewName("hello");
return mv;
}
Copy the code
You can also manually create a ModelAndView object, pass in the name of the view to jump to, and then call the object’s addObject method to set the data information.
@RequestMapping("/hello")
public ModelAndView hello(a){
ModelAndView modelAndView = new ModelAndView("hello");
modelAndView.addObject("msg"."this is msg from modelAndView");
return modelAndView;
}
Copy the code
${MSG} ${MSG}
Of course, not only simple information can be passed in here, but also Map, List, etc., in the JSP page through C :foreach can be retrieved.
2) Map and Model
Spring MVC creates an implicit Model object as a storage container for Model data before calling a method. If method inputs are of type Map or Model, Spring MVC passes a reference to the implicit Model to those inputs.
In the method body, we can access all the data in the model through the input object, and we can also add new attribute data to the model.
In fact, any incoming Model, Map, or ModelMap will eventually be converted to a BindingAwareModelMap object.
@RequestMapping("/hello")
public String hello(ModelMap modelMap, Map
map, Model model)
,object>{
modelMap.addAttribute("msg"."hello modelMap");
map.put("msg2"."hello map");
model.addAttribute("msg3"."hello model");
return "hello";
}
Copy the code
3) Parameter collection
① Native data types
In addition to declaring HttpServletRequest at the input location and then retrieving the parameters via Request.getParameter (), this type of data can also be passed the parameters to be retrieved directly at the input location.
@RequestMapping("/hello")
public String hello(HttpServletRequest request) {
String name = request.getParameter("name");
System.out.println("name is "+ name);
return "result";
}
Copy the code
@RequestMapping("/hello")
public String hello(String name) {
System.out.println("name is "+ name);
return "result";
}
Copy the code
When we call /hello? If name=”test”, the result can be successfully printed in the controller.
② Model type
Suppose we have an Employee object with id and name attributes. Now we need to wrap the name and ID from the parameters into an Employee object. We don’t need to do this manually. In SpringMVC, if a request parameter name corresponds to a property in the model class, SpringMVC automatically matches the request parameter name with the POJO property name, automatically populates the object with property values, and supports cascading properties.
@RequestMapping("/hello")
public String hello(Employee employee) {
System.out.println("Employee is "+ employee);
return "result";
}
Copy the code
When we call /hello? If id=1&name=”test”, the result can be printed successfully in the controller.
③ Use notes
In SpringMVC, the @requestParam annotation can also be used to obtain parameters. This method does not require the user to participate in the specified parameter one-to-one mapping, but can specify the parameter name to obtain.
@RequestMapping("/hello")
public String hello(@RequestParam("username")String name) {
System.out.println("name is "+ name);
return "result";
}
Copy the code
Call /hello? If username=”test”, the result can be successfully printed in the controller.
Now that we’ve solved the problem of getting inconsistent parameter names, what about access without parameters? Measurement throws exceptions because the default is to pass in parameters. This annotation also has an attribute, required, which indicates whether the specified parameters must be carried in the request parameters. The default value is true. There is also an attribute, defaultValue, that specifies the defaultValue if the parameter is not passed.
@RequestMapping("/hello")
public String hello(@RequestParam(value = "username",required = false,defaultValue = "default")String name) {
System.out.println("name is "+ name);
return "result";
}
Copy the code
Access to /hello does not throw an exception and prints default.
④ Other notes
In addition to the annotation to get parameters, SpringMVC also has an annotation @requestheader to get the value of a header property, and an annotation @cookievalue to get the value of a cookie property.
@RequestMapping("/hello")
public String hello(@RequestHeader("User-Agent")String userAgent,
@CookieValue("JSESSIONID")String jid){}
Copy the code
4) Garbled code
When receiving the POST request parameters, there may be a problem with Chinese garbled characters due to inconsistent encoding sets. Request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request request ForceResponseEncoding specifies the encoding for the response. Here we just need to configure the filter in web.xml and set the intercepting path to /*.
<web-app>
<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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/ *</url-pattern>
</filter-mapping>
</web-app>
Copy the code
If the GET request is garbled, you should consider the Encoding Settings of Tomcat.
5. Request mapping
SpringMVC uses the @RequestMapping annotation to specify which URL requests the controller can handle. This annotation can be annotated on a class or on a method. If @requestMapping (“/admin”) is annotated on a class, then all methods under that class must be accessible with /admin as the prefix.
/ / such as:
@Controller
@RequestMapping("/admin")
public class MyController {}
Copy the code
@RequestMapping("/hello")
public String hello(a) {return "hello"}
Copy the code
To access the hello. JSP page, you must use /admin/hello.
In addition, @requestMapping also provides some restriction attributes for request headers. Value represents the request URL, method represents the request method, params represents the request parameters, and heads represents the request headers. The combination of multiple conditions makes the request mapping more precise.
In addition, SpringMVC provides several annotations that define how requests are made:
- @getMapping (“xx”) : Specifies the GET mode
- @postMapping (“xx”) : Specifies the POST mode
- @putMapping (“xx”) : Specifies the PUT mode
- @deletemapping (“xx”) : Specifies the delete mode
RESTful style
REST, or Representational State Transfer, is one of the most popular Internet software architectures. It has a clear structure, meets standards, is easy to understand, easy to expand, so more and more sites are using it.
Each request represents an interaction between the client and the server. HTTP is a stateless protocol, that is, all states are stored on the server side. Therefore, if the client wants to operate the server, it must somehow make a “state transition” occur on the server side. This transformation is based on the presentation layer, so it is the “presentation layer state transformation”.
To be specific, there are four verbs in the HTTP protocol that denote operation modes: GET, POST, PUT, and DELETE. They correspond to four basic operations: GET to obtain resources, POST to create resources, PUT to update resources, and DELETE to DELETE resources. The RESTful style relates these four approaches to the operation of resources.
For example, suppose you want to add, delete, change, and check employee information. A RESTful URL might look something like this:
- Employee list: /emps get method
- Employee add: /emp post method
- Employee modification: /emp/{id} put method
- Employee delete: /emp/{id} delete method
- Employee query: /emp/{id} get method
{id} here represents the dynamic id passing in. In SpringMVC, you can use @pathVariable (” ID “) notation in the Controller parameter position to get the specified value in the URL.
@RequestMapping(value = "/emp/{id}")
public String getEmp(@PathVariable("id")Integer id){... }Copy the code
So that when we access /emp/1 as GET, we can GET the specific ID in the getEmp method.
7. Return JSON data
1) Package guide and configuration
SpringMVC integrates mainstream JSON conversion tools and uses Jackson for JSON format conversion by default. Using Jackson requires maven dependencies, including jackson-core, Jackson-Annotations, and jackson-databind. After importing the dependencies, you also need to configure the JSON converter. An easy way to do this is to include an annotation-driven configuration in the SpringMVC configuration file, or you can do it manually.
<! -- Enable annotation driver -->
<mvc:annotation-driven/>
Copy the code
2) @ ResponseBody
You also need to annotate @responsebody on the Controller corresponding method to indicate that the method return information is returned as the ResponseBody (wrapped in json format by the Jackson package).
// False data for example
Employee emp = new Employee(1."test01"."[email protected]");
Copy the code
@ResponseBody
@RequestMapping("/getinfo")
public Employee getInfo(a){
return emp;
}
Copy the code
You can also set the return value type to ResponseEntity
and then new the object in a method that sets the response body, response header, and response status code.
@RequestMapping("/getinfo2")
public ResponseEntity<Employee> getInfo2(a){
return new ResponseEntity<>(emp,HttpStatus.OK);
}
Copy the code
3) @ RestController
When all mapping methods in a Controller class return JSON data, it is not practical to annotate @responseBody on each method. You can annotate @responseBody directly on the class, or you can annotate it on the Controller class using the @RestController annotation, which is equivalent to @Controller and @responseBody.
4) @ RequestBody
The opposite of @responsebody is @requestbody, which wraps json-formatted data in the RequestBody into a specified object.
@PostMapping("/saveinfo")
@ResponseBody
public void saveInfo(@RequestBody Employee employee) {
System.out.println(employee);
}
Copy the code
When we POST this path with jSON-formatted data, it encapsulates the data in the request body (if there is a pair) as an Employee object.
You can also declare the parameter as HttpEntity
, so that the declared parameter can get the request header as well as the request body.
@PostMapping("/saveinfo2")
@ResponseBody
public void saveInfo(HttpEntity<Employee> httpEntity) {
Employee emp = httpEntity.getBody();
System.out.println(emp);
}
Copy the code
8. Static resource configuration
1) Default processor
If we try to import js or CSS from the project path, we will find that it is not accessible. The problem is that we configured the DispatcherServlet request mapping in SpringMVC as /, in which case the static resource request is also treated as a normal request and an error occurs because the corresponding processor cannot be found.
The default handler can be configured in the SpringMVC configuration file to solve the static resource problem:
<mvc:default-servlet-handler/>
Copy the code
Work is defined, the SpringMVC context DefaultServletHttpRequestHandler, it will enter the DispatcherServlet request for screening, if found to be without the mapping request, The request is processed by the default Servlet of the WEB application server; If it is not a static resource request, the DispatcherServlet will continue to process it. The default Servlet name of a WEB application server is default. If the default Servlet name of the WEB server is not default, you need to specify it explicitly using the default-servlet-name attribute
2) Parse the configuration
In addition to using default processor resolution, you can explicitly configure resolution for static resources. This is configured using the XML < MVC: Resources > tag, where cache-period indicates the cache duration.
<mvc:resources mapping="/js/**" location="/scripts/" />
<mvc:resources mapping="/css/**" location="/css/" cache-period="2592000" />
Copy the code
Access to js files is resolved to the project’s scripts directory, and CSS is resolved to the CSS directory.
9. File upload and download
1) File upload
(1) guide rely on
You need to import the dependencies required for file uploading, including commons-Fileupload, commons-io, and IoC and MVC dependencies.
(2) write configuration
In the XML-based configuration, a file upload handler (CommonsMultipartResolver) needs to be configured first. DefaultEncoding can be used to set the file encoding, maxUploadSize can be used to set the maximum file size. Note that the id of the configured bean must be multipartResolver, otherwise it will not be recognized.
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="# {1024 * 1024 * 20}"/>
</bean>
Copy the code
③ Receiving files
Now write a JSP page with a form containing the file to upload to /upload under the project:
<form action="${ctp}/upload" method="post" enctype="multipart/form-data"> File upload: <input type="file" name="uploadFile"/>
<input type="submit" value="Submit"/>
</form>
Copy the code
At the Controller layer we write a method to handle the /upload request, passing in a parameter of type MultipartFile to receive the uploaded file:
@Controller
public class UploadController {
@PostMapping("/upload")
public String upload(@RequestParam("uploadFile")MultipartFile file){...}
}
Copy the code
④ Save the file
MultipartFile has a getOriginalFilename method that can be used to get the original file name. If the file is saved locally, the MultipartFile transferTo() can be called. New File(xx) can be persisted to the local. If you want to save to the database, you can get the file’s bytecode to save.
file.transferTo(new File("I:\upload\"+filename)); byte[] bytes = file.getBytes();Copy the code
2) File download
To download the file, place the file’s byte[] data in the ResponseEntity<> that was written earlier, then set the response header and return the object, which is shown here as an image display.
@Controller
public class DownloadController {
@RequestMapping("/getImg")
public ResponseEntity<byte[]> getImg() throws IOException {
String filename = "I:\upload\mvc.png";
byte[] bytes = Files.readAllBytes(Paths.get(filename));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", filename);
return newResponseEntity<>(bytes, headers, HttpStatus.CREATED); }}Copy the code
Just use an IMG tag on the JSP page.
<img src="${pageContext.request.contextPath}/getImg">
Copy the code
10. Exception handlers
So far, all of our exceptions have been thrown directly, and when we use the GET method to access a path that restricts access to the POST method, we get Tomcat’s exception page, which is very user experience unfriendly and code security problematic. So we need to have the DispatcherServlet, the front controller, handle the exception.
Spring MVC has four main implementation classes that handle exceptions through HandlerExceptionResolver exceptions, including Handler mapping, data binding, and exceptions that occur when the target method executes:
- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
- SimpleMappingExceptionResolver
1) ExceptionHandlerExceptionResolver
The exception parser primarily handles exceptions marked with the @ExceptionHandle annotation, which is provided by SpringMVC to declaratively catch the specified exception. Annotation of this annotation can be divided into two types: one is configured in the class that marks @Controller, also known as the class configuration; One is to configure in a separate class, also known as global configuration.
① This configuration
Create a @ExceptionHandle(value=”xx”) annotation on the class’s method annotation. The value attribute specifies the exception to catch. The return value of this method is parsed by the view parser.
@ExceptionHandler(value = {NullPointerException.class} )
public ModelAndView exceptionHandle(NullPointerException npe){
npe.printStackTrace();
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception",npe.getMessage());
return mv;
}
Copy the code
② Global Configuration
Create a class for handling exceptions, annotating @ControllerAdvice to indicate that this class is intended to handle exceptions centrally. Next, define the exception handling method. The procedure is the same as that configured in this class.
@ControllerAdvice
public class ExceptionController {
@ExceptionHandler(value = {NullPointerException.class})
public ModelAndView exceptionHandle(NullPointerException npe){
npe.printStackTrace();
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception",npe.getMessage());
returnmv; }}Copy the code
If both the global and this class have configuration exception handling, this class takes precedence. If more than one handler catches the exception, precision takes precedence.
2) ResponseStatusExceptionResolver
The reason attribute indicates the error cause, and the value attribute and code attribute indicate the HttpStatus error code. This annotation is primarily annotated on the custom exception class, and then the error type is thrown at the code logic exception handler, which SpringMVC will call when caught.
// Create a custom exception class
@responsestatus (reason = "user access exception ", code = httpstatus.not_acceptable)
class UserNotFoundInAdminException extends RuntimeException{
static final long serialVersionUID = 1L;
}
Copy the code
@RequestMapping("/admin")
public String loginAdmin(@RequestParam("user")String user){
if(user! ="admin") {throw newUserNotFoundInAdminException(); }... }Copy the code
3) SimpleMappingExceptionResolver
For configuring simple exception resolution, which can be configured in the SpringMVC configuration file. Which class for class for SimpleMappingExceptionResolver full name of the class, all the key is to deal with the abnormal exceptionMappings attribute class name, the value for abnormal jump after view name; The value of the exceptionAttribute attribute is the key in the domain where the exception information is stored.
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.NullPointerException">error</prop>
</props>
</property>
<property name="exceptionAttribute" value="ex"/>
</bean>
Copy the code
4) DefaultHandlerExceptionResolver
Used to handle exceptions that come with SpringMVC, and when no other exception parser is found, the exception parser is used to resolve.
11. Interceptor
1) overview
First, there are some distinctions between interceptors and filters. An interceptor is an API design in SpringMVC, and a filter is a component in a Servlet. All requests that go through the Servlet container can be intercepted by the filter, whereas the interceptor is only valid for requests that go through the DispatcherServlet. In addition, interceptors are centrally managed through IoC, so they can be injected arbitrarily.
2) configuration
The core interface of the interceptor is HandleInterceptor, which is implemented by custom intercepting rules. There are three main methods in this interface, representing three execution times:
- PreHandle: Before the target method is run, return true to permit;
- PostHandle: after the target method runs;
- AfterCompletion: After the view responds;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle.....");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle.....");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion....."); }}Copy the code
We then need to register the interceptor with the IoC container, using the < MVC: Interceptors > tag, which also means that you can register multiple interceptors; The < MVC :interceptor> tag contains a < MVC: Mapping > to configure the interceptor path and a
to configure the interceptor:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/"/>
<bean class="top.jtszt.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
Copy the code
3) Intercept the process
From the above we can see that the interceptor runs at three times: before the target method runs, after the target method runs, and after the view responds. The request flow with interceptors is roughly as follows:
- preHandle
- Target method run
- postHandle
- View the response
- afterCompletion
4) Multiple interceptors
Assuming that two interceptors are configured, the first one is named interceptor1 and the second interceptor2 in the configuration order.
12. Cross-domain issues
Cross-domain indicates that the domain that initiates the request is different from the domain of the resource to which the request is directed. The concept of domain refers to the protocol, domain name, and port (same-origin policy). It only belongs to the same domain if all three are the same. When any one of these three is different, cross-domain problems arise.
SpringMVC can annotate @Crossorigin annotations on methods that allow cross-domain, on which cross-domain scopes can be specified. This annotation actually adds an access-Control-Allow-Origin: to the response header.
References:
- The Spring Framework 5.1.3.release documentation
- Learn Spring- Nuggets from 0
- Brief introduction to MVC and three-tier architecture -CSDN
- SpringMVC view parser -CSDN
- Spring5 system architecture -CSDN
- Leifeng Spring, Spring MVC, MyBatis course – Bilibili