You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Spring 2.0.1.RELEASE的自定义工作流优化设计咨询

Hey Sahil, let's refine your Spring 2.0.1.RELEASE workflow implementation to be more maintainable, reusable, and aligned with Spring's best practices. Based on your requirements, here's a structured approach that keeps separation of concerns while handling the step-by-step flow and exception hierarchy properly.

1. 定义步骤专属异常类

First, we need explicit exceptions for each workflow stage—this lets us target step-specific handlers before falling back to a global one, avoiding messy conditional checks.

// 转换阶段异常(覆盖DTO↔Domain双向转换的错误)
public class TransformException extends RuntimeException {
    public TransformException(String message) {
        super(message);
    }
    public TransformException(String message, Throwable cause) {
        super(message, cause);
    }
}

// 验证阶段异常(Domain对象校验失败时抛出)
public class ValidationException extends RuntimeException {
    public ValidationException(String message) {
        super(message);
    }
    public ValidationException(String message, Throwable cause) {
        super(message, cause);
    }
}

// 服务处理阶段异常(业务逻辑或持久化失败时抛出)
public class ServiceProcessingException extends RuntimeException {
    public ServiceProcessingException(String message) {
        super(message);
    }
    public ServiceProcessingException(String message, Throwable cause) {
        super(message, cause);
    }
}
2. 通用组件接口定义

To make the workflow reusable across different domain/DTO pairs, define generic interfaces for your transformers, validators, and services. This way, you can swap implementations without changing the core workflow logic.

// 双向转换接口:统一DTO与Domain的转换规则
public interface Transformer<DTO, Domain> {
    Domain transformToDomain(DTO dto) throws TransformException;
    DTO transformToDTO(Domain domain) throws TransformException;
}

// 验证接口:统一Domain对象的校验逻辑
public interface Validator<Domain> {
    void validate(Domain domain) throws ValidationException;
}

// 业务服务接口:统一业务规则应用与持久化操作
public interface BusinessService<Domain> {
    Domain save(Domain domain) throws ServiceProcessingException;
}
3. 通用工作流执行器

Create a generic workflow executor that injects the required components and runs the steps in order. This keeps your controller code clean and avoids repeating the flow for different entity types.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class WorkflowExecutor<DTO, Domain> {

    private final Transformer<DTO, Domain> transformer;
    private final Validator<Domain> validator;
    private final BusinessService<Domain> businessService;

    // Spring 2.0.1 supports constructor injection or field injection; constructor injection is more robust
    @Autowired
    public WorkflowExecutor(Transformer<DTO, Domain> transformer,
                            Validator<Domain> validator,
                            BusinessService<Domain> businessService) {
        this.transformer = transformer;
        this.validator = validator;
        this.businessService = businessService;
    }

    public DTO execute(DTO inputDto) {
        // Step 1: Convert DTO to Domain object
        Domain domain = transformer.transformToDomain(inputDto);
        
        // Step 2: Validate the Domain object
        validator.validate(domain);
        
        // Step 3: Apply business rules and persist
        Domain savedDomain = businessService.save(domain);
        
        // Step 4: Convert back to DTO for response
        return transformer.transformToDTO(savedDomain);
    }
}
4. 异常处理实现(适配Spring 2.0.1)

Since Spring 2.0.1 doesn't support @ControllerAdvice (introduced in Spring 3.2), we'll implement HandlerExceptionResolver for global exception handling, which is fully compatible with your Spring version.

4.1 全局异常处理器

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class WorkflowExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        try {
            // Route exceptions to step-specific handlers first
            if (ex instanceof TransformException) {
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Transformation failed: " + ex.getMessage());
            } else if (ex instanceof ValidationException) {
                response.sendError(HttpServletResponse.SC_UNPROCESSABLE_ENTITY, "Validation failed: " + ex.getMessage());
            } else if (ex instanceof ServiceProcessingException) {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Service processing failed: " + ex.getMessage());
            } else {
                // Fallback to global handler for uncaught exceptions
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unexpected error occurred: " + ex.getMessage());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ModelAndView(); // Empty ModelAndView signals we've handled the exception
    }
}

4.2 注册处理器到Spring上下文

Add this bean definition to your Spring configuration file (e.g., applicationContext.xml):

<bean class="com.yourpackage.WorkflowExceptionResolver"/>
5. 完整用例演示

Let's put this all together with a User domain/DTO example to show how everything works end-to-end.

5.1 基础实体类

// User DTO (API request/response model)
public class UserDTO {
    private Long id;
    private String username;
    private String email;
    
    // Getters and Setters
}

// User Domain (business logic model)
public class User {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createdAt;
    
    // Getters and Setters
}

5.2 实现Transformer

import org.springframework.stereotype.Component;

@Component
public class UserTransformer implements Transformer<UserDTO, User> {

    @Override
    public User transformToDomain(UserDTO dto) throws TransformException {
        try {
            User user = new User();
            user.setId(dto.getId());
            user.setUsername(dto.getUsername());
            user.setEmail(dto.getEmail());
            return user;
        } catch (Exception e) {
            throw new TransformException("Failed to convert UserDTO to User", e);
        }
    }

    @Override
    public UserDTO transformToDTO(User domain) throws TransformException {
        try {
            UserDTO dto = new UserDTO();
            dto.setId(domain.getId());
            dto.setUsername(domain.getUsername());
            dto.setEmail(domain.getEmail());
            return dto;
        } catch (Exception e) {
            throw new TransformException("Failed to convert User to UserDTO", e);
        }
    }
}

5.3 实现Validator

import org.springframework.stereotype.Component;

@Component
public class UserValidator implements Validator<User> {

    @Override
    public void validate(User user) throws ValidationException {
        if (user.getUsername() == null || user.getUsername().trim().isEmpty()) {
            throw new ValidationException("Username cannot be empty");
        }
        if (user.getEmail() == null || !user.getEmail().matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
            throw new ValidationException("Invalid email format");
        }
    }
}

5.4 实现BusinessService

import org.springframework.stereotype.Service;

@Service
public class UserService implements BusinessService<User> {

    // Inject your persistence layer (e.g., JdbcTemplate or Hibernate SessionFactory for Spring 2.0.1)
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public User save(User user) throws ServiceProcessingException {
        try {
            // Apply business rule: set creation timestamp
            user.setCreatedAt(LocalDateTime.now());
            return userRepository.save(user);
        } catch (Exception e) {
            throw new ServiceProcessingException("Failed to save User", e);
        }
    }
}

5.5 控制器调用工作流

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/users")
public class UserController {

    private final WorkflowExecutor<UserDTO, User> userWorkflowExecutor;

    @Autowired
    public UserController(WorkflowExecutor<UserDTO, User> userWorkflowExecutor) {
        this.userWorkflowExecutor = userWorkflowExecutor;
    }

    @PostMapping
    public ResponseEntity<UserDTO> createUser(@RequestBody UserDTO userDTO) {
        UserDTO savedUserDto = userWorkflowExecutor.execute(userDTO);
        return ResponseEntity.ok(savedUserDto);
    }
}
为什么这个方案更优?
  • Reusability: The generic interfaces and workflow executor let you easily add support for new entity types without rewriting core logic.
  • Separation of Concerns: Each component handles one responsibility (transformation, validation, business logic, error handling), making code easier to test and maintain.
  • Clear Error Feedback: Step-specific exceptions ensure users get precise error messages instead of generic failures.
  • Spring Compatibility: Fully leverages Spring 2.0.1's dependency injection and exception handling features, no workarounds needed.

内容的提问来源于stack exchange,提问作者Sahil Verma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:26:08