具体需求:
一 文件上传:
(1) 前端使用ant design上传组件完成上传, 直接点击按钮提交,
上传成功后需要服务端返回成功标识;
(2) 后端提供独立的服务,
(3) 需要判断权限,预留接口
(4) 上传下载的表本身与具体业务没有关系
(5) 前端先调上传服务,再调业务服务来完成整个业务
二 文件下载:
(1) 前端给后端提供下载标识,由服务端给出下载链接
(2) 下载需要断点续传
(3) 需要判断权限,预留接口
(4) 支持下载计数, 支持tag,
(5) 目录结构设计需要考虑
(6) 考虑加Job 清理过期文件,预留接口
(7) 考虑文件版本设计,预留接口
(8) 考虑根据hash排除重复文件,预留接口
(9) 考虑需要CND支持,预留接口
三 文件导入导出:
(1)基于MQ实现导入导出的异步,给出通知(预留接口)
(2)文件导入支持excel csv
(3) 如果导入文件不存在复杂校验已经数据量小,客户端可以解析文件后发送纯数据给服务端。
如果存在较复杂业务逻辑校验,文件过大,服务端处理
(4)预留接口支持大文件或大批量文件导入导出的性能优化
设计:
文件导入设计:
(1)客户端用户发起导入文件请求
(2)业务服务响应请求并接受数据
(3),(5)业务使用Java8 Aync异步调用导入导出公用接口(Jar包形式)
(4)服务端返回前端消息已成功收到文件
(6)对接受到IO流进行解析并转换为DTO数据
6.1.1,6.1.2, 6.1.3 如果成功转换成DTO,对获取的数据进行后续业务处理,并把导入结果发送消息到通知队列
6.2.1,6.2.2 如果转换数据失败,调用文件存储服务对导入的文件进行有效期设置并进行存储,最后发送消息到通知队列
(7)通知服务持续监听通知队列
(8)读取消息队列后根据不同的通知类型进行封装
(9)通知相应的客户端
(10)客户端收到通知,提示用户
流程图如下:
文件导出设计:
(1)客户端用户发起导出文件请求
(2)业务服务响应请求并接受数据
(3),(4.2)业务使用Java8 Aync初始化需要导出的数据
(4.1)服务端返回前端消息已成功收到文件
(5)导入导出公用接口(Jar包形式)接受到导出数据
(6)根据导出数据生成需要导出的Eexcel元数据
(7)将需要导出的excel数据转换为IO流
(8.1.1)如果业务服务正常获取IO流后直接导出到前端
(8.1.2)调用文件存储服务将导出的文件进行保存
(8.1.3)发出消息到通知队列
(8.2.1)如果业务服务没有正常获取导出的IO流,发出消息到通知队列
(9)通知服务持续监听通知队列
(10)读取消息队列后根据不同的通知类型进行封装
(11)通知相应的客户端
(12)客户端收到通知,提示用户
流程图如下:
导入导出实现:
创建自定义注解,用以以泛型的方式匹配大部分业务导入导出
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface IOHeader { String headerName() default ""; int index() default 0; }
注解中headerName代表导入的标题
index代表字段在表格中的位置,目前index只对导出起作用
添加类 IOHeaderInfo 包含以下属性
private String property; //导入导出数据所对应实体中的字段 private String headerName; //导入导出表格中的标题 private Integer index; //导出的字段顺序
添加工具类 IOHeaderUtil 包含方法
public static List<IOHeaderInfo> getIOHeaderInfo(Class<?> clazz)
根据传入的clazz返回IOHeaderInfo类集合, clazz为带有
@IOHeader注解的类
例如
public class InventoryPortationDTO { @IOHeader(headerName = "库区编号",index = 0) private String areaCode; @IOHeader(headerName = "库位编号",index = 1) private String locationCode; @IOHeader(headerName = "备件编号",index = 2) private String sparePartCode; @IOHeader(headerName = "备件名称",index = 3) private String sparePartName; @IOHeader(headerName = "盘点数量",index = 4) private Integer quantity; @IOHeader(headerName = "备注",index = 5) private String remark;
………………
}
文件导入:
/** * 文件导入 * @param outputStream 异常信息输出流 导入的数据不符合clazz字段格式时会把对应信息输出到outputStream中,若格式无误则本参数不做处理 * @param file 所导入的文件 * @param clazz 导入文件中数据所对应的带有@IOHeader注解的DTO * @return 返回DTO的集合,若导入的数据不符合,则会抛出异常 * @throws Exception */ List<T> fileImport(OutputStream outputStream, MultipartFile file, Class<T> clazz) throws Exception;
调用方式如下所示:
List<WarehousePotationDTO> warehousePotationDTOList = dataPortationService.fileImport(outputStream, multipartFile, WarehousePotationDTO.class);
文件导出:
/** * 文件导出初始化 * @param response * @param fileName */
void initResponse(HttpServletResponse response, String fileName);
本方法会对输出格式做出处理,根据fileName定义输出文件的文件名称
调用方式如下所示:
String fileName = multipartFile.getOriginalFilename();
dataPortationService.initResponse(response, fileName);
/** * 文件导出 * @param os 所要导出的文件流 * @param list 带有@IOHeader注解的DTO集合 * @param clazz 带有@IOHeader注解的DTO类 * @throws Exception */ void fileExport(OutputStream os, List<T> list, Class<T> clazz) throws Exception;
调用方式如下所示:
dataPortationService.fileImport(os,list, WarehousePotationDTO.class);