《Spring Boot+策略模式:企业级度假订单Excel导入系统的架构演进与技术实现》

前言

在数字化时代背景下,订单管理系统的高效性与灵活性成为企业竞争力的核心要素。本文档详细剖析了一个基于 策略模式 的度假订单导入系统,通过分层架构设计实现了多源异构数据的标准化处理。系统以 Spring Boot 为核心框架,结合 MyBatis Plus、Excel 工具库和 Swagger 文档化工具,构建了一个支持动态扩展、批量处理、事务安全的订单管理解决方案。

本文将从数据模型定义、策略模式实现、核心业务流程三个维度展开,深入解读系统如何通过 灵活的时间解析高效的事务管理可扩展的架构设计,实现从 Excel 文件到数据库记录的全链路处理。无论是架构师、开发人员还是技术管理者,均可通过本文快速掌握系统设计精髓。

阅读指引

为高效理解本系统,建议按以下路径阅读:

一、架构概览
  1. 数据层(DAO)
    • 核心模型:RouteOrderInfoDO(线路订单数据对象)
    • 核心能力:字段映射、状态枚举关联、多租户支持
    • 路径:数据层 > RouteOrderInfoDO
  1. 服务层(Service)
    • 策略模式:VacationOrderImportStrategy(策略接口)与 TempOrderImportStrategy(具体策略)
    • 工厂模式:VacationProductCategoryFactory(策略路由工厂)
    • 路径:服务层 > 策略 服务层 > 酒店品类工厂
  1. 控制层(Controller)
    • 核心接口:RouteOrderExcelController(Excel 导入/导出)
    • 功能清单:订单导出、多策略导入、模板下载
    • 路径:控制层 > RouteOrderExcelController
二、核心流程
  1. 订单导入流程
    • 阶段分解:Excel 解析 → 数据转换 → 批量持久化
    • 关键代码:TempOrderImportStrategy.importExcel()
    • 路径:数据处理流程
  1. 时间处理机制
    • 双阶段解析:格式标准化 → 智能降级解析
    • 设计亮点:parseDateTime() 方法的多格式兼容性
    • 路径:时间处理
三、扩展指南
  • 新增订单来源:扩展策略接口与工厂路由
  • 性能优化:批量 SQL 优化与异步处理建议
  • 安全增强:文件校验与防 SQL 注入方案

核心总结

1. 架构亮点

维度

设计亮点

分层架构

清晰的 Controller-Service-DAO 分层,通过策略模式实现业务逻辑解耦

扩展性

策略接口标准化 + 工厂路由动态分发,新增订单来源只需实现新策略类,符合开闭原则

性能

批量 SQL 操作(insertBatch/updateBatch)减少数据库交互,事务注解保障原子性

健壮性

双重时间解析机制(支持 3+ 时间格式)、异常分类处理(IO/格式/数据库异常)

2. 关键技术栈
- 核心框架:Spring Boot + MyBatis Plus  
- 策略模式:策略接口 + 工厂路由  
- Excel 处理:Alibaba EasyExcel + 自定义 DictConvert 转换器  
- 事务管理:Spring @Transactional 注解  
- 文档化:Swagger3 + @Schema 注解  
3. 性能数据(示例)

指标

数值(单文件)

千级订单处理耗时

≤2s(含IO与DB操作)

内存占用峰值

≤50MB(万级订单)

批量插入效率

5000条/秒

4. 扩展建议
  • 校验增强:添加 @Validated 参数校验与自定义校验注解
  • 监控集成:通过 Micrometer 实现导入成功率、耗时等指标采集
  • 异步化改造:使用 @Async 注解实现大文件异步导入,提升接口响应速度

通过本文的系统解读,读者可快速掌握基于策略模式的订单导入架构设计方法论,并基于现有代码扩展出符合业务需求的定制化功能。

数据层

RouteOrderInfoDO


package cn.iocoder.central.module.vacation.dal.dataobject.order;import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 线路订单信息 DO** @author 陕文旅*/
@TableName("order_route_order_info")
@KeySequence("order_route_order_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RouteOrderInfoDO extends BaseDO {/*** 主键*/@TableIdprivate Long id;/*** 渠道订单号*/private String systemCode;/*** 订单状态** 枚举 {@link TODO order_module_order_status 对应的类}*/private Integer orderStatus;/*** 订单总金额*/private BigDecimal totalAmount;/*** 支付方式** 枚举 {@link TODO order_module_payment_method 对应的类}*/private Integer paymentMethod;/*** 支付状态** 枚举 {@link TODO order_module_payment_status 对应的类}*/private Integer paymentStatus;/*** 路线ID*/private Long routeId;/*** 路线名称*/private String routeName;/*** 游玩人数*/private Integer playPersonNumber;/*** 下单时间*/private LocalDateTime buyTime;/*** 游玩开始时间*/private LocalDateTime playStartTime;/*** 游玩结束时间*/private LocalDateTime playEndTime;/*** 取票人/收货人/联系人*/private String orderUserName;/*** 手机号*/private String orderUserPhone;/*** 创建者*/private String creator;/*** 创建时间*/private LocalDateTime createTime;/*** 更新者*/private String updater;/*** 更新时间*/private LocalDateTime updateTime;/*** 是否删除*/private Boolean deleted;/*** 租户编号*/private Long tenantId;/** 来源渠道* */private String origin;
}

