1. The background

Sping MVC is a framework on top of Spring for developing Web applications.

2. Preliminary understanding of Spring MVC

2.1 knowledge

Spring MVC is a Web Framework built on Servlet APIS and included in the Spring Framework. MVC means model, view, controller, and Spring MVC implements this idea.

Spring MVC separates the roles of controller, model object, filter, and handler object, which makes them easier to customize.

Spring MVC doesn’t rely on JSP and can use other template engines (JSP, Thymeleaf, etc.). The JSON format returned by RESTful apis can be interpreted as a JSON View, which is also MVC.

Spring MVC, like many other Web frameworks, is designed around a front Controller pattern, where dispatcherServlets provide a unified entry point for request processing and delegate components handle the actual work.

An HTTP request passes through Spring MVC as follows:

  • 1. The HTTP request arrives at the DispactcherServlet with the content requested by the user, such as forms.
  • 2 and 3. The DispactcherServlet needs to delegate the request to other components. It queries Handler Mapping to determine which Controller to forward the request to.
  • 4 and 5. The DispactcherServlet forwards the request to the specifically selected Controller, which accesses the service and database to get the Model and returns a view name.
  • 6 and 7, the DispactcherServlet sends the model and View to a View Resolver, which uses the model to render output to the View.
  • 8 and 9. The DispactcherServlet returns the rendered content of the view and responds to the requested content to the client.

2.2 Write a lean MVC project

Having just described the process that a request goes through and mentioned several components, let’s take a closer look at this by building the base version of the project.

Traditional Web projects require a web.xml configuration, including configuration mapping of servlets, request mapping, view parsing, exception handling, delegate components, and so on. The DispatcherServlet needs to know about these configurations.

Instead of doing this, Java code configures the DispatcherServlet. Through inheritance AbstractAnnotationConfigDispatcherServletInitializer, when it is deployed in the servlet 3.0 container, the container automatically find it and application configuration, example:

