Pārlūkot izejas kodu

1.优化图片水印问题,应对各种大小不一的图片进行水印调整
2.修复获取标签bug报错问题
3.获取class板块优化响应速度

fangzhen 3 dienas atpakaļ
vecāks
revīzija
07b2dbab26

+ 3 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java

@@ -126,6 +126,9 @@ public class SysProfileController extends BaseController {
 
             // 更新缓存用户信息
             tokenService.setLoginUser(loginUser);
+            // 移除用户对应的板块信息
+            String userClassCacheKey = CacheConstants.COMMUNITY_ARTICLE_CLASS + ":" + loginUser.getUserId();
+            redisCache.deleteObject(userClassCacheKey);
             return success();
         }
         return error("修改个人信息异常,请联系管理员");

+ 40 - 5
ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java

@@ -84,11 +84,6 @@ public class CacheConstants
      */
     public static final String COMMUNITY_USER_LIKE = "community:user:like";
 
-    /**
-     * 文章板块数据
-     */
-    public static final String COMMUNITY_ARTICLE_CLASS = "community:article:class";
-
     /**
      * 文章点赞数据
      */
@@ -123,4 +118,44 @@ public class CacheConstants
      * 文章标签
      */
     public static final String COMMUNITY_TAG = "community:tag";
+
+    /**
+     * 社区文章浏览量缓存key
+     */
+    public static final String COMMUNITY_VIEW = "community:view:";
+
+    /**
+     * 社区文章评论数缓存key
+     */
+    public static final String COMMUNITY_COMMENT = "community:comment:";
+
+    /**
+     * 社区文章点赞用户集合缓存key
+     */
+    public static final String COMMUNITY_LIKE_USER = "community:like:user:";
+
+    /**
+     * 社区文章收藏用户集合缓存key
+     */
+    public static final String COMMUNITY_COLLECT_USER = "community:collect:user:";
+
+    /**
+     * 社区文章浏览用户集合缓存key
+     */
+    public static final String COMMUNITY_VIEW_USER = "community:view:user:";
+
+    /**
+     * 社区文章分类列表缓存key
+     */
+    public static final String COMMUNITY_ARTICLE_CLASS = "community:article:class";
+
+    /**
+     * 缓存有效期,默认720(分钟)
+     */
+    public final static long EXPIRATION = 720;
+
+    /**
+     * 缓存刷新时间,默认120(分钟)
+     */
+    public final static long REFRESH_TIME = 120;
 }

+ 60 - 8
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java

