自定义拦截器
@RequiredArgsConstructor
public class WaterMarkHandler implements SheetWriteHandler {
private final String WATER_MARK;
public static ByteArrayOutputStream createWaterMark(String content) throws IOException {
int width = 200;
int height = 150;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 获取bufferedImage对象
String fontType = "微软雅黑";
int fontStyle = Font.BOLD;
int fontSize = 20;
Font font = new Font(fontType, fontStyle, fontSize);
Graphics2D g2d = image.createGraphics(); // 获取Graphics2d对象
image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
g2d.dispose();
g2d = image.createGraphics();
g2d.setColor(new Color(0, 0, 0, 80)); //设置字体颜色和透明度,最后一个参数为透明度
g2d.setStroke(new BasicStroke(1)); // 设置字体
g2d.setFont(font); // 设置字体类型 加粗 大小
g2d.rotate(-0.5, (double) image.getWidth() / 2, (double) image.getHeight() / 2);//设置倾斜度
FontRenderContext context = g2d.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(content, context);
double x = (width - bounds.getWidth()) / 2;
double y = (height - bounds.getHeight()) / 2;
double ascent = -bounds.getY();
double baseY = y + ascent;
// 写入水印文字原定高度过小,所以累计写水印,增加高度
g2d.drawString(content, (int) x, (int) baseY);
// 设置透明度
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
// 释放对象
g2d.dispose();
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, "png", os);
return os;
}
/**
* 为Excel打上水印工具函数
*
* @param sheet excel sheet
* @param bytes 水印图片字节数组
*/
public static void putWaterRemarkToExcel(XSSFSheet sheet, byte[] bytes) {
//add relation from sheet to the picture data
XSSFWorkbook workbook = sheet.getWorkbook();
int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
String rID = sheet.addRelation(null, XSSFRelation.IMAGES, workbook.getAllPictures().get(pictureIdx))
.getRelationship().getId();
//set background picture to sheet
sheet.getCTWorksheet().addNewPicture().setId(rID);
}
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
try (ByteArrayOutputStream waterMark = createWaterMark(WATER_MARK)){
XSSFSheet sheet = (XSSFSheet) writeSheetHolder.getSheet();
putWaterRemarkToExcel(sheet, waterMark.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
}
}
控制层
@RequestMapping("/waterMark")
public void waterMark(HttpServletResponse response) throws IOException {
service.waterMark(response);
}
实现层
@Override
public void waterMark(HttpServletResponse response) throws IOException {
ServletOutputStream outputStream = EasyExcelUtil.getOutputStream(response);
ExcelWriter writer = EasyExcel.write(outputStream).inMemory(true).build();
WriteSheet sheet = EasyExcel
.writerSheet(0,"水印测试")
.registerWriteHandler(new WaterMarkHandler("赵今麦Angel"))
.sheetName("水印测试sheet")
.build();
writer.write(new ArrayList(),sheet);
writer.finish();
}
注意: Excel添加水印,只支持XSSFWorkbook,其余类别:SXSSFWorkbook、SXSSFWorkbook不支持。
EasyExcel使用时需要设置inMemory(true)
参数,否者默认使用的是SXSSFWorkbook,会报错
实现效果
水印乱码问题或文字不显示
在我的使用过程中,本地测试导出水印正常,但是在服务器上面导出水印不显示中文,查找原因发现是缺少中文字体,解决办法如下:
1.下载中文字体, 微软雅黑
2.将下载的ttf
字体文件放在resource
目录下
3.pom文件
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
</includes>
<excludes>
<exclude>**/*.ttf</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<!--一定要在filtering=false中加载字体文件,否则maven打包破坏字体文件-->
<filtering>false</filtering>
<includes>
<include>**/*.ttf</include>
</includes>
</resource>
</resources>
</build>
4.修改创建水印的代码
public static ByteArrayOutputStream createWaterMark(String content) throws IOException, FontFormatException {
int width = 200;
int height = 150;
// 添加中文字体 加载下载的中文字体,这样就不会出现中文乱码或中文丢失的情况
ClassPathResource resource = new ClassPathResource("font/msyh.ttf");
InputStream fi = resource.getInputStream();
BufferedInputStream fb = new BufferedInputStream(fi);
// String fontType = "微软雅黑";
int fontStyle = Font.PLAIN;
int fontSize = 20;
// Font font = new Font(fontType, fontStyle, fontSize);
Font font = Font.createFont(fontStyle,fb);
font = font.deriveFont(fontStyle,fontSize);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 获取bufferedImage对象
// 获取Graphics2d对象
Graphics2D g2d = image.createGraphics();
image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
g2d.dispose();
g2d = image.createGraphics();
//设置字体颜色和透明度,最后一个参数为透明度
g2d.setColor(new Color(0, 0, 0, 80));
// 设置字体
g2d.setStroke(new BasicStroke(1));
// 设置字体类型 加粗 大小
g2d.setFont(font);
g2d.rotate(-0.5, (double) image.getWidth() / 2, (double) image.getHeight() / 2);//设置倾斜度
FontRenderContext context = g2d.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(content, context);
double x = (width - bounds.getWidth()) / 2;
double y = (height - bounds.getHeight()) / 2;
double ascent = -bounds.getY();
double baseY = y + ascent;
// 写入水印文字原定高度过小,所以累计写水印,增加高度
g2d.drawString(content, (int) x, (int) baseY);
// 设置透明度
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
// 释放对象
g2d.dispose();
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, "png", os);
return os;
}