在 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. 📦 接口返回结构统一(避免直接返回 MapString

定义统一响应类:

@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 语义清晰

注解

说明

@RequestParam

URL 参数

@PathVariable

URL 路径中的参数

@RequestBody

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 = 少逻辑、多转发、返回一致、参数可校验、异常有处理、文档可生成”