feat(仪表板、数据大屏): 导出明细支持水印

This commit is contained in:
wangjiahao
2024-12-11 10:53:30 +08:00
parent c1d611d945
commit 84e0e598cf
4 changed files with 165 additions and 4 deletions

View File

@@ -35,6 +35,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

View File

@@ -0,0 +1,112 @@
package io.dataease.commons.utils;
import io.dataease.api.permissions.user.vo.UserFormVO;
import io.dataease.visualization.dto.WatermarkContentDTO;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.awt.Color;
import java.awt.Font;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;
public class ExcelWatermarkUtils {
public static String transContent(String content, UserFormVO userInfo) {
content = content.replaceAll("\\$\\{ip}", userInfo.getIp() == null?"127.0.0.1":userInfo.getIp());
content = content.replaceAll("\\$\\{username}", userInfo.getAccount());
content = content.replaceAll("\\$\\{nickName}", userInfo.getName());
content = content.replaceAll("\\$\\{time}", new Date().toString());
return content;
}
/**
* 添加水印图片到工作簿并返回图片 ID
*/
public static int addWatermarkImage(XSSFWorkbook wb, WatermarkContentDTO watermarkContent, UserFormVO userInfo) {
byte[] imageBytes = createTextImage(transContent(watermarkContent.getContent(),userInfo), 300, 100, 12); // 生成文字水印图片
return wb.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG); // 添加到工作簿并返回 ID
}
public static void addWatermarkToSheet(Sheet sheet, XSSFWorkbook wb, int pictureIdx) {
XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch();
// 获取工作表的总列数和行数
int lastRowNum = sheet.getLastRowNum();
int totalColumns = 0;
for (int i = 0; i <= lastRowNum; i++) {
Row row = sheet.getRow(i);
if (row != null) {
totalColumns = Math.max(totalColumns, row.getLastCellNum());
}
}
// 如果没有内容则假设默认覆盖100行和50列
if (lastRowNum == 0 && totalColumns == 0) {
lastRowNum = 100;
totalColumns = 50;
}
// 根据总行列数循环绘制水印
for (int row = 0; row <= lastRowNum; row += 15) { // 每15行绘制一行水印
for (int col = 0; col <= totalColumns; col += 8) { // 每8列绘制一列水印
ClientAnchor anchor = wb.getCreationHelper().createClientAnchor();
// 设置图片位置
anchor.setCol1(col); // 起始列
anchor.setRow1(row); // 起始行
anchor.setCol2(col + 5); // 终止列
anchor.setRow2(row + 10); // 终止行
anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE); // 防止移动和调整大小
XSSFPicture picture = drawing.createPicture(anchor, pictureIdx);
// 锁定图片(不可移动、不可调整大小)
picture.getCTPicture().getNvPicPr().getCNvPicPr().addNewPicLocks().setNoChangeAspect(true);
picture.getCTPicture().getNvPicPr().getCNvPicPr().addNewPicLocks().setNoMove(true);
picture.getCTPicture().getNvPicPr().getCNvPicPr().addNewPicLocks().setNoResize(true);
}
}
}
public static byte[] createTextImage(String text, int width, int height, int fontSize) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
// 设置透明背景
image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
g2d.dispose();
g2d = image.createGraphics();
// 设置抗锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 设置字体
g2d.setFont(new Font("Arial", Font.BOLD, fontSize));
g2d.setColor(new Color(0, 0, 0, 50)); // 半透明颜色
g2d.rotate(Math.toRadians(25), width / 2.0, height / 2.0); // 旋转文字
// 绘制文字
FontMetrics fontMetrics = g2d.getFontMetrics();
int textWidth = fontMetrics.stringWidth(text);
int textHeight = fontMetrics.getHeight();
int x = (width - textWidth) / 2;
int y = (height + textHeight) / 2 - fontMetrics.getDescent();
g2d.drawString(text, x, y);
g2d.dispose();
// 转为字节数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(image, "png", baos);
} catch (IOException e) {
e.printStackTrace();
}
return baos.toByteArray();
}
}

View File

@@ -12,11 +12,13 @@ import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
import io.dataease.api.dataset.union.UnionDTO;
import io.dataease.api.export.BaseExportApi;
import io.dataease.api.permissions.dataset.dto.DataSetRowPermissionsTreeDTO;
import io.dataease.api.permissions.user.vo.UserFormVO;
import io.dataease.api.xpack.dataFilling.DataFillingApi;
import io.dataease.api.xpack.dataFilling.dto.DataFillFormTableDataRequest;
import io.dataease.auth.bo.TokenUserBO;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
import io.dataease.chart.server.ChartDataServer;
import io.dataease.commons.utils.ExcelWatermarkUtils;
import io.dataease.dataset.dao.auto.entity.CoreDatasetGroup;
import io.dataease.dataset.dao.auto.mapper.CoreDatasetGroupMapper;
import io.dataease.dataset.manage.*;
@@ -49,9 +51,13 @@ import io.dataease.model.ExportTaskDTO;
import io.dataease.system.manage.CoreUserManage;
import io.dataease.system.manage.SysParameterManage;
import io.dataease.utils.*;
import io.dataease.visualization.dao.auto.entity.VisualizationWatermark;
import io.dataease.visualization.dao.auto.mapper.VisualizationWatermarkMapper;
import io.dataease.visualization.dto.WatermarkContentDTO;
import io.dataease.visualization.server.DataVisualizationServer;
import io.dataease.websocket.WsMessage;
import io.dataease.websocket.WsService;
import io.dataease.xpack.permissions.user.manage.UserPageManage;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
@@ -60,6 +66,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
@@ -100,8 +107,13 @@ public class ExportCenterManage implements BaseExportApi {
private int core;
@Value("${dataease.export.max.size:10}")
private int max;
@Resource
private VisualizationWatermarkMapper watermarkMapper;
@Resource(name = "userPageManage")
private UserPageManage userPageManage;
private final static String DATA_URL_TITLE = "data:image/jpeg;base64,";
private static final String exportData_path = "/opt/dataease2.0/data/exportData/";
@@ -644,7 +656,7 @@ public class ExportCenterManage implements BaseExportApi {
try {
exportTask.setExportStatus("IN_PROGRESS");
exportTaskMapper.updateById(exportTask);
Workbook wb = new SXSSFWorkbook();
XSSFWorkbook wb = new XSSFWorkbook();
CellStyle cellStyle = wb.createCellStyle();
Font font = wb.createFont();
font.setFontHeightInPoints((short) 12);
@@ -683,12 +695,22 @@ public class ExportCenterManage implements BaseExportApi {
} else {
downloadNotTableInfoData(request, wb);
}
VisualizationWatermark watermark = watermarkMapper.selectById("system_default");
WatermarkContentDTO watermarkContent = JsonUtil.parseObject(watermark.getSettingContent(), WatermarkContentDTO.class);
if (watermarkContent.getExcelEnable()) {
UserFormVO userInfo = userPageManage.queryForm(AuthUtils.getUser().getUserId());
// 在主逻辑中添加水印
int watermarkPictureIdx = ExcelWatermarkUtils.addWatermarkImage(wb, watermarkContent,userInfo); // 生成水印图片并获取 ID
for (Sheet sheet : wb) {
ExcelWatermarkUtils.addWatermarkToSheet(sheet, wb, watermarkPictureIdx); // 为每个 Sheet 添加水印
}
}
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(wb);
try (FileOutputStream outputStream = new FileOutputStream(dataPath + "/" + exportTask.getId() + ".xlsx")) {
wb.write(outputStream);
sxssfWorkbook.write(outputStream);
outputStream.flush();
}
wb.close();
sxssfWorkbook.close();
exportTask.setExportProgress("100");
exportTask.setExportStatus("SUCCESS");
setFileSize(dataPath + "/" + exportTask.getId() + ".xlsx", exportTask);

View File

@@ -0,0 +1,26 @@
package io.dataease.visualization.dto;
import lombok.Data;
@Data
public class WatermarkContentDTO {
private Boolean enable;
private Boolean excelEnable = false;
private Boolean enablePanelCustom;
private String type;
private String content;
private String watermark_color;
private Integer watermark_x_space;
private Integer watermark_y_space;
private Integer watermark_fontsize;
}