Spring MVC

Core execution process
When Spring MVC processes requests, the main components and responsibilities are as follows:
DispatcherServlet: Front-end controller that uniformly receives requests and coordinates subsequent processing processes.HandlerMapping: Method to find the corresponding processor based on the request address.HandlerAdapter: Call the processor in a unified way and complete parameter analysis and other work.Handler: Controller method for actually processing requests.ModelAndView: Encapsulate model data and logical view names at the same time.ViewResolver: Parse logical view names into specific views.View: Responsible for rendering response content.
Build a traditional Spring MVC project
Creating the Maven Web Project
Introduce Spring MVC dependencies. The following versions only correspond to the original course example environment:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
Configure DispatcherServlet
Register the front-end controller in web.xml:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>/ means having DispatcherServlet handle most requests except for special requests inside the container, while still having static resources processed by the default Servlet. Configuration with /* is generally not recommended because it may affect container behavior such as JSP forwarding.
Create a Spring MVC configuration file
<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
https://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.hyxy.controller"/>
<mvc:annotation-driven/>
</beans>creation controller
@Controller
public class TestController {
@RequestMapping("/test")
@ResponseBody
public String test() {
return "test";
}
}
After starting the server and accessing /test, test will be returned in the response body.
request map
@RequestMapping
@RequestMapping can modify classes and methods. Classes usually represent a uniform address prefix; methods represent specific request mappings.
Common attributes include:
valueorpath: Request address.method: Allowed request methods.params: Require the request to include or not include the specified parameters.headers: Further restrict mapping based on request headers.consumes: Limit the media type of the request body.produces: Statement response media type.
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/add", method = RequestMethod.POST)
@ResponseBody
public String add() {
return "add";
}
}In actual projects, more semantically explicit combination annotations, such as @GetMapping, @PostMapping, @PutMapping and @DeleteMapping, can also be used.
Request parameter binding
Binding simple parameters
Spring MVC can automatically bind when the request parameter name is the same as the method parameter name. If parameter names are not reserved at compile time, or if you want to specify parameter names explicitly, use @RequestParam.
@GetMapping("/user")
@ResponseBody
public String getUser(
@RequestParam(name = "name") String username,
@RequestParam(name = "age", required = false, defaultValue = "0") Integer age) {
return username + ":" + age;
}
When using basic types to receive optional parameters, missing parameters will cause type conversion to fail, so optional numeric parameters generally use wrapper types.
Binding path variables
@GetMapping("/add/{name}/{pwd}")
@ResponseBody
public String add(
@PathVariable("name") String username,
@PathVariable("pwd") String password) {
return username + ":" + password;
}
For example, when accessing http://localhost:8088/mvc/test/add/tom/123, the value of username is tom, and the value of password is 123.
Read request headers and cookies
@GetMapping("/header")
@ResponseBody
public String header(
@RequestHeader("Accept") String accept,
@CookieValue(value = "username", defaultValue = "rose") String username) {
return accept + ":" + username;
}
Binding Java objects
When the request parameter name is the same as the object property name, you can bind the parameter to the object.
@PostMapping("/emp")
@ResponseBody
public Emp add(Emp emp) {
return emp;
}
For associated objects, you can use property paths to pass parameters. For example, when Emp includes Dept dept, the request parameter can be written as dept.deptName=开发部.
public class Emp {
private String empNo;
private String empName;
private Dept dept;
// getter 和 setter
}
public class Dept {
private String deptName;
// getter 和 setter
}Get Servlet API objects
When you need to access the original request or session, you can declare it directly in the controller method parameters.
@GetMapping("/request-info")
@ResponseBody
public String requestInfo(HttpServletRequest request, HttpSession session) {
session.setAttribute("method", request.getMethod());
return request.getMethod();
}
Business code should not rely too much on the Servlet API. For scenarios that can be completed through annotations and parameter binding, Spring MVC’s parameter parsing mechanism should be preferred.
View jumps and model data
Returns the logical view name
@GetMapping("/books")
public String books(Model model) {
model.addAttribute("bookList", List.of("Java", "Spring"));
return "book/list";
}
When combined with the view parser, book/list will be parsed into a specific page path.
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
Return to ModelAndView
@GetMapping("/detail")
public ModelAndView detail() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", "Spring MVC");
modelAndView.setViewName("book/detail");
return modelAndView;
}
Static resource processing
Static resource mappings can be explicitly configured:
<mvc:annotation-driven/>
<mvc:resources mapping="/html/**" location="/html/"/>
You can also use the default Servlet to handle unmatched static resources:
<mvc:default-servlet-handler/>
Separate development of front and rear ends
@RequestBody
@RequestBody will read the request body and convert JSON into Java objects through a message converter. The request header should usually contain Content-Type: application/json.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
@RestController
@RequestMapping("/test")
public class TestController {
@PostMapping("/emp")
public Emp save(@RequestBody Emp emp) {
return emp;
}
}

JSON field names should match Java attribute names. When field naming is inconsistent, you can use Jackson annotations to map.
@ResponseBody
@ResponseBody means to write the method return value to the response body. When returning an object, Spring MVC serializes it into JSON through a message converter; when returning a string, it usually writes the text directly.
@GetMapping("/get")
@ResponseBody
public User get() {
User user = new User();
user.setUsername("jack");
user.setPassword("123456");
return user;
}
@RestController
@RestController is equivalent to the class-level combination of @Controller and @ResponseBody, and is suitable for controllers with JSON as the main response content.
Unified response object
public class Result<T> {
private boolean success;
private T data;
private String message;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.success = true;
result.data = data;
return result;
}
public static <T> Result<T> failure(String message) {
Result<T> result = new Result<>();
result.success = false;
result.message = message;
return result;
}
// getter 和 setter
}cross-domain requests
The browser’s same-origin policy restricts scripts from accessing resources from different sources. The source is determined by the protocol, host and port, and any difference is a cross-source request.
Using @CrossOrigin
@RestController
@RequestMapping("/book")
@CrossOrigin(origins = "http://localhost:8081")
public class BookController {
}
Globally configure CORS
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8081")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}When opening credentials, you cannot simply configure the allowed source as a wildcard. The production environment should only open up the sources, methods and requests that are actually needed.
Front-end proxy versus Nginx reverse proxy
Development environments can request through the front-end development server proxy interface; production environments usually use Nginx to unify front-end static resources and back-end interfaces into the same site.


The reverse proxy only changes the request forwarding method and does not replace the backend’s own authentication, authority verification, and input verification.
file upload
Profile parser
In traditional Spring MVC projects, CommonsMultipartResolver can be configured:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5242880"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
The form should use POST request and set enctype="multipart/form-data".
Write an upload interface
@RestController
public class FileUploadController {
private static final Path UPLOAD_DIR = Paths.get("D:/Lesson/uploadFile");
@PostMapping("/upload")
public Result<String> upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Result.failure("上传文件不能为空");
}
String originalName = file.getOriginalFilename();
String safeName = originalName == null
? UUID.randomUUID().toString()
: Paths.get(originalName).getFileName().toString();
try {
Files.createDirectories(UPLOAD_DIR);
Path target = UPLOAD_DIR.resolve(safeName).normalize();
if (!target.startsWith(UPLOAD_DIR)) {
return Result.failure("文件名不合法");
}
file.transferTo(target);
return Result.success(safeName);
} catch (IOException e) {
return Result.failure(e.getMessage());
}
}
}Do not directly trust the original file name submitted by the client. Actual projects should also check file size, extension, MIME type and storage permissions, and avoid exposing the upload directory as an executable directory.

If you enjoyed this, leave a comment~