diff --git a/pom.xml b/pom.xml index c5885bd0..8f2f43ee 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ 4.5.5.B + 2.9.3 @@ -232,6 +233,12 @@ ${weixin-java.version} + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + diff --git a/sql/mysql5/youlai_boot.sql b/sql/mysql5/youlai_boot.sql index 2459df40..ab74d5ae 100644 --- a/sql/mysql5/youlai_boot.sql +++ b/sql/mysql5/youlai_boot.sql @@ -144,6 +144,7 @@ CREATE TABLE `sys_log` ( `browser` varchar(100) DEFAULT NULL COMMENT '浏览器', `browser_version` varchar(100) DEFAULT NULL COMMENT '浏览器版本', `os` varchar(100) DEFAULT NULL COMMENT '终端系统', + `user_agent` varchar(255) DEFAULT NULL COMMENT '原生的用户代理字符串', `create_by` bigint DEFAULT NULL COMMENT '创建人ID', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '逻辑删除标识(1-已删除 0-未删除)', diff --git a/sql/mysql8/youlai_boot.sql b/sql/mysql8/youlai_boot.sql index 7aead97f..677b923a 100644 --- a/sql/mysql8/youlai_boot.sql +++ b/sql/mysql8/youlai_boot.sql @@ -416,6 +416,7 @@ CREATE TABLE `sys_log` ( `browser` varchar(100) DEFAULT NULL COMMENT '浏览器', `browser_version` varchar(100) DEFAULT NULL COMMENT '浏览器版本', `os` varchar(100) DEFAULT NULL COMMENT '终端系统', + `user_agent` varchar(255) DEFAULT NULL COMMENT '原生的用户代理字符串', `create_by` bigint DEFAULT NULL COMMENT '创建人ID', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '逻辑删除标识(1-已删除 0-未删除)', diff --git a/src/main/java/com/youlai/boot/config/CaffeineConfig.java b/src/main/java/com/youlai/boot/config/CaffeineConfig.java new file mode 100644 index 00000000..bba14491 --- /dev/null +++ b/src/main/java/com/youlai/boot/config/CaffeineConfig.java @@ -0,0 +1,37 @@ +package com.youlai.boot.config; + +import com.github.benmanes.caffeine.cache.Caffeine; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.CacheManager; +import org.springframework.cache.caffeine.CaffeineCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * caffeine缓存配置 + * + * @author Theo + * @since 2025-01-22 17:40:23 + */ +@Slf4j +@Configuration +public class CaffeineConfig { + + @Value("${spring.cache.caffeine.spec}") + private String caffeineSpec; + + /** + * 缓存管理器 + * + * @return CacheManager 缓存管理器 + */ + @Bean + public CacheManager cacheManager() { + CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager(); + Caffeine caffeineBuilder = Caffeine.from(caffeineSpec); + caffeineCacheManager.setCaffeine(caffeineBuilder); + return caffeineCacheManager; + } +} + diff --git a/src/main/java/com/youlai/boot/core/aspect/LogAspect.java b/src/main/java/com/youlai/boot/core/aspect/LogAspect.java index 9fe680e4..39c72941 100644 --- a/src/main/java/com/youlai/boot/core/aspect/LogAspect.java +++ b/src/main/java/com/youlai/boot/core/aspect/LogAspect.java @@ -3,9 +3,11 @@ package com.youlai.boot.core.aspect; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.TimeInterval; import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgentUtil; import cn.hutool.json.JSONUtil; +import com.alibaba.excel.util.StringUtils; import com.aliyun.oss.HttpMethod; import com.youlai.boot.common.enums.LogModuleEnum; import com.youlai.boot.common.util.IPUtils; @@ -21,6 +23,7 @@ import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; +import org.springframework.cache.CacheManager; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -37,14 +40,18 @@ import java.util.Objects; * @author Ray.Hao * @since 2024/6/25 */ +@Slf4j @Aspect @Component @RequiredArgsConstructor -@Slf4j public class LogAspect { private final LogService logService; private final HttpServletRequest request; + private final CacheManager cacheManager; + /** + * 切点 + */ @Pointcut("@annotation(com.youlai.boot.common.annotation.Log)") public void logPointcut() { } @@ -72,7 +79,12 @@ public class LogAspect { } /** - * 保持日志 + * 保存日志 + * + * @param joinPoint 切点 + * @param e 异常 + * @param jsonResult 响应结果 + * @param logAnnotation 日志注解 */ private void saveLog(final JoinPoint joinPoint, final Exception e, Object jsonResult, com.youlai.boot.common.annotation.Log logAnnotation) { String requestURI = request.getRequestURI(); @@ -120,8 +132,9 @@ public class LogAspect { log.setExecutionTime(executionTime); // 获取浏览器和终端系统信息 String userAgentString = request.getHeader("User-Agent"); - UserAgent userAgent = UserAgentUtil.parse(userAgentString); - if(Objects.nonNull(userAgent)) { + log.setUserAgent(userAgentString); + UserAgent userAgent = resolveUserAgent(userAgentString); + if (Objects.nonNull(userAgent)) { // 系统信息 log.setOs(userAgent.getOs().getName()); // 浏览器信息 @@ -193,4 +206,27 @@ public class LogAspect { return obj instanceof MultipartFile || obj instanceof HttpServletRequest || obj instanceof HttpServletResponse; } + + /** + * 解析UserAgent + * + * @param userAgentString UserAgent字符串 + * @return UserAgent + */ + public UserAgent resolveUserAgent(String userAgentString) { + if (StringUtils.isBlank(userAgentString)) { + return null; + } + // 给userAgentStringMD5加密一次防止过长 + String userAgentStringMD5 = DigestUtil.md5Hex(userAgentString); + //判断是否命中缓存 + UserAgent userAgent = Objects.requireNonNull(cacheManager.getCache("userAgent")).get(userAgentStringMD5, UserAgent.class); + if (userAgent != null) { + return userAgent; + } + userAgent = UserAgentUtil.parse(userAgentString); + Objects.requireNonNull(cacheManager.getCache("userAgent")).put(userAgentStringMD5, userAgent); + return userAgent; + } + } diff --git a/src/main/java/com/youlai/boot/system/controller/UserController.java b/src/main/java/com/youlai/boot/system/controller/UserController.java index 0b5e39fa..2e2b626a 100644 --- a/src/main/java/com/youlai/boot/system/controller/UserController.java +++ b/src/main/java/com/youlai/boot/system/controller/UserController.java @@ -1,5 +1,6 @@ package com.youlai.boot.system.controller; +import cn.hutool.json.JSONUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -63,6 +64,7 @@ public class UserController { @Valid UserPageQuery queryParams ) { IPage result = userService.getUserPage(queryParams); + return PageResult.success(result); } diff --git a/src/main/java/com/youlai/boot/system/model/entity/Log.java b/src/main/java/com/youlai/boot/system/model/entity/Log.java index 0e807f36..7181acc1 100644 --- a/src/main/java/com/youlai/boot/system/model/entity/Log.java +++ b/src/main/java/com/youlai/boot/system/model/entity/Log.java @@ -2,7 +2,6 @@ package com.youlai.boot.system.model.entity; import com.baomidou.mybatisplus.annotation.*; import com.youlai.boot.common.enums.LogModuleEnum; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serializable; @@ -87,6 +86,11 @@ public class Log implements Serializable { */ private String os; + /** + * 原生的用户代理字符串 + */ + private String userAgent; + /** * 执行时间(毫秒) */ diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 18094a6e..d53a2843 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -35,6 +35,8 @@ spring: time-to-live: 3600000 # 缓存null值,防止缓存穿透 cache-null-values: true + caffeine: + spec: initialCapacity=50,maximumSize=1000,expireAfterWrite=600s # 邮件配置 mail: host: smtp.youlai.tech diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 2fa52d4a..b8a47f2c 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -48,7 +48,8 @@ spring: enable: true # 邮件发送者 from: youlaitech@163.com - + caffeine: + spec: initialCapacity=50,maximumSize=500,expireAfterWrite=3600s mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml global-config: