重构 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
*/
全部评论
base南京OD,机会多多,可私信
点赞 回复 分享
发布于 08-20 20:10 贵州

相关推荐

昨天 22:29
门头沟学院 Java
投递小鹅通等公司10个岗位
点赞 评论 收藏
分享
程序员花海:实习太简单了 学历可以的 实习描述应该是先介绍业务 再介绍技术 技术咋推动业务的 做到了啥收益 有没有做实验 实验组和对照组有什么不同 你最后学到了什么 有没有参与处理过线上问题 有没有参与过公司的code review 有没有参与过技术分享 这些都是可以在实习描述中写的 并且实习和项目不一样不会撞车 应该放在最前面 放在教育背景下面 另外项目有点烂大街 可以看下我主页的简历优化案例
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务