From db55b2f7489a785ca25c69f1823bca19a1c48ff2 Mon Sep 17 00:00:00 2001 From: zhuangtianxiang <2913129173@qq.com> Date: Sun, 16 Feb 2025 17:50:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(operation-log):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=97=A5=E5=BF=97=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增操作日志相关实体类、控制器、服务类和仓库类 - 实现操作日志的记录和查询功能- 添加操作日志的数据库表结构 - 优化用户相关操作的日志记录 --- pom.xml | 18 ++- .../edu/gateway/IotGatewayApplication.java | 5 +- .../service/impl/BulletinServiceImpl.java | 6 +- .../controller/OperationController.java | 48 +++++++ .../operationLog/dto/OperationLogDto.java | 36 ------ .../entity/ExpressionRootObject.java | 10 +- .../operationLog/entity/FunctionTypeEnum.java | 51 ++++++++ .../operationLog/entity/ModuleTypeEnum.java | 66 ++++++++++ .../operationLog/entity/OperationLog.java | 55 +------- .../entity/OperationLogAnnotation.java | 5 + .../mapper/OperationLogMapper.java | 15 --- .../operationLog/query/OperationLogQuery.java | 41 ++++++ .../repo/OperationLogRepository.java | 3 + .../service/OperationLogService.java | 7 - .../service/impl/OperationLogServiceImpl.java | 16 --- .../util/ExpressionEvaluator.java | 41 ++++++ .../operationLog/util/OperationLogAspect.java | 120 ++++++++++++++++++ .../system/controller/UserController.java | 14 ++ .../modules/system/repo/UserRepository.java | 5 +- .../system/service/impl/UserServiceImpl.java | 2 +- src/main/resources/application-dev.yml | 3 + src/main/resources/db/gateway.sql | 13 ++ .../db/gateway/public/operation_log.sql | 29 +++++ 23 files changed, 466 insertions(+), 143 deletions(-) create mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/controller/OperationController.java delete mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/dto/OperationLogDto.java create mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/FunctionTypeEnum.java create mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/ModuleTypeEnum.java delete mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/mapper/OperationLogMapper.java create mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/query/OperationLogQuery.java delete mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/service/OperationLogService.java delete mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/service/impl/OperationLogServiceImpl.java create mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/util/ExpressionEvaluator.java create mode 100644 src/main/java/com/zsc/edu/gateway/modules/operationLog/util/OperationLogAspect.java create mode 100644 src/main/resources/db/gateway/public/operation_log.sql diff --git a/pom.xml b/pom.xml index 454470f..2838b29 100644 --- a/pom.xml +++ b/pom.xml @@ -142,7 +142,23 @@ 3.0.0 - + + org.slf4j + slf4j-api + 2.0.16 + + + io.jsonwebtoken + jjwt + 0.9.1 + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot spring-boot-starter-test test diff --git a/src/main/java/com/zsc/edu/gateway/IotGatewayApplication.java b/src/main/java/com/zsc/edu/gateway/IotGatewayApplication.java index 20186d0..8b0562b 100644 --- a/src/main/java/com/zsc/edu/gateway/IotGatewayApplication.java +++ b/src/main/java/com/zsc/edu/gateway/IotGatewayApplication.java @@ -2,11 +2,10 @@ package com.zsc.edu.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.EnableAspectJAutoProxy; -/** - * @author zhuang - */ @SpringBootApplication +@EnableAspectJAutoProxy public class IotGatewayApplication { public static void main(String[] args) { diff --git a/src/main/java/com/zsc/edu/gateway/modules/message/service/impl/BulletinServiceImpl.java b/src/main/java/com/zsc/edu/gateway/modules/message/service/impl/BulletinServiceImpl.java index e35141e..fb218c8 100644 --- a/src/main/java/com/zsc/edu/gateway/modules/message/service/impl/BulletinServiceImpl.java +++ b/src/main/java/com/zsc/edu/gateway/modules/message/service/impl/BulletinServiceImpl.java @@ -51,9 +51,9 @@ public class BulletinServiceImpl extends ServiceImpl query(Page page, OperationLogQuery query) { + return repo.selectPage(page, query.wrapper()); + } + + /** + * 批量删除操作日志 + */ + @DeleteMapping("/batch") + public int deleteBatch(@RequestBody List ids) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(OperationLog::getId, ids); + return repo.delete(wrapper); + } + +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/dto/OperationLogDto.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/dto/OperationLogDto.java deleted file mode 100644 index 80c4d85..0000000 --- a/src/main/java/com/zsc/edu/gateway/modules/operationLog/dto/OperationLogDto.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.zsc.edu.gateway.modules.operationLog.dto; - -import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; - -/** - * @author zhuang - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -public class OperationLogDto { - /** - * 模块类型 - */ - private OperationLog.ModelType modelType; - - /** - * 操作类型 - */ - private OperationLog.OperationType operationType; - - /** - * 操作内容 - */ - private String content; - - /** - * 操作时间 - */ - private LocalDateTime makeTime; -} diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/ExpressionRootObject.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/ExpressionRootObject.java index 1048ed2..0d2dbaf 100644 --- a/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/ExpressionRootObject.java +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/ExpressionRootObject.java @@ -1,5 +1,8 @@ package com.zsc.edu.gateway.modules.operationLog.entity; +import lombok.Getter; + +@Getter public class ExpressionRootObject { private final Object object; private final Object[] args; @@ -9,11 +12,4 @@ public class ExpressionRootObject { this.args = args; } - public Object getObject() { - return object; - } - - public Object[] getArgs() { - return args; - } } diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/FunctionTypeEnum.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/FunctionTypeEnum.java new file mode 100644 index 0000000..0b084a5 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/FunctionTypeEnum.java @@ -0,0 +1,51 @@ +package com.zsc.edu.gateway.modules.operationLog.entity; + +import com.baomidou.mybatisplus.annotation.IEnum; +import com.zsc.edu.gateway.common.enums.IState; +import lombok.Getter; + +/** + * @author lenovo + */ + +@Getter +public enum FunctionTypeEnum implements IEnum, IState { + save("save", "save"), + update("update", "update"), + delete("delete", "delete"), + query("query", "query"), + other("other", "other"); + + private final String code; + private final String message; + + FunctionTypeEnum(String code, String message) { + this.code = code; + this.message = message; + } + + @Override + public String getValue() { + return code; + } + + @Override + public String toString() { + return this.message; + } + + /** + * 根据代码获取消息 + * + * @param code 代码 + * @return 消息 + */ + public static String getMessageByCode(String code) { + for (FunctionTypeEnum type : FunctionTypeEnum.values()) { + if (type.getCode().equalsIgnoreCase(code)) { + return type.getMessage(); + } + } + return other.getMessage(); + } +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/ModuleTypeEnum.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/ModuleTypeEnum.java new file mode 100644 index 0000000..4bd0e18 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/ModuleTypeEnum.java @@ -0,0 +1,66 @@ +package com.zsc.edu.gateway.modules.operationLog.entity; + +import com.baomidou.mybatisplus.annotation.IEnum; +import com.zsc.edu.gateway.common.enums.IState; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author lenovo + */ +@Getter +public enum ModuleTypeEnum implements IEnum, IState { + user("user", "user"), + role("role", "role"), + menu("menu", "menu"), + dept("dept", "dept"), + device("device", "device"), + product("product", "product"), + serve("serve", "serve"), + event("event", "event"), + property("property", "property"), + notice("notice", "notice"), + bulletin("bulletin", "bulletin"), + attachment("attachment", "attachment"), + other("other", "other"); + + private final String code; + private final String messageCode; + + private static final Map CODE_MAP = Arrays.stream(values()) + .collect(Collectors.toMap( + type -> type.getCode().toLowerCase(), + type -> type + )); + + ModuleTypeEnum(String code, String message) { + this.code = code; + this.messageCode = message; + } + + @Override + public String getValue() { + return code; + } + + @Override + public String toString() { + return this.messageCode; + } + + /** + * 根据代码获取消息 + * + * @param code 代码 + * @return 消息 + */ + public static String getMessageByCode(String code) { + ModuleTypeEnum type = CODE_MAP.get(code.toLowerCase()); + return Objects.requireNonNullElse(type, other).getMessageCode(); + } + +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/OperationLog.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/OperationLog.java index 1a06d2d..1cb8a40 100644 --- a/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/OperationLog.java +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/OperationLog.java @@ -1,10 +1,8 @@ package com.zsc.edu.gateway.modules.operationLog.entity; -import com.baomidou.mybatisplus.annotation.IEnum; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.zsc.edu.gateway.common.enums.IState; import lombok.*; import java.time.LocalDateTime; @@ -27,12 +25,12 @@ public class OperationLog { /** * 模块类型 */ - private ModelType modelType; + private ModuleTypeEnum moduleType; /** * 操作类型 */ - private OperationType operationType; + private FunctionTypeEnum functionType; /** * 操作内容 @@ -43,53 +41,4 @@ public class OperationLog { * 操作时间 */ private LocalDateTime makeTime; - - public enum ModelType implements IEnum, IState { - ATTACHMENT(1, "附件模块"), - IOT(2, "物模型模块"), - MESSAGE(3, "公告消息模块"), - SYSTEM(4, "系统模块"); - - private final Integer value; - private final String name; - - ModelType(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public Integer getValue() { - return this.value; - } - - @Override - public String toString() { - return this.name; - } - } - - public enum OperationType implements IEnum, IState { - CREATE(1, "添加"), - UPDATE(2, "更新"), - DELETE(3, "删除"); - - private final Integer value; - private final String name; - - OperationType(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public Integer getValue() { - return this.value; - } - - @Override - public String toString() { - return this.name; - } - } } diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/OperationLogAnnotation.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/OperationLogAnnotation.java index ac0f062..56fc0ac 100644 --- a/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/OperationLogAnnotation.java +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/entity/OperationLogAnnotation.java @@ -13,4 +13,9 @@ public @interface OperationLogAnnotation { * 日志内容,支持SpEL表达式 */ String content() default ""; + + /** + * 操作类型,例如:SAVE, UPDATE, DELETE, QUERY + */ + String operationType() default ""; } diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/mapper/OperationLogMapper.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/mapper/OperationLogMapper.java deleted file mode 100644 index 95850ca..0000000 --- a/src/main/java/com/zsc/edu/gateway/modules/operationLog/mapper/OperationLogMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.zsc.edu.gateway.modules.operationLog.mapper; - -import com.zsc.edu.gateway.common.mapstruct.BaseMapper; -import com.zsc.edu.gateway.modules.operationLog.dto.OperationLogDto; -import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; - -/** - * @author zhuang - */ -@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE) -public interface OperationLogMapper extends BaseMapper { -} diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/query/OperationLogQuery.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/query/OperationLogQuery.java new file mode 100644 index 0000000..6c7c8be --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/query/OperationLogQuery.java @@ -0,0 +1,41 @@ +package com.zsc.edu.gateway.modules.operationLog.query; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog; +import com.zsc.edu.gateway.modules.operationLog.entity.FunctionTypeEnum; +import com.zsc.edu.gateway.modules.operationLog.entity.ModuleTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * @author zhuang + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OperationLogQuery { + private String username; + private ModuleTypeEnum moduleType; + private FunctionTypeEnum functionType; + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime publishTimeBegin; + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime publishTimeEnd; + + public LambdaQueryWrapper wrapper() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.like(StringUtils.hasText(this.username), OperationLog::getContent, this.username); + queryWrapper.eq(Objects.nonNull(this.moduleType), OperationLog::getModuleType, this.moduleType); + queryWrapper.eq(Objects.nonNull(this.functionType), OperationLog::getFunctionType, this.functionType); + if (publishTimeBegin != null && publishTimeEnd != null) { + queryWrapper.between(OperationLog::getMakeTime, this.publishTimeBegin, this.publishTimeEnd); + } + return queryWrapper; + } +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/repo/OperationLogRepository.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/repo/OperationLogRepository.java index c52d126..947dbce 100644 --- a/src/main/java/com/zsc/edu/gateway/modules/operationLog/repo/OperationLogRepository.java +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/repo/OperationLogRepository.java @@ -3,5 +3,8 @@ package com.zsc.edu.gateway.modules.operationLog.repo; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog; +/** + * @author zhuang + */ public interface OperationLogRepository extends BaseMapper { } diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/service/OperationLogService.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/service/OperationLogService.java deleted file mode 100644 index 40253c4..0000000 --- a/src/main/java/com/zsc/edu/gateway/modules/operationLog/service/OperationLogService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.zsc.edu.gateway.modules.operationLog.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog; - -public interface OperationLogService extends IService { -} diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/service/impl/OperationLogServiceImpl.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/service/impl/OperationLogServiceImpl.java deleted file mode 100644 index 5d6f427..0000000 --- a/src/main/java/com/zsc/edu/gateway/modules/operationLog/service/impl/OperationLogServiceImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.zsc.edu.gateway.modules.operationLog.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog; -import com.zsc.edu.gateway.modules.operationLog.repo.OperationLogRepository; -import com.zsc.edu.gateway.modules.operationLog.service.OperationLogService; -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Service; - -/** - * @author zhuang - */ -@AllArgsConstructor -@Service -public class OperationLogServiceImpl extends ServiceImpl implements OperationLogService { -} diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/util/ExpressionEvaluator.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/util/ExpressionEvaluator.java new file mode 100644 index 0000000..68c0254 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/util/ExpressionEvaluator.java @@ -0,0 +1,41 @@ +package com.zsc.edu.gateway.modules.operationLog.util; + + +import com.zsc.edu.gateway.modules.operationLog.entity.ExpressionRootObject; +import org.springframework.aop.support.AopUtils; +import org.springframework.context.expression.AnnotatedElementKey; +import org.springframework.context.expression.CachedExpressionEvaluator; +import org.springframework.context.expression.MethodBasedEvaluationContext; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.Expression; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ExpressionEvaluator extends CachedExpressionEvaluator { + private final ParameterNameDiscoverer paramNameDiscoverer = (ParameterNameDiscoverer) new DefaultParameterNameDiscoverer(); + private final Map conditionCache = new ConcurrentHashMap<>(64); + private final Map targetMethodCache = new ConcurrentHashMap<>(64); + + public MethodBasedEvaluationContext createEvaluationContext(Object object, Class targetClass, Method method, Object[] args) { + Method targetMethod = getTargetMethod(targetClass, method); + ExpressionRootObject root = new ExpressionRootObject(object, args); + return new MethodBasedEvaluationContext(root, targetMethod, args, this.paramNameDiscoverer); + } + + public T condition(String conditionExpression, AnnotatedElementKey elementKey, MethodBasedEvaluationContext evalContext, Class clazz) { + return (T) getExpression(this.conditionCache, elementKey, conditionExpression).getValue(evalContext, clazz); + } + + private Method getTargetMethod(Class targetClass, Method method) { + AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass); + Method targetMethod = this.targetMethodCache.get(methodKey); + if (targetMethod == null) { + targetMethod = AopUtils.getMostSpecificMethod(method, targetClass); + this.targetMethodCache.put(methodKey, targetMethod); + } + return targetMethod; + } +} \ No newline at end of file diff --git a/src/main/java/com/zsc/edu/gateway/modules/operationLog/util/OperationLogAspect.java b/src/main/java/com/zsc/edu/gateway/modules/operationLog/util/OperationLogAspect.java new file mode 100644 index 0000000..41cded6 --- /dev/null +++ b/src/main/java/com/zsc/edu/gateway/modules/operationLog/util/OperationLogAspect.java @@ -0,0 +1,120 @@ +package com.zsc.edu.gateway.modules.operationLog.util; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.zsc.edu.gateway.framework.security.UserDetailsImpl; +import com.zsc.edu.gateway.modules.operationLog.entity.FunctionTypeEnum; +import com.zsc.edu.gateway.modules.operationLog.entity.ModuleTypeEnum; +import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog; +import com.zsc.edu.gateway.modules.operationLog.entity.OperationLogAnnotation; +import com.zsc.edu.gateway.modules.operationLog.repo.OperationLogRepository; +import com.zsc.edu.gateway.modules.system.repo.UserRepository; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.context.expression.AnnotatedElementKey; +import org.springframework.context.expression.MethodBasedEvaluationContext; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Method; +import java.time.LocalDateTime; + +/** + * @author zhuang + */ +@Slf4j +@Aspect +@Component +public class OperationLogAspect { + + private static final ExpressionEvaluator EVALUATOR = new ExpressionEvaluator<>(); + + @Resource + OperationLogRepository operationLogRepository; + @Resource + UserRepository userRepository; + + /** + * 被执行方法上添加OperationLogAnnotation注解的才会执行这个方法 + */ + @AfterReturning(pointcut = "@annotation(com.zsc.edu.gateway.modules.operationLog.entity.OperationLogAnnotation)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) { + handleOperationLog(joinPoint, jsonResult); + } + + /** + * 操作日志处理逻辑,包括:格式处理,持久化 + */ + protected void handleOperationLog(final JoinPoint joinPoint, Object jsonResult) { + + OperationLogAnnotation operationLogAnnotation = ((MethodSignature) joinPoint.getSignature()).getMethod(). + getAnnotation(OperationLogAnnotation.class); + + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + HttpServletRequest request = attributes.getRequest(); + + // 获取方法名 + String methodName = joinPoint.getSignature().getName().toLowerCase(); + // 根据方法名判定方法类型 + String methodType = FunctionTypeEnum.getMessageByCode(methodName); + + // 获取类名 + String className = joinPoint.getTarget().getClass().getSimpleName().toLowerCase(); + String moduleType = className.substring(0, className.length() - "controller".length()); + moduleType = ModuleTypeEnum.getMessageByCode(moduleType); + + + // 使用SecurityContextHolder获取当前用户信息 + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.isAuthenticated()) { + UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); + + // content的默认值为返回结果 + String content = ""; + + // 获取operationLogAnnotation注解的content内容 + if (StringUtils.isNotBlank(operationLogAnnotation.content())) { + // 解析EL表达式 + content = this.evalExpression(joinPoint, operationLogAnnotation.content()); + log.info("expression:{}", content); + } + + // 获取操作类型 + String operationType = operationLogAnnotation.operationType(); + if (StringUtils.isNotBlank(operationType)) { + content = operationType + " " + content; + } + + // 添加操作人信息 + content = "操作人:" + userDetails.getUsername() + " " + content; + + // 操作日志保存到数据库内 + OperationLog operationLog = new OperationLog(); + if (StringUtils.isNotBlank(moduleType) && StringUtils.isNotBlank(methodType)) { + operationLog.setModuleType(ModuleTypeEnum.valueOf(moduleType)); + operationLog.setFunctionType(FunctionTypeEnum.valueOf(methodType)); + operationLog.setContent(content); + operationLog.setMakeTime(LocalDateTime.now()); + operationLogRepository.insert(operationLog); + } + } + } + + private String evalExpression(JoinPoint point, String expression) { + MethodSignature ms = (MethodSignature) point.getSignature(); + Method method = ms.getMethod(); + Object[] args = point.getArgs(); + Object target = point.getTarget(); + Class targetClass = target.getClass(); + MethodBasedEvaluationContext context = EVALUATOR.createEvaluationContext(target, target.getClass(), method, args); + AnnotatedElementKey elementKey = new AnnotatedElementKey(method, targetClass); + return EVALUATOR.condition(expression, elementKey, context, String.class); + } +} diff --git a/src/main/java/com/zsc/edu/gateway/modules/system/controller/UserController.java b/src/main/java/com/zsc/edu/gateway/modules/system/controller/UserController.java index de55e38..dd67f4d 100644 --- a/src/main/java/com/zsc/edu/gateway/modules/system/controller/UserController.java +++ b/src/main/java/com/zsc/edu/gateway/modules/system/controller/UserController.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.sun.source.tree.Tree; import com.zsc.edu.gateway.framework.mybatisplus.DataPermission; import com.zsc.edu.gateway.framework.security.UserDetailsImpl; +import com.zsc.edu.gateway.modules.operationLog.entity.OperationLogAnnotation; import com.zsc.edu.gateway.modules.system.dto.UserCreateDto; import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdateDto; import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdatePasswordDto; @@ -51,6 +52,7 @@ public class UserController { * @param csrfToken csrf令牌 * @return 包含csrf令牌和登录用户的认证主体信息 */ + @OperationLogAnnotation(operationType = "登录") @RequestMapping(value = "me", method = {RequestMethod.POST, RequestMethod.GET}) public Map me(@AuthenticationPrincipal Object principal, CsrfToken csrfToken) { Map map = new LinkedHashMap<>(); @@ -59,6 +61,10 @@ public class UserController { return map; } + /** + * 切换角色 + */ + @OperationLogAnnotation(content = "切换角色", operationType = "更新") @PatchMapping("/switch/{roleId}") public UserDetailsImpl switchRole(@PathVariable Long roleId) { return service.switchRole(roleId); @@ -90,6 +96,7 @@ public class UserController { * @param dto 表单数据 * @return 更新后的用户信息 */ + @OperationLogAnnotation(content = "信息", operationType = "更新") @PatchMapping("self") public Boolean selfUpdate( @AuthenticationPrincipal UserDetailsImpl userDetails, @@ -104,6 +111,8 @@ public class UserController { * @param userDetails 操作用户 * @param dto 表单数据 */ + + @OperationLogAnnotation(content = "'密码'", operationType = "更新") @PatchMapping("self/update-password") public Boolean selfUpdatePassword( @AuthenticationPrincipal UserDetailsImpl userDetails, @@ -138,6 +147,8 @@ public class UserController { * @param dto 表单数据 * @return 新建的用户信息 */ + + @OperationLogAnnotation(operationType = "新建") @PostMapping @PreAuthorize("hasAuthority('system:user:create')") public Boolean create(@RequestBody UserCreateDto dto) { @@ -151,6 +162,7 @@ public class UserController { * @param id ID * @return 更新后的用户 */ + @OperationLogAnnotation(operationType = "更新") @PatchMapping("{id}") @PreAuthorize("hasAuthority('system:user:update')") public Boolean update(@RequestBody UserUpdateDto dto, @PathVariable("id") Long id) { @@ -163,6 +175,7 @@ public class UserController { * @param id ID * @param password 新密码 */ + @OperationLogAnnotation(content = "'密码'", operationType = "更新") @PatchMapping("{id}/update-password") @PreAuthorize("hasAuthority('system:user:update')") public Boolean updatePassword(@PathVariable("id") Long id, @RequestParam String password) { @@ -183,6 +196,7 @@ public class UserController { /** * 删除用户 hasAuthority('SYSTEM:USER:DELETE') * */ + @OperationLogAnnotation(operationType = "删除") @DeleteMapping("{id}") @PreAuthorize("hasAuthority('system:user:delete')") public Boolean delete(@PathVariable("id") Long id) { diff --git a/src/main/java/com/zsc/edu/gateway/modules/system/repo/UserRepository.java b/src/main/java/com/zsc/edu/gateway/modules/system/repo/UserRepository.java index ca88d7a..b68076d 100644 --- a/src/main/java/com/zsc/edu/gateway/modules/system/repo/UserRepository.java +++ b/src/main/java/com/zsc/edu/gateway/modules/system/repo/UserRepository.java @@ -16,5 +16,8 @@ public interface UserRepository extends BaseMapper { User selectByUsername(String username); @Select("select sys_user.name from sys_user where sys_user.id=#{id}") - String selectNameById(Long id); + static String selectNameById(Long id) { + return null; + } + } diff --git a/src/main/java/com/zsc/edu/gateway/modules/system/service/impl/UserServiceImpl.java b/src/main/java/com/zsc/edu/gateway/modules/system/service/impl/UserServiceImpl.java index 06fea54..10cf1a7 100644 --- a/src/main/java/com/zsc/edu/gateway/modules/system/service/impl/UserServiceImpl.java +++ b/src/main/java/com/zsc/edu/gateway/modules/system/service/impl/UserServiceImpl.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.zsc.edu.gateway.exception.ConstraintException; import com.zsc.edu.gateway.framework.security.SecurityUtil; import com.zsc.edu.gateway.framework.security.UserDetailsImpl; +import com.zsc.edu.gateway.modules.operationLog.entity.OperationLogAnnotation; import com.zsc.edu.gateway.modules.system.dto.UserCreateDto; import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdateDto; import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdatePasswordDto; @@ -63,7 +64,6 @@ public class UserServiceImpl extends ServiceImpl implement } return true; } - @Override public Boolean update(UserUpdateDto dto, Long id) { User user = getById(id); diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index f1dcd17..95c0800 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -54,3 +54,6 @@ storage: attachment: ./storage/attachment temp: ./storage/temp +jwt: + secret: your_secret_key_here + expiration: 3600 diff --git a/src/main/resources/db/gateway.sql b/src/main/resources/db/gateway.sql index 937fbac..fc3d442 100644 --- a/src/main/resources/db/gateway.sql +++ b/src/main/resources/db/gateway.sql @@ -766,3 +766,16 @@ VALUES (1, 1, 'user1', 'password1', '13800138000', 'user1@example.com', '张三' 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '备注4', '启用', 4), (5, 5, 'user5', 'password5', '13800138004', 'user5@example.com', '孙七', 'avatar5.jpg', '杭州市', 'admin', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '备注5', '启用', 5); + +INSERT INTO operation_log (module_type, function_type, content, make_time) +VALUES ('user', 'create', 'Created a new user', '2023-10-01 10:00:00'), + ('role', 'update', 'Updated role permissions', '2023-10-01 10:15:00'), + ('menu', 'delete', 'Deleted a menu item', '2023-10-01 10:30:00'), + ('dept', 'create', 'Created a new department', '2023-10-01 10:45:00'), + ('device', 'update', 'Updated device settings', '2023-10-01 11:00:00'), + ('product', 'create', 'Added a new product', '2023-10-01 11:15:00'), + ('serve', 'delete', 'Removed a service', '2023-10-01 11:30:00'), + ('event', 'create', 'Logged an event', '2023-10-01 11:45:00'), + ('property', 'update', 'Updated property value', '2023-10-01 12:00:00'), + ('notice', 'create', 'Sent a notice', '2023-10-01 12:15:00'); + diff --git a/src/main/resources/db/gateway/public/operation_log.sql b/src/main/resources/db/gateway/public/operation_log.sql new file mode 100644 index 0000000..0eed9c2 --- /dev/null +++ b/src/main/resources/db/gateway/public/operation_log.sql @@ -0,0 +1,29 @@ +create table operation_log +( + id bigint generated by default as identity + constraint operation_log_pk + primary key, + module_type varchar not null, + function_type varchar not null, + content varchar, + make_time timestamp +); + +comment +on column operation_log.id is '主键'; + +comment +on column operation_log.module_type is '模块类型'; + +comment +on column operation_log.function_type is '操作类型'; + +comment +on column operation_log.content is '操作内容'; + +comment +on column operation_log.make_time is '操作时间'; + +alter table operation_log + owner to gitea; +