SpringMVC核心注解与最佳实践指南
一、核心请求处理注解体系
1.1 @Controller与@RestController
在SpringMVC框架中,控制器是处理HTTP请求的核心组件。@Controller注解用于标记类为控制器:
@Controller
public class UserController {
@RequestMapping("/users")
public String listUsers(Model model) {
model.addAttribute("userList", userService.getAllUsers());
return "user/list";
}
}
@RestController是Spring 4.0引入的组合注解,等价于@Controller + @ResponseBody:
@RestController
@RequestMapping("/api/users")
public class UserApiController {
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
}
开发建议:
- Web页面交互优先使用@Controller
- RESTful API优先使用@RestController
- 注意模板引擎与JSON序列化的区别
1.2 请求映射注解家族
Spring 4.3引入了更语义化的请求方法注解:
注解 | 等价形式 | HTTP方法 |
---|---|---|
@GetMapping | @RequestMapping(method=GET) | GET |
@PostMapping | @RequestMapping(method=POST) | POST |
@PutMapping | @RequestMapping(method=PUT) | PUT |
@DeleteMapping | @RequestMapping(method=DELETE) | DELETE |
使用示例:
@RestController
@RequestMapping("/products")
public class ProductController {
@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
return productService.findById(id);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Product createProduct(@RequestBody Product product) {
return productService.save(product);
}
}
1.3 复杂路径匹配
路径匹配支持Ant风格和正则表达式:
@GetMapping("/files/{fileId:[a-f0-9]{32}}")
public ResponseEntity<byte[]> getFile(@PathVariable String fileId) {
// 处理32位哈希值的文件请求
}
@GetMapping("/images/**")
public String handleImages() {
// 匹配/images/开头的所有路径
}
二、参数绑定深度解析
2.1 @RequestParam高级用法
@GetMapping("/search")
public Page<User> searchUsers(
@RequestParam(defaultValue = "") String keyword,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
// 分页查询逻辑
}
参数处理技巧:
- 设置默认值避免NullPointerException
- 使用Optional包装可能缺失的参数
- 通过required属性控制参数必填性
2.2 @PathVariable类型转换
自定义类型转换示例:
@GetMapping("/orders/{orderNo}")
public Order getOrder(@PathVariable("orderNo") Order order) {
return order;
}
// 自定义转换器
@Component
public class OrderConverter implements Converter<String, Order> {
@Override
public Order convert(String orderNo) {
return orderService.findByNo(orderNo);
}
}
2.3 @RequestBody处理策略
复杂JSON绑定示例:
@PostMapping("/complex")
public ResponseData handleComplex(@Valid @RequestBody ComplexDTO dto) {
// 处理多层嵌套对象
}
// DTO定义
public class ComplexDTO {
@NotNull
private UserInfo user;
@NotEmpty
private List<OrderItem> items;
// 嵌套对象验证
public static class UserInfo {
@NotBlank
private String name;
@Email
private String email;
}
}
三、响应处理机制
3.1 视图解析技术
传统MVC视图解析流程:
@Controller
public class ReportController {
@GetMapping("/monthly-report")
public ModelAndView generateReport() {
ModelAndView mav = new ModelAndView();
mav.addObject("reportData", reportService.generate());
mav.setViewName("reports/monthly");
return mav;
}
}
视图解析器配置示例:
# Thymeleaf配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.cache=false
3.2 ResponseEntity精细控制
完全控制HTTP响应:
@GetMapping("/download")
public ResponseEntity<Resource> downloadFile() throws IOException {
Path filePath = Paths.get("/data/files/report.pdf");
Resource resource = new InputStreamResource(Files.newInputStream(filePath));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"report.pdf\"")
.contentType(MediaType.APPLICATION_PDF)
.contentLength(Files.size(filePath))
.body(resource);
}
3.3 全局响应包装
统一响应格式处理:
@RestControllerAdvice
public class ResponseWrapper implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType,
Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof ApiResponse) {
return body;
}
return new ApiResponse<>(200, "success", body);
}
}
四、模型处理机制
4.1 @ModelAttribute进阶
方法级@ModelAttribute的预加载:
@ModelAttribute("categories")
public List<Category> loadCategories() {
return categoryService.getAllActiveCategories();
}
@ModelAttribute
public void preloadModel(Model model) {
model.addAttribute("currentUser", userService.getCurrentUser());
}
表单绑定示例:
<!-- Thymeleaf模板 -->
<form th:action="@{/products}" method="post" th:object="${product}">
<input type="text" th:field="*{name}">
<input type="number" th:field="*{price}">
</form>
4.2 会话管理策略
@SessionAttributes使用模式:
@Controller
@SessionAttributes("checkoutInfo")
public class CheckoutController {
@GetMapping("/checkout/step1")
public String step1(Model model) {
model.addAttribute("checkoutInfo", new CheckoutInfo());
return "checkout/step1";
}
@PostMapping("/checkout/step2")
public String step2(@ModelAttribute CheckoutInfo checkoutInfo) {
return "checkout/step2";
}
}
会话超时配置:
server.servlet.session.timeout=1800 # 30分钟
五、拦截与切面处理
5.1 拦截器深度集成
自定义拦截器示例:
public class AuditInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
log.info("Request [{}] from {}",
request.getRequestURI(),
request.getRemoteAddr());
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) {
// 可修改ModelAndView
}
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuditInterceptor())
.addPathPatterns("/api/**");
}
}
5.2 异常处理体系
全局异常处理示例:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
return new ErrorResponse("NOT_FOUND", ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleValidationErrors(MethodArgumentNotValidException ex) {
List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.toList());
return new ErrorResponse("VALIDATION_FAILED", errors);
}
}
六、RESTful API最佳实践
6.1 HATEOAS实现
使用Spring HATEOAS构建超媒体API:
@RestController
@RequestMapping("/api/books")
public class BookController {
@GetMapping("/{id}")
public EntityModel<Book> getBook(@PathVariable Long id) {
Book book = bookService.findById(id);
return EntityModel.of(book,
linkTo(methodOn(BookController.class).getBook(id)).withSelfRel(),
linkTo(methodOn(BookController.class).getAllBooks()).withRel("books"));
}
}
6.2 版本控制策略
三种常用版本控制方式:
- URI路径版本控制:
@RestController
@RequestMapping("/api/v1/products")
public class ProductV1Controller { ... }
@RestController
@RequestMapping("/api/v2/products")
public class ProductV2Controller { ... }
- 请求头版本控制:
@GetMapping(value = "/products", headers = "X-API-Version=2")
public ProductV2 getProductV2() { ... }
- 内容协商版本控制:
@GetMapping(value = "/products", produces = "application/vnd.company.v1+json")
public ProductV1 getProductV1() { ... }
@GetMapping(value = "/products", produces = "application/vnd.company.v2+json")
public ProductV2 getProductV2() { ... }
七、性能优化技巧
7.1 异步处理
DeferredResult使用示例:
@GetMapping("/async")
public DeferredResult<String> asyncRequest() {
DeferredResult<String> result = new DeferredResult<>();
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(3000);
result.setResult("Async result");
} catch (InterruptedException e) {
result.setErrorResult(e.getMessage());
}
});
return result;
}
7.2 缓存策略
方法级缓存示例:
@GetMapping("/products/{id}")
@Cacheable(value = "products", key = "#id")
public Product getProduct(@PathVariable Long id) {
return productService.findById(id);
}
@CacheEvict(value = "products", key = "#product.id")
@PutMapping("/products")
public Product updateProduct(@RequestBody Product product) {
return productService.update(product);
}
八、安全防护措施
8.1 CSRF防护
Thymeleaf模板自动处理CSRF:
<form method="post">
<input type="hidden"
th:name="${_csrf.parameterName}"
th:value="${_csrf.token}" />
<!-- 其他表单字段 -->
</form>
8.2 XSS防护
使用HtmlUtils进行内容转义:
@PostMapping("/comments")
public String postComment(@RequestParam String content) {
String safeContent = HtmlUtils.htmlEscape(content);
commentService.save(safeContent);
return "redirect:/comments";
}
九、测试验证方案
9.1 控制器单元测试
MockMvc测试示例:
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void getUserById() throws Exception {
given(userService.findById(1L))
.willReturn(new User(1L, "testuser"));
mockMvc.perform(get("/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("testuser"));
}
}
9.2 集成测试
SpringBootTest完整测试:
@SpringBootTest
@AutoConfigureMockMvc
class ApplicationIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void contextLoads() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk());
}
}
正文到此结束
相关文章
热门推荐
评论插件初始化中...