Spring MVC 处理请求的完整流程详解
Spring MVC 处理请求的完整流程详解
Spring MVC 处理一个 HTTP 请求的完整流程涉及多个组件协同工作。下面我将详细说明每个步骤,并举例说明。
1. 整体流程图
Client → DispatcherServlet → HandlerMapping → Controller → HandlerAdapter → Controller Method → ModelAndView → ViewResolver → View → Response → Client
2. 详细步骤分析
步骤1:客户端发送请求
GET /users/123?name=John HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Authorization: Bearer token123
步骤2:DispatcherServlet接收请求
DispatcherServlet是Spring MVC的核心前端控制器,负责接收所有HTTP请求。
// web.xml配置(传统方式)
<servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>// 或者通过Java配置
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
步骤3:HandlerMapping查找处理器
DispatcherServlet使用HandlerMapping来确定哪个Controller应该处理当前请求。
// Controller示例
@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public User getUser(@PathVariable Long id, @RequestParam(required = false) String name) {return userService.findById(id);}@PostMappingpublic User createUser(@RequestBody User user) {return userService.createUser(user);}
}
HandlerMapping会根据请求URL /users/123
找到对应的处理器方法 getUser
。
步骤4:HandlerAdapter调用处理器
HandlerAdapter负责实际调用Controller中的方法。
// HandlerAdapter处理流程示例
public class RequestMappingHandlerAdapter {public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1. 参数解析Object[] args = getArguments(request, handler);// 2. 反射调用Controller方法Object result = invokeHandlerMethod(handler, args);// 3. 处理返回结果return getModelAndView(result);}
}
步骤5:参数解析和绑定
Spring MVC自动解析和绑定请求参数。
@GetMapping("/{id}")
public User getUser(@PathVariable Long id, // 路径变量@RequestParam(required = false) String name, // 查询参数@RequestHeader("Authorization") String token, // 请求头@CookieValue("sessionId") String sessionId, // Cookie值HttpServletRequest request) { // 原始请求对象System.out.println("ID: " + id);System.out.println("Name: " + name);System.out.println("Token: " + token);System.out.println("Session ID: " + sessionId);return userService.findById(id);
}
参数解析过程:
@PathVariable
:从URL路径中提取参数/users/123
→id=123
@RequestParam
:从查询字符串中提取参数?name=John
→name="John"
@RequestHeader
:从请求头中提取Authorization: Bearer token123
→token="Bearer token123"
- 类型转换:字符串"123"自动转换为Long类型
步骤6:数据验证
@PostMapping
public User createUser(@Valid @RequestBody User user, BindingResult bindingResult) {// 验证失败处理if (bindingResult.hasErrors()) {List<String> errors = bindingResult.getFieldErrors().stream().map(error -> error.getField() + ": " + error.getDefaultMessage()).collect(Collectors.toList());throw new ValidationException(errors.toString());}return userService.createUser(user);
}// User实体类
public class User {@NotNull(message = "ID不能为空")private Long id;@NotBlank(message = "姓名不能为空")@Size(min = 2, max = 50, message = "姓名长度必须在2-50之间")private String name;@Email(message = "邮箱格式不正确")private String email;@Min(value = 0, message = "年龄不能小于0")@Max(value = 150, message = "年龄不能大于150")private Integer age;// getters and setters
}
步骤7:执行Controller方法
@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable Long id) {User user = userService.findById(id);if (user != null) {return ResponseEntity.ok(user);} else {return ResponseEntity.notFound().build();}}@PostMappingpublic ResponseEntity<User> createUser(@RequestBody User user) {User createdUser = userService.createUser(user);// 返回201状态码和创建的资源return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);}
}
步骤8:处理返回值
Spring MVC支持多种返回值类型:
@Controller
public class ExampleController {// 1. 返回ModelAndView@RequestMapping("/page1")public ModelAndView showPage1() {ModelAndView mav = new ModelAndView("user/profile");mav.addObject("user", userService.getCurrentUser());return mav;}// 2. 返回String(视图名称)@RequestMapping("/page2")public String showPage2(Model model) {model.addAttribute("user", userService.getCurrentUser());return "user/profile";}// 3. 返回对象(@ResponseBody自动序列化为JSON)@GetMapping("/api/user/{id}")@ResponseBodypublic User getUserApi(@PathVariable Long id) {return userService.findById(id);}// 4. 使用@RestController自动序列化@GetMapping("/api/users")public List<User> getAllUsers() {return userService.findAll();}// 5. 返回ResponseEntity(包含状态码和响应头)@PostMapping("/api/users")public ResponseEntity<User> createUserWithResponse(@RequestBody User user) {User createdUser = userService.createUser(user);return ResponseEntity.created(URI.create("/api/users/" + createdUser.getId())).body(createdUser);}
}
步骤9:视图解析
如果返回的是视图名称,ViewResolver会解析视图:
// 视图解析器配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {@Beanpublic ViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver;}
}// Controller返回视图名称
@Controller
public class HomeController {@RequestMapping("/home")public String home(Model model) {model.addAttribute("message", "Hello Spring MVC!");// 返回视图名称"home"return "home";}
}// 视图解析过程:
// ViewResolver将"home"解析为"/WEB-INF/views/home.jsp"
步骤10:视图渲染
<!-- /WEB-INF/views/home.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>Home Page</title>
</head>
<body><h1>Welcome</h1><p>${message}</p><c:if test="${not empty user}"><p>Hello, ${user.name}!</p></c:if>
</body>
</html>
步骤11:响应返回客户端
// 最终HTTP响应
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 1234<html>
<head><title>Home Page</title>
</head>
<body><h1>Welcome</h1><p>Hello Spring MVC!</p>
</body>
</html>
3. 完整示例演示
让我们通过一个完整的示例来演示整个流程:
// 1. 实体类
public class Product {private Long id;private String name;private BigDecimal price;private String category;// constructors, getters, setters
}// 2. Service层
@Service
public class ProductService {public Product findById(Long id) {// 模拟数据库查询return new Product(id, "Product " + id, new BigDecimal("99.99"), "Electronics");}public List<Product> findAll() {return Arrays.asList(new Product(1L, "Laptop", new BigDecimal("1299.99"), "Electronics"),new Product(2L, "Book", new BigDecimal("29.99"), "Education"));}public Product create(Product product) {product.setId(System.currentTimeMillis()); // 简单生成IDreturn product;}
}// 3. Controller层
@RestController
@RequestMapping("/api/products")
public class ProductController {@Autowiredprivate ProductService productService;// GET /api/products/1@GetMapping("/{id}")public ResponseEntity<Product> getProduct(@PathVariable Long id) {System.out.println("Processing request for product ID: " + id);Product product = productService.findById(id);if (product != null) {return ResponseEntity.ok(product);} else {return ResponseEntity.notFound().build();}}// GET /api/products?category=Electronics&page=0&size=10@GetMappingpublic ResponseEntity<List<Product>> getAllProducts(@RequestParam(required = false) String category,@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size) {System.out.println("Getting products - Category: " + category + ", Page: " + page + ", Size: " + size);List<Product> products = productService.findAll();return ResponseEntity.ok(products);}// POST /api/products@PostMappingpublic ResponseEntity<Product> createProduct(@Valid @RequestBody Product product) {System.out.println("Creating product: " + product.getName());Product createdProduct = productService.create(product);return ResponseEntity.created(URI.create("/api/products/" + createdProduct.getId())).body(createdProduct);}
}// 4. 全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ResponseEntity<String> handleException(Exception e) {return ResponseEntity.status(500).body("Internal Server Error: " + e.getMessage());}
}
4. 请求处理流程总结
- 请求到达:客户端发送HTTP请求到服务器
- 前端控制器:DispatcherServlet接收请求
- 处理器映射:HandlerMapping根据URL找到对应的Controller方法
- 处理器适配:HandlerAdapter准备调用Controller方法
- 参数解析:解析并绑定请求参数到方法参数
- 数据验证:对输入数据进行验证
- 方法执行:通过反射调用Controller方法
- 返回处理:处理方法返回值
- 视图解析:如果需要,解析视图名称为具体视图
- 视图渲染:渲染视图生成响应内容
- 响应返回:将结果返回给客户端
整个流程中,Spring MVC通过各种组件的协同工作,大大简化了Web开发的复杂性,让开发者能够专注于业务逻辑的实现。