Skip to content

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 MVCExpress.js
路由定义注解函数调用
参数绑定自动手动
数据验证内置需要库
类型安全✅❌
依赖注入✅手动

返回第二章概览

用心记录每一步成长