/** * Init helper class for Web App. Is equal to the web. XML * / public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@ Override  protected Class<? >[] getRootConfigClasses() { return new Class<? >[]{RootConfig.class}; } @Override protected Class<? >[] getServletConfigClasses() { return new Class<? >[]{ServletConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; }}Copy the code

The configuration description in the above code is as follows:

  • The class returned by getRootConfigClasses() will be used to configure the Bean in the application context created by ContextLoaderListener.
  • GetServletConfigClasses () returns classes to configure Web applications, such as controllers, view parsers, and so on.

There are usually two contexts in a Web application:

  • Servlet WebApplicationContext: contains controller, view parser, Handler mapping, etc.
  • Root WebApplicationContext: Typically contains infrastructure beans, such as data repositories and business service beans.

The relationship is as follows:

I have an empty RootConfig here.

@Configuration
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)})
public class RootConfig {
}

Copy the code

A JSP view parser is configured in the ServletConfig class.

@Configuration @EnableWebMvc @ComponentScan public class ServletConfig extends WebMvcConfigurerAdapter { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); }}Copy the code

Write a simple Controller

@Controller @RequestMapping("/main") public class HelloWorldController { @RequestMapping(value = "/say", method = RequestMethod.GET) public String sayHello(Model model) { model.addAttribute("yourname", "zhangsan"); return "welcome"; }}Copy the code

Welcome.jsp file code:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <! PUBLIC DOCTYPE HTML "- / / / / W3C DTD HTML 4.01 Transitional / / EN" "http://www.w3.org/TR/html4/loose.dtd" > < HTML > < head > < meta  http-equiv="Content-Type" content="text/html; </h1> Your Name: ${yourname} </body> </ HTML >Copy the code

A streamlined version of the project using Spring with Spring MVC is set up. My complete code example is at: github.com/vir56k/java…

2.3 Reading Parameters in the Request

The following parameters are supported:

  • Query string
  • In the Form Form
  • In the request path

Example:

Use @requestParam to read the parameter values in the query string or form data

    @GetMapping
    public String setupForm(@RequestParam("petId") int petId, Model model) { 
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }
Copy the code

Use @pathVariable annotation to read qingqi path parameters.

@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") 
public void findPet(@PathVariable String petId) {
    // ...
}
Copy the code

2.4 Validity verification of parameters

The Spring Framework provides support for the Java Bean Validation API.

Example:

public class PersonForm {

    @NotNull
    @Size(max=64)
    private String name;

    @Min(0)
    private int age;
}
Copy the code
public class User { private String email; @NotNull @Email public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } public class UserService { public void createUser(@Email String email, @NotNull String name) { ... }}Copy the code

For more information: beanvalidation.org/

2.5 View Rendering

And similar JSP development is an ancient method. More recent is the Thymeleaf framework. At present, the more popular development method is the technology of front and back end separation, using ReactJS, VUE to develop the project separately. This article will not cover more.

2.6 Using HTTP Message Converter

Message Converter Message conversion provides a more direct way to convert the data generated by the controller into a representation (JSON, XML, etc.) that serves the client.

When using message transformation, the DispatcherServlet no longer delivers model data to the view, it converts directly to the specified format through the message converter.

Such as If Jackson JSON classpath, then the processing method returns the object will be in the hands of MappingJacksonHttpMessageConverter to deal with.

Normally, when a handler returns a Java object, it is placed in the model and rendered for use in the view. However, if message transformation is used, we need to tell Spring to skip the normal model/view flow and use a message translator. The easiest way to do this is to annotate the controller method with @responseBody.

@RequestMapping("/login")
@ResponseBody
public Object login(String name, String password, HttpSession session) {
	...
	return new JsonResult(user);
}
Copy the code

If you use @RestController instead of @Controller on a Controller class, Spring will apply message conversion to all of the Controller’s processing methods. We don’t have to add @responseBody to every method.

@RestController
public class XxxController{
   ...
}
Copy the code

A controller method can return a ResponseEntity object. ResponseEntity can contain response-related metadata, such as header information and status codes, as well as the object entity to be transformed.

@GetMapping("/custom")
ResponseEntity<String> custom() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Custom-Header", "foo");

    return new ResponseEntity<>(
      "Custom header set", headers, HttpStatus.OK);
}
Copy the code

2.7 extensions

UriComponentsBuilder Spring provides UriComponentsBuilder that can give us some help. It is a build class that we can use to build UriComponents instances by progressively specifying various components in the URL, such as host, port, path, and query.

UriComponents uriComponents=UriComponentsBuilder
        .fromHttpUrl("http://localhost:8080//hello")
        .queryParams(params).build() 
String uri=uriComponents.toUriString();
Copy the code

RequestMapping @requestmapping identifies this as a RequestMapping, and there are other methods based on this extension, such as the following, which can be inferred by name.

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

Custom servlet and filter extension, through inheritance WebApplicationInitializer can register a custom servlet and filter:

Initialization / * * * * / public web application class MyWebApplicationInitializer implements WebApplicationInitializer {public void OnStartup (ServletContext ServletContext) throws ServletException {/ / registered a servlet ServletRegistration. Dynamic servlet =  servletContext.addServlet("myservlet1", MyServlet.class); servlet.addMapping("/custom/**"); / / register a filter FilterRegistration. Dynamic filter1 = servletContext. AddFilter (" filter1, "MyFilter1. Class); filter1.addMappingForUrlPatterns(null, false, "/custom/*"); }}Copy the code

Multipart parser and file upload Register a Multipart parser

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { // ... @Override protected void customizeRegistration(ServletRegistration.Dynamic registration) { // Optionally also set maxFileSize, maxRequestSize, fileSizeThreshold registration.setMultipartConfig(new MultipartConfigElement("/tmp")); }}Copy the code

Receiving uploaded Files

@Controller
public class FileUploadController {

    @PostMapping("/form")
    public String handleFormUpload(@RequestParam("name") String name,
            @RequestParam("file") MultipartFile file) {

        if (!file.isEmpty()) {
            byte[] bytes = file.getBytes();
            // store the bytes somewhere
            return "redirect:uploadSuccess";
        }
        return "redirect:uploadFailure";
    }
}
Copy the code

Spring MVC provides several ways to turn exceptions into responses:

  • Specific Spring exceptions are automatically mapped to HTTP status codes
  • The @reponseStatus annotation is used on an exception to map it to an HTTP status code
  • The @ExceptionHandler annotation is used on the method to indicate that an exception is being handled.

The @responseStatus annotation’s custom exception is automatically mapped to the HTTP status code:

@responseStatus (value = httpstatus. NOT_FOUND, reason = "") @responseStatus (value = httpstatus. NOT_FOUND, reason =" ) public class MyException extends RuntimeException { }Copy the code

Catch exceptions with the @ExceptionHandler annotation: When the @ExceptionHandler is applied to the Controller class, you can catch exceptions for this Controller.

// @exceptionHandler @ExceptionHandler(myException2.class) Public String handleException() {return "errorrrr"; }Copy the code

The @ExceptionHandler annotation combined with “Controller notification” catches exceptions for all controllers.

Controller advise is a class annotated with the @ControllerAdvice annotation. This class can be used with the following annotations:

  • @ExceptionHandle Method of labeling
  • InitBinder annotation method
  • Method of the @modelAttribute annotation

In a class labeled @ControllerAdvice, the above three methods are applied to the @requestMapping method on all controllers in the application. Example:

@controllerAdvice public class ExceptionHandler {// @exceptionHandler @ExceptionHandler(myException3.class) Public String handleException() {return "errorrrr"; }}Copy the code

Example 3.

Examples of my code can be found at: github.com/vir56k/java…

4. Reference:

Docs. Spring. IO/spring – fram…

Websystique.com/springmvc/s…