SpringBoot+POI方式导出excel加水印
Posted 经理,天台风好大
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot+POI方式导出excel加水印相关的知识,希望对你有一定的参考价值。
本篇是针对接口开发的案例~~
一、Poi实现Excel导出
Apache POI提供了HSSFWorkbook
操作2003版本的Excel文件, XSSFWorkbook
操作2007版Excel文件.
Excel文件导出操作在我们工作中有很多场景都会用到. 如报表数据下载, 消费记录下载等…
下面针对不同场景, 封装了不同的工具类, 但底层都是用的基础的公共api, 我使用的是HSSFWorkbook, 如果要生成2007版的Excel文件, 只需将HSSFWorkbook替换成XSSFWorkbook即可。
简单的具体实现在网上有很多案例可以参考学习, 我就不写入门案例了, 下面我会将自己工作中用到的场景封装成工具类记录下来, 供以后翻看复习。
注意:
EXCEL的压缩率特别高,能达到80%,12M的文件压缩后才2M左右。 如果未经过压缩、不仅会占用用户带宽,且会导致负载服务器(apache)和应用服务器之间,长时间占用连接(二进制流转发),导致负载服务器请求阻塞,不能提供服务。
- 一定要注意文件流的关闭
- 防止前台(页面)连续触发导出EXCEL
二、工具类参考
所有方式仅供参考,具体实现根据业务自行封装对应的工具类。
2.1 maven参考
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.8</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.16</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.0</version>
</dependency>
<!--hutool 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.11</version>
</dependency>
2.2 ExcelUtils
此工具类以下几种输出方式:
- 直接导出excel
- 导出excel,带背景图水印(不可打印)
- 导出excel,带插入图片的水印(可打印),原理类似于打印单上带着印章
- 其他几种导出方式自行研究。
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.ai.sop.common.constants.WebConstant;
import com.ai.system.entity.beans.TdSysStaff;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.merge.LoopMergeStrategy;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
/**
* @author daniel
* @description excel 导出工具类
*/
public class ExcelUtils
private static final Logger log = LoggerFactory.getLogger(ExcelUtils.class);
/**
* 用户信息导出类(添加水印,可打印,插入图片的方式)
* @desc 支持HSSFWorkbook格式的导出,插入图片方法.没有考虑合并单元格等情况.
* @param response 响应
* @param fileName 文件名
* @param columnList 每列的标题名
* @param dataList 导出的数据
*/
public static void exportExcelWaterMarkPrint(HttpServletResponse response,String fileName,List<String> columnList,List<List<String>> dataList)
//声明输出流
OutputStream os = null;
//设置响应头
setResponseHeader(response,fileName);
try
//获取输出流
os = response.getOutputStream();
String user = "daniel";
String date = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_FORMAT); //yyyy-MM-dd HH:mm:ss
String watermark = user + " " + date;
// String watermark = "daniel 2022-09-29 11:55:66";
//内存中保留1000条数据,以免内存溢出,其余写入硬盘
HSSFWorkbook wb = new HSSFWorkbook();
log.info("报表导出Size: " + dataList.size() + "条。");
Sheet sheet = null;
int excelRow = 0;//定义表格行
int index = 1;//定义初始sheet页码
HSSFPatriarch patriarch = null;
BufferedImage waterimg = null;
java.io.ByteArrayOutputStream wos = null;
List<HSSFClientAnchor> wanList = null;
sheet = wb.createSheet("sheet" + index);
sheet.setDefaultColumnWidth((short)20);//将默认的列宽设为25个文字大小
//创建标题行
Row titleRow = sheet.createRow(excelRow++);
for(int i = 0;i<columnList.size();i++)
//创建该行下的每一列,并写入标题数据
Cell cell = titleRow.createCell(i);
cell.setCellValue(columnList.get(i));
//设置内容行
if(dataList != null && dataList.size() > 0)
//外层for循环创建行
for(int i = 0;i<dataList.size();i++)
Row dataRow = sheet.createRow((i+1)%65000 == 0 ? 65000 : (i+1)%65000);
//内层for循环创建每行对应的列,并赋值
for(int j = 0;j<dataList.get(i).size();j++)
Cell cell = dataRow.createCell(j);
cell.setCellValue(dataList.get(i).get(j));
//每65000条数据创建一个sheet页
if ((i+1)%65000 == 0)
index++;
sheet = wb.createSheet("sheet" + index);
sheet.setDefaultColumnWidth((short)20);//将默认的列宽设为20个文字大小
Row title = sheet.createRow(0);
for(int k = 0; k < columnList.size();k++)//新建的sheet页表头写入
//创建该行下的每一列,并写入标题数据
Cell cell = title.createCell(k);
cell.setCellValue(columnList.get(k));
//获取excel工作簿中sheet个数
int sheets = wb.getNumberOfSheets();
wos = new java.io.ByteArrayOutputStream();
waterimg = createWaterRemark(watermark);//设置水印图片
ImageIO.write(waterimg, "png", wos);
//遍历sheet页并计算水印覆盖面积
for (int q = 0; q < sheets; q++)
sheet.protectSheet("123456");//excel表格的编辑密码
sheet = wb.getSheetAt(q);//获取sheet
//开始在每个sheet页部署水印
patriarch = (HSSFPatriarch) sheet.createDrawingPatriarch();
//计算水印覆盖面积
wanList = circulationPic((HSSFSheet) sheet, watermark);
//根据行与列计算实际所需多少水印
for (HSSFClientAnchor wanchor : wanList)
patriarch.createPicture(wanchor, wb.addPicture(wos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_PNG));
//将整理好的excel数据写入流中
wb.write(os);
catch (IOException e)
e.printStackTrace();
finally
try
// 关闭输出流
if (os != null)
os.close();
catch (IOException e)
e.printStackTrace();
/**
* 用户信息导出类(带水印,背景图,非插入图片的方式)
* @param response 响应
* @param fileName 文件名
* @param columnList 每列的标题名
* @param dataList 导出的数据
*/
public static void exportExcelWaterMark(HttpServletResponse response, String fileName, List<String> columnList, List<List<String>> dataList)
//声明输出流
OutputStream os = null;
//设置响应头
setResponseHeader(response,fileName);
try
//获取输出流
os = response.getOutputStream();
//内存中保留1000条数据,以免内存溢出,其余写入硬盘
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
//获取该工作区的第一个sheet
SXSSFSheet sheet1 = wb.createSheet("sheet1");
//添加水印
WaterMarkUtil.insertWaterMarkTextToXlsx(wb);
sheet1.trackAllColumnsForAutoSizing();
int excelRow = 0;
//创建标题行
Row titleRow = sheet1.createRow(excelRow++);
for(int i = 0;i<columnList.size();i++)
//创建该行下的每一列,并写入标题数据
Cell cell = titleRow.createCell(i);
cell.setCellValue(columnList.get(i));
sheet1.autoSizeColumn(i);
sheet1.setColumnWidth(i,sheet1.getColumnWidth(i)*17/10);
//设置内容行
if(dataList!=null && dataList.size()>0)
//序号是从1开始的
// int count = 1;
//外层for循环创建行
for(int i = 0;i<dataList.size();i++)
Row dataRow = sheet1.createRow(excelRow++);
//内层for循环创建每行对应的列,并赋值(这种写法加了一个序号列。)
// for(int j = -1;j<dataList.get(0).size();j++)//由于多了一列序号列所以内层循环从-1开始
// Cell cell = dataRow.createCell(j+1);
// if(j==-1)
// //第一列是序号列,不是在数据库中读取的数据,因此手动递增赋值
// cell.setCellValue(count++);
//
// else//其余列是数据列,将数据库中读取到的数据依次赋值
// cell.setCellValue(dataList.get(i).get(j));
//
//
//根据业务重新修改(如果第一列不要序号列,为了防止第一列为空导致异常,不能get(0),要get(i))
for (int j = 0; j<dataList.get(i).size(); j++)
Cell cell = dataRow.createCell(j);
cell.setCellValue(dataList.get(i).get(j));
sheet1.autoSizeColumn(j);
sheet1.setColumnWidth(j, sheet1.getColumnWidth(j) * 17 / 10);
//设置密码
sheet1.protectSheet("123456");
//将整理好的excel数据写入流中
wb.write(os);
catch (IOException e)
e.printStackTrace();
finally
try
// 关闭输出流
if (os != null)
os.close();
catch (IOException e)
e.printStackTrace();
/**
* 用户信息导出类(不带水印直接导出)
* @param response 响应
* @param fileName 文件名
* @param columnList 每列的标题名
* @param dataList 导出的数据
*/
public static void exportExcel(HttpServletResponse response, String fileName, List<String> columnList, List<List<String>> dataList)
//声明输出流
OutputStream os = null;
//设置响应头
setResponseHeader(response,fileName);
try
//获取输出流
os = response.getOutputStream();
//内存中保留1000条数据,以免内存溢出,其余写入硬盘
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
//获取该工作区的第一个sheet
SXSSFSheet sheet1 = wb.createSheet("sheet1");
sheet1.trackAllColumnsForAutoSizing();
int excelRow = 0;
//创建标题行
Row titleRow = sheet1.createRow(excelRow++);
for(int以上是关于SpringBoot+POI方式导出excel加水印的主要内容,如果未能解决你的问题,请参考以下文章
springboot使用poi导出数据生成excel(.xlsx)文件