流程

原来写过一篇文章,是介绍EasyExcel的,但是现在有些业务需要解决,流程如下

1.需要把导出条件转换成中文并存入数据库

2.需要分页导出

3.需要上传FTP或者以后上传OSS

解决方案

大体的流程采用摸板方法模式,这样简化条件转换以及上传FTP操作

public abstract class EasyExcelUtil {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final CloudOrderManagementDao cloudOrderManagementDao;

    //上下文对象
private final ExportDTO dto; //ftp信息
private final FileClient fileClient; protected final RedisUtil redisUtil; private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30,
60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));;
/**
* 构造方法子类必须实现
*
* @param cloudOrderManagementDao dao
* @param dto 上下文对象
* @param fileClient 文件上传对象
* @param redisUtil redis
*/
public EasyExcelUtil(CloudOrderManagementDao cloudOrderManagementDao, ExportDTO dto, FileClient fileClient, RedisUtil redisUtil) {
this.cloudOrderManagementDao = cloudOrderManagementDao;
this.dto = dto;
this.fileClient = fileClient;
this.redisUtil = redisUtil;
} /**
* 主方法
*/
public final void createExcel() {
try {
File file = this.createFile();
CloudExportInfo exportInfo = this.createExportInfo(file.getName());
threadPoolExecutor.execute(() -> {
this.easyCreate(file);
this.uploadFile(file);
updateExportInfo(exportInfo);
});
} catch (Exception e) {
logger.error("ExcelUtil error{}", e);
}
} /**
* 创建文件
*
* @return 文件对象
* @throws IOException
*/
private File createFile() throws IOException {
File temp = File.createTempFile("temp", ".xlsx");
logger.info("ExcelUtil创建文件成功{}", temp.getAbsolutePath());
return temp;
} /**
* 创建导出对象,并存数据库
*
* @param fileName 文件名
* @return 导出对象
*/
private CloudExportInfo createExportInfo(String fileName) {
CloudExportInfo exportInfo = new CloudExportInfo();
exportInfo.setId(dto.getUuid());
exportInfo.setUserId(dto.getUserId());
exportInfo.setCreateBy(dto.getUserName());
exportInfo.setExportStatus(com.blgroup.vision.common.utils.R.CloudConstant.TWO);
exportInfo.setExportType(dto.getExportType());
exportInfo.setQueryParam(this.transitionQuery());
exportInfo.setExportCount(dto.getTotal());
exportInfo.setFileName(fileName);
exportInfo.setExportDir(dto.getBasisDir() + File.separator + fileName);
cloudOrderManagementDao.saveExportInfo(exportInfo);// 初始化导出信息
redisUtil.set(R.CloudConstant.CLOUD_DOWNLOAD_PROGRESS + "_" + dto.getUuid(), "5", 60 * 5);
logger.info("ExcelUtil创建导出信息成功{}", JSON.toJSONString(exportInfo));
return exportInfo;
} /**
* 上传文件
*
* @param file 文件,策略模式 未来可能支持OSS
*/
private void uploadFile(File file) {
redisUtil.set(R.CloudConstant.CLOUD_DOWNLOAD_PROGRESS + "_" + dto.getUuid(), "95", 60 * 5);
fileClient.uploadFile(file, dto.getBasisDir());
redisUtil.set(R.CloudConstant.CLOUD_DOWNLOAD_PROGRESS + "_" + dto.getUuid(), "100", 60 * 5);
} /**
* 上传完成,更新导出对象
*
* @param exportInfo
* @return
*/
private CloudExportInfo updateExportInfo(CloudExportInfo exportInfo) {
exportInfo.setExportStatus(com.blgroup.vision.common.utils.R.CloudConstant.ONE);
cloudOrderManagementDao.saveExportInfo(exportInfo);// 初始化导出信息
logger.info("ExcelUtil上完成");
return exportInfo;
} /**
* 导出方法,可以实现分批导出,也可以一次性导出
*
* @param file 文件
*/
public abstract void easyCreate(File file); /**
* 对查询字段进行转换
* @return
*/
public abstract String transitionQuery();
}

这样子类只需要实现easyCreatetransitionQuery方法即可

查询条件转换

针对查询条件转换,例如QO字段为'merchantId' 需要转换为商户值需要转换为ID对应的商户名称

如果是每个导出方法写一段转换类太麻烦这里使用注解的方式

在属性上使用表明中文意思和转换方法

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface FieldNameTransition {
/**
* 中文名称
* @return
*/
String value(); String transitionMethod() default ""; }

指定转换类

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
/**
* 指定转换类
*/
public @interface TransitionClass {
Class<?> value();
}

通过反射进行转换

public class ExcelTransitionFieldUtil {
public static Logger logger = LoggerFactory.getLogger(ExcelTransitionFieldUtil.class); private final ApplicationContext applicationContext; public ExcelTransitionFieldUtil(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
} public String transition(Object object) {
List<Map<String, String>> resultList = new ArrayList<>();
Object transitionBean = null;
//获取传过来的对象
Class<?> dtoClass = object.getClass();
if (dtoClass.isAnnotationPresent(TransitionClass.class)) {
//获取类上的注解,得到转换类 获取spring ioc中转换类的对象
transitionBean = applicationContext.getBean(dtoClass.getAnnotation(TransitionClass.class).value());
}
//获取对象的全部字段
Field[] fields = dtoClass.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(FieldNameTransition.class)) {
field.setAccessible(true);
//获取字段中需要转换的注解
try {
if (field.get(object) != null && StringUtils.isNotBlank(field.get(object).toString())) {
FieldNameTransition fieldAnnotation = field.getAnnotation(FieldNameTransition.class);
Map<String, String> tempMap = new HashMap<>();
tempMap.put("name", fieldAnnotation.value());
//如果定义了转换方法
if (StringUtils.isNotBlank(fieldAnnotation.transitionMethod()) && transitionBean != null) {
Method method = transitionBean.getClass().getMethod(fieldAnnotation.transitionMethod(), dtoClass);
Object invoke = method.invoke(transitionBean, object);
tempMap.put("value", invoke.toString());
} else {
tempMap.put("value", field.get(object).toString());
}
resultList.add(tempMap);
}
}catch (Exception e){
logger.error("反射转换发生异常 {}", e);
}
}
}
return JSON.toJSONString(resultList);
}
}

使用

QueryMerchantExportQO queryDTO = QueryMerchantExportQO.builder()
.isNeedAudit(request.getParameter("isNeedAudit"))
.keyword(request.getParameter("keyword"))
.merchantType(request.getParameter("merchantType"))
.shopId(request.getParameter("shopId"))
.storeCode(request.getParameter("storeCode"))
.storeType(request.getParameter("storeType"))
.hideFlag(request.getParameter("hideFlag")).build();
ExportDTO exportDTO = ExportDTO.builder().userId(UserUtils.getUser().getId())
.userName(UserUtils.getUser().getName())
.exportType("9")
.uuid(UUID.randomUUID().toString())
.basisDir("/cloudDownFile" + File.separator + LocalDate.now().getYear() + File.separator + LocalDate.now().getMonth().getValue())
.total(Integer.valueOf(request.getParameter("total")))
.build();
FtpInfo ftpInfo = new FtpInfo(server, uname, pwd, port);
new EasyExcelUtil(cloudOrderManagementDao, exportDTO, new FtpFileClient(ftpInfo), redisUtil) {
@Override
public void easyCreate(File file) {
//do something
} @Override
public String transitionQuery() {
//转换
return new ExcelTransitionFieldUtil(applicationContext).transition(queryDTO);
}
}.createExcel();
}

结尾

现在问题是转换类型只能是String类型,以后可能改进

Excel优雅导出的更多相关文章

  1. laravel Excel导入导出

    1.简介 Laravel Excel 在 Laravel 5 中集成 PHPOffice 套件中的 PHPExcel,从而方便我们以优雅的.富有表现力的代码实现Excel/CSV文件的导入和导出. 该 ...

  2. 【基于WinForm+Access局域网共享数据库的项目总结】之篇二:WinForm开发扇形图统计和Excel数据导出

    篇一:WinForm开发总体概述与技术实现 篇二:WinForm开发扇形图统计和Excel数据导出 篇三:Access远程连接数据库和窗体打包部署 [小记]:最近基于WinForm+Access数据库 ...

  3. C# 之 EXCEL导入导出

    以下方式是本人总结的一些经验,肯定有很多种方法,在此先记下,留待以后补充... 希望朋友们一起来探讨相关想法,请在下方留言. A-1:EXCEL模板导出 非常简单,将EXCEL模板上传到项目中后,将其 ...

  4. 利用反射实现通用的excel导入导出

    如果一个项目中存在多种信息的导入导出,为了简化代码,就需要用反射实现通用的excel导入导出 实例代码如下: 1.创建一个 Book类,并编写set和get方法 package com.bean; p ...

  5. Excel导入导出的业务进化场景及组件化的设计方案(上)

    1:前言 看过我文章的网友们都知道,通常前言都是我用来打酱油扯点闲情的. 自从写了上面一篇文章之后,领导就找我谈话了,怕我有什么想不开. 所以上一篇的(下)篇,目前先不出来了,哪天我异地二次回忆的时候 ...

  6. java实现excel模板导出

    一. 准备工作 1. 点击此下载相关开发工具 2. 将poi-3.8.jxls-core-1.0两个jar包放到工程中,并引用 3. 将excel模板runRecord.xls放到RunRecordB ...

  7. Excel导入-----导出(包含所选和全部)操作

    在做系统的时候,很多时候信息量太大,这时候就需要进行Excel表格信息的导入和导出,今天就来给大家说一下我使用Excel表格信息导入和导出的心得. 1:首先需要在前端显示界面View视图中添加导入Ex ...

  8. C#实现Excel模板导出和从Excel导入数据

    午休时间写了一个Demo关于Excel导入导出的简单练习 1.窗体 2.引用office命名空间 添加引用-程序集-扩展-Microsoft.Office.Interop.Excel 3.封装的Exc ...

  9. 如何将jsp页面的table报表转换到excel报表导出

    假设这就是你的jsp页面: 我们会添加一个“导出到excel”的超链接,它会把页面内容导出到excel文件中.那么这个页面会变成这个样子 在此,强调一下搜索时关键词的重要性,这样一下子可以定位到文章, ...

随机推荐

  1. deepin 20安装后系统没有声音解决方案(亲测有效)

    打开终端: sudo vi /etc/default/grub GRUB_CMDLINE_LINUX_DEFAULT原有配置后面添加 snd_hda_intel.dmic_detect=0 即GRUB ...

  2. 精尽 MyBatis 源码分析 - 基础支持层

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  3. 安恒DASCTF 四月战 WP

    web1 打开提就是源码审计 考点:反序列化POP链.反序列化字符串逃逸 show_source("index.php"); function write($data) { ret ...

  4. __METHOD__

  5. 算法学习笔记:Tarjan算法

    在上一篇文章当中我们分享了强连通分量分解的一个经典算法Kosaraju算法,它的核心原理是通过将图翻转,以及两次递归来实现.今天介绍的算法名叫Tarjan,同样是一个很奇怪的名字,奇怪就对了,这也是以 ...

  6. Camtasia处理音频制作BGM

    我们在剪辑自己录制的视频时经常会需要同时对音频进行处理,camtasia是一个可以对视频的音频或者单独的音频文件进行处理的软件,那我们就来看看到底如何使用camtasia 2019(Win)来处理音频 ...

  7. Java中的主线程

    目录 概览 主线程 怎么来控制主线程 主线程和main()函数的关系 主线程中的死锁(单个线程) 概览 前段时间有同事提到了主线程这个名词,但当时我们说的主线程是指Java Web程序中每一个请求进来 ...

  8. SpringSecurity之整合JWT

    SpringSecurity之整合JWT 目录 SpringSecurity之整合JWT 1. 写在前面的话 2. JWT依赖以及工具类的编写 3. JWT过滤器 4. 登录成功结果处理器 5. Sp ...

  9. [COCI2016-2017#1] Mag 结论证明

    结论:最多包含一个 \(2\),并且不在链的两端点. 证明:我们问题分成两个 \(\texttt{pass}\). \(\texttt{pass 1}\):\(\forall u,s.t.x_{u}\ ...

  10. Java集合【1】--俯瞰java集合分类

    目录 (一) java集合分类 (1) Iterable接口 1. 内部定义的方法 1.1 iterator方法 1.2 forEach方法 1.3 spliterator方法 2. Collecti ...