这是一份非常全面的 Spring MVC 注解全教程,从基础到高级,涵盖了几乎所有常用注解。
1. Spring MVC 基础概念
Spring MVC 工作原理简图:
-
用户请求到达
DispatcherServlet(前端控制器) -
DispatcherServlet查询HandlerMapping找到对应的控制器 -
控制器处理请求并返回逻辑视图名或数据
-
DispatcherServlet查询ViewResolver解析视图 -
渲染视图并返回响应
2. 控制器相关注解
@Controller
-
作用:标记一个类作为Spring MVC控制器
-
说明:配合视图解析器使用,方法通常返回视图名
java
@Controller
public class HomeController {
@GetMapping("/home")
public String home() {
return "home"; // 解析为 /WEB-INF/views/home.jsp
}
}
@RestController
-
作用 :组合注解 =
@Controller+@ResponseBody -
说明:适用于RESTful API,方法返回值直接写入响应体
java
@RestController
public class ApiController {
@GetMapping("/api/data")
public User getData() {
return new User("John", 25); // 直接返回JSON
}
}
@RequestMapping
- 作用:映射HTTP请求到控制器方法
java
@Controller
@RequestMapping("/users") // 类级别路径
public class UserController {
// 访问路径: /users/profile
@RequestMapping("/profile")
public String profile() {
return "profile";
}
// 指定方法和更多属性
@RequestMapping(value = "/save", method = {RequestMethod.POST, RequestMethod.PUT})
public String saveUser() {
return "success";
}
}
3. 请求映射注解(@RequestMapping 的快捷方式)
| 注解 | 说明 | 示例 |
|---|---|---|
@GetMapping |
处理GET请求 | @GetMapping("/users") |
@PostMapping |
处理POST请求 | @PostMapping("/users") |
@PutMapping |
处理PUT请求 | @PutMapping("/users/{id}") |
@DeleteMapping |
处理DELETE请求 | @DeleteMapping("/users/{id}") |
@PatchMapping |
处理PATCH请求 | @PatchMapping("/users/{id}") |
完整示例:
java
@RestController
@RequestMapping("/api/v1")
public class UserController {
@GetMapping("/users")
public List<User> getUsers() {
return userService.findAll();
}
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.save(user);
}
@PutMapping("/users/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.update(user);
}
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteById(id);
}
}
4. 请求参数处理注解
@PathVariable - 路径变量
java
@GetMapping("/users/{id}/orders/{orderId}")
public String getUserOrder(
@PathVariable Long id,
@PathVariable String orderId,
@PathVariable Map<String, String> pathVars) { // 获取所有路径变量
System.out.println("用户ID: " + id); // 123
System.out.println("订单ID: " + orderId); // "abc"
System.out.println("所有路径变量: " + pathVars); // {id=123, orderId=abc}
return "order-details";
}
// 访问: GET /users/123/orders/abc
@RequestParam - 查询参数
java
@GetMapping("/search")
public String searchUsers(
// 必需参数
@RequestParam String keyword,
// 可选参数,带默认值
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size,
// 明确指定非必需
@RequestParam(required = false) String sort,
// 获取所有查询参数
@RequestParam Map<String, String> allParams) {
System.out.println("关键词: " + keyword); // "john"
System.out.println("页码: " + page); // 1
System.out.println("排序: " + sort); // null
return "search-results";
}
// 访问: GET /search?keyword=john&page=1
@RequestBody - 请求体
java
@PostMapping("/users")
public User createUser(@RequestBody User user) {
// 自动将JSON请求体转换为User对象
return userService.save(user);
}
@PostMapping("/batch")
public List<User> createUsers(@RequestBody List<User> users) {
// 支持集合类型
return userService.saveAll(users);
}
@RequestHeader - 请求头
java
@GetMapping("/info")
public String getUserInfo(
@RequestHeader("User-Agent") String userAgent,
@RequestHeader(value = "Authorization", required = false) String auth,
@RequestHeader Map<String, String> headers) { // 所有请求头
System.out.println("浏览器: " + userAgent);
System.out.println("Token: " + auth);
return "user-info";
}
@CookieValue - Cookie值
java
@GetMapping("/profile")
public String getProfile(@CookieValue("sessionId") String sessionId,
@CookieValue(value = "theme", defaultValue = "light") String theme) {
System.out.println("会话ID: " + sessionId);
System.out.println("主题: " + theme);
return "profile";
}
@RequestPart - 文件上传
java
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String uploadFile(
@RequestPart("file") MultipartFile file,
@RequestPart("metadata") String metadata) { // 其他表单字段
if (!file.isEmpty()) {
String fileName = file.getOriginalFilename();
long size = file.getSize();
// 保存文件...
}
return "upload-success";
}
@ModelAttribute - 模型属性
java
// 在方法上使用 - 在每个请求前执行,添加公共数据
@ModelAttribute
public void addCommonAttributes(Model model) {
model.addAttribute("currentYear", LocalDate.now().getYear());
model.addAttribute("siteName", "我的网站");
}
// 在参数上使用 - 绑定表单数据
@PostMapping("/register")
public String registerUser(@ModelAttribute User user, BindingResult result) {
if (result.hasErrors()) {
return "register-form";
}
userService.save(user);
return "redirect:/success";
}
5. 响应处理注解
@ResponseBody - 直接写响应体
java
@Controller
public class DataController {
@GetMapping("/user.json")
@ResponseBody // 返回值直接写入响应体,不经过视图解析器
public User getUser() {
return new User("John", 25);
}
}
@ResponseStatus - 定义HTTP状态码
java
@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED) // 201 Created
public User createUser(@RequestBody User user) {
return userService.save(user);
}
@GetMapping("/not-found")
@ResponseStatus(HttpStatus.NOT_FOUND) // 404 Not Found
public void notFound() {
// 方法体可以为空,直接返回404
}
@CrossOrigin - 跨域请求
java
@RestController
@CrossOrigin(origins = "*", maxAge = 3600) // 类级别配置
public class ApiController {
@GetMapping("/public/data")
@CrossOrigin(origins = "https://example.com") // 方法级别覆盖
public String getPublicData() {
return "public data";
}
}
6. 数据验证注解
在实体类中定义验证规则:
java
public class User {
private Long id;
@NotBlank(message = "姓名不能为空")
@Size(min = 2, max = 30, message = "姓名长度必须在2-30之间")
private String name;
@Email(message = "邮箱格式不正确")
@NotBlank(message = "邮箱不能为空")
private String email;
@Min(value = 18, message = "年龄必须大于18岁")
@Max(value = 100, message = "年龄必须小于100岁")
private Integer age;
@Pattern(regexp = "^(USER|ADMIN)$", message = "角色必须是USER或ADMIN")
private String role;
@Future(message = "生效时间必须是未来时间")
private LocalDateTime effectiveDate;
// getter/setter省略
}
在控制器中进行验证:
java
@PostMapping("/users")
public ResponseEntity<?> createUser(@Valid @RequestBody User user,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
// 处理验证错误
List<String> errors = bindingResult.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.toList());
return ResponseEntity.badRequest().body(errors);
}
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
7. 异常处理注解
@ControllerAdvice + @ExceptionHandler
java
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理特定异常
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
public ErrorResponse handleUserNotFound(UserNotFoundException ex) {
return new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
}
// 处理验证异常
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ErrorResponse handleValidationErrors(MethodArgumentNotValidException ex) {
List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.toList());
return new ErrorResponse("VALIDATION_ERROR", errors);
}
// 处理所有未捕获异常
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorResponse handleAllExceptions(Exception ex) {
return new ErrorResponse("INTERNAL_ERROR", "系统内部错误");
}
}
// 错误响应类
public class ErrorResponse {
private String code;
private Object message;
private long timestamp;
public ErrorResponse(String code, Object message) {
this.code = code;
this.message = message;
this.timestamp = System.currentTimeMillis();
}
// getter/setter
}
8. 模型和视图注解
@SessionAttributes - 会话属性
java
@Controller
@RequestMapping("/cart")
@SessionAttributes("cart") // 将名为"cart"的模型属性存入会话
public class ShoppingCartController {
// 初始化购物车
@ModelAttribute("cart")
public ShoppingCart initializeCart() {
return new ShoppingCart();
}
@PostMapping("/add")
public String addToCart(@ModelAttribute("cart") ShoppingCart cart,
@RequestParam Long productId) {
cart.addItem(productId);
return "redirect:/cart/view";
}
}
直接使用 Model 和 ModelMap
java
@Controller
public class PageController {
@GetMapping("/home")
public String homePage(Model model) {
// 添加单个属性
model.addAttribute("welcomeMessage", "欢迎访问我们的网站!");
// 添加多个属性
Map<String, Object> stats = new HashMap<>();
stats.put("userCount", 1000);
stats.put("onlineUsers", 150);
model.addAllAttributes(stats);
// 添加对象
model.addAttribute("currentUser", new User("John", 25));
return "home";
}
@GetMapping("/profile")
public String profilePage(ModelMap modelMap) {
// ModelMap 用法类似 Model
modelMap.addAttribute("pageTitle", "用户资料");
modelMap.addAttribute("user", userService.getCurrentUser());
return "profile";
}
}
9. 配置相关注解
@EnableWebMvc - 启用MVC配置
java
@Configuration
@EnableWebMvc // 启用Spring MVC,提供默认配置
@ComponentScan("com.example.controller")
public class WebConfig implements WebMvcConfigurer {
// 配置视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
// 配置静态资源
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/static/");
}
}
10. 完整综合示例
java
@RestController
@RequestMapping("/api/v1/products")
@Validated
@CrossOrigin(origins = "*")
public class ProductController {
@GetMapping
public Page<Product> getProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String category,
@RequestParam(required = false) @Min(0) Double minPrice,
@RequestParam(required = false) @Max(10000) Double maxPrice) {
return productService.findProducts(page, size, category, minPrice, maxPrice);
}
@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
return productService.findById(id)
.orElseThrow(() -> new ProductNotFoundException("产品不存在: " + id));
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Product createProduct(@Valid @RequestBody Product product) {
return productService.save(product);
}
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id,
@Valid @RequestBody Product product) {
product.setId(id);
return productService.update(product);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteProduct(@PathVariable Long id) {
productService.deleteById(id);
}
@PostMapping("/{id}/images")
public Product uploadImage(@PathVariable Long id,
@RequestPart("image") MultipartFile image) {
return productService.uploadImage(id, image);
}
}
这份教程涵盖了 Spring MVC 中最重要和最常用的注解,掌握这些注解就能够应对大多数的 Web 开发场景。建议在实际项目中多加练习,熟能生巧!