前言

传统ERP系统中,和Excel的交互比较频繁。主要步骤分为:导入,基础数据校验,业务等特殊校验,返回导入结果。工作中的系统原版是手动解析,然后进行校验,有很多共性的基础校验没有整合,代码冗余过多。现打算重构代码,主要使用了策略模式责任链模式进行改造。不多说直接上代码。

代码实现

各种类的基本功能

  1. 策略模式

    • 通过 ImportHandlerExportHandler 接口定义导入导出的行为

    • 具体实现类如 UserImportHandler 实现特定类型的导入逻辑

    • ExcelProcessor 作为上下文,根据类型选择合适的处理器

  2. 责任链模式

    • Validator 接口定义校验行为

    • ValidatorChain 管理校验器链

    • 基本字段校验器和业务校验器依次执行

  3. 注解驱动的基本校验

    • 使用 @Required@MaxLength@NumberRange 等注解定义字段约束

    • BasicValidator 通过反射检查字段注解进行基本校验

  4. 可扩展的业务校验

    • BusinessValidationRule 接口允许自定义业务校验规则

    • BusinessValidator 动态添加和执行这些规则

策略模式部分

策略模式主要定义导入导出的,通过实现接口来自定义导入导出逻辑

ImportHandler(定义导入行为),BaseImportHandler(基础导入步骤)UserImportHandler(导入最终实现方案)

public interface ImportHandler {
    ImportResult handleImport(InputStream inputStream) throws IOException;
}    
public abstract class BaseImportHandler implements ImportHandler {
    private List<Validator> validators = new ArrayList<>();

    public BaseImportHandler() {
        // 添加基本字段校验器
        validators.add(createBasicValidator());
        // 添加业务校验器
        validators.add(createBusinessValidator());
    }

    protected abstract Validator createBasicValidator();
    protected abstract Validator createBusinessValidator();

    @Override
    public ImportResult handleImport(InputStream inputStream) throws IOException {
        // 1. 解析Excel
        List<Map<String, Object>> records = parseExcel(inputStream);
        
        // 2. 构建责任链
        ValidatorChain chain = new ValidatorChain(validators);
        
        // 3. 执行校验
        ImportResult result = new ImportResult();
        for (Map<String, Object> record : records) {
            ValidationResult validationResult = chain.validate(record);
            if (validationResult.isValid()) {
                // 4. 校验通过,执行数据插入
                insertRecord(record);
                result.getSuccessRecords().add(record);
            } else {
                result.getFailedRecords().add(record);
                result.getErrorMessages().addAll(validationResult.getErrorMessages());
            }
        }
        
        return result;
    }

    protected abstract List<Map<String, Object>> parseExcel(InputStream inputStream) throws IOException;
    protected abstract void insertRecord(Map<String, Object> record);
}    
public class UserImportHandler extends BaseImportHandler {
    @Override
    protected Validator createBasicValidator() {
        return new BasicValidator(User.class);
    }

    @Override
    protected Validator createBusinessValidator() {
        BusinessValidator businessValidator = new BusinessValidator();
        
        // 添加业务校验规则
        businessValidator.addValidationRule("age", new BusinessValidationRule() {
            @Override
            public boolean validate(Object value) {
                if (value == null) return false;
                try {
                    int age = Integer.parseInt(value.toString());
                    return age >= 18 && age <= 60;
                } catch (NumberFormatException e) {
                    return false;
                }
            }

            @Override
            public String getErrorMessage() {
                return "年龄必须在18到60岁之间";
            }
        });
        
        return businessValidator;
    }

    @Override
    protected List<Map<String, Object>> parseExcel(InputStream inputStream) throws IOException {
        // 实际实现中使用Apache POI或EasyExcel解析Excel文件
        // 这里仅作示例,返回模拟数据
        List<Map<String, Object>> records = new ArrayList<>();
        
        Map<String, Object> record1 = new HashMap<>();
        record1.put("name", "张三");
        record1.put("age", 25);
        record1.put("email", "zhangsan@example.com");
        records.add(record1);
        
        Map<String, Object> record2 = new HashMap<>();
        record2.put("name", "李四");
        record2.put("age", 17); // 不合法年龄
        record2.put("email", "lisi@example.com");
        records.add(record2);
        
        return records;
    }

    @Override
    protected void insertRecord(Map<String, Object> record) {
        // 实际实现中插入数据库
        System.out.println("插入用户数据: " + record);
    }
}
@Service
public class ExcelProcessor {
    private final Map<String, ImportHandler> importHandlers = new HashMap<>();
    private final Map<String, ExportHandler> exportHandlers = new HashMap<>();

    // 注册导入处理器
    public void registerImportHandler(String type, ImportHandler handler) {
        importHandlers.put(type, handler);
    }

    // 注册导出处理器
    public void registerExportHandler(String type, ExportHandler handler) {
        exportHandlers.put(type, handler);
    }

    // 执行导入
    public ImportResult importExcel(String type, InputStream inputStream) throws IOException {
        ImportHandler handler = importHandlers.get(type);
        if (handler == null) {
            throw new IllegalArgumentException("不支持的导入类型: " + type);
        }
        return handler.handleImport(inputStream);
    }

    // 执行导出
    public void exportExcel(String type, OutputStream outputStream, List<?> data) throws IOException {
        ExportHandler handler = exportHandlers.get(type);
        if (handler == null) {
            throw new IllegalArgumentException("不支持的导出类型: " + type);
        }
        handler.handleExport(outputStream, data);
    }
}