@@ -121,8 +121,41 @@ public class ImageUtils {
             Graphics2D g2d = (Graphics2D) image.getGraphics();
             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 
-            // 根据图片大小调整字体大小
-            int fontSize = Math.max(width, height) / 40; // 字体大小为图片较大边长的 1/20
+            // 根据图片大小和比例调整字体大小
+            double aspectRatio = (double) height / width;
+            int fontSize;
+            
+            // 计算图片的面积和对角线长度,用于评估图片的整体大小
+            double area = width * height;
+            double diagonal = Math.sqrt(width * width + height * height);
+            
+            // 根据不同的图片比例调整字体大小计算方式(减小约三分之一)
+            if (aspectRatio > 2.0) {
+                // 长条形图片(高远大于宽)
+                fontSize = (int) (width / (30 + aspectRatio * 3));
+            } else if (aspectRatio < 0.5) {
+                // 宽大于高的横向图片
+                fontSize = (int) (height / 23);
+            } else if (Math.abs(aspectRatio - 1.0) < 0.2) {
+                // 接近正方形的图片(长宽比在0.8到1.2之间)
+                fontSize = (int) (Math.min(width, height) / 45); // 使用更小的字体
+            } else {
+                // 普通矩形的图片
+                fontSize = (int) (Math.min(width, height) / 38);
+            }
+            
+            // 对于特别大或特别小的图片进行额外调整
+            if (area > 4000000) { // 大于约2000*2000的大图
+                fontSize = (int) (fontSize * 1.2); // 稍微增大字体
+            } else if (area < 250000) { // 小于约500*500的小图
+                fontSize = (int) (fontSize * 0.8); // 稍微减小字体
+            }
+            
+            // 设置字体大小的上下限
+            int minFontSize = 10;
+            int maxFontSize = 50;
+            fontSize = Math.max(minFontSize, Math.min(fontSize, maxFontSize));
+            
             g2d.setFont(new Font("SimHei", Font.BOLD, fontSize));
 //        g2d.setColor(new Color(255, 255, 255, 128)); // 白色半透明
 
@@ -135,12 +168,31 @@ public class ImageUtils {
             // 第二行水印的宽度
             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 = Math.max(10, Math.min(width, height) / 50); // 边距,确保最小值为10像素
+            int x1, x2, y1, y2;
+            
+            // 根据图片比例决定水印位置
+            if (aspectRatio > 3.0) {
+                // 对于非常高的长条形图片,仍然放在右下角(按照用户要求)
+                x1 = width - textWidth1 - padding;
+                x2 = width - textWidth2 - padding;
+                y1 = height - textHeight - padding;
+                y2 = height - padding;
+            } else if (aspectRatio < 0.33) {
+                // 对于非常宽的横向图片,将水印放在右下角,但增加边距
+                int widePadding = (int)(padding * 1.5);
+                x1 = width - textWidth1 - widePadding;
+                x2 = width - textWidth2 - widePadding;
+                y1 = height - textHeight - widePadding;
+                y2 = height - widePadding;
+            } else {
+                // 对于接近正方形或普通矩形的图片,保持在右下角
+                x1 = width - textWidth1 - padding;
+                x2 = width - textWidth2 - padding;
+                y1 = height - textHeight - padding;
+                y2 = height - padding;
+            }
 
             // 分析水印区域的背景颜色(取样水印区域的平均颜色)
             Color averageColor = getAverageColor(image, x1, y1 - textHeight, textWidth1, textHeight + (y2 - y1));

+ 67 - 4
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/OssUtils.java

@@ -9,6 +9,8 @@ import com.aliyun.oss.model.PutObjectRequest;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
 import java.io.*;
 import java.time.LocalDateTime;
 import java.util.Base64;
@@ -266,7 +268,7 @@ public class OssUtils {
     }
 
     /**
-     * 添加全屏水印
+     * 添加全屏水印,根据图片大小动态调整水印大小
      *
      * @param objectName OSS对象名称
      * @param destFile 目标文件
@@ -275,14 +277,75 @@ public class OssUtils {
      */
     public static void addWatermark(String objectName, File destFile, String watermarkText) throws Exception {
         try {
-            //将文字转换base64
+            // 首先获取图片信息
+            BufferedImage image = null;
+            File tempFile = null;
+            try {
+                // 创建临时文件来获取图片信息
+                tempFile = File.createTempFile("oss_temp_", ".tmp");
+                GetObjectRequest infoRequest = new GetObjectRequest(bucketName, objectName);
+                getOssClient().getObject(infoRequest, tempFile);
+                image = ImageIO.read(tempFile);
+            } catch (Exception e) {
+                log.warn("获取图片信息失败,将使用默认水印大小: {}", e.getMessage());
+            }
+            
+            // 计算适当的水印大小
+            int watermarkSize = 100; // 默认大小
+            if (image != null) {
+                int width = image.getWidth();
+                int height = image.getHeight();
+                double aspectRatio = (double) height / width;
+                
+                // 计算图片的面积和对角线长度
+                double area = width * height;
+                double diagonal = Math.sqrt(width * width + height * height);
+                
+                // 根据不同的图片比例调整水印大小(减小约三分之一)
+                if (aspectRatio > 2.0) {
+                    // 长条形图片(高远大于宽)
+                    watermarkSize = (int) (width / 23);
+                } else if (aspectRatio < 0.5) {
+                    // 宽大于高的横向图片
+                    watermarkSize = (int) (height / 15);
+                } else if (Math.abs(aspectRatio - 1.0) < 0.2) {
+                    // 接近正方形的图片
+                    watermarkSize = (int) (Math.min(width, height) / 30);
+                } else {
+                    // 普通矩形的图片
+                    watermarkSize = (int) (Math.min(width, height) / 23);
+                }
+                
+                // 对于特别大或特别小的图片进行额外调整
+                if (area > 4000000) { // 大于约2000*2000的大图
+                    watermarkSize = (int) (watermarkSize * 1.2);
+                } else if (area < 250000) { // 小于约500*500的小图
+                    watermarkSize = (int) (watermarkSize * 0.8);
+                }
+                
+                // 设置水印大小的上下限
+                watermarkSize = Math.max(30, Math.min(watermarkSize, 300));
+                
+                log.info("图片尺寸: {}x{}, 水印大小: {}", width, height, watermarkSize);
+            }
+            
+            // 删除临时文件
+            if (tempFile != null && tempFile.exists()) {
+                tempFile.delete();
+            }
+
+            // 将文字转换base64
             watermarkText = Base64.getEncoder().encodeToString(watermarkText.getBytes("utf-8"))
                     .replace("+", "-")
                     .replace("/", "_")
                     .replaceFirst("=+$", "");
 
-            // 添加水印
-            String style = "image/watermark,text_" + watermarkText + ",pady_10,size_100,fill_1,t_30,rotate_45,type_d3F5LW1pY3JvaGVp";
+            // 添加水印,使用计算出的大小
+            String style = "image/watermark,text_" + watermarkText + 
+                    ",pady_10" + 
+                    ",size_" + watermarkSize + 
+                    ",fill_1,t_30,rotate_45,type_d3F5LW1pY3JvaGVp";
+            
             GetObjectRequest request = new GetObjectRequest(bucketName, objectName);
             request.setProcess(style);
             // 将处理后的图片保存到本地

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

@@ -6,11 +6,13 @@ import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.constant.CacheConstants;
 import com.ruoyi.common.constant.HttpStatus;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.page.TableDataInfo;
+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.*;
@@ -33,6 +35,7 @@ import org.springframework.web.bind.annotation.*;
 
 import java.text.ParseException;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -142,6 +145,9 @@ public class CommunityArticleController extends BaseController {
     @Autowired
     private CommunityImageProcessService communityImageProcessService;
 
+    @Autowired
+    private RedisCache redisCache;
+
     /**
      * 获取文章列表信息
      */
@@ -345,12 +351,33 @@ public class CommunityArticleController extends BaseController {
     @ApiOperation("获取文章分类列表")
     //@Anonymous
     public AjaxResult getClassList() {
-
-        List<CommunityClass> communityClasses = null;
-        //获取用户信息
-        CommunityUserInfoVo communityUserInfoVo = null;
         try {
             Long userId = SecurityUtils.getLoginUser().getUserId();
+            
+            // 构建用户特定的缓存key
+            String userClassCacheKey = CacheConstants.COMMUNITY_ARTICLE_CLASS + ":" + userId;
+            
+            // 尝试从缓存中获取用户特定的排序列表
+            List<CommunityClass> sortedCommunityClasses = redisCache.getCacheObject(userClassCacheKey);
+            if (sortedCommunityClasses != null) {
+                log.info("从缓存中获取用户特定的文章分类列表");
+                return AjaxResult.success(sortedCommunityClasses);
+            }
+            
+            // 尝试从缓存中获取所有分类列表
+            List<CommunityClass> allCommunityClasses = redisCache.getCacheObject(CacheConstants.COMMUNITY_ARTICLE_CLASS);
+            if (allCommunityClasses == null) {
+                // 缓存中没有数据,从数据库查询
+                log.info("从数据库中获取文章分类列表");
+                allCommunityClasses = communityClassMapper.selectList(new QueryWrapper<CommunityClass>().orderByAsc("sort"));
+                
+                // 将查询结果存入缓存,设置24小时过期
+                redisCache.setCacheObject(CacheConstants.COMMUNITY_ARTICLE_CLASS, allCommunityClasses, 7, TimeUnit.DAYS);
+            } else {
+                log.info("从缓存中获取所有文章分类列表");
+            }
+            
+            // 获取用户信息
             String classId = communityArticleService.selectCommunityUserInfoById(userId, true).getClassId();
 
             if (classId != null && !classId.isEmpty()) {
@@ -359,14 +386,11 @@ public class CommunityArticleController extends BaseController {
                         .map(Long::parseLong)
                         .collect(Collectors.toList());
 
-                // 假设 allCommunityClasses 是从数据库查询出来的结果
-                List<CommunityClass> allCommunityClasses = communityClassMapper.selectList(new QueryWrapper<CommunityClass>().orderByAsc("sort"));
-
                 // 将 allCommunityClasses 按照 sortOrder 分组并排序
+                Map<Long, CommunityClass> classMap = allCommunityClasses.stream()
+                        .collect(Collectors.toMap(CommunityClass::getId, c -> c));
 
-                Map<Long, CommunityClass> classMap = allCommunityClasses.stream().collect(Collectors.toMap(CommunityClass::getId, c -> c));
-
-                List<CommunityClass> sortedCommunityClasses = new ArrayList<>();
+                sortedCommunityClasses = new ArrayList<>();
                 // 按 sortOrder 先添加在列表中的元素
                 for (Long order : sortOrder) {
                     if (classMap.containsKey(order)) {
@@ -379,17 +403,20 @@ public class CommunityArticleController extends BaseController {
                         .collect(Collectors.toList());
 
                 sortedCommunityClasses.addAll(remainingClasses);
+                
+                // 将用户特定的排序列表存入缓存,设置1小时过期(用户排序可能会变化,所以过期时间短一些)
+                redisCache.setCacheObject(userClassCacheKey, sortedCommunityClasses, 1, TimeUnit.HOURS);
+                
                 return AjaxResult.success(sortedCommunityClasses);
             } else {
-                communityClasses = communityClassMapper.selectList(new QueryWrapper<CommunityClass>().orderByAsc("sort"));
-
+                // 将所有分类列表作为用户特定的排序列表存入缓存
+                redisCache.setCacheObject(userClassCacheKey, allCommunityClasses, 1, TimeUnit.HOURS);
+                return AjaxResult.success(allCommunityClasses);
             }
         } catch (Exception e) {
-            //e.printStackTrace();
             log.info(e.getMessage());
             throw new ProjectException();
         }
-        return AjaxResult.success(communityClasses);
     }
 
 

+ 13 - 12
ruoyi-generator/src/main/java/com/ruoyi/generator/controller/CommunityTagController.java

@@ -56,6 +56,7 @@ public class CommunityTagController extends BaseController {
 
     @Autowired
     private CommunityUserTagMapper communityUserTagMapper;
+
     /**
      * 获取标签信息
      */
@@ -87,7 +88,7 @@ public class CommunityTagController extends BaseController {
                                     .eq("user_id", userId)
                                     .eq("is_delete", 0));
 
-                    if (userTag != null){
+                    if (userTag != null) {
                         communityTag.setIsLike(true);
                     }
 
@@ -101,7 +102,6 @@ public class CommunityTagController extends BaseController {
                 }
 
 
-
             }
         } catch (Exception e) {
             System.out.println(e.getMessage());
@@ -213,11 +213,11 @@ public class CommunityTagController extends BaseController {
                     .selectPage(page, queryWrapper).getRecords();
 
             List<Long> tagList = userTags.stream().map(CommunityUserTag::getTagId).collect(Collectors.toList());
-            if (tagList.size() == 0){
+            if (tagList.size() == 0) {
                 return AjaxResult.success(communityTags);
             }
 
-            communityTags= communityTagMapper.selectList(new QueryWrapper<CommunityTag>()
+            communityTags = communityTagMapper.selectList(new QueryWrapper<CommunityTag>()
                     .in("id", tagList)
                     .and((wrapper) -> {
                         wrapper.ne("is_delete", 1).or().isNull("is_delete");
@@ -239,7 +239,7 @@ public class CommunityTagController extends BaseController {
     @GetMapping("/tagsTakeBlock")
     @Transactional
     //@Anonymous
-    public AjaxResult tagsTakeBlock(String tagName,Long userId, boolean isToken) {
+    public AjaxResult tagsTakeBlock(String tagName, Long userId, boolean isToken) {
        /* List<CommunityTagVo> communityTagVos = new ArrayList<>();
         try {
             Page<CommunityTag> page = new Page<>(1, 10);
@@ -306,11 +306,11 @@ public class CommunityTagController extends BaseController {
             List<CommunityTagBlock> userTags = communityTagBlockMapper.selectPage(page, queryWrapper).getRecords();
 
             List<Long> tagList = userTags.stream().map(CommunityTagBlock::getTagId).collect(Collectors.toList());
-            if (tagList.isEmpty()){
+            if (tagList.isEmpty()) {
                 return AjaxResult.success(communityTags);
             }
 
-            communityTags= communityTagMapper.selectList(new QueryWrapper<CommunityTag>()
+            communityTags = communityTagMapper.selectList(new QueryWrapper<CommunityTag>()
                     .in("id", tagList)
                     .and((wrapper) -> {
                         wrapper.ne("is_delete", 1).or().isNull("is_delete");
@@ -326,7 +326,7 @@ public class CommunityTagController extends BaseController {
                                     .eq("user_id", userId)
                                     .eq("is_delete", 0));
 
-                    if (userTag != null){
+                    if (userTag != null) {
                         communityTag.setIsLike(true);
                     }
                 }
@@ -337,9 +337,10 @@ public class CommunityTagController extends BaseController {
             System.out.println(e.getMessage());
             throw new ProjectException();
         } finally {
-            assert communityTags != null;
-            for (CommunityTag communityTag : communityTags) {
-                communityTag.setIsBlock(true);
+            if (communityTags != null) {
+                for (CommunityTag communityTag : communityTags) {
+                    communityTag.setIsBlock(true);
+                }
             }
         }
 
@@ -353,7 +354,7 @@ public class CommunityTagController extends BaseController {
     @PostMapping("/addTag")
     @Transactional
     //@Anonymous
-    public AjaxResult addTag(String tagName,String attribute1,String attribute2,String attribute3,String attribute4,String attribute5) {
+    public AjaxResult addTag(String tagName, String attribute1, String attribute2, String attribute3, String attribute4, String attribute5) {
         if (StringUtils.isEmpty(tagName)) {
             return AjaxResult.error("参数异常!");
         }

+ 2 - 2
ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/CommunityImageProcessService.java

@@ -1,7 +1,7 @@
 package com.ruoyi.generator.service.impl;
 
 
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.file.FileUtils;
 import com.ruoyi.common.utils.file.ImageUtils;
@@ -130,7 +130,7 @@ public class CommunityImageProcessService {
                     imagesList.add(articleImages);
                 }
                 //先删除再插入
-                communityArticleImagesService.remove(new QueryWrapper<CommunityArticleImages>().eq("article_id", articleId));
+                communityArticleImagesService.update(new UpdateWrapper<CommunityArticleImages>().eq("article_id", articleId).set("is_delete", 1));
                 communityArticleImagesService.saveBatch(imagesList);
 
                 log.info("文章[{}]的图片水印处理完成并已更新", articleId);