在 Spring Boot 项目中写出“优雅的 Controller”意味着代码清晰、结构规范、责任明确、异常处理完善、接口文档清晰,同时遵循一些业界最佳实践。以下是编写优雅 Controller 的全面指南。
✅ 一、Controller 基本结构规范
@RestController
@RequestMapping("/api/user")
@RequiredArgsConstructor
public class UserController {private final UserService userService;@GetMapping("/{id}")public ResponseEntity<UserDto> getUserById(@PathVariable Long id) {UserDto user = userService.getUserById(id);return ResponseEntity.ok(user);}@PostMappingpublic ResponseEntity<Void> createUser(@Valid @RequestBody UserCreateRequest request) {userService.createUser(request);return ResponseEntity.status(HttpStatus.CREATED).build();}
}
✅ 二、最佳实践详解
1. 📦 接口返回结构统一(避免直接返回 Map
、String
)
定义统一响应类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class R<T> {private int code;private String message;private T data;public static <T> R<T> ok(T data) {return new R<>(200, "success", data);}public static R<Void> error(String message) {return new R<>(500, message, null);}
}
Controller 使用:
@GetMapping("/{id}")
public R<UserDto> getUser(@PathVariable Long id) {return R.ok(userService.getUserById(id));
}
2. ✅ 参数校验(@Valid
/ @Validated
)
@PostMapping
public R<Void> save(@Valid @RequestBody UserCreateRequest request) {userService.save(request);return R.ok(null);
}
DTO 示例:
@Data
public class UserCreateRequest {@NotBlank(message = "用户名不能为空")private String username;@Email(message = "邮箱格式不正确")private String email;
}
3. ✅ 异常统一处理(全局异常处理器)
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public R<Void> handleValidationException(MethodArgumentNotValidException ex) {String errorMsg = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();return R.error(errorMsg);}@ExceptionHandler(BizException.class)public R<Void> handleBizException(BizException ex) {return R.error(ex.getMessage());}@ExceptionHandler(Exception.class)public R<Void> handleOtherExceptions(Exception ex) {// log errorreturn R.error("服务器内部错误");}
}
4. ✅ 明确职责划分(Controller 只做转发)
- Controller:只处理请求、调用 Service、返回结果
- Service:处理业务逻辑
- Repository/Mapper:数据访问
这样做的好处是单元测试、维护都方便。
5. ✅ 使用 @RequestParam
、@PathVariable
、@RequestBody
语义清晰
注解 | 说明 |
| URL 参数 |
| URL 路径中的参数 |
| JSON 请求体 |
例:
@GetMapping("/search")
public R<List<UserDto>> search(@RequestParam String keyword) {...}@GetMapping("/{id}")
public R<UserDto> detail(@PathVariable Long id) {...}@PostMapping
public R<Void> create(@RequestBody @Valid UserCreateRequest request) {...}
6. ✅ 增加接口文档支持(Swagger/OpenAPI)
@Operation(summary = "创建用户", description = "传入用户信息进行创建")
@PostMapping
public R<Void> createUser(@Valid @RequestBody UserCreateRequest request) {...
}
配合 Springdoc-OpenAPI 使用:
<!-- pom.xml -->
<dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>2.0.4</version>
</dependency>
访问地址:http://localhost:8080/swagger-ui.html
7. ✅ 分页查询结构统一
分页响应结构建议封装:
@Data
public class PageResult<T> {private long total;private List<T> list;public PageResult(Page<?> page) {this.total = page.getTotal();this.list = page.getRecords();}
}
Controller 示例:
@GetMapping("/page")
public R<PageResult<UserDto>> pageQuery(@Valid PageRequest request) {Page<UserDto> page = userService.pageQuery(request);return R.ok(new PageResult<>(page));
}
🔚 总结一句话
“优雅的 Controller = 少逻辑、多转发、返回一致、参数可校验、异常有处理、文档可生成”