服务层

策略

TempOrderImportStrategy

package cn.iocoder.central.module.vacation.service.order.excel.strategy;import cn.iocoder.central.module.vacation.controller.admin.order.excel.vo.RouteImportRespVo;
import cn.iocoder.central.module.vacation.dal.dataobject.order.RouteOrderInfoDO;
import cn.iocoder.central.module.vacation.dal.mysql.order.RouteOrderInfoMapper;
import cn.iocoder.central.module.vacation.service.order.excel.vo.TempVacationOrderVo;
import cn.iocoder.yudao.framework.common.util.date.DateTimeFormatterUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;@Component
@Slf4j
public class TempOrderImportStrategy implements VacationOrderImportStrategy {@Resourceprivate RouteOrderInfoMapper routeOrderInfoMapper;@Override@Transactional(rollbackFor = Exception.class)public RouteImportRespVo importExcel(MultipartFile file, String origin) throws IOException {// 1. 读取Excel文件内容List<TempVacationOrderVo> orderList = ExcelUtils.read(file, TempVacationOrderVo.class);// 2. 初始化数据容器List<RouteOrderInfoDO> createRouteOrderList = new ArrayList<>();  // 待新增订单列表List<RouteOrderInfoDO> updateRouteOrderList = new ArrayList<>();  // 待更新订单列表List<String> addOrderCodes = new ArrayList<>();  // 新增订单编号集合List<String> updateOrderCodes = new ArrayList<>();  // 更新订单编号集合// 3. 处理每条订单数据for (TempVacationOrderVo order : orderList) {// 3.1 转换VO为DO对象RouteOrderInfoDO RouteOrderInfoDO = BeanUtils.toBean(order, RouteOrderInfoDO.class);RouteOrderInfoDO.setOrigin(origin);  // 设置订单来源// 3.2 格式化时间字段RouteOrderInfoDO.setBuyTime(parseDateTime(DateTimeFormatterUtils.formatDateTime(order.getBuyTime())));RouteOrderInfoDO.setPlayStartTime(parseDateTime(DateTimeFormatterUtils.formatDateTime(order.getPlayStartTime())));RouteOrderInfoDO.setPlayEndTime(parseDateTime(DateTimeFormatterUtils.formatDateTime(order.getPlayEndTime())));// 3.3 检查订单是否已存在Long tableId = RouteOrderInfoMapper.selectIdBySystemCodeAndOrigin(RouteOrderInfoDO.getSystemCode(),RouteOrderInfoDO.getOrigin());if (tableId != null) {// 3.4 已存在订单 - 准备更新RouteOrderInfoDO.setId(tableId);updateRouteOrderList.add(RouteOrderInfoDO);updateOrderCodes.add(RouteOrderInfoDO.getSystemCode());} else {// 3.5 新订单 - 准备新增createRouteOrderList.add(RouteOrderInfoDO);addOrderCodes.add(RouteOrderInfoDO.getSystemCode());}}// 4. 批量数据库操作if (!createRouteOrderList.isEmpty()) {routeOrderInfoMapper.insertBatch(createRouteOrderList);// 批量插入新订单}if (!updateRouteOrderList.isEmpty()) {routeOrderInfoMapper.updateBatch(updateRouteOrderList);  // 批量更新已有订单}RouteImportRespVo respVo = new RouteImportRespVo();respVo.setAddOrderCodes(addOrderCodes);  // 设置新增订单编号列表respVo.setUpdateOrderCodes(updateOrderCodes);  // 设置更新订单编号列表respVo.setFailureOrderCodes(Collections.emptyList());  // 空列表表示没有失败订单return respVo;}/*** 自动解析日期或日期时间字符串为LocalDateTime* 支持以下格式:* - 日期格式:yyyy-MM-dd* - 日期时间格式:yyyy-MM-dd'T'HH:mm:ss 或 yyyy-MM-dd HH:mm:ss** @param timeString 输入的时间字符串* @return 转换后的LocalDateTime* @throws DateTimeParseException 如果时间字符串格式不正确*/public static LocalDateTime parseDateTime(String timeString) throws DateTimeParseException {try {// 尝试直接解析为LocalDateTime(适用于包含时间的格式)return LocalDateTime.parse(timeString);} catch (DateTimeParseException e1) {try {// 尝试解析为LocalDate(适用于只有日期的格式)LocalDate date = LocalDate.parse(timeString);// 将日期与默认时间00:00:00组合return date.atTime(LocalTime.MIDNIGHT);} catch (DateTimeParseException e2) {// 如果两种格式都不匹配,抛出异常throw new DateTimeParseException("无法解析时间字符串:" + timeString, timeString, 0);}}}}

数据处理流程

我来详细讲解 <mcsymbol name="TempOrderImportStrategy" filename="TempOrderImportStrategy.java" path="c:\project\centralservice\central-module-vacation\central-module-vacation-biz\src\main\java\cn\iocoder\central\module\vacation\service\order\excel\strategy\TempOrderImportStrategy.java" startline="1" type="class"></mcsymbol> 的数据处理流程:

1. 整体流程

这是一个实现 VacationOrderImportStrategy 接口的订单导入策略类,专门处理临时订单的Excel导入,主要流程分为4个阶段:

  1. 读取Excel数据
  2. 初始化数据容器
  3. 逐条处理订单数据
  4. 批量数据库操作
2. 详细数据流转过程
2.1 读取Excel阶段
List<TempVacationOrderVo> orderList = ExcelUtils.read(file, TempVacationOrderVo.class);
  • 输入:MultipartFile 类型的Excel文件
  • 输出:List<TempVacationOrderVo> 订单VO列表
  • 技术:使用 ExcelUtils.read() 将Excel自动映射为Java对象列表
2.2 数据容器初始化
List<RouteOrderInfoDO> createRouteOrderList = new ArrayList<>();  // 待新增
List<RouteOrderInfoDO> updateRouteOrderList = new ArrayList<>();  // 待更新
List<String> addOrderCodes = new ArrayList<>();  // 新增订单号
List<String> updateOrderCodes = new ArrayList<>();  // 更新订单号
  • 创建4个集合分别存储:
    • 需要新增的DO对象
    • 需要更新的DO对象
    • 新增订单的编号(用于返回结果)
    • 更新订单的编号(用于返回结果)
2.3 单条数据处理流程

对每条订单数据执行以下操作:

  1. VO转DO转换
RouteOrderInfoDO RouteOrderInfoDO = BeanUtils.toBean(order, RouteOrderInfoDO.class);
RouteOrderInfoDO.setOrigin(origin);  // 设置来源
  • 使用 BeanUtils.toBean() 进行对象属性拷贝
  • 手动设置订单来源字段
  1. 时间字段处理
RouteOrderInfoDO.setBuyTime(parseDateTime(...));
RouteOrderInfoDO.setPlayStartTime(parseDateTime(...)); 
RouteOrderInfoDO.setPlayEndTime(parseDateTime(...));
  • 调用 parseDateTime() 方法统一处理各种时间格式
  • 支持两种时间格式:
    • 完整日期时间格式:yyyy-MM-dd'T'HH:mm:ssyyyy-MM-dd HH:mm:ss
    • 简单日期格式:yyyy-MM-dd (会自动补全时间为00:00:00)
  1. 订单存在性检查
Long tableId = RouteOrderInfoMapper.selectIdBySystemCodeAndOrigin(RouteOrderInfoDO.getSystemCode(),RouteOrderInfoDO.getOrigin()
);
  • 根据系统编号和来源查询是否已存在相同订单
  • 返回已存在订单的ID或null
  1. 数据分类存储
if (tableId != null) {// 更新逻辑RouteOrderInfoDO.setId(tableId);updateRouteOrderList.add(RouteOrderInfoDO);updateOrderCodes.add(RouteOrderInfoDO.getSystemCode());
} else {// 新增逻辑createRouteOrderList.add(RouteOrderInfoDO);addOrderCodes.add(RouteOrderInfoDO.getSystemCode());
}
2.4 批量数据库操作
if (!createRouteOrderList.isEmpty()) {routeOrderInfoMapper.insertBatch(createRouteOrderList);
}
if (!updateRouteOrderList.isEmpty()) {routeOrderInfoMapper.updateBatch(updateRouteOrderList); 
}
  • 使用批量操作提高性能
  • 分别处理新增和更新操作
2.5 返回结果构造
RouteImportRespVo respVo = new RouteImportRespVo();
respVo.setAddOrderCodes(addOrderCodes);
respVo.setUpdateOrderCodes(updateOrderCodes); 
respVo.setFailureOrderCodes(Collections.emptyList());
  • 构造包含处理结果的响应对象
  • 当前实现没有失败订单(空列表)
3. 关键设计点
  1. 事务管理@Transactional 确保整个导入过程原子性
  2. 批量处理:使用批量SQL提高性能
  3. 灵活的时间解析parseDateTime() 方法支持多种时间格式
  4. 结果追踪:记录所有处理过的订单编号
  5. 策略模式:实现标准接口,便于扩展其他导入方式
4. 数据流转图
Excel文件 → List<TempVacationOrderVo> → List<RouteOrderInfoDO> (分新增/更新)→ 批量SQL操作→ RouteImportRespVo (结果统计)

这个实现很好地平衡了性能、可靠性和可维护性,是典型的批处理数据导入解决方案。

!!时间处理

我来详细讲解 <mcsymbol name="TempOrderImportStrategy" filename="TempOrderImportStrategy.java" path="c:\project\centralservice\central-module-vacation\central-module-vacation-biz\src\main\java\cn\iocoder\central\module\vacation\service\order\excel\strategy\TempOrderImportStrategy.java" startline="52" type="function"></mcsymbol> 中的时间处理逻辑:

1. 时间处理流程分解

这三行代码处理了三个时间字段(购买时间、游玩开始时间、游玩结束时间),处理流程完全一致,分为两个关键步骤:

RouteOrderInfoDO.setBuyTime(parseDateTime(DateTimeFormatterUtils.formatDateTime(order.getBuyTime())));
  1. 格式化阶段DateTimeFormatterUtils.formatDateTime()
    • 将原始时间对象格式化为标准字符串
    • 确保时间格式统一化处理
  1. 解析阶段parseDateTime()
    • 将格式化后的字符串解析为 LocalDateTime 对象
    • 支持多种时间格式的灵活解析
2. 关键技术点解析
2.1 格式化阶段

DateTimeFormatterUtils.formatDateTime() 的作用:

  • 输入:可能是各种格式的时间对象(Date/LocalDateTime/String等)
  • 输出:统一格式的字符串(如 yyyy-MM-dd HH:mm:ss
  • 确保后续解析阶段输入格式的一致性
2.2 解析阶段

parseDateTime() 方法的智能解析逻辑:

  1. 优先尝试解析完整时间格式
    • 支持 ISO 格式:yyyy-MM-dd'T'HH:mm:ss
    • 支持常规格式:yyyy-MM-dd HH:mm:ss
  1. 降级解析日期格式
    • 当完整时间解析失败时,尝试解析简单日期:yyyy-MM-dd
    • 自动补全时间为 00:00:00
  1. 异常处理
    • 双重异常捕获确保解析可靠性
    • 最终会抛出包含详细错误信息的 DateTimeParseException
3. 设计优势
  1. 格式兼容性
    • 可以处理来自不同数据源的多样化时间格式
    • Excel、数据库、API等不同来源的时间数据都能适配
  1. 数据一致性
    • 最终统一存储为 LocalDateTime 类型
    • 确保业务逻辑处理时时间格式统一
  1. 健壮性设计
    • 通过格式化+解析的两阶段处理增加可靠性
    • 清晰的错误提示便于问题排查
4. 处理流程图解
原始时间对象(order.getBuyTime())→ DateTimeFormatterUtils.formatDateTime() → 标准化时间字符串 → parseDateTime() → LocalDateTime对象→ 设置到RouteOrderInfoDO
5. 典型应用场景

这种处理方式特别适合:

  • 从Excel导入的时间数据(可能有各种格式)
  • 需要与数据库时间字段对接的场景
  • 需要严格时间计算的业务逻辑(如游玩时长计算)

这种设计既保证了灵活性,又确保了最终数据的一致性,是时间处理的最佳实践。

VacationOrderImportStrategy

package cn.iocoder.central.module.vacation.service.order.excel.strategy;import cn.iocoder.central.module.vacation.controller.admin.order.excel.vo.RouteImportRespVo;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;public interface VacationOrderImportStrategy {/*** 导入Excel** @param file* @param origin* @return*/RouteImportRespVo importExcel(MultipartFile file, String origin) throws IOException;}

我来详细讲解 <mcsymbol name="VacationOrderImportStrategy" filename="VacationOrderImportStrategy.java" path="c:\project\centralservice\central-module-vacation\central-module-vacation-biz\src\main\java\cn\iocoder\central\module\vacation\service\order\excel\strategy\VacationOrderImportStrategy.java" startline="1" type="interface"></mcsymbol> 这个策略接口的核心作用:

核心定位

这是订单导入功能的标准策略接口,采用策略模式设计,主要作用包括:

  1. 统一导入规范
    • 定义所有订单导入策略必须实现的importExcel方法
    • 标准化输入参数和返回值格式
  1. 多源订单支持
    • 通过origin参数区分不同来源的订单
    • 允许为不同来源实现定制化导入逻辑
  1. 解耦设计
    • 将导入逻辑与业务调用方解耦
    • 新增导入渠道只需实现新策略,无需修改现有代码

方法详解

RouteImportRespVo importExcel(MultipartFile file, String origin) throws IOException;
  • 参数说明
    • file:需要导入的Excel文件
    • origin:订单来源标识(如"shanwenlv")
  • 返回值
    • 统一返回RouteImportRespVo结果对象
    • 包含成功/失败订单统计信息
  • 异常处理
    • 声明抛出IOException处理文件读取异常
    • 实现类可添加更多特定异常

设计优势

  1. 扩展性
    • 轻松支持新增订单来源
    • 已有策略互不影响
  1. 可维护性
    • 每种导入策略独立实现
    • 便于单独测试和修改
  1. 业务隔离
    • 不同来源的导入逻辑完全隔离
    • 避免代码耦合

典型实现

如之前看到的TempOrderImportStrategy就是其具体实现,处理特定来源的订单导入。

这个接口是订单导入功能的核心抽象,为系统提供了灵活、可扩展的导入架构。

service-vo

package cn.iocoder.central.module.vacation.service.order.excel.vo;import cn.iocoder.central.module.vacation.enums.DictTypeConstants;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.math.BigDecimal;@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
public class TempVacationOrderVo {//    导入渠道订单号@ExcelProperty("订单编号")private String systemCode;@ExcelProperty(value = "订单状态", converter = DictConvert.class)@DictFormat(DictTypeConstants.ORDER_MODULE_ORDER_STATUS)private String orderStatus;@ExcelProperty("产品名称")private String routeName;@ExcelProperty("下单时间")private String buyTime;@ExcelProperty("游玩人数")private Integer playPersonNumber;@ExcelProperty("开始时间")private String playStartTime;@ExcelProperty("结束时间")private String playEndTime;@ExcelProperty("金额")private BigDecimal totalAmount;@ExcelProperty(value = "支付方式", converter = DictConvert.class)@DictFormat(DictTypeConstants.ORDER_MODULE_PAYMENT_METHOD)private String paymentMethod;@ExcelProperty(value = "支付状态", converter = DictConvert.class)@DictFormat(DictTypeConstants.ORDER_MODULE_PAYMENT_STATUS)private String paymentStatus;@ExcelProperty("联系人")private String orderUserName;@ExcelProperty("联系方式")private String orderUserPhone;
}

我来详细讲解 TempVacationOrderVo 这个类的作用和设计特点:

核心定位

这是一个Excel导入数据映射的VO(Value Object)类,专门用于临时度假订单的Excel导入场景,主要作用包括:

  1. Excel数据映射
    • 定义了Excel列名与Java字段的映射关系
    • 通过注解实现Excel列到对象属性的自动转换
  1. 数据格式转换
    • 处理字典类型数据的转换(如订单状态、支付方式等)
    • 规范时间、金额等特殊字段的格式

关键设计特点

  1. Excel映射配置
    • 使用@ExcelProperty注解配置Excel列名
    • 支持自定义转换器(如字典转换)
  1. 字典数据处理
    • 通过@DictFormat关联字典常量
    • 使用DictConvert实现字典值与显示文本的转换
  1. 数据类型设计
    • 金额使用BigDecimal保证精度
    • 时间字段使用String保持原始格式
  1. Lombok简化
    • 自动生成getter/setter等方法
    • 禁用链式调用避免导入问题

业务价值

  1. 标准化导入
    • 统一Excel导入的数据结构
    • 确保不同来源订单的导入一致性
  1. 扩展性
    • 新增字段只需添加属性
    • 不影响现有导入逻辑
  1. 数据校验
    • 通过注解实现基础校验
    • 为后续业务处理提供干净数据

这个VO类在订单导入流程中起到了承上启下的关键作用,既对接了前端Excel文件的结构,又为后端业务处理提供了标准化的数据对象。

酒店品类工厂

package cn.iocoder.central.module.vacation.service.order.excel;import cn.iocoder.central.module.vacation.service.order.excel.strategy.TempOrderImportStrategy;
import cn.iocoder.central.module.vacation.service.order.excel.strategy.VacationOrderImportStrategy;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;/*** 酒店品类工厂工厂*/
@Component
public class VacationProductCategoryFactory {private static final String TEMP_TYPE = "shanwenlv";@Resourceprivate TempOrderImportStrategy tempOrderImportStrategy;public VacationOrderImportStrategy getImportStrategy(String origin) {return switch (origin) {case TEMP_TYPE -> tempOrderImportStrategy;default -> null;};}
}

我来详细讲解 VacationProductCategoryFactory 这个工厂类的作用和设计特点:

核心定位

这是一个基于策略模式的工厂类,专门用于管理和提供不同来源的订单导入策略实现,主要作用包括:

  1. 策略集中管理
    • 统一管理所有订单导入策略实现
    • 作为策略模式的入口点
  1. 策略动态分发
    • 根据订单来源标识动态返回对应策略
    • 隔离调用方与具体策略实现的耦合

关键设计特点

  1. 简单工厂模式
    • 通过静态常量定义支持的来源类型
    • 使用switch-case返回对应策略
  1. 松耦合设计
    • 依赖注入具体策略实现
    • 新增策略只需扩展工厂方法
  1. 可扩展性
    • 预留了default分支便于扩展
    • 新增来源只需添加case分支

业务价值

  1. 统一入口
    • 为订单导入提供标准化的策略获取方式
    • 简化调用方的使用复杂度
  1. 灵活扩展
    • 支持动态新增订单来源类型
    • 不影响现有导入流程
  1. 维护便利
    • 策略变更只需修改工厂类
    • 不影响业务调用代码

这个工厂类在订单导入系统中起到了策略路由的关键作用,是策略模式的核心实现组件。

控制层

RouteOrderExcelController

package cn.iocoder.central.module.vacation.controller.admin.order.excel;import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.central.module.vacation.controller.admin.order.excel.vo.RouteImportRespVo;
import cn.iocoder.central.module.vacation.controller.admin.order.excel.vo.RouteImportVo;
import cn.iocoder.central.module.vacation.controller.admin.order.vo.RouteOrderInfoPageReqVO;
import cn.iocoder.central.module.vacation.controller.admin.order.vo.RouteOrderInfoRespVO;
import cn.iocoder.central.module.vacation.dal.dataobject.order.RouteOrderInfoDO;
import cn.iocoder.central.module.vacation.service.order.RouteOrderInfoService;
import cn.iocoder.central.module.vacation.service.order.excel.VacationProductCategoryFactory;
import cn.iocoder.central.module.vacation.service.order.excel.strategy.TempOrderImportStrategy;
import cn.iocoder.central.module.vacation.service.order.excel.strategy.VacationOrderImportStrategy;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.util.List;import static cn.iocoder.central.module.vacation.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;@Tag(name = "管理后台 - 度假订单 Excel")
@RestController
@RequestMapping("/vacation/order/excel")
@Validated
public class RouteOrderExcelController {@Resourceprivate RouteOrderInfoService routeOrderInfoService;@Resourceprivate VacationProductCategoryFactory vacationProductCategoryFactory;@GetMapping("/export-excel")@Operation(summary = "导出度假订单信息 Excel")
//    @PreAuthorize("@ss.hasPermission('order:child-route-order-info:export')")@ApiAccessLog(operateType = EXPORT)public void exportChildRouteOrderInfoExcel(@Valid RouteOrderInfoPageReqVO pageReqVO,HttpServletResponse response) throws IOException {pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);List<RouteOrderInfoRespVO> list = routeOrderInfoService.getRouteOrderInfoPage(pageReqVO).getList();// 导出 ExcelExcelUtils.write(response, "路线订单信息.xls", "数据", RouteOrderInfoRespVO.class,BeanUtils.toBean(list, RouteOrderInfoRespVO.class));}@PostMapping("/import")@Operation(summary = "导入度假订单信息")@Parameters({@Parameter(name = "file", description = "Excel 文件", required = true),@Parameter(name = "origin", description = "来源", example = "true")})
//    @PreAuthorize("@ss.hasPermission('order:child-route-order-info:import')")public CommonResult<RouteImportRespVo> importExcel(@RequestParam("file") MultipartFile file,@RequestParam("origin") String origin) throws Exception {VacationOrderImportStrategy importStrategy = vacationProductCategoryFactory.getImportStrategy(origin);if (ObjectUtil.isEmpty(importStrategy)) {return error(VACATION_NOT_FOUND_STRATEGY);}try {RouteImportRespVo orderImportRespVo = importStrategy.importExcel(file, origin);return success(orderImportRespVo);} catch (IOException e) {return error(VACATION_IMPORT_ERROR);}}@GetMapping("/get-route-import-template")@Operation(summary = "获取度假导入模板")public void RouteImportTemplate(HttpServletResponse response) throws IOException {ExcelUtils.write(response, "度假导入模板.xlsx", "度假列表", RouteImportVo.class, null);}}

是一个Spring Boot的RESTful控制器,用于处理与度假订单Excel文件相关的操作。具体功能如下:1. 提供导出度假订单信息到Excel文件的接口。2. 提供导入度假订单信息的接口,根据不同来源选择不同的导入策略。3. 提供获取度假导入模板的接口。

`@Tag(name = "管理后台 - 度假订单 Excel")` :这是Swagger的注解,用于为API文档添加标签,方便在API文档工具(如Swagger UI)中对接口进行分组和展示。这里将该控制器下的所有接口归为“管理后台 - 度假订单 Excel”这一类别。2.`@RestController` :这是Spring框架的注解,它是`@Controller` 和`@ResponseBody` 的组合注解。表示该类是一个控制器,并且其方法返回的对象会自动序列化为JSON格式的响应体,用于构建RESTful风格的API。3.`@RequestMapping("/vacation/order/excel")` :这也是Spring框架的注解,用于映射HTTP请求的URL路径。它将该控制器下的所有处理方法的URL前缀都设置为`/vacation/order/excel` ,即访问该控制器中的任何接口时,URL都需要以这个前缀开头。4.`@Validated` :这是Spring框架的注解,用于开启方法级别的数据验证。当控制器的方法参数使用了`@Valid` 注解进行验证时,`@Validated` 注解会确保验证逻辑生效。

RouteImportRespVo

package cn.iocoder.central.module.vacation.controller.admin.order.excel.vo;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;import java.util.List;@Schema(description = "管理后台 - 路线订单导入 Response VO")
@Data
public class RouteImportRespVo {@Schema(description = "导入成功的订单编号数组", requiredMode = Schema.RequiredMode.REQUIRED)public List<String> addOrderCodes;@Schema(description = "更新成功的订单编号数组", requiredMode = Schema.RequiredMode.REQUIRED)public List<String> updateOrderCodes;@Schema(description = "导入失败的订单编号数组", requiredMode = Schema.RequiredMode.REQUIRED)public List<String> failureOrderCodes;// 如果需要,可以手动添加其他方法,如自定义的 getter、setter 或者业务逻辑方法
}

文件定义了一个名为`RouteImportRespVo` 的类,它是一个用于管理后台的路线订单导入响应视图对象(VO)。该类使用了`@Schema` 注解来描述类的用途,方便生成API文档。类中包含三个`List<String>` 类型的属性,分别记录导入成功、更新成功和导入失败的订单编号数组,便于前端展示导入结果。同时,使用了`@Data` 注解自动生成getter、setter等方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/900992.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SSRF漏洞公开报告分析

文章目录 1. SSRF | 获取元数据 | 账户接管2. AppStore | 版本上传表单 | Blind SSRF3. HOST SSRF一、为什么HOST修改不会影响正常访问二、案例 4. Turbonomic 的 终端节点 | SSRF 获取元密钥一、介绍二、漏洞分析 5. POST | Blind SSRF6. CVE-2024-40898利用 | SSRF 泄露 NTL…

告别 ifconfig:为什么现代 Linux 系统推荐使用 ip 命令

告别 ifconfig&#xff1a;为什么现代 Linux 系统推荐使用 ip 命令 ifconfig 指令已经被视为过时的工具&#xff0c;不再是查看和配置网络接口的推荐方式。 与 netstat 被 ss 替代类似。 本文简要介绍 ip addr 命令的使用 简介ip ifconfig 属于 net-tools 包&#xff0c;这个…

VLC快速制作rtsp流媒体服务器

1.安装vlc media player工具 2.打开后点击菜单 媒体->流 3.添加mp4视频&#xff0c;选择串流 4.选择 下一个 5.新目标选择 RTSP&#xff0c;点击添加按钮 6.端口和路径随便填写&#xff0c;如果推流失败就换个端口。一路操作下去 7.点击 流 按钮后&#xff0c;就可以看到下图…

基于 JavaWeb 的 SSM 在线视频教育系统设计和实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

RK3568 基于Gstreamer的多媒体调试记录

文章目录 1、环境介绍2、概念理清3、提前准备4、GStreamer编译5、GStreamer基础介绍6、视频播放初体验7、视频硬编码7.1、h2647.2、h265 8、视频硬解码8.1、解码视频并播放解码视频并播放带音频 1、环境介绍 硬件&#xff1a;飞凌ok3568-c开发板 软件&#xff1a;原厂rk356x …

Mac学习使用全借鉴模式

Reference https://zhuanlan.zhihu.com/p/923417581.快捷键 macOS 的快捷键组合很多&#xff0c;相应的修饰键就多达 6 个&#xff08;Windows 系统级就 4 个&#xff09;&#xff1a; Command ⌘ Shift ⇧ Option ⌥ Control ⌃ Caps Lock ⇪ Fn 全屏/退出全屏 command con…

SpringBoot多线程,保证各个子线程和主线程事物一致性

SpringBoot多线程&#xff0c;保证各个子线程和主线程事物一致性 1、第一种写法1.1、TransactionalUntil工具类1.2、service业务类 2、第二种写法2.1、service业务类 1、第一种写法 1.1、TransactionalUntil工具类 import org.springframework.jdbc.datasource.DataSourceTra…

高并发的业务场景下,如何防止数据库事务死锁

一、 一致的锁定顺序 定义: 死锁的常见原因之一是不同的事务以不同的顺序获取锁。当多个事务获取了不同资源的锁,并且这些资源之间发生了互相依赖,就会形成死锁。 解决方法: 确保所有的事务在获取多个锁时,按照相同的顺序请求锁。例如,如果事务A需要锁定表A和表B,事务…

【从0到1学MybatisPlus】MybatisPlus入门

Mybatis-Plus 使用场景 大家在日常开发中应该能发现&#xff0c;单表的CRUD功能代码重复度很高&#xff0c;也没有什么难度。而这部分代码量往往比较大&#xff0c;开发起来比较费时。 因此&#xff0c;目前企业中都会使用一些组件来简化或省略单表的CRUD开发工作。目前在国…

力扣HOT100之链表: 148. 排序链表

这道题直接用蠢办法来做的&#xff0c;直接先遍历一遍链表&#xff0c;用一个哈希表统计每个值出现的次数&#xff0c;由于std::map<int, int>会根据键进行升序排序&#xff0c;因此我们将节点的值作为键&#xff0c;其在整个链表中的出现次数作为值&#xff0c;当所有元…

Transformer多卡训练初始化分布式环境:(backend=‘nccl‘)

Transformer多卡训练初始化分布式环境:(backend=‘nccl’) dist.init_process_group(backend=nccl)在多卡环境下初始化分布式训练环境,并为每个进程分配对应的 GPU 设备。下面为你逐行解释代码的含义: 1. 初始化分布式进程组 try:dist.init_process_group(backend=nccl) e…

使用Mybatis时在XML中SQL高亮显示的方法

如图所示&#xff0c;上方的SQL代码很像是一个字符串&#xff0c;那么如何把上方的SQL改成和下方一样的SQL,使得IDEA可以识别SQL方言呢&#xff1f; 1.选中SQL中的一部分代码&#xff0c;此时左侧会出现一个黄色的灯泡图案&#xff0c;点击2.选择这个注入语言或者引用

Spring Boot MongoDB自定义连接池配置

手打不易&#xff0c;如果转摘&#xff0c;请注明出处&#xff01; 注明原文&#xff1a;http://zhangxiaofan.blog.csdn.net/article/details/144341407 一、引言 在 Spring Boot 应用中使用 MongoDB 时&#xff0c;合理配置连接池可以显著提升数据库访问的性能和稳定性。默…

Tabnet介绍(Decision Manifolds)和PyTorch TabNet之TabNetRegressor

Tabnet介绍&#xff08;Decision Manifolds&#xff09;和PyTorch TabNet之TabNetRegressor Decision ManifoldsTabNet1.核心思想2. 架构组成3. 工作流程4. 优点 PyTorch TabNetTabNetRegressor参数1. 模型相关参数n_dn_an_stepsgammacat_idxscat_dimscat_emb_dim 2. 训练相关参…

图像变换方式区别对比(Opencv)

1. 变换示例 import cv2 import matplotlib.pyplot as plotimg cv2.imread(url) img_cut img[100:200, 200:300] img_rsize cv2.resize(img, (50, 50)) (hight,width) img.shape[:2] rotate_matrix cv2.getRotationMatrix2D((hight//2, width//2), 50, 1) img_wa cv2.wa…

Navicat分组、查询分享

1、分组 有些项目业务表比较多&#xff0c;多达几百张&#xff0c;如果通过人眼看&#xff0c;很容易头晕。这时候可以通过Navicat表分组来进行分类。 使用场景 按版本分组按业务功能分组 创建分组 示例&#xff1a;按版本分组&#xff0c;可以将1.0版本的表放到1.0中。 分组…

大模型在初治CLL成人患者诊疗全流程风险预测与方案制定中的应用研究

目录 一、绪论 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与内容 二、大模型技术与慢性淋巴细胞白血病相关知识 2.1 大模型技术原理与特点 2.2 慢性淋巴细胞白血病的病理生理与诊疗现状 三、术前风险预测与手术方案制定 3.1 术前数据收集与预处理 3.2 大模…

for循环的优化方式、循环的种类、使用及平替方案。

本篇文章主要围绕for循环,来讲解循环处理数据中常见的六种方式及其特点,性能。通过本篇文章你可以快速了解循环的概念,以及循环在实际使用过程中的调优方案。 作者:任聪聪 日期:2025年4月11日 一、循环的种类 1.1 默认有以下类型 原始 for 循环 for(i = 0;i<10;i++){…

穿透三层内网VPC1

网络拓扑: 打开入口web服务 信息收集发现漏洞CVE-2024-4577 PHP CGI Windows平台远程代码执行漏洞&#xff08;CVE-2024-4577&#xff09;复现_cve-2024-4577漏洞复现-CSDN博客 利用POC&#xff1a; 执行成功&#xff0c;那么直接上传马子&#xff0c;注意&#xff0c;这里要…

【计算机网络】同步操作 vs 异步操作:核心区别与实战场景解析

&#x1f4cc; 引言 在网络通信和分布式系统中&#xff0c;**同步&#xff08;Synchronous&#xff09;和异步&#xff08;Asynchronous&#xff09;**是两种基础却易混淆的操作模式。本文将通过代码示例、生活类比和对比表格&#xff0c;帮你彻底理解它们的区别与应用场景。 1…