mirror of
https://github.com/dataease/dataease.git
synced 2026-05-14 21:12:33 +08:00
feat(仪表板、数据大屏): 导出明细支持水印
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user