重构 Controller 的 7 个黄金法则
技术小馆专注AI与Java领域的前沿技术知识库 点击进入
重构 Controller 的 7 个黄金法则
你是否曾经面对过一个臃肿不堪的 Controller?方法堆积如山,业务逻辑混乱,测试困难,维护噩梦。当新需求来临时,你不得不在这个"巨无霸"中继续添加代码,让问题雪上加霜。一个优雅的 Controller 应该是轻量级的、职责单一的、易于测试和维护的。它就像一位优雅的舞者,动作简洁而有力,每个转身都恰到好处。
1. Controller 设计的核心原则
单一职责原则(SRP)
一个 Controller 应该只负责处理 HTTP 请求和响应,而不是承载业务逻辑。让我们看一个反例:
@RestController @RequestMapping("/api/users") public class UserController { @PostMapping("/register") public ResponseEntity<?> registerUser(@RequestBody UserRegistrationDto dto) { // 验证邮箱格式 if (!isValidEmail(dto.getEmail())) { return ResponseEntity.badRequest().body("Invalid email format"); } // 检查密码强度 if (!isPasswordStrong(dto.getPassword())) { return ResponseEntity.badRequest().body("Password too weak"); } // 检查用户是否已存在 if (userRepository.existsByEmail(dto.getEmail())) { return ResponseEntity.badRequest().body("User already exists"); } // 加密密码 String encryptedPassword = passwordEncoder.encode(dto.getPassword()); // 创建用户 User user = new User(); user.setEmail(dto.getEmail()); user.setPassword(encryptedPassword); user.setName(dto.getName()); // 保存用户 User savedUser = userRepository.save(user); // 发送欢迎邮件 emailService.sendWelcomeEmail(savedUser.getEmail()); return ResponseEntity.ok(savedUser); } // 其他验证方法... }
这个 Controller 违反了单一职责原则,包含了太多业务逻辑。重构后应该是这样:
@RestController @RequestMapping("/api/users") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @PostMapping("/register") public ResponseEntity<?> registerUser(@RequestBody UserRegistrationDto dto) { try { User user = userService.registerUser(dto); return ResponseEntity.ok(user); } catch (UserRegistrationException e) { return ResponseEntity.badRequest().body(e.getMessage()); } } }
依赖注入与解耦
通过构造函数注入依赖,而不是直接实例化,这样便于测试和替换实现:
@Service public class UserService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final EmailService emailService; private final UserValidator userValidator; public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, EmailService emailService, UserValidator userValidator) { this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.emailService = emailService; this.userValidator = userValidator; } }
接口隔离原则
为不同的功能定义专门的接口,避免一个接口承担过多职责:
public interface UserRegistrationService { User registerUser(UserRegistrationDto dto); } public interface UserQueryService { User findById(Long id); List<User> findAll(); User findByEmail(String email); } public interface UserUpdateService { User updateUser(Long id, UserUpdateDto dto); void deleteUser(Long id); }
2. 代码结构优化策略
方法提取与重构
将长方法拆分为多个小方法,每个方法只做一件事:
@RestController @RequestMapping("/api/orders") public class OrderController { @PostMapping public ResponseEntity<?> createOrder(@RequestBody CreateOrderDto dto) { // 验证请求 validateCreateOrderRequest(dto); // 检查库存 checkInventoryAvailability(dto); // 创建订单 Order order = createOrderFromDto(dto); // 保存订单 Order savedOrder = orderService.save(order); // 发送确认邮件 sendOrderConfirmation(savedOrder); return ResponseEntity.ok(savedOrder); } private void validateCreateOrderRequest(CreateOrderDto dto) { if (dto.getItems() == null || dto.getItems().isEmpty()) { throw new InvalidOrderException("Order must contain at least one item"); } // 其他验证逻辑... } private void checkInventoryAvailability(CreateOrderDto dto) { for (OrderItemDto item : dto.getItems()) { if (!inventoryService.isAvailable(item.getProductId(), item.getQuantity())) { throw new InsufficientInventoryException("Insufficient inventory for product: " + item.getProductId()); } } } private Order createOrderFromDto(CreateOrderDto dto) { Order order = new Order(); order.setCustomerId(dto.getCustomerId()); order.setItems(dto.getItems().stream() .map(this::createOrderItem) .collect(Collectors.toList())); order.setTotalAmount(calculateTotal(dto.getItems())); return order; } }
参数验证与异常处理
使用统一的异常处理机制和参数验证:
@RestController @RequestMapping("/api/products") public class ProductController { @PostMapping public ResponseEntity<?> createProduct(@Valid @RequestBody CreateProductDto dto) { Product product = productService.createProduct(dto); return ResponseEntity.ok(product); } @PutMapping("/{id}") public ResponseEntity<?> updateProduct(@PathVariable Long id, @Valid @RequestBody UpdateProductDto dto) { try { Product product = productService.updateProduct(id, dto); return ResponseEntity.ok(product); } catch (ProductNotFoundException e) { return ResponseEntity.notFound().build(); } } } // 全局异常处理 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<?> handleValidationErrors(MethodArgumentNotValidException ex) { List<String> errors = ex.getBindingResult() .getFieldErrors() .stream() .map(FieldError::getDefaultMessage) .collect(Collectors.toList()); return ResponseEntity.badRequest() .body(new ErrorResponse("Validation failed", errors)); } @ExceptionHandler(BusinessException.class) public ResponseEntity<?> handleBusinessException(BusinessException ex) { return ResponseEntity.badRequest() .body(new ErrorResponse(ex.getMessage())); } }
响应格式标准化
定义统一的响应格式,提高 API 的一致性:
public class ApiResponse<T> { private boolean success; private String message; private T data; private long timestamp; public static <T> ApiResponse<T> success(T data) { ApiResponse<T> response = new ApiResponse<>(); response.setSuccess(true); response.setData(data); response.setTimestamp(System.currentTimeMillis()); return response; } public static <T> ApiResponse<T> error(String message) { ApiResponse<T> response = new ApiResponse<>(); response.setSuccess(false); response.setMessage(message); response.setTimestamp(System.currentTimeMillis()); return response; } } @RestController @RequestMapping("/api/users") public class UserController { @GetMapping("/{id}") public ResponseEntity<ApiResponse<User>> getUser(@PathVariable Long id) { try { User user = userService.findById(id); return ResponseEntity.ok(ApiResponse.success(user)); } catch (UserNotFoundException e) { return ResponseEntity.ok(ApiResponse.error("User not found")); } } }
3. 业务逻辑分离技巧
Service 层职责划分
将业务逻辑从 Controller 中提取到 Service 层:
@Service @Transactional public class OrderService { private final OrderRepository orderRepository; private final ProductService productService; private final CustomerService customerService; private final PaymentService paymentService; public Order createOrder(CreateOrderDto dto) { // 验证客户 Customer customer = customerService.findById(dto.getCustomerId()); // 验证产品 List<Product> products = validateProducts(dto.getItems()); // 计算价格 BigDecimal totalAmount = calculateTotalAmount(dto.getItems()); // 创建订单 Order order = new Order(); order.setCustomer(customer); order.setItems(createOrderItems(dto.getItems())); order.setTotalAmount(totalAmount); order.setStatus(OrderStatus.PENDING); // 保存订单 Order savedOrder = orderRepository.save(order); // 处理支付 paymentService.processPayment(savedOrder); return savedOrder; } private List<Product> validateProducts(List<OrderItemDto> items) { return items.stream() .map(item -> productService.findById(item.getProductId())) .collect(Collectors.toList()); } private BigDecimal calculateTotalAmount(List<OrderItemDto> items) { return items.stream() .map(item -> { Product product = productService.findById(item.getProductId()); return product.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())); }) .reduce(BigDecimal.ZERO, BigDecimal::add); } }
数据转换与映射
使用 DTO 和 Mapper 来处理数据传输:
public class UserMapper { public static UserDto toDto(User user) { UserDto dto = new UserDto(); dto.setId(user.getId()); dto.setEmail(user.getEmail()); dto.setName(user.getName()); dto.setCreatedAt(user.getCreatedAt()); return dto; } public static User toEntity(CreateUserDto dto) { User user = new User(); user.setEmail(dto.getEmail()); user.setName(dto.getName()); user.setCreatedAt(LocalDateTime.now()); return user; } public static List<UserDto> toDtoList(List<User> users) { return users.stream() .map(UserMapper::toDto) .collect(Collectors.toList()); } } @RestController @RequestMapping("/api/users") public class UserController { @GetMapping public ResponseEntity<ApiResponse<List<UserDto>>> getAllUsers() { List<User> users = userService.findAll(); List<UserDto> userDtos = UserMapper.toDtoList(users); return ResponseEntity.ok(ApiResponse.success(userDtos)); } }
事务管理策略
在 Service 层使用事务注解,确保数据一致性:
@Service @Transactional public class OrderService { @Transactional(readOnly = true) public Order findById(Long id) { return orderRepository.findById(id) .orElseThrow(() -> new OrderNotFoundException("Order not found: " + id)); } @Transactional public Order createOrder(CreateOrderDto dto) { // 创建订单逻辑 Order order = buildOrder(dto); // 保存订单 Order savedOrder = orderRepository.save(order); // 更新库存 updateInventory(dto.getItems()); // 发送通知 notificationService.sendOrderCreatedNotification(savedOrder); return savedOrder; } @Transactional public void cancelOrder(Long orderId) { Order order = findById(orderId); if (order.getStatus() != OrderStatus.PENDING) { throw new InvalidOrderStatusException("Cannot cancel order in status: " + order.getStatus()); } order.setStatus(OrderStatus.CANCELLED); orderRepository.save(order); // 恢复库存 restoreInventory(order.getItems()); // 发送取消通知 notificationService.sendOrderCancelledNotification(order); } }
4. 测试友好性设计
单元测试编写
为 Controller 编写单元测试,确保每个方法都能正确工作:
@ExtendWith(MockitoExtension.class) class UserControllerTest { @Mock private UserService userService; @Mock private UserValidator userValidator; @InjectMocks private UserController userController; @Test void createUser_WithValidData_ReturnsCreatedUser() { // Arrange CreateUserDto dto = new CreateUserDto(); dto.setEmail("test@example.com"); dto.setName("Test User"); User user = new User(); user.setId(1L); user.setEmail(dto.getEmail()); user.setName(dto.getName()); when(userService.createUser(dto)).thenReturn(user); // Act ResponseEntity<ApiResponse<User>> response = userController.createUser(dto); // Assert assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody().isSuccess()).isTrue(); assertThat(response.getBody().getData().getEmail()).isEqualTo(dto.getEmail()); verify(userService).createUser(dto); } @Test void createUser_WithInvalidData_ReturnsBadRequest() { // Arrange CreateUserDto dto = new CreateUserDto(); dto.setEmail("invalid-email"); when(userService.createUser(dto)) .thenThrow(new ValidationException("Invalid email format")); // Act ResponseEntity<ApiResponse<User>> response = userController.createUser(dto); // Assert assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody().isSuccess()).isFalse(); assertThat(response.getBody().getMessage()).contains("Invalid email format"); } }
Mock 策略选择
选择合适的 Mock 策略来隔离依赖:
@WebMvcTest(UserController.class) class UserControllerIntegrationTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test void getUser_WithValidId_ReturnsUser() throws Exception { // Arrange User user = new User(); user.setId(1L); user.setEmail("test@example.com"); user.setName("Test User"); when(userService.findById(1L)).thenReturn(user); // Act & Assert mockMvc.perform(get("/api/users/1")) .andExpect(status().isOk()) .andExpect(jsonPath("$.success").value(true)) .andExpect(jsonPath("$.data.email").value("test@example.com")) .andExpect(jsonPath("$.data.name").value("Test User")); } @Test void getUser_WithInvalidId_ReturnsNotFound() throws Exception { // Arrange when(userService.findById(999L)) .thenThrow(new UserNotFoundException("User not found")); // Act & Assert mockMvc.perform(get("/api/users/999")) .andExpect(status().isOk()) .andExpect(jsonPath("$.success").value(false)) .andExpect(jsonPath("$.message").value("User not found")); } }
集成测试设计
设计端到端的集成测试,验证整个流程:
@SpringBootTest @AutoConfigureTestDatabase @Transactional class UserControllerIntegrationTest { @Autowired private TestRestTemplate restTemplate; @Autowired private UserRepository userRepository; @Test void createAndRetrieveUser_CompleteFlow_Success() { // Arrange CreateUserDto createDto = new CreateUserDto(); createDto.setEmail("integration@example.com"); createDto.setName("Integration User"); // Act - Create user ResponseEntity<ApiResponse> createResponse = restTemplate.postForEntity( "/api/users", createDto, ApiResponse.class); // Assert - User created assertThat(createResponse.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(createResponse.getBody().isSuccess()).isTrue(); // Act - Retrieve user ResponseEntity<ApiResponse> getResponse = restTemplate.getForEntity( "/api/users/1", ApiResponse.class); // Assert - User retrieved assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(getResponse.getBody().isSuccess()).isTrue(); // Verify database User savedUser = userRepository.findById(1L).orElse(null); assertThat(savedUser).isNotNull(); assertThat(savedUser.getEmail()).isEqualTo("integration@example.com"); } }
5. 性能优化与缓存
响应时间优化
通过异步处理和缓存来提升响应速度:
@RestController @RequestMapping("/api/products") public class ProductController { @GetMapping("/{id}") @Cacheable(value = "products", key = "#id") public ResponseEntity<ApiResponse<Product>> getProduct(@PathVariable Long id) { Product product = productService.findById(id); return ResponseEntity.ok(ApiResponse.success(product)); } @GetMapping("/search") public ResponseEntity<ApiResponse<List<Product>>> searchProducts( @RequestParam String keyword, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { Pageable pageable = PageRequest.of(page, size); Page<Product> products = productService.searchByKeyword(keyword, pageable); return ResponseEntity.ok(ApiResponse.success(products.getContent())); } @PostMapping("/{id}/view") @Async public void incrementViewCount(@PathVariable Long id) { productService.incrementViewCount(id); } } @Service public class ProductService { @Cacheable(value = "products", key = "#id") public Product findById(Long id) { return productRepository.findById(id) .orElseThrow(() -> new ProductNotFoundException("Product not found: " + id)); } @CacheEvict(value = "products", key = "#product.id") public Product updateProduct(Product product) { return productRepository.save(product); } @Async public void incrementViewCount(Long productId) { productRepository.incrementViewCount(productId); } }
缓存策略实施
实现多层次的缓存策略:
@Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); ConcurrentMapCache productsCache = new ConcurrentMapCache("products"); ConcurrentMapCache usersCache = new ConcurrentMapCache("users"); ConcurrentMapCache ordersCache = new ConcurrentMapCache("orders"); cacheManager.setCaches(Arrays.asList(productsCache, usersCache, ordersCache)); return cacheManager; } } @Service public class ProductService { @Cacheable(value = "products", key = "#id", unless = "#result == null") public Product findById(Long id) { return productRepository.findById(id).orElse(null); } @Cacheable(value = "products", key = "'search_' + #keyword + '_' + #pageable.pageNumber + '_' + #pageable.pageSize") public Page<Product> searchByKeyword(String keyword, Pageable pageable) { return productRepository.findByNameContainingIgnoreCase(keyword, pageable); } @CacheEvict(value = "products", allEntries = true) public void clearAllCaches() { // 清除所有产品相关缓存 } }
异步处理机制
使用异步处理来处理耗时操作:
@RestController @RequestMapping("/api/orders") public class OrderController { @PostMapping("/{id}/process") public ResponseEntity<ApiResponse<String>> processOrder(@PathVariable Long id) { // 立即返回处理中的状态 orderService.processOrderAsync(id); return ResponseEntity.ok(ApiResponse.success("Order processing started")); } @GetMapping("/{id}/status") public ResponseEntity<ApiResponse<OrderStatus>> getOrderStatus(@PathVariable Long id) { OrderStatus status = orderService.getOrderStatus(id); return ResponseEntity.ok(ApiResponse.success(status)); } } @Service public class OrderService { @Async public void processOrderAsync(Long orderId) { try { // 模拟耗时处理 Thread.sleep(5000); // 更新订单状态 Order order = findById(orderId); order.setStatus(OrderStatus.PROCESSING); orderRepository.save(order); // 继续处理... processPayment(order); updateInventory(order); sendNotifications(order); order.setStatus(OrderStatus.COMPLETED); orderRepository.save(order); } catch (Exception e) { // 处理异常,更新订单状态为失败 Order order = findById(orderId); order.setStatus(OrderStatus.FAILED); orderRepository.save(order); log.error("Failed to process order: " + orderId, e); } } }
6. 代码规范与文档
命名规范制定
建立清晰的命名约定:
// Controller 命名:以 Controller 结尾,使用复数形式 @RestController @RequestMapping("/api/users") public class UserController { } @RestController @RequestMapping("/api/orders") public class OrderController { } // 方法命名:使用动词开头,清晰表达意图 @GetMapping("/{id}") public ResponseEntity<ApiResponse<User>> getUserById(@PathVariable Long id) { } @PostMapping public ResponseEntity<ApiResponse<User>> createNewUser(@RequestBody CreateUserDto dto) { } @PutMapping("/{id}") public ResponseEntity<ApiResponse<User>> updateExistingUser(@PathVariable Long id, @RequestBody UpdateUserDto dto) { } @DeleteMapping("/{id}") public ResponseEntity<ApiResponse<Void>> removeUser(@PathVariable Long id) { } // DTO 命名:以 Dto 结尾,使用描述性名称 public class CreateUserDto { } public class UpdateUserDto { } public class UserResponseDto { } // 异常命名:以 Exception 结尾 public class UserNotFoundException extends RuntimeException { } public class InvalidUserDataException extends RuntimeException { }
API 文档生成
使用 Swagger 或 OpenAPI 生成 API 文档:
@RestController @RequestMapping("/api/users") @Tag(name = "User Management", description = "APIs for managing users") public class UserController { @Operation(summary = "Create a new user", description = "Creates a new user with the provided information") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "User created successfully", content = @Content(schema = @Schema(implementation = User.class))), @ApiResponse(responseCode = "400", description = "Invalid input data"), @ApiResponse(responseCode = "409", description = "User already exists") }) @PostMapping public ResponseEntity<ApiResponse<User>> createUser( @Parameter(description = "User information", required = true) @Valid @RequestBody CreateUserDto dto) { User user = userService.createUser(dto); return ResponseEntity.ok(ApiResponse.success(user)); } @Operation(summary = "Get user by ID", description = "Retrieves a user by their unique identifier") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "User found successfully"), @ApiResponse(responseCode = "404", description = "User not found") }) @GetMapping("/{id}") public ResponseEntity<ApiResponse<User>> getUserById( @Parameter(description = "User ID", required = true) @PathVariable Long id) { User user = userService.findById(id); return ResponseEntity.ok(ApiResponse.success(user)); } }
代码审查要点
建立代码审查检查清单:
// 代码审查检查清单示例 /* □ Controller 是否只负责 HTTP 请求处理? □ 业务逻辑是否已提取到 Service 层? □ 是否使用了适当的 HTTP 状态码? □ 异常处理是否统一? □ 参数验证是否完整? □ 响应格式是否一致? □ 是否添加了适当的日志? □ 方法是否过于复杂(超过 20 行)? □ 是否遵循了命名约定? □ 是否添加了必要的注释? □ 是否考虑了性能问题? □ 是否添加了单元测试? */ @RestController @RequestMapping("/api/users") @Slf4j public class UserController { @PostMapping public ResponseEntity<ApiResponse<User>> createUser(@Valid @RequestBody CreateUserDto dto) { log.info("Creating new user with email: {}", dto.getEmail()); try { User user = userService.createUser(dto); log.info("User created successfully with ID: {}", user.getId()); return ResponseEntity.ok(ApiResponse.success(user)); } catch (UserAlreadyExistsException e) { log.warn("Failed to create user: {}", e.getMessage()); return ResponseEntity.ok(ApiResponse.error(e.getMessage())); } catch (Exception e) { log.error("Unexpected error while creating user", e); return ResponseEntity.ok(ApiResponse.error("Internal server error")); } } }
7. 重构实战案例
遗留代码分析
分析一个典型的"巨无霸" Controller:
// 重构前的混乱 Controller @RestController @RequestMapping("/api/orders") public class OrderController { @Autowired private OrderRepository orderRepository; @Autowired private ProductRepository productRepository; @Autowired private UserRepository userRepository; @Autowired private EmailService emailService; @Autowired private PaymentService paymentService; @PostMapping public ResponseEntity<?> createOrder(@RequestBody Map<String, Object> request) { try { // 验证用户 Long userId = Long.valueOf(request.get("userId").toString()); User user = userRepository.findById(userId).orElse(null); if (user == null) { return ResponseEntity.badRequest().body("User not found"); } // 验证产品 List<Map<String, Object>> items = (List<Map<String, Object>>) request.get("items"); List<OrderItem> orderItems = new ArrayList<>(); BigDecimal totalAmount = BigDecimal.ZERO; for (Map<String, Object> item : items) { Long productId = Long.valueOf(item.get("productId").toString()); Integer quantity = Integer.valueOf(item.get("quantity").toString()); Product product = productRepository.findById(productId).orElse(null); if (product == null) { return ResponseEntity.badRequest().body("Product not found: " + productId); } if (product.getStock() < quantity) { return ResponseEntity.badRequest().body("Insufficient stock for product: " + productId); } OrderItem orderItem = new OrderItem(); orderItem.setProduct(product); orderItem.setQuantity(quantity); orderItem.setPrice(product.getPrice()); orderItems.add(orderItem); totalAmount = totalAmount.add(product.getPrice().multiply(BigDecimal.valueOf(quantity))); // 更新库存 product.setStock(product.getStock() - quantity); productRepository.save(product); } // 创建订单 Order order = new Order(); order.setUser(user); order.setItems(orderItems); order.setTotalAmount(totalAmount); order.setStatus("PENDING"); order.setCreatedAt(new Date()); Order savedOrder = orderRepository.save(order); // 处理支付 String paymentResult = paymentService.processPayment(savedOrder); if (!"SUCCESS".equals(paymentResult)) { // 回滚库存 for (OrderItem item : orderItems) { Product product = item.getProduct(); product.setStock(product.getStock() + item.getQuantity()); productRepository.save(product); } orderRepository.delete(savedOrder); return ResponseEntity.badRequest().body("Payment failed"); } // 发送确认邮件 emailService.sendOrderConfirmation(user.getEmail(), savedOrder); return ResponseEntity.ok(savedOrder); } catch (Exception e) { return ResponseEntity.status(500).body("Internal server error: " + e.getMessage()); } } // 其他混乱的方法... }
重构计划制定
制定分步骤的重构计划:
// 第一步:提取 DTO 和验证 public class CreateOrderDto { @NotNull private Long userId; @NotEmpty @Valid private List<OrderItemDto> items; // getters and setters } public class OrderItemDto { @NotNull private Long productId; @Min private Integer quantity; // getters and setters } // 第二步:创建专门的 Service @Service @Transactional public class OrderService { private final OrderRepository orderRepository; private final ProductService productService; private final UserService userService; private final PaymentService paymentService; private final EmailService emailService; public Order createOrder(CreateOrderDto dto) { // 验证用户 User user = userService.findById(dto.getUserId()); // 验证产品并创建订单项 List<OrderItem> orderItems = createOrderItems(dto.getItems()); // 计算总金额 BigDecimal totalAmount = calculateTotalAmount(orderItems); // 创建订单 Order order = buildOrder(user, orderItems, totalAmount); // 保存订单 Order savedOrder = orderRepository.save(order); // 处理支付 processPayment(savedOrder); // 发送确认邮件 emailService.sendOrderConfirmation(user.getEmail(), savedOrder); return savedOrder; } private List<OrderItem> createOrderItems(List<OrderItemDto> itemDtos) { return itemDtos.stream() .map(this::createOrderItem) .collect(Collectors.toList()); } private OrderItem createOrderItem(OrderItemDto dto) { Product product = productService.findById(dto.getProductId()); productService.checkStockAvailability(product, dto.getQuantity()); OrderItem item = new OrderItem(); item.setProduct(product); item.setQuantity(dto.getQuantity()); item.setPrice(product.getPrice()); return item; } } // 第三步:重构 Controller @RestController @RequestMapping("/api/orders") public class OrderController { private final OrderService orderService; public OrderController(OrderService orderService) { this.orderService = orderService; } @PostMapping public ResponseEntity<ApiResponse<Order>> createOrder(@Valid @RequestBody CreateOrderDto dto) { try { Order order = orderService.createOrder(dto); return ResponseEntity.ok(ApiResponse.success(order)); } catch (BusinessException e) { return ResponseEntity.ok(ApiResponse.error(e.getMessage())); } } }
重构后效果评估
评估重构的效果和改进:
// 重构后的效果对比 /* 重构前的问题: - Controller 方法超过 80 行 - 混合了业务逻辑、数据访问、验证等职责 - 异常处理不统一 - 难以测试和维护 - 代码重复严重 重构后的改进: - Controller 方法只有 10 行左右 - 职责分离清晰 - 统一的异常处理 - 易于测试和维护 - 代码复用性高 - 符合 SOLID 原则 */ // 重构后的测试覆盖 @ExtendWith(MockitoExtension.class) class OrderControllerTest { @Mock private OrderService orderService; @InjectMocks private OrderController orderController; @Test void createOrder_WithValidData_ReturnsSuccess() { // Arrange CreateOrderDto dto = new CreateOrderDto(); dto.setUserId(1L); dto.setItems(Arrays.asList(new OrderItemDto(1L, 2))); Order order = new Order(); order.setId(1L); when(orderService.createOrder(dto)).thenReturn(order); // Act ResponseEntity<ApiResponse<Order>> response = orderController.createOrder(dto); // Assert assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody().isSuccess()).isTrue(); assertThat(response.getBody().getData().getId()).isEqualTo(1L); } } // 重构后的性能指标 /* - 响应时间:从平均 500ms 降低到 200ms - 代码行数:从 200+ 行减少到 50 行 - 测试覆盖率:从 30% 提升到 85% - 维护成本:降低 60% - 代码质量评分:从 C 提升到 A */