瀏覽代碼

优化水印和发布文章接口

fangzhen 1 月之前
父節點
當前提交
0656926bbc

+ 6 - 0
pom.xml

@@ -200,6 +200,12 @@
                 <version>${tika.version}</version>
             </dependency>
 
+            <!-- https://mvnrepository.com/artifact/com.aliyun.oss/aliyun-sdk-oss -->
+            <dependency>
+                <groupId>com.aliyun.oss</groupId>
+                <artifactId>aliyun-sdk-oss</artifactId>
+                <version>3.18.1</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 

+ 5 - 0
ruoyi-admin/pom.xml

@@ -66,6 +66,11 @@
             <artifactId>aliyun-sdk-oss</artifactId>
             <version>3.11.2</version>
         </dependency>
+
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 33 - 20
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java

@@ -141,7 +141,7 @@ public class CommonController {
      * 通用上传请求(单个) OSS
      */
     @PostMapping("/upload")
-    public AjaxResult uploadFile(MultipartFile file, boolean waterMark) throws Exception {
+    public AjaxResult uploadFile(MultipartFile file, boolean waterMark, boolean isFillWater) throws Exception {
         try {
             String fileType = FileUtils.getFileType(file);
 //            if ("image".equalsIgnoreCase(fileType)) {
@@ -169,33 +169,46 @@ public class CommonController {
                 new File(tempThumbnailFile).delete();
             }
 
-            if ("image".equalsIgnoreCase(fileType) && waterMark) {
-                //获取用户名
-                String nickName = SecurityUtils.getLoginUser().getUser().getNickName();
+            if ("image".equalsIgnoreCase(fileType)) {
+                String tempWatermarkFile = "";
                 // 下载源文件到本地临时目录
                 String tempSourceFile = System.getProperty("java.io.tmpdir") + File.separator + "source_" + FileUtils.getName(fileName);
                 OssUtils.downloadFile(fileName.replace("https://cysd.oss-cn-shanghai.aliyuncs.com/", ""), tempSourceFile);
+                if (waterMark) {
+                    //获取用户名
+                    String nickName = SecurityUtils.getLoginUser().getUser().getNickName();
+                    // 本地临时水印文件路径
+                    tempWatermarkFile = System.getProperty("java.io.tmpdir") + File.separator + "watermark_" + FileUtils.getName(fileName);
+                    // 添加水印
+                    ImageUtils.addWatermark(
+                            isFillWater,
+                            fileName.replace("https://cysd.oss-cn-shanghai.aliyuncs.com/", ""),
+                            new File(tempSourceFile),
+                            new File(tempWatermarkFile),
+                            "@" + nickName,
+                            "ACG爱好者社区"
+                    );
+                    // 上传加水印的文件到OSS
+                    fileNameResult = OssUtils.uploadFile(tempWatermarkFile);
+                }
+
                 //缩略图上传
                 String compressedFile = System.getProperty("java.io.tmpdir") + File.separator + "compress_" + FileUtils.getName(fileName);
                 ImageUtils.compressAndGenerateThumbnail(tempSourceFile, compressedFile, 500, 350, 0.8f);
                 compressedFileUrl = OssUtils.uploadFile(compressedFile);
-                // 本地临时水印文件路径
-                String tempWatermarkFile = System.getProperty("java.io.tmpdir") + File.separator + "watermark_" + FileUtils.getName(fileName);
-                // 添加水印
-                ImageUtils.addWatermark(
-                        new File(tempSourceFile),
-                        new File(tempWatermarkFile),
-                        "@" + nickName,
-                        "次元时代-ACG爱好者社区"
-                );
-
-                // 上传加水印的文件到OSS
-                fileNameResult = OssUtils.uploadFile(tempWatermarkFile);
 
                 // 删除临时文件
-                new File(tempSourceFile).delete();
-                new File(compressedFile).delete();
-                new File(tempWatermarkFile).delete();
+                if (new File(tempSourceFile).exists()) {
+                    new File(tempSourceFile).delete();
+                }
+
+                if (new File(compressedFile).exists()) {
+                    new File(compressedFile).delete();
+                }
+
+                if (new File(tempWatermarkFile).exists()) {
+                    new File(tempWatermarkFile).delete();
+                }
             }
 
             fileNameResult = fileNameResult.replace("https://cysd.oss-cn-shanghai.aliyuncs.com", fileUrl);
@@ -221,7 +234,7 @@ public class CommonController {
         // 1. 取出图片
         List<CommunityArticleImages> images = communityArticleImagesMapper.selectList(new QueryWrapper<CommunityArticleImages>()
                 .isNotNull("image_url")
-                .like("image_url","47.122.10.161:8084"));
+                .like("image_url", "47.122.10.161:8084"));
 
         for (CommunityArticleImages image : images) {
             // 2. 对URL中的路径部分进行编码

+ 53 - 48
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java

@@ -83,63 +83,68 @@ public class ImageUtils {
     /**
      * 添加图片水印
      *
-     * @param sourceFile    文件源路径
-     * @param destFile      文件路径
+     * @param sourceFile     文件源路径
+     * @param destFile       文件路径
      * @param watermarkText1 水印信息上
      * @param watermarkText2 水印信息下
      * @throws Exception 异常
      */
-    public static void addWatermark(File sourceFile, File destFile, String watermarkText1, String watermarkText2) throws Exception {
-        // 读取图片
-        BufferedImage image = ImageIO.read(sourceFile);
-
-        // 获取图片宽高
-        int width = image.getWidth();
-        int height = image.getHeight();
-
-        // 创建 Graphics2D 对象
-        Graphics2D g2d = (Graphics2D) image.getGraphics();
-        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
-        // 根据图片大小调整字体大小
-        int fontSize = Math.max(width, height) / 40; // 字体大小为图片较大边长的 1/20
-        g2d.setFont(new Font("SimHei", Font.BOLD, fontSize));
+    public static void addWatermark(boolean isFillWater, String objectName, File sourceFile, File destFile, String watermarkText1, String watermarkText2) throws Exception {
+        if (isFillWater) {
+            String watermarkText = watermarkText2 + "-" + watermarkText1;
+            OssUtils.addWatermark(objectName, destFile, watermarkText);
+        } else {
+            // 读取图片
+            BufferedImage image = ImageIO.read(sourceFile);
+
+            // 获取图片宽高
+            int width = image.getWidth();
+            int height = image.getHeight();
+
+            // 创建 Graphics2D 对象
+            Graphics2D g2d = (Graphics2D) image.getGraphics();
+            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+            // 根据图片大小调整字体大小
+            int fontSize = Math.max(width, height) / 40; // 字体大小为图片较大边长的 1/20
+            g2d.setFont(new Font("SimHei", Font.BOLD, fontSize));
 //        g2d.setColor(new Color(255, 255, 255, 128)); // 白色半透明
 
-        // 计算水印文本宽高
-        FontMetrics fontMetrics = g2d.getFontMetrics();
-        // 第一行水印的宽高
-        int textWidth1 = fontMetrics.stringWidth(watermarkText1);
-        int textHeight = fontMetrics.getHeight(); // 每行的高度
+            // 计算水印文本宽高
+            FontMetrics fontMetrics = g2d.getFontMetrics();
+            // 第一行水印的宽高
+            int textWidth1 = fontMetrics.stringWidth(watermarkText1);
+            int textHeight = fontMetrics.getHeight(); // 每行的高度
 
-        // 第二行水印的宽度
-        int textWidth2 = fontMetrics.stringWidth(watermarkText2);
+            // 第二行水印的宽度
+            int textWidth2 = fontMetrics.stringWidth(watermarkText2);
 
-        // 计算水印的位置(右下角,分两行)
-        int padding = width / 50; // 边距
-        int x1 = width - textWidth1 - padding; // 第一行水平位置
-        int x2 = width - textWidth2 - padding; // 第二行水平位置
-        int y1 = height - textHeight - padding; // 第一行垂直位置
-        int y2 = height - padding; // 第二行垂直位置
+            // 计算水印的位置(右下角,分两行)
+            int padding = width / 50; // 边距
+            int x1 = width - textWidth1 - padding; // 第一行水平位置
+            int x2 = width - textWidth2 - padding; // 第二行水平位置
+            int y1 = height - textHeight - padding; // 第一行垂直位置
+            int y2 = height - padding; // 第二行垂直位置
 
-        // 分析水印区域的背景颜色(取样水印区域的平均颜色)
-        Color averageColor = getAverageColor(image, x1, y1 - textHeight, textWidth1, textHeight + (y2 - y1));
+            // 分析水印区域的背景颜色(取样水印区域的平均颜色)
+            Color averageColor = getAverageColor(image, x1, y1 - textHeight, textWidth1, textHeight + (y2 - y1));
 
-        // 判断背景颜色是否浅色或深色
-        Color watermarkColor = isLightColor(averageColor) ? new Color(0, 0, 0, 180) : new Color(255, 255, 255, 128);
+            // 判断背景颜色是否浅色或深色
+            Color watermarkColor = isLightColor(averageColor) ? new Color(0, 0, 0, 180) : new Color(255, 255, 255, 128);
 
-        // 设置水印颜色
-        g2d.setColor(watermarkColor);
+            // 设置水印颜色
+            g2d.setColor(watermarkColor);
 
-        // 绘制两行水印
-        g2d.drawString(watermarkText1, x1, y1);
-        g2d.drawString(watermarkText2, x2, y2);
-        g2d.dispose();
+            // 绘制两行水印
+            g2d.drawString(watermarkText1, x1, y1);
+            g2d.drawString(watermarkText2, x2, y2);
+            g2d.dispose();
 
-        // 保存处理后的图片
+            // 保存处理后的图片
 //        ImageIO.write(image, "jpg", destFile);
-        String format = sourceFile.getName().substring(sourceFile.getName().lastIndexOf(".") + 1);
-        ImageIO.write(image, format, destFile);
+            String format = sourceFile.getName().substring(sourceFile.getName().lastIndexOf(".") + 1);
+            ImageIO.write(image, format, destFile);
+        }
     }
 
 
@@ -158,10 +163,10 @@ public class ImageUtils {
     /**
      * 获取指定区域的平均颜色
      *
-     * @param image 图片
-     * @param x 起始横坐标
-     * @param y 起始纵坐标
-     * @param width 区域宽度
+     * @param image  图片
+     * @param x      起始横坐标
+     * @param y      起始纵坐标
+     * @param width  区域宽度
      * @param height 区域高度
      * @return 平均颜色
      */
@@ -187,7 +192,7 @@ public class ImageUtils {
      * @param width             缩略图宽度
      * @param height            缩略图高度
      * @param quality           压缩质量,范围0-1,值越低压缩越厉害
-     * @throws IOException      IO异常
+     * @throws IOException IO异常
      */
     public static void compressAndGenerateThumbnail(String originalImagePath, String thumbImagePath, int width, int height, float quality) throws IOException {
         // 压缩图片并生成缩略图

+ 46 - 3
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/OssUtils.java

@@ -1,5 +1,6 @@
 package com.ruoyi.common.utils.file;
 
+import com.aliyun.oss.ClientException;
 import com.aliyun.oss.OSS;
 import com.aliyun.oss.OSSClientBuilder;
 import com.aliyun.oss.OSSException;
@@ -10,6 +11,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 import java.io.*;
 import java.time.LocalDateTime;
+import java.util.Base64;
 import java.util.UUID;
 
 /**
@@ -54,11 +56,11 @@ public class OssUtils {
         return uploadMultipartFile(bucketName, getOssFilePath(multipartFile.getOriginalFilename()), multipartFile);
     }
 
-    public static void test1(MultipartFile multipartFile){
+    public static void test1(MultipartFile multipartFile) {
         try {
             String filePath = multipartFile.getOriginalFilename();
             String fileSuf = filePath.substring(filePath.indexOf(".") + 1);
-            String objectName =  UUID.randomUUID().toString() + "." + fileSuf;
+            String objectName = UUID.randomUUID().toString() + "." + fileSuf;
             // 将原图转换为PNG格式。
             String image = "image/format,png";
             GetObjectRequest request = new GetObjectRequest(bucketName, objectName);
@@ -73,7 +75,7 @@ public class OssUtils {
             System.out.println("Error Code:" + oe.getErrorCode());
             System.out.println("Request ID:" + oe.getRequestId());
             System.out.println("Host ID:" + oe.getHostId());
-        }  finally {
+        } finally {
             if (ossClient != null) {
                 ossClient.shutdown();
             }
@@ -181,4 +183,45 @@ public class OssUtils {
         return getOssDefaultPath() + UUID.randomUUID().toString() + "." + fileSuf;
     }
 
+    /**
+     * 添加全屏水印
+     *
+     * @param destFile       文件路径
+     * @param watermarkText 水印信息
+     * @throws Exception 异常
+     */
+    public static void addWatermark(String objectName, File destFile, String watermarkText) throws Exception {
+        try {
+            //将文字转换base64
+            watermarkText = Base64.getEncoder().encodeToString(watermarkText.getBytes("utf-8"))
+                    .replace("+", "-")
+                    .replace("/", "_")
+                    .replaceFirst("=+$", "");
+
+            // 添加水印
+            String style = "image/watermark,text_" + watermarkText + ",fill_1,t_30,rotate_45,type_d3F5LW1pY3JvaGVp";
+            GetObjectRequest request = new GetObjectRequest(bucketName, objectName);
+            request.setProcess(style);
+            // 将处理后的图片命名为example-new.jpg并保存到本地。
+            // 如果未指定本地路径只填写了文件名称(例如example-new.jpg),则文件默认保存到示例程序所属项目对应本地路径中。
+            ossClient.getObject(request, destFile);
+        } catch (OSSException oe) {
+            System.out.println("请求已发送到OSS,但由于某种原因被拒绝并返回错误响应。");
+            System.out.println("Error Message:" + oe.getErrorMessage());
+            System.out.println("Error Code:" + oe.getErrorCode());
+            System.out.println("Request ID:" + oe.getRequestId());
+            System.out.println("Host ID:" + oe.getHostId());
+        } catch (ClientException ce) {
+            System.out.println("Caught an ClientException, which means the client encountered "
+                    + "a serious internal problem while trying to communicate with OSS, "
+                    + "such as not being able to access the network.");
+            System.out.println("Error Message:" + ce.getMessage());
+        }
+//        finally {
+//            if (ossClient != null) {
+//                ossClient.shutdown();
+//            }
+//        }
+    }
+
 }

+ 47 - 14
ruoyi-generator/src/main/java/com/ruoyi/generator/controller/CommunityArticleController.java

@@ -14,6 +14,9 @@ import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.core.text.Convert;
 import com.ruoyi.common.exception.user.ProjectException;
 import com.ruoyi.common.utils.*;
+import com.ruoyi.common.utils.file.FileUtils;
+import com.ruoyi.common.utils.file.ImageUtils;
+import com.ruoyi.common.utils.file.OssUtils;
 import com.ruoyi.common.utils.ip.IpUtils;
 import com.ruoyi.generator.domain.Community.*;
 import com.ruoyi.generator.mapper.community.*;
@@ -28,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
+import java.io.File;
 import java.text.ParseException;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -191,7 +195,7 @@ public class CommunityArticleController extends BaseController {
 
             //判断当前用户有没有被禁言
             SysUser sysUser = sysUserMapper.selectUserById(SecurityUtils.getUserId());
-            if (sysUser != null){
+            if (sysUser != null) {
                 String userState = sysUser.getUserState();
                 Date reportTime = sysUser.getReportTime();
                 if ("2".equals(userState) && reportTime != null) {
@@ -202,7 +206,7 @@ public class CommunityArticleController extends BaseController {
                     // 检查 reportTime 小于当前时间
                     if (currentTime.before(reportTime)) {
                         // 返回封号的提示
-                        return   AjaxResult.success("当前用户已被禁言!");
+                        return AjaxResult.success("当前用户已被禁言!");
                     }
                 }
             }
@@ -219,6 +223,35 @@ public class CommunityArticleController extends BaseController {
                 return AjaxResult.error(MessageUtils.message("article.content.error"));
             }
 
+            //检查附近是否是需要加水印
+            boolean isWaterMark = communityArticle.isWaterMark();
+            boolean isFillWater = communityArticle.isFillWater();
+            if (isWaterMark) {
+                //获取用户名
+                String nickName = SecurityUtils.getLoginUser().getUser().getNickName();
+                // 添加水印
+                for (CommunityImagesVo image : communityArticle.getImages()) {
+                    String fileType = FileUtils.getFileTypeFromUrl(image.getImages());
+                    if ("image".equals(fileType)) {
+                        // 本地临时水印文件路径
+                        String tempWatermarkFile = System.getProperty("java.io.tmpdir") + File.separator + "watermark_" + FileUtils.getName(image.getImages());
+                        String tempSourceFile = System.getProperty("java.io.tmpdir") + File.separator + "source_" + FileUtils.getName(image.getImages());
+                        OssUtils.downloadFile(image.getImages().replace("http://file.iciyuanshidai.com/", ""), tempSourceFile);
+                        ImageUtils.addWatermark(
+                                isFillWater,
+                                image.getImages().replace("http://file.iciyuanshidai.com/", ""),
+                                new File(tempSourceFile),
+                                new File(tempWatermarkFile),
+                                "@" + nickName,
+                                "ACG爱好者社区"
+                        );
+                        // 上传加水印的文件到OSS
+                        String fileNameResult = OssUtils.uploadFile(tempWatermarkFile);
+                        image.setImages(fileNameResult.replace("https://cysd.oss-cn-shanghai.aliyuncs.com", "http://file.iciyuanshidai.com/"));
+                    }
+                }
+            }
+
             communityArticleService.insertCommunityArticle(communityArticle);
         } catch (Exception e) {
             System.out.println(e.getMessage());
@@ -313,7 +346,7 @@ public class CommunityArticleController extends BaseController {
             Long userId = SecurityUtils.getLoginUser().getUserId();
             String classId = communityArticleService.selectCommunityUserInfoById(userId, true).getClassId();
 
-            if (classId != null && !classId.isEmpty()){
+            if (classId != null && !classId.isEmpty()) {
                 List<Long> sortOrder = Arrays.stream(classId.split(","))
                         .map(String::trim)
                         .map(Long::parseLong)
@@ -340,7 +373,7 @@ public class CommunityArticleController extends BaseController {
 
                 sortedCommunityClasses.addAll(remainingClasses);
                 return AjaxResult.success(sortedCommunityClasses);
-            }else {
+            } else {
                 communityClasses = communityClassMapper.selectList(new QueryWrapper<CommunityClass>().orderByAsc("sort"));
 
             }
@@ -353,7 +386,6 @@ public class CommunityArticleController extends BaseController {
     }
 
 
-
     @GetMapping("/circleList")
     @ApiOperation("获取文章圈子列表")
     //@Anonymous
@@ -402,7 +434,7 @@ public class CommunityArticleController extends BaseController {
         }
         //判断当前用户有没有被禁言
         SysUser sysUser = sysUserMapper.selectUserById(SecurityUtils.getUserId());
-        if (sysUser != null){
+        if (sysUser != null) {
             String userState = sysUser.getUserState();
             Date reportTime = sysUser.getReportTime();
             if ("2".equals(userState) && reportTime != null) {
@@ -411,7 +443,7 @@ public class CommunityArticleController extends BaseController {
                 // 检查 reportTime 小于当前时间
                 if (currentTime.before(reportTime)) {
                     // 返回封号的提示
-                    return   AjaxResult.success("当前用户已被禁言!");
+                    return AjaxResult.success("当前用户已被禁言!");
                 }
             }
         }
@@ -812,7 +844,7 @@ public class CommunityArticleController extends BaseController {
     @ApiOperation("获取用户信息")
     @GetMapping("/userInfo")
     @Anonymous
-    public AjaxResult userInfo(@RequestParam(required = false) Long userId,boolean isToken) {
+    public AjaxResult userInfo(@RequestParam(required = false) Long userId, boolean isToken) {
         if (Objects.isNull(userId)) {
             userId = SecurityUtils.getLoginUser().getUserId();
 
@@ -826,7 +858,7 @@ public class CommunityArticleController extends BaseController {
 
         CommunityUserInfoVo communityUserInfoVo = null;
         try {
-            communityUserInfoVo = communityArticleService.selectCommunityUserInfoById(userId,isToken);
+            communityUserInfoVo = communityArticleService.selectCommunityUserInfoById(userId, isToken);
         } catch (Exception e) {
             System.out.println(e.getMessage());
             throw new ProjectException();
@@ -1231,7 +1263,7 @@ public class CommunityArticleController extends BaseController {
     @ApiOperation("查询用户合集")
     @GetMapping("/getCollection")
     @Anonymous
-    public AjaxResult getCollection(Long collectionId, Long searchType,@RequestParam(required = false) Long userId) {
+    public AjaxResult getCollection(Long collectionId, Long searchType, @RequestParam(required = false) Long userId) {
         if (Objects.isNull(collectionId)) {
             return AjaxResult.error("合集不存在!");
         }
@@ -1243,7 +1275,7 @@ public class CommunityArticleController extends BaseController {
         List<CommunityCollectionArticleVo> collectionArticleVos = null;
         JSONArray jsonArray;
         try {
-            jsonArray = communityCollectionService.selectArticleInfoInCollection(userId,collectionId, searchType);
+            jsonArray = communityCollectionService.selectArticleInfoInCollection(userId, collectionId, searchType);
         } catch (Exception e) {
             System.out.println(e.getMessage());
             throw new ProjectException();
@@ -1318,6 +1350,7 @@ public class CommunityArticleController extends BaseController {
         }
         return AjaxResult.success(communityUserPromptVo);
     }
+
     @ApiOperation("个人未加入集合文章")
     @GetMapping("/userNoCo")
     @Anonymous
@@ -1483,13 +1516,13 @@ public class CommunityArticleController extends BaseController {
                 return AjaxResult.success("文章不属于当前用户,无法置顶");
             }
             Boolean isTop = toparticle.getIsTop();
-            if (!isTop){
+            if (!isTop) {
                 communityArticleService.update(new UpdateWrapper<CommunityArticle>()
                         .set("is_top", true)
                         .set("top_time", DateUtils.parseDate(DateUtils.getTime()))
                         .eq("id", communityArticle.getId()));
                 msg = "已置顶";
-            }else {
+            } else {
                 communityArticleService.update(new UpdateWrapper<CommunityArticle>()
                         .set("is_top", false)
                         .set("top_time", DateUtils.parseDate(DateUtils.getTime()))
@@ -1504,7 +1537,7 @@ public class CommunityArticleController extends BaseController {
                         wrapper.ne("is_delete", 1).or().isNull("is_delete");
                     }));
             if (communityArticles.size() > 3) {
-               //大于三条则 排序
+                //大于三条则 排序
                 communityArticles = communityArticles.stream()
                         .sorted(Comparator.comparing(CommunityArticle::getTopTime).reversed()) // 降序排列(最新文章排在前面)
                         .limit(3)

+ 14 - 0
ruoyi-generator/src/main/java/com/ruoyi/generator/domain/Community/CommunityArticle.java

@@ -206,6 +206,20 @@ public class CommunityArticle implements Serializable {
     @TableField(exist = false)
     private List<Long> atUserIds;
 
+    /**
+     * 父文章id(编辑文章,草稿箱来源)
+     */
+    @ApiModelProperty("图片是否增加水印")
+    @TableField(exist = false)
+    private boolean waterMark;
+
+    /**
+     * 父文章id(编辑文章,草稿箱来源)
+     */
+    @ApiModelProperty("图片水印模式:true-全图水印,false-有下角水印")
+    @TableField(exist = false)
+    private boolean fillWater;
+
     /**
      * 文章类型
      */