主页 > 游戏开发  > 

EasyPoi系列之通用导入接口设计

EasyPoi系列之通用导入接口设计

EasyPoi系列之通用导入接口设计 1 背景2 分析及设计2.1 标准导入交互分析2.2 设计2.2.1 导入模板生成接口2.2.2 数据导入接口 3、代码实现3.1 人员实体-PersonEntity3.2 定义数据保存通用接口-ExcelImporter3.3 人员数据保存实现- PersonService3.4 建立业务与实体及保存实现类之间的关系-EnumImportType3.5 编写模板导出接口3.6 通用导入接口3.7 完整接口-ImporterController 4 接口测试4.1 导出模板4.2 数据导入4.2.1 模板数据填充4.2.2 执行导入 5 后记

1 背景

在业务管理系统中,经常会涉及到数据导入的功能,针对各个业务场景各自编写相应接口,会发现外部接口除了参数之外,其他编码都一样,显得过于重复,那是否可以通过编写统一的导入接口,各个应用只需要实现各自接收数据后的数据加工存储即可,以达到提升代码的简洁性的效果呢?

2 分析及设计 2.1 标准导入交互分析

在数据导入过程中,尝尝设计到先导入对应的模板,然后根据模板进行相应导入数据填充后,再通过导入接口将填充后的数据进行导入。标准数据导入流程如下图:

标记1:提供模板下载接口,根据业务不同,导出相应的模板标记2:提供数据导入接口,虽然业务不同,调用接口基本一致,都是Excel文件上传,并解析Excel文件内容标记3:根据解析后的数据,进行循环解析验证处理,针对验证无误的数据,保存至数据库进行存储 2.2 设计

从导入交互分析可得,我们主要需要实现的根据业务不同生成对应的导入模板,以及导入时,根据业务不同,执行相应的解析后入库即可。

2.2.1 导入模板生成接口

通过分析可知,导入模板是根据业务不同,生成不同的模板,故可设计为在前端进行接口调用的时候,增加一个业务类型的参数,后端根据业务类型进行相应的判断,然后执行相应的逻辑,完成导入模板的生成。 通过上文 EasyPoi系列之框架集成及基础使用 可知,EasyPoi通过Entity实体+@Excel注解的方式即可实现Excel数据的导出(如后文代码片段),那基于此,生成导入模板时,可通过EasyPoi导出数据接口来实现,只是数据列表为空而已,所以我们只需要将业务类型参数与后端Entity实体建立联系,即可实现数据导入模板的快速生成。

/** * 通过实体导出Excel * @param response */ @RequestMapping("exportByEntity") public void exportByEntity(HttpServletResponse response) throws Exception { ExportParams exportParams = new ExportParams(); List<ExportEntity> datas = this.buildExportData(10); Workbook workbook = null; try{ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("测试exportByEntity", "utf-8") + ".xlsx"); //此处可将datas传入空集合,则导出Excel就只会有表头 workbook = ExcelExportUtil.exportExcel(exportParams, ExportEntity.class, datas); workbook.write(response.getOutputStream()); }finally { IoUtil.close(workbook); } } 2.2.2 数据导入接口

通过分析可得,用户导入填充后的模板,第一步均是调用后端指定接口进行文件上传至服务端,服务端获取到文件流,进行进一步的Excel数据解析为实体集合,然后保存即可。 通过上文 EasyPoi系列之框架集成及基础使用 可知,EasyPoi可快速将文件流读取后转换为对应实体集合(如后文代码片段),此处,我们也可参考模板导出的实现方式

通过前端传入一个业务参数,然后服务端根据业务参数,转换为对应的实体集合。定义通用的保存接口,并定义一个保存方法,需要进行数据保存的业务实现该方法,然后通过业务参数与具体实现了保存方法的类进行关联即可。 /** * 数据导入 * @param response */ @PostMapping("importData") @ResponseBody public List<ExportEntity> importData(HttpServletResponse response, MultipartFile file) throws Exception{ ImportParams importParams = new ImportParams(); //EasyPoi提供的方法,用于将文件流转换为实体集合 List<ExportEntity> datas = ExcelImportUtil.importExcel(file.getInputStream(), ExportEntity.class, importParams); return datas; } 3、代码实现

以人员基础信息导入为例

3.1 人员实体-PersonEntity import cn.afterturn.easypoi.excel.annotation.Excel; import lombok.Data; import java.util.Date; /** * 人员实体 */ @Data public class PersonEntity { @Excel(name = "人员姓名",width = 50) private String personName; @Excel(name = "年龄",width = 50) private Integer age; @Excel(name = "出生日期",width = 50) private Date birthday; @Excel(name = "手机号",width = 50) private String phone; } 3.2 定义数据保存通用接口-ExcelImporter import java.util.List; /** * 定义通用导入接口 * @param <T> */ public interface ExcelImporter<T> { /** * 数据保存方法<br/> * 需要执行导入的业务,均实现 * @param data */ void save(List<T> data); } 3.3 人员数据保存实现- PersonService

参考企业级实现方式,先定义一个IPersonService接口:

/** * 人员服务,由于人员涉及到导入,故接口继承ExcelImporter */ public interface IPersonService extends ExcelImporter<PersonEntity>{ //TODO 人员标准业务,其他业务处理方法 }

具体的PersonService 实现类:

import com.alibaba.fastjson.JSON; import org.springframework.stereotype.Service; import java.util.List; /** * 人员服务实现类,通过多继承,实现对应的导入方法 */ @Service public class PersonService implements IPersonService{ @Override public void save(List<PersonEntity> data) { //TODO 实现保存方法 System.out.println(JSON.toJSONString(data)); } } 3.4 建立业务与实体及保存实现类之间的关系-EnumImportType import lombok.AllArgsConstructor; import lombok.Getter; /** * 导入类型关系枚举 */ @AllArgsConstructor @Getter public enum EnumImportType { //定义person业务,其关联的实体为PersonEntity,关联的保存服务为PersonService person("人员信息", PersonEntity.class, IPersonService.class) ; /** * 描述 */ private String title; /** * 实体类 */ private Class<?> clazz; /** * 导入数据 */ private Class<? extends ExcelImporter<?>> importer; } 3.5 编写模板导出接口 /** * 通用数据导出 * @param importType 导入类型 * @param response */ @GetMapping("/exportTemplate") public void exportDataTemplate(HttpServletRequest request, String importType, HttpServletResponse response) throws Exception { //根据导入类型,匹配对应枚举的关联关系 EnumImportType enumExportType = EnumUtil.fromStringQuietly(EnumImportType.class, importType); if (null == enumExportType) { throw new RuntimeException("未知模板类型"); } ExportParams exportParams = new ExportParams(); Workbook workbook = null; try{ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(enumExportType.getTitle(), "utf-8") + ".xlsx"); //通过匹配的关联关系,填充对应的实体,其中数据列表传入一个空列表 workbook = ExcelExportUtil.exportExcel(exportParams, enumExportType.getClazz(), new ArrayList<>()); workbook.write(response.getOutputStream()); }finally { IoUtil.close(workbook); } } 3.6 通用导入接口 /** * 通用数据导入 * @param importType 模版类型 */ @PostMapping("/importData") @ResponseBody public Map importData(MultipartFile file, String importType) throws Exception { Map<String,Object> result = new HashMap<>(); EnumImportType enumExportType = EnumUtil.fromStringQuietly(EnumImportType.class, importType); if (null == enumExportType) { throw new RuntimeException("未知导入类型:"+importType); } ImportParams importParams = new ImportParams(); List<ExportEntity> datas = ExcelImportUtil.importExcel(file.getInputStream(), enumExportType.getClazz(), importParams); if(null != datas && !datas.isEmpty()){ //通过SpringUtil 获取当前匹配的导入实现类 ExcelImporter importer = SpringUtil.getBean(enumExportType.getImporter()); //调用保存方法 importer.save(datas); } result.put("code",200); result.put("msg","导入成功"); return result; } 3.7 完整接口-ImporterController /** * 数据导入接口 */ @Controller @RequestMapping("/importer") public class ImporterController { /** * 通用数据导出 * @param importType 导入类型 * @param response */ @GetMapping("/exportTemplate") public void exportDataTemplate(HttpServletRequest request, String importType, HttpServletResponse response) throws Exception { //根据导入类型,匹配对应枚举的关联关系 EnumImportType enumExportType = EnumUtil.fromStringQuietly(EnumImportType.class, importType); if (null == enumExportType) { throw new RuntimeException("未知模板类型"); } ExportParams exportParams = new ExportParams(); Workbook workbook = null; try{ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(enumExportType.getTitle(), "utf-8") + ".xlsx"); //通过匹配的关联关系,填充对应的实体,其中数据列表传入一个空列表 workbook = ExcelExportUtil.exportExcel(exportParams, enumExportType.getClazz(), new ArrayList<>()); workbook.write(response.getOutputStream()); }finally { IoUtil.close(workbook); } } /** * 通用数据导入 * @param importType 模版类型 */ @PostMapping("/importData") @ResponseBody public Map importData(MultipartFile file, String importType) throws Exception { Map<String,Object> result = new HashMap<>(); EnumImportType enumExportType = EnumUtil.fromStringQuietly(EnumImportType.class, importType); if (null == enumExportType) { throw new RuntimeException("未知导入类型:"+importType); } ImportParams importParams = new ImportParams(); List<ExportEntity> datas = ExcelImportUtil.importExcel(file.getInputStream(), enumExportType.getClazz(), importParams); if(null != datas && !datas.isEmpty()){ //通过SpringUtil 获取当前匹配的导入实现类 ExcelImporter importer = SpringUtil.getBean(enumExportType.getImporter()); //调用保存方法 importer.save(datas); } result.put("code",200); result.put("msg","导入成功"); return result; } } 4 接口测试 4.1 导出模板

浏览器访问 http://ip:port/importer/exportTemplate?importType=person 链接(ip与port根据实际情况进行替换),导出的模板内容如下:

4.2 数据导入 4.2.1 模板数据填充

针对4.1中导出的模板,填写一些样例数据如下:

4.2.2 执行导入

在ApiFox中按如下方式进行接口配置,并选择编写好的导入数据文件,点击发送: 后端断点效果如下,可看到Excel总的3条数据已读入到实体集合中,若需要保存至数据库,只需要调用存储接口即可:

5 后记

后续需要新增导入业务类,只需要在EnumImportType新增一个关联映射关系枚举,并参考Person用户导入方式,编写对应的类即可,无需再重复编写模板导出与数据导入的接口。 提示:前端也可以进行组件封装,通过传入业务类型,实现组件的重复利用(如下图) 组件使用参考:

<common-import ref="commonImport" :title="'用户信息导入'" <!--弹框标题--> import-type="person" <!--导入类型--> @importSuccess="importSuccess"> <!--导入成功后的处理,如刷新列表--> </data-import>

标签:

EasyPoi系列之通用导入接口设计由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“EasyPoi系列之通用导入接口设计