From cf7e692b1cb1b9a3defe6298fa3d785012bcbf77 Mon Sep 17 00:00:00 2001 From: cwchen <1048842385@qq.com> Date: Thu, 3 Apr 2025 15:26:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B0=B4=E5=8D=B0=E7=85=A7=E7=89=87=E7=94=9F?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SynthesisQueryController.java | 8 ++ .../backstage/dao/SynthesisQueryDao.java | 18 +++ .../backstage/entity/SynthesisQueryVo.java | 5 + .../service/SynthesisQueryService.java | 10 ++ .../impl/SynthesisQueryServiceImpl.java | 43 ++++++++ .../bonus/imgTool/config/WebMvcConfig.java | 5 +- .../imgTool/utils/HighQualityWatermark.java | 40 +++++-- .../backstage/SynthesisQueryMapper.xml | 11 +- src/main/resources/static/js/publicJs.js | 2 +- .../js/synthesisQuery/synthesisQuery.js | 4 +- .../js/synthesisQuery/synthesisQueryAjax.js | 22 ++++ .../js/synthesisQuery/synthesisQueryCommon.js | 103 +----------------- 12 files changed, 161 insertions(+), 110 deletions(-) diff --git a/src/main/java/com/bonus/imgTool/backstage/controller/SynthesisQueryController.java b/src/main/java/com/bonus/imgTool/backstage/controller/SynthesisQueryController.java index d80463d..6fbccb5 100644 --- a/src/main/java/com/bonus/imgTool/backstage/controller/SynthesisQueryController.java +++ b/src/main/java/com/bonus/imgTool/backstage/controller/SynthesisQueryController.java @@ -3,6 +3,7 @@ package com.bonus.imgTool.backstage.controller; import com.bonus.imgTool.annotation.DecryptAndVerify; import com.bonus.imgTool.annotation.LogAnnotation; import com.bonus.imgTool.backstage.entity.QueryParamDto; +import com.bonus.imgTool.backstage.entity.SynthesisQueryVo; import com.bonus.imgTool.backstage.service.SynthesisQueryService; import com.bonus.imgTool.model.SysUser; import com.bonus.imgTool.system.vo.EncryptedReq; @@ -57,6 +58,13 @@ public class SynthesisQueryController { return synthesisQueryService.collectData(data.getData()); } + @ApiOperation("生成水印") + @PostMapping(value = "generateWatermark") + @DecryptAndVerify(decryptedClass = SynthesisQueryVo.class) + public ServerResponse generateWatermark(EncryptedReq data) { + return synthesisQueryService.generateWatermark(data.getData()); + } + /*@PostMapping(value = "getProClassifyStatisticsList") @DecryptAndVerify(decryptedClass = QueryParamDto.class)//加解密统一管理 @LogAnnotation(operModul = "综合查询-照片综合查询", operation = "查询照片", operDesc = "系统级事件",operType="查询") diff --git a/src/main/java/com/bonus/imgTool/backstage/dao/SynthesisQueryDao.java b/src/main/java/com/bonus/imgTool/backstage/dao/SynthesisQueryDao.java index fbd01e9..ba60519 100644 --- a/src/main/java/com/bonus/imgTool/backstage/dao/SynthesisQueryDao.java +++ b/src/main/java/com/bonus/imgTool/backstage/dao/SynthesisQueryDao.java @@ -48,4 +48,22 @@ public interface SynthesisQueryDao { void addComprehensiveQuery(ComprehensiveQueryVo comprehensiveQueryVo); void updateComprehensiveQuery(ComprehensiveQueryVo comprehensiveQueryVo); + + /** + * 生成水印照片 + * @param vo + * @return void + * @author cwchen + * @date 2025/4/3 14:44 + */ + void updateSyData(SynthesisQueryVo vo); + + /** + * 获取水印照片地址 + * @param vo + * @return String + * @author cwchen + * @date 2025/4/3 14:57 + */ + String getSyData(SynthesisQueryVo vo); } diff --git a/src/main/java/com/bonus/imgTool/backstage/entity/SynthesisQueryVo.java b/src/main/java/com/bonus/imgTool/backstage/entity/SynthesisQueryVo.java index 504f6d9..bd803cf 100644 --- a/src/main/java/com/bonus/imgTool/backstage/entity/SynthesisQueryVo.java +++ b/src/main/java/com/bonus/imgTool/backstage/entity/SynthesisQueryVo.java @@ -2,6 +2,7 @@ package com.bonus.imgTool.backstage.entity; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; @@ -16,6 +17,9 @@ import java.util.Date; public class SynthesisQueryVo { private Long id; + + /**工程名称*/ + private String proName; /** * 原图图片路径 */ @@ -41,6 +45,7 @@ public class SynthesisQueryVo { * 上传时间 */ @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd") private Date uploadTime; /** * 资源类型 diff --git a/src/main/java/com/bonus/imgTool/backstage/service/SynthesisQueryService.java b/src/main/java/com/bonus/imgTool/backstage/service/SynthesisQueryService.java index e178fcc..ef57ee7 100644 --- a/src/main/java/com/bonus/imgTool/backstage/service/SynthesisQueryService.java +++ b/src/main/java/com/bonus/imgTool/backstage/service/SynthesisQueryService.java @@ -2,6 +2,7 @@ package com.bonus.imgTool.backstage.service; import com.bonus.imgTool.backstage.entity.ComprehensiveQueryVo; import com.bonus.imgTool.backstage.entity.QueryParamDto; +import com.bonus.imgTool.backstage.entity.SynthesisQueryVo; import com.bonus.imgTool.utils.ServerResponse; /** @@ -53,4 +54,13 @@ public interface SynthesisQueryService { * @return ServerResponse */ void updateComprehensiveQuery(ComprehensiveQueryVo comprehensiveQueryVo); + + /** + * 生成水印 + * @param data + * @return ServerResponse + * @author cwchen + * @date 2025/4/3 14:23 + */ + ServerResponse generateWatermark(SynthesisQueryVo data); } diff --git a/src/main/java/com/bonus/imgTool/backstage/service/impl/SynthesisQueryServiceImpl.java b/src/main/java/com/bonus/imgTool/backstage/service/impl/SynthesisQueryServiceImpl.java index 1173890..dcd4af9 100644 --- a/src/main/java/com/bonus/imgTool/backstage/service/impl/SynthesisQueryServiceImpl.java +++ b/src/main/java/com/bonus/imgTool/backstage/service/impl/SynthesisQueryServiceImpl.java @@ -7,7 +7,9 @@ import com.bonus.imgTool.backstage.entity.SynthesisNumVo; import com.bonus.imgTool.backstage.entity.SynthesisQueryVo; import com.bonus.imgTool.backstage.service.SynthesisQueryService; import com.bonus.imgTool.system.vo.LoginUser; +import com.bonus.imgTool.utils.HighQualityWatermark; import com.bonus.imgTool.utils.ServerResponse; +import com.bonus.imgTool.utils.SystemUtils; import com.bonus.imgTool.utils.UserUtil; import com.bonus.imgTool.webResult.Constants; import com.github.pagehelper.PageHelper; @@ -20,6 +22,8 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import javax.annotation.Resource; +import java.io.File; +import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @@ -104,4 +108,43 @@ public class SynthesisQueryServiceImpl implements SynthesisQueryService { public void updateComprehensiveQuery(ComprehensiveQueryVo comprehensiveQueryVo) { synthesisQueryDao.updateComprehensiveQuery(comprehensiveQueryVo); } + + @Override + @Transactional(rollbackFor = Exception.class) + public ServerResponse generateWatermark(SynthesisQueryVo vo) { + try { + String path = SystemUtils.getUploadPath() + vo.getOriginalFilePath(); + if (!new File(path).exists()) { + return ServerResponse.createErroe("原照片不存在"); + } + String syPath = synthesisQueryDao.getSyData(vo); + if(StringUtils.isBlank(syPath)){ + syPath = generateWatermarkData(vo); + } + vo.setWatermarkFilePath(syPath); + synthesisQueryDao.updateSyData(vo); + return ServerResponse.createSuccess("操作成功",syPath); + } catch (Exception e) { + log.error(e.toString(), e); + return ServerResponse.createErroe("操作失败"); + } + } + + public String generateWatermarkData(SynthesisQueryVo vo){ + // 准备多行水印文本 + List watermarkLines = new ArrayList<>(); + String uploadTime = new SimpleDateFormat("yyyy-MM-dd").format(vo.getUploadTime()); + watermarkLines.add(uploadTime); + watermarkLines.add(vo.getProName().replaceAll("(.{18})", "$1@@")); + watermarkLines.add(vo.getUploadTypeName()); + String sourceTypeName = null; + if (Objects.equals(vo.getSourceType(), "9")) { + sourceTypeName = vo.getTitle(); + } else { + sourceTypeName = vo.getSourceTypeName().split("-")[1]; + } + watermarkLines.add(sourceTypeName); + String localPath = SystemUtils.getUploadPath() +File.separator+ vo.getOriginalFilePath(); + return HighQualityWatermark.generateWatermark(watermarkLines,localPath); + } } diff --git a/src/main/java/com/bonus/imgTool/config/WebMvcConfig.java b/src/main/java/com/bonus/imgTool/config/WebMvcConfig.java index 5c6da73..70dbce7 100644 --- a/src/main/java/com/bonus/imgTool/config/WebMvcConfig.java +++ b/src/main/java/com/bonus/imgTool/config/WebMvcConfig.java @@ -1,5 +1,6 @@ package com.bonus.imgTool.config; +import java.io.File; import java.util.List; import com.bonus.imgTool.utils.SystemUtils; @@ -60,9 +61,9 @@ public class WebMvcConfig implements WebMvcConfigurer { String filePath=SystemUtils.getUploadPath();//获取文件上传路径 /** 本地文件上传路径 */ registry.addResourceHandler("/statics/**") - .addResourceLocations("file:" + filePath); + .addResourceLocations("file:" + filePath + File.separator); registry.addResourceHandler("/files/**") - .addResourceLocations("file:"+filePath); + .addResourceLocations("file:"+filePath + File.separator); } } diff --git a/src/main/java/com/bonus/imgTool/utils/HighQualityWatermark.java b/src/main/java/com/bonus/imgTool/utils/HighQualityWatermark.java index e501419..33afb39 100644 --- a/src/main/java/com/bonus/imgTool/utils/HighQualityWatermark.java +++ b/src/main/java/com/bonus/imgTool/utils/HighQualityWatermark.java @@ -1,4 +1,5 @@ package com.bonus.imgTool.utils; + import javax.imageio.*; import javax.imageio.plugins.jpeg.JPEGImageWriteParam; import javax.imageio.stream.FileImageOutputStream; @@ -8,6 +9,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; + /** * @className:HighQualityWatermark * @author:cwchen @@ -28,12 +30,13 @@ public class HighQualityWatermark { /** * 添加高质量多行水印 + * * @param sourceImagePath 源图片路径 * @param targetImagePath 目标图片路径 - * @param textLines 多行水印文本 - * @param position 水印位置 - * @param opacity 透明度 - * @param fontName 字体名称 + * @param textLines 多行水印文本 + * @param position 水印位置 + * @param opacity 透明度 + * @param fontName 字体名称 */ public static void addHighQualityWatermark(String sourceImagePath, String targetImagePath, List textLines, String position, @@ -81,7 +84,7 @@ public class HighQualityWatermark { // 设置水印颜色和透明度 Color watermarkColor = new Color(DEFAULT_COLOR.getRed(), DEFAULT_COLOR.getGreen(), - DEFAULT_COLOR.getBlue(), (int)(opacity * 255)); + DEFAULT_COLOR.getBlue(), (int) (opacity * 255)); g2d.setColor(watermarkColor); // 计算水印起始位置 @@ -117,7 +120,7 @@ public class HighQualityWatermark { int imgHeight, String fontName) { // 基于图片对角线长度计算初始字体大小 double diagonal = Math.sqrt(imgWidth * imgWidth + imgHeight * imgHeight); - int initialSize = (int)(diagonal * 0.03); + int initialSize = (int) (diagonal * 0.03); initialSize = Math.max(MIN_FONT_SIZE, Math.min(initialSize, MAX_FONT_SIZE)); Font testFont = new Font(fontName, DEFAULT_FONT_STYLE, initialSize); @@ -221,7 +224,7 @@ public class HighQualityWatermark { private static Point calculateWatermarkPosition(String position, int imgWidth, int imgHeight, int maxLineWidth, int totalHeight, FontMetrics fm) { - int margin = (int)(Math.min(imgWidth, imgHeight) * 0.05); // 5%边距 + int margin = (int) (Math.min(imgWidth, imgHeight) * 0.05); // 5%边距 int x = 0; int y = 0; @@ -308,6 +311,29 @@ public class HighQualityWatermark { } } + /** + * 生成图片水印 + * @return String + * @author cwchen + * @date 2025/4/3 14:28 + */ + public static String generateWatermark(List watermarkLines,String localPath) { + try { + String suffix = IDUtils.getSuffix(localPath); + String path = File.separator + "sy" + File.separator + IDUtils.createID() + suffix; + String outPath = SystemUtils.getUploadPath() + path; + // 添加高质量水印 + addHighQualityWatermark(localPath, outPath, + watermarkLines, "bottom-left", + 0.7f, "Microsoft YaHei"); + System.out.println("高质量水印添加完成,图片已无损输出"); + return path; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + public static void main(String[] args) { try { // 准备多行水印文本 diff --git a/src/main/resources/mappers/backstage/SynthesisQueryMapper.xml b/src/main/resources/mappers/backstage/SynthesisQueryMapper.xml index 15861a8..f6d2f02 100644 --- a/src/main/resources/mappers/backstage/SynthesisQueryMapper.xml +++ b/src/main/resources/mappers/backstage/SynthesisQueryMapper.xml @@ -103,7 +103,8 @@ source_type AS sourceType, A.dict_name AS sourceTypeName, IF(tpc.file_resource_id IS NULL,'0','1') AS collectStatus, - tcq.title + tcq.title, + tcq.pro_name AS proName FROM tb_comprehensive_query tcq LEFT JOIN sys_file_resource sfr ON tcq.id = sfr.source_id AND tcq.upload_type = sfr.upload_type AND sfr.is_active = '1' LEFT JOIN tb_photo_collect tpc ON sfr.id = tpc.file_resource_id AND tpc.collect_user_id = #{userId} @@ -205,6 +206,10 @@ ORDER BY sfr.create_time DESC + + @@ -217,6 +222,10 @@ DELETE FROM tb_photo_collect WHERE file_resource_id = #{id} AND collect_user_id = #{userId} + + + UPDATE sys_file_resource SET watermark_file_path = #{watermarkFilePath} WHERE id = #{id} + update tb_comprehensive_query diff --git a/src/main/resources/static/js/publicJs.js b/src/main/resources/static/js/publicJs.js index 7b2b536..59a7652 100644 --- a/src/main/resources/static/js/publicJs.js +++ b/src/main/resources/static/js/publicJs.js @@ -28,7 +28,7 @@ if(url.indexOf("112.27.246.86")!=-1){ } // console.log(dataUrl) -let imgUrl = dataUrl + /files/; +let imgUrl = dataUrl + '/files'; let tokens = localStorage.getItem("token"); function error(xhr) { diff --git a/src/main/resources/static/js/synthesisQuery/synthesisQuery.js b/src/main/resources/static/js/synthesisQuery/synthesisQuery.js index b199a3c..0fff49c 100644 --- a/src/main/resources/static/js/synthesisQuery/synthesisQuery.js +++ b/src/main/resources/static/js/synthesisQuery/synthesisQuery.js @@ -113,8 +113,8 @@ function initImgData(list) { " " + "
" + "
" + - "
" + - "
" + + "
" + + "
" + setCollectImg(item) + "
" + " "); diff --git a/src/main/resources/static/js/synthesisQuery/synthesisQueryAjax.js b/src/main/resources/static/js/synthesisQuery/synthesisQueryAjax.js index 189ab39..83c3928 100644 --- a/src/main/resources/static/js/synthesisQuery/synthesisQueryAjax.js +++ b/src/main/resources/static/js/synthesisQuery/synthesisQueryAjax.js @@ -42,4 +42,26 @@ function collectData(objParams) { error(xhr) }); return flag; +} + +/**生成水印照片*/ +function generateWatermark(objParams) { + let url = dataUrl + "/backstage/synthesisQuery/generateWatermark" + let params = { + encryptedData: encryptCBC(JSON.stringify(objParams)) + } + let loadingMsg = layer.msg("水印照片生成中,请稍候...", {icon: 16, scrollbar: false, time: 0,}); + ajaxRequest(url, "POST", params, true, function () { + }, function (result) { + layer.close(loadingMsg); + if (result.status === 200) { + objParams.watermarkFilePath = result.data; + imgDownLoad(objParams, 2); + }else{ + parent.layer.msg(result.msg, {icon: 2}); + } + }, function (xhr) { + error(xhr) + layer.close(loadingMsg); + }); } \ No newline at end of file diff --git a/src/main/resources/static/js/synthesisQuery/synthesisQueryCommon.js b/src/main/resources/static/js/synthesisQuery/synthesisQueryCommon.js index 1024daa..d5201cd 100644 --- a/src/main/resources/static/js/synthesisQuery/synthesisQueryCommon.js +++ b/src/main/resources/static/js/synthesisQuery/synthesisQueryCommon.js @@ -17,12 +17,12 @@ function viewImg(item) { } /**原图下载*/ -function imgDownLoad(item) { - let orginalPath = item.originalFilePath; +function imgDownLoad(item, type) { + let path = type === 1 ? item.originalFilePath : item.watermarkFilePath; let obj = { - imgPath: orginalPath, + imgPath: path, } - let loadingMsg = layer.msg("原图下载中,请稍候...", {icon: 16, scrollbar: false, time: 0,}); + let loadingMsg = layer.msg("照片下载中,请稍候...", {icon: 16, scrollbar: false, time: 0,}); let url = dataUrl + "/common/download/downloadImage?token=" + tokens + "&encryptedData=" + encodeURIComponent(encryptCBC(JSON.stringify(obj))); let xhr = new XMLHttpRequest(); xhr.open("get", url, true); @@ -35,103 +35,12 @@ function imgDownLoad(item) { var a = document.createElement("a"); var url = window.URL.createObjectURL(blob); a.href = url; - a.download = orginalPath.substring(orginalPath.lastIndexOf('/') + 1, orginalPath.length); // 文件名 + a.download = path.substring(path.lastIndexOf('/') + 1, path.length); // 文件名 } else { - layer.msg("原图下载发生异常,请稍后重试", {icon: 16, scrollbar: false, time: 2000}); + layer.msg("照片下载发生异常,请稍后重试", {icon: 16, scrollbar: false, time: 2000}); } a.click(); window.URL.revokeObjectURL(url); }; - // xhr.send(params); xhr.send(); -} - -/**水印下载*/ -function waterImgDownLoad(item) { - /* let orginalPath = item.originalFilePath; - let obj = { - imgPath: orginalPath, - } - let loadingMsg = layer.msg("水印图片下载中,请稍候...", {icon: 16, scrollbar: false, time: 0,}); - let url = dataUrl + "/common/download/downloadImage?token=" + tokens + "&encryptedData=" + encodeURIComponent(encryptCBC(JSON.stringify(obj))); - let xhr = new XMLHttpRequest(); - xhr.open("get", url, true); - xhr.responseType = "blob"; // 转换流 - xhr.setRequestHeader('Content-Type','application/json;charset=UTF-8') - xhr.onload = function () { - layer.close(loadingMsg); - if (this.status === 200) { - let blob = this.response; - var a = document.createElement("a"); - var url = window.URL.createObjectURL(blob); - a.href = url; - a.download = orginalPath.substring(orginalPath.lastIndexOf('/') + 1,orginalPath.length); // 文件名 - } else { - layer.msg("水印图片下载发生异常,请稍后重试", {icon: 16, scrollbar: false, time: 2000}); - } - a.click(); - window.URL.revokeObjectURL(url); - }; - // xhr.send(params); - xhr.send();*/ - - function downloadImage(imageUrl) { - let orginalPath = item.originalFilePath; - let obj = { - imgPath: orginalPath, - } - $.ajax({ - url: dataUrl + "/common/download/downloadImage?token=" + tokens, - type: 'GET', - data: { - encryptedData: encodeURIComponent(encryptCBC(JSON.stringify(obj))) - }, - xhrFields: { - responseType: 'blob' // 重要:指定响应类型为blob - }, - success: function (data, status, xhr) { - // 检查是否是blob数据(图片) - if (data instanceof Blob) { - // 创建临时URL用于下载 - var blobUrl = URL.createObjectURL(data); - - // 创建下载链接 - var a = document.createElement('a'); - a.href = blobUrl; - a.download = orginalPath.substring(orginalPath.lastIndexOf('/') + 1,orginalPath.length); // 提取文件名 - document.body.appendChild(a); - a.click(); - - // 清理 - setTimeout(function () { - document.body.removeChild(a); - URL.revokeObjectURL(blobUrl); - }, 100); - } else { - // 如果返回的不是blob,可能是错误信息 - console.error('服务器返回意外响应:', data); - alert('下载失败: 服务器返回无效数据'); - } - }, - error: function (xhr, status, error) { - // 尝试解析错误信息 - var errorMsg = '下载失败'; - if (xhr.responseText) { - try { - var errorResponse = JSON.parse(xhr.responseText); - errorMsg = errorResponse.message || errorMsg; - } catch (e) { - errorMsg = xhr.responseText; - } - } - alert(errorMsg); - } - }); - } - - // 使用示例 - $('#download-btn').click(function () { - var imageUrl = $('#image-url').val(); - downloadImage(imageUrl); - }); } \ No newline at end of file