通过自定义拦截器优雅的导出Excel并标红的重复数据
平时我们导入导出Excel的时候如果用poi导出,会发现光设置格式都要很多代码,看起来非常的不优雅。后来业务中遇到了需要导入非常巨大的Excel的需求。如果继续用poi的方式,因为poi把所有excel数据都缓存到内存中,服务器资源又是有限的,所以就有可能导致内存溢出,为了解决这个问题,我发现阿里的EasyExcel导出可以完美的解决这个问题,并且实现方式更加优雅。
如果业务中需要标红重复的数据,先列一下大致代码。
/**
* 导出重复的数据
*
* @param planId
* @param stream
* @param tenaId
* @param fileId
* @param response
* @throws IOException
*/
public void screeningExport(Long planId, InputStream stream, Long tenaId, Long fileId, HttpServletResponse response) throws IOException { response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("重复项", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), ScreeningEasyExcelVo.class)
.registerWriteHandler(new CustomCellWriteHandle())
.sheet("模板" + Constant.fileIdSeparator + fileId).doWrite(data(stream, planId, tenaId, fileId)); }
大致的来说,就是我们传入excel文件流,和对应的业务字段就可以导出了。
但是如果想标红某一单元格的数据,那我们就需要自己定义拦截器,同时我们需要知道到底是哪行是重复的,具体校验重复行就不在这里写了,
得到重复行之后,我们把行数存入redis,并且在拦截器中和excel中的行数做对比,如果验证为同一行,那我们就可以对这一行做标红处理,
具体的代码如下
package com.guantong.seeing.screening.common; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.guantong.seeing.screening.util.SpringContextHelper;
import org.apache.poi.ss.usermodel.*;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils; import java.util.List;
import java.util.stream.Stream; /**
* @author cuixinxin
* @desc easyExcel 自定义拦截器
*/
public class CustomCellWriteHandle implements CellWriteHandler { public CustomCellWriteHandle() {
} @Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) { } @Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {
} /**
* 重写单元格格式--》通过修改每一个单元格格式达到整列标红的效果
* @param writeSheetHolder
* @param writeTableHolder
* @param list
* @param cell
* @param head
* @param integer
* @param aBoolean
*/
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) { Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
CellStyle cellStyle = cellStyle(workbook);
//根据校验结果设置单元格文字颜色
String sheetName = writeSheetHolder.getSheet().getSheetName();
Long fileId = Long.valueOf(sheetName.substring(sheetName.indexOf(Constant.fileIdSeparator) + 8));
writeSheetHolder.setSheetName(sheetName.substring(0, sheetName.indexOf(Constant.fileIdSeparator)));
int rowIndex = cell.getRowIndex();
if (isExistRepeatData(rowIndex, fileId)) {
//设置单元格背景色
Font font = workbook.createFont();
font.setColor(IndexedColors.RED.getIndex());
cellStyle.setFont(font);
} cell.setCellStyle(cellStyle);
} private boolean isExistRepeatData(Integer rowNow, Long fileId) {
StringRedisTemplate stringRedisTemplate = SpringContextHelper.getBean(StringRedisTemplate.class);
String value = stringRedisTemplate.opsForValue().get(fileId.toString());
if (StringUtils.isEmpty(value)) {
return false;
}
return Stream.of(value.split(","))
.anyMatch(k -> k.equals(rowNow.toString())); } /**
* 通用样式
*
* @param workbook
* @return
*/
public static CellStyle cellStyle(Workbook workbook) {
CellStyle cellStyle = workbook.createCellStyle();
//居中
cellStyle.setAlignment(HorizontalAlignment.LEFT);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
//设置边框
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
return cellStyle; }
}
整体来看,代码逻辑分工更加清晰,只有标红的拦截器和获取数据以及导出三部分,更加优雅
通过自定义拦截器优雅的导出Excel并标红的重复数据的更多相关文章
- Flume自定义拦截器(Interceptors)或自带拦截器时的一些经验技巧总结(图文详解)
不多说,直接上干货! 一.自定义拦截器类型必须是:类全名$内部类名,其实就是内部类名称 如:zhouls.bigdata.MySearchAndReplaceInterceptor$Builder 二 ...
- Mybatis自定义拦截器与插件开发
在Spring中我们经常会使用到拦截器,在登录验证.日志记录.性能监控等场景中,通过使用拦截器允许我们在不改动业务代码的情况下,执行拦截器的方法来增强现有的逻辑.在mybatis中,同样也有这样的业务 ...
- spring mvc <mvc:annotation-driven/> 自定义拦截器不走
<mvc:annotation-driven/> 这个便签会注册2个自定义拦截器,所以导致请求过来就会自己去走注册的这2个拦截器和定义的一堆bean 但是这个便签是必须得定义的 直接贴代码 ...
- 12.Struts2自定义拦截器
12.自定义拦截器 拦截器是Struts2的一个重要特性.因为Struts2的大多数核心功能都是通过拦截器实现的. 拦截器之所以称之为“拦截器”,是因为它可以拦截Action方法的执行, ...
- 【Java EE 学习 35 下】【struts2】【struts2文件上传】【struts2自定义拦截器】【struts2手动验证】
一.struts2文件上传 1.上传文件的时候要求必须使得表单的enctype属性设置为multipart/form-data,把它的method属性设置为post 2.上传单个文件的时候需要在Act ...
- SpringMVC——自定义拦截器、异常处理以及父子容器配置
自定义拦截器: 一.若想实现自定义拦截器,需要实现 org.springframework.web.servlet.HandlerInterceptor 接口. 二.HandlerIntercepto ...
- Struts2 自定义拦截器
自定义拦截器(权限管理),包含了对ajax和表单请求的拦截 package com.interceptor; import java.io.IOException; import java.io.Pr ...
- Struts2自定义拦截器
1. 需求 自定义拦截器实现,用户登录的访问控制. 2. 定义拦截器类 public class LoginInterceptor extends AbstractInterceptor { @Ove ...
- SpringMvc自定义拦截器
SpringMvc也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义拦截器必须实现HandlerInterceptor接口 -preHandle():这个方法在业务处理器 ...
随机推荐
- 阿里P6晋升到P7是一个坎吗? P7 晋升总结
作者:程序之心丁仪 来源:https://chengxuzhixin.com/blog/post/P6_jin_sheng_dao_P7_zong_jie.html 公众号停更了挺长一段时间,首先说声 ...
- Docker(12)- docker run 命令详解
如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 作用 创建一个新的容器并运行一个 ...
- 使用Haproxy代理rabbitmq集群,用keepalive保证haproxy高可用
原文地址:https://www.jianshu.com/p/440b8e1d5339 使用Haproxy代理rabbitmq集群 上一篇文章教了rabbitmq集群搭建.但是这样搭建出来的集群是3个 ...
- Java_大体介绍(超级短的那种)
Java三大版本 Java SE: Java Standard Edition, 定位于客户端, 用于桌面应用软件编程 Java ME: Java Micro Edition, 用于嵌入式系统开发 J ...
- NER的数据处理
import os class TransferData: def __init__(self): cur = '/'.join(os.path.abspath(__file__).split('/' ...
- 17flask分页
一,flask_sqlachemy的使用 如果想要展示出来的页面是分页显示,则首先需要知道每页应该分多少个条目,然后通过数据库去查找对应的条数,同时也需要和分页所需的"paginate&qu ...
- Mysql 日期-字符串转换。
mysql的字符串和日期类型的转换. 1.now()和curdate()的区别: now():datetime类型. mysql> select now(); +---------------- ...
- JS仿贪吃蛇:一串跟着鼠标的Div
贪吃蛇是一款80后.90后比较熟悉的经典游戏,下面通过简单的JS代码来实现低仿版贪吃蛇效果:随着鼠标的移动,在页面中呈现所有Div块跟随鼠标依次移动,效果如下图所示. <!DOCTYPE htm ...
- TCP中RTT的测量和RTO的计算
https://blog.csdn.net/zhangskd/article/details/7196707 tcp传输往返时间是指:发送方发送tcp断开时, 到发送方接收到改段立即响应的所耗费的时间 ...
- c++中的几种函数调用约定(转)
C++中的函数调用约定(调用惯例)主要针对三个问题: 1.参数传递的方式(是否采用寄存器传递参数.采用哪个寄存器传递参数.参数压桟的顺序等): 参数的传递方式,最常见的是通过栈传递.函数的调用方将参数 ...