Spring MVC 架构:请求处理流程
核心理念
Spring MVC 是一个基于 Model-View-Controller 设计模式的 Web 框架。在现代 REST API 开发中,我们主要使用其请求处理和数据绑定能力。
Spring MVC 核心组件
1. DispatcherServlet - 前端控制器
所有请求的入口,负责分发请求到对应的 Controller。
HTTP Request → DispatcherServlet → HandlerMapping → Controller → Service → Repository
↓
HTTP Response ← ViewResolver/MessageConverter ←────────────┘2. Controller - 控制器
java
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}注解说明:
@RestController=@Controller+@ResponseBody- 自动将返回值转换为 JSON(通过 Jackson)
3. @RequestMapping 系列注解
java
@GetMapping("/users") // GET /users
@PostMapping("/users") // POST /users
@PutMapping("/users/{id}") // PUT /users/1
@DeleteMapping("/users/{id}") // DELETE /users/1
@PatchMapping("/users/{id}") // PATCH /users/1参数绑定
1. 路径变量 @PathVariable
java
@GetMapping("/users/{id}/posts/{postId}")
public Post getPost(
@PathVariable Long id,
@PathVariable Long postId
) {
return postService.findByUserAndId(id, postId);
}2. 查询参数 @RequestParam
java
@GetMapping("/users")
public List<User> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size
) {
return userService.search(name, page, size);
}URL示例:GET /users?name=John&page=0&size=20
3. 请求体 @RequestBody
java
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.save(user);
}自动转换:Jackson 将 JSON 转换为 Java 对象
4. 请求头 @RequestHeader
java
@GetMapping("/protected")
public String protectedResource(
@RequestHeader("Authorization") String token
) {
return "Token: " + token;
}响应处理
1. ResponseEntity - 完全控制响应
java
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(user -> ResponseEntity.ok(user))
.orElse(ResponseEntity.notFound().build());
}
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
User saved = userService.save(user);
return ResponseEntity
.created(URI.create("/api/users/" + saved.getId()))
.body(saved);
}2. HTTP 状态码
java
@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED) // 201
public User createUser(@RequestBody User user) {
return userService.save(user);
}
@DeleteMapping("/users/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT) // 204
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}数据验证
1. Bean Validation
java
public class User {
@NotBlank(message = "Username is required")
@Size(min = 3, max = 20)
private String username;
@Email(message = "Email should be valid")
private String email;
@Min(18)
@Max(120)
private Integer age;
}
@PostMapping("/users")
public User createUser(@Valid @RequestBody User user) {
// 验证失败自动返回 400 错误
return userService.save(user);
}2. 自定义验证器
java
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueEmailValidator.class)
public @interface UniqueEmail {
String message() default "Email already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
@Autowired
private UserRepository userRepository;
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
return !userRepository.existsByEmail(email);
}
}内容协商
根据 Accept 头返回不同格式
java
@GetMapping(value = "/users/{id}", produces = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE
})
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}请求:
bash
curl -H "Accept: application/json" http://localhost:8080/api/users/1
curl -H "Accept: application/xml" http://localhost:8080/api/users/1与 Express.js 对比
| 特性 | Spring MVC | Express.js |
|---|---|---|
| 路由定义 | 注解 | 函数调用 |
| 参数绑定 | 自动 | 手动 |
| 数据验证 | 内置 | 需要库 |
| 类型安全 | ✅ | ❌ |
| 依赖注入 | ✅ | 手动 |
返回第二章概览