caozixuan 1 gadu atpakaļ
vecāks
revīzija
b0f9744fbf
20 mainītis faili ar 680 papildinājumiem un 11 dzēšanām
  1. 14 0
      sop-business/src/main/java/com/qmth/sop/business/annotation/EditKey.java
  2. 26 0
      sop-business/src/main/java/com/qmth/sop/business/annotation/OperationLog.java
  3. 306 0
      sop-business/src/main/java/com/qmth/sop/business/aspect/LogAspect.java
  4. 32 0
      sop-business/src/main/java/com/qmth/sop/business/bean/dto/LogArgsDto.java
  5. 32 0
      sop-business/src/main/java/com/qmth/sop/business/bean/result/SysLogResult.java
  6. 68 0
      sop-business/src/main/java/com/qmth/sop/business/entity/SysLog.java
  7. 17 1
      sop-business/src/main/java/com/qmth/sop/business/mapper/SysLogMapper.java
  8. 11 1
      sop-business/src/main/java/com/qmth/sop/business/mapper/SysUserRoleMapper.java
  9. 15 0
      sop-business/src/main/java/com/qmth/sop/business/service/SysLogService.java
  10. 11 0
      sop-business/src/main/java/com/qmth/sop/business/service/SysUserRoleService.java
  11. 11 0
      sop-business/src/main/java/com/qmth/sop/business/service/impl/SysLogServiceImpl.java
  12. 7 0
      sop-business/src/main/java/com/qmth/sop/business/service/impl/SysUserRoleServiceImpl.java
  13. 12 1
      sop-business/src/main/resources/db/log/caozixuan_update_log.sql
  14. 18 0
      sop-business/src/main/resources/mapper/SysLogMapper.xml
  15. 13 0
      sop-business/src/main/resources/mapper/SysUserRoleMapper.xml
  16. 22 0
      sop-common/src/main/java/com/qmth/sop/common/contant/SystemConstant.java
  17. 2 0
      sop-common/src/main/java/com/qmth/sop/common/enums/ExceptionResultEnum.java
  18. 20 6
      sop-common/src/main/java/com/qmth/sop/common/enums/LogTypeEnum.java
  19. 15 0
      sop-common/src/main/java/com/qmth/sop/common/util/ServletUtil.java
  20. 28 2
      sop-server/src/main/java/com/qmth/sop/server/api/SysLogController.java

+ 14 - 0
sop-business/src/main/java/com/qmth/sop/business/annotation/EditKey.java

@@ -0,0 +1,14 @@
+package com.qmth.sop.business.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @Description: 编辑 新增和更新的主键
+ * @Author: CaoZixuan
+ * @Date: 2023-08-07
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EditKey {
+}

+ 26 - 0
sop-business/src/main/java/com/qmth/sop/business/annotation/OperationLog.java

@@ -0,0 +1,26 @@
+package com.qmth.sop.business.annotation;
+
+import com.qmth.sop.common.enums.LogTypeEnum;
+
+import java.lang.annotation.*;
+
+/**
+ * @Description: 操作日志注解
+ * @Author: CaoZixuan
+ * @Date: 2023-08-03
+ */
+@Documented
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface OperationLog {
+
+    /**
+     * 日志记录 - 具体操作的内容(默认为空)
+     */
+    String detail() default "";
+
+    /**
+     * 日志记录 - 自定义记录操作类型(默认 - 未知)
+     */
+    LogTypeEnum logType() default LogTypeEnum.UN_KNOW;
+}

+ 306 - 0
sop-business/src/main/java/com/qmth/sop/business/aspect/LogAspect.java

@@ -0,0 +1,306 @@
+package com.qmth.sop.business.aspect;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qmth.boot.api.exception.ApiException;
+import com.qmth.sop.business.annotation.EditKey;
+import com.qmth.sop.business.annotation.OperationLog;
+import com.qmth.sop.business.bean.dto.LogArgsDto;
+import com.qmth.sop.business.entity.SysLog;
+import com.qmth.sop.business.entity.SysPrivilege;
+import com.qmth.sop.business.entity.SysRole;
+import com.qmth.sop.business.entity.SysUser;
+import com.qmth.sop.business.service.SysLogService;
+import com.qmth.sop.business.service.SysPrivilegeService;
+import com.qmth.sop.business.service.SysUserRoleService;
+import com.qmth.sop.common.contant.SystemConstant;
+import com.qmth.sop.common.enums.LogTypeEnum;
+import com.qmth.sop.common.enums.PrivilegeEnum;
+import com.qmth.sop.common.util.ResultUtil;
+import com.qmth.sop.common.util.ServletUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.BeanPropertyBindingResult;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 日志操作记录拦截aop
+ * @Author: CaoZixuan
+ * @Date: 2023-08-03
+ */
+@Aspect
+@Component
+public class LogAspect {
+    @Resource
+    private SysLogService sysLogService;
+    @Resource
+    private SysPrivilegeService sysPrivilegeService;
+    @Resource
+    private SysUserRoleService sysUserRoleService;
+
+    private final static Logger log = LoggerFactory.getLogger(LogAspect.class);
+
+    /**
+     * 日志注解切入点
+     */
+    @Pointcut("@annotation(com.qmth.sop.business.annotation.OperationLog)")
+    public void operationLog() {
+
+    }
+
+    /**
+     * 环绕增强,操作日志环绕切入
+     *
+     * @param joinPoint joinPoint
+     * @return return
+     * @throws Throwable Throwable
+     */
+    @Around(value = "operationLog()")
+    public Object aroundOperationLogPoint(ProceedingJoinPoint joinPoint) throws Throwable {
+        Object res = null;
+        long beginTime = System.currentTimeMillis();
+        long endTime = 0;
+        String runStatus = "成功";
+        try {
+            res = joinPoint.proceed();
+            endTime = System.currentTimeMillis();
+            return res;
+        } catch (Exception e) {
+            endTime = System.currentTimeMillis();
+            res = "Exception: " + e.getMessage();
+            runStatus = "失败";
+            log.error(SystemConstant.LOG_ERROR, e);
+            if (e instanceof ApiException) {
+                return ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                return ResultUtil.error(e.getMessage());
+            }
+        } finally {
+            try {
+                //方法执行完成后增加日志
+                addOperationLog(joinPoint, res, endTime - beginTime, runStatus);
+            } catch (Exception e) {
+                log.error("LogAspect 操作失败:" + e.getMessage());
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+    /**
+     * 记录日志操作
+     *
+     * @param joinPoint joinPoint
+     * @param res       返回值
+     * @param time      方法执行时间
+     * @param runStatus 方法执行状态
+     */
+    private void addOperationLog(JoinPoint joinPoint, Object res, long time, String runStatus) throws IllegalAccessException {
+        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
+        String userName = requestUser.getLoginName();
+        HttpServletRequest request = ServletUtil.getRequest();
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        Long privilegeId = ServletUtil.getCurrentPrivilegeId();
+        Object[] args = joinPoint.getArgs();
+        String[] paramsName = signature.getParameterNames();
+
+        SysLog sysLog = new SysLog();
+
+        // 方法中的信息
+        sysLog.setId(SystemConstant.getDbUuid());
+
+        sysLog.setUrl(request.getServletPath());
+        sysLog.setArgs(this.getTranslateArgs(paramsName, args));
+        sysLog.setRunTime(time);
+        sysLog.setRunStatus(runStatus);
+        sysLog.setUserId(requestUser.getId());
+        sysLog.setUserName(userName);
+        sysLog.setCreateTime(System.currentTimeMillis());
+
+        // 注解中的信息
+        OperationLog annotation = signature.getMethod().getAnnotation(OperationLog.class);
+        if (annotation != null) {
+            List<SysRole> sysRoleList = sysUserRoleService.listRoleByUserId(requestUser.getId());
+            String detail = annotation.detail();
+            if (detail != null && detail.length() > 0) {
+                detail = getDetail(((MethodSignature) joinPoint.getSignature()).getParameterNames(), joinPoint.getArgs(), annotation);
+            } else {
+                detail = autoCreateOperationLogDetailByUrlAndPrivilegeId(request.getServletPath(), privilegeId);
+            }
+            if (CollectionUtils.isNotEmpty(sysRoleList)) {
+                String roleNames = sysRoleList.stream().map(SysRole::getName).collect(Collectors.joining(","));
+                detail = "[" + roleNames + "] " + detail;
+            }
+            sysLog.setContent(detail);
+
+            LogTypeEnum logType = annotation.logType();
+            if (LogTypeEnum.EDIT.equals(logType)) {
+                logType = this.getAddOrUpdateByParam(args);
+            }
+
+            sysLog.setType(logType);
+        }
+        // 保存操作日志
+        sysLogService.save(sysLog);
+    }
+
+    private String getTranslateArgs(String[] paramsName, Object[] args) {
+        List<LogArgsDto> logArgsDtoList = new ArrayList<>();
+        for (int i = 0; i < args.length; i++) {
+            if (Objects.nonNull(args[i]) && (args[i] instanceof HttpServletRequest || args[i] instanceof HttpServletResponse || args[i] instanceof CommonsMultipartFile || args[i] instanceof MultipartFile || args[i] instanceof BeanPropertyBindingResult)) {
+                continue;
+            }
+            LogArgsDto logArgsDto = new LogArgsDto();
+            logArgsDto.setArg(args[i]);
+            logArgsDto.setParamName(paramsName[i]);
+            logArgsDtoList.add(logArgsDto);
+        }
+        return JSON.toJSONString(logArgsDtoList);
+    }
+
+    private LogTypeEnum getAddOrUpdateByParam(Object[] args) throws IllegalAccessException {
+        for (Object arg : args) {
+            if (Objects.nonNull(arg) && (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse || arg instanceof MultipartFile || arg instanceof BeanPropertyBindingResult)) {
+                continue;
+            }
+            Class<?> clazz = arg.getClass();
+            Field[] fields = clazz.getDeclaredFields();
+            for (Field field : fields) {
+                EditKey editKey = field.getAnnotation(EditKey.class);
+                if (editKey != null) {
+                    // 捕捉到编辑对象的id
+                    field.setAccessible(true);
+                    Object obj = field.get(arg);
+                    if (Objects.nonNull(obj)) {
+                        return LogTypeEnum.UPDATE;
+                    } else {
+                        return LogTypeEnum.ADD;
+                    }
+                }
+            }
+            Class<?> supperClazz = clazz.getSuperclass();
+            if (Objects.nonNull(supperClazz)) {
+                Field[] supperFields = supperClazz.getDeclaredFields();
+                for (Field field : supperFields) {
+                    EditKey editKey = field.getAnnotation(EditKey.class);
+                    if (editKey != null) {
+                        // 捕捉到编辑对象的id
+                        field.setAccessible(true);
+                        Object obj = field.get(arg);
+                        if (Objects.nonNull(obj)) {
+                            return LogTypeEnum.UPDATE;
+                        } else {
+                            return LogTypeEnum.ADD;
+                        }
+                    }
+                }
+            }
+        }
+        return LogTypeEnum.EDIT;
+    }
+
+    /**
+     * 对当前登录用户和占位符处理
+     *
+     * @param argNames   方法参数名称数组
+     * @param args       方法参数数组
+     * @param annotation 注解信息
+     * @return 返回处理后的描述
+     */
+    private String getDetail(String[] argNames, Object[] args, OperationLog annotation) {
+        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
+
+
+        Map<Object, Object> map = new HashMap<>();
+        for (int i = 0; i < argNames.length; i++) {
+            if (Objects.nonNull(args[i]) && (args[i] instanceof HttpServletRequest || args[i] instanceof HttpServletResponse || args[i] instanceof CommonsMultipartFile || args[i] instanceof MultipartFile || args[i] instanceof BeanPropertyBindingResult)) {
+                continue;
+            }
+            map.put(argNames[i], args[i]);
+        }
+
+        String detail = annotation.detail();
+        try {
+            detail = "'" + requestUser.getRealName() + "'=》" + annotation.detail();
+            for (Map.Entry<Object, Object> entry : map.entrySet()) {
+                Object k = entry.getKey();
+                Object v = entry.getValue();
+                detail = detail.replace("{{" + k + "}}", JSON.toJSONString(v));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return detail;
+    }
+
+    /**
+     * 根据权限url和所在菜单的权限id自动创建操作日志详情
+     *
+     * @param url         url
+     * @param privilegeId 所属菜单的权限id
+     * @return 操作日志详情
+     */
+    private String autoCreateOperationLogDetailByUrlAndPrivilegeId(String url, Long privilegeId) {
+        String result = "";
+        SysPrivilege menu = sysPrivilegeService.getById(privilegeId);
+        SysPrivilege urlP = sysPrivilegeService.getOne(new QueryWrapper<SysPrivilege>()
+                .lambda()
+                .select(SysPrivilege::getName)
+                .eq(SysPrivilege::getUrl, url)
+                .eq(SysPrivilege::getType, PrivilegeEnum.URL));
+        if (Objects.nonNull(menu) && Objects.nonNull(urlP)) {
+            result = result + menu.getName() + SystemConstant.CATALOG_LINK + urlP.getName();
+        } else if (Objects.nonNull(menu)) {
+            result = result + menu.getName();
+        } else if (Objects.nonNull(urlP)) {
+            result = result + urlP.getName();
+        }
+        return result;
+    }
+
+    @Before(value = "operationLog()")
+    public void doBeforeAdvice(JoinPoint joinPoint) {
+        log.info("进入方法前执行.....");
+    }
+
+    /**
+     * 处理完请求,返回内容
+     *
+     * @param ret ret
+     */
+    @AfterReturning(returning = "ret", pointcut = "operationLog()")
+    public void doAfterReturning(Object ret) {
+        log.info("方法的返回值 : " + ret);
+    }
+
+    /**
+     * 后置异常通知
+     */
+    @AfterThrowing(value = "operationLog()")
+    public void throwss(JoinPoint jp) {
+        log.info("方法异常时执行.....");
+    }
+
+
+    /**
+     * 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
+     */
+    @After(value = "operationLog()")
+    public void after(JoinPoint jp) {
+        log.info("方法最后执行.....");
+    }
+}

+ 32 - 0
sop-business/src/main/java/com/qmth/sop/business/bean/dto/LogArgsDto.java

@@ -0,0 +1,32 @@
+package com.qmth.sop.business.bean.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: 日志方法中参数Dto
+ * @Author: CaoZixuan
+ * @Date: 2023-08-07
+ */
+public class LogArgsDto {
+    @ApiModelProperty(value = "参数")
+    private Object arg;
+
+    @ApiModelProperty(value = "参数名称")
+    private String paramName;
+
+    public Object getArg() {
+        return arg;
+    }
+
+    public void setArg(Object arg) {
+        this.arg = arg;
+    }
+
+    public String getParamName() {
+        return paramName;
+    }
+
+    public void setParamName(String paramName) {
+        this.paramName = paramName;
+    }
+}

+ 32 - 0
sop-business/src/main/java/com/qmth/sop/business/bean/result/SysLogResult.java

@@ -0,0 +1,32 @@
+package com.qmth.sop.business.bean.result;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: 系统日志查询结果类
+ * @Author: CaoZixuan
+ * @Date: 2023-08-07
+ */
+public class SysLogResult {
+    @ApiModelProperty("日志内容")
+    private String content;
+
+    @ApiModelProperty("创建时间")
+    private Long createTime;
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+}

+ 68 - 0
sop-business/src/main/java/com/qmth/sop/business/entity/SysLog.java

@@ -25,6 +25,13 @@ public class SysLog implements Serializable {
     @JsonSerialize(using = ToStringSerializer.class)
     private Long id;
 
+    @ApiModelProperty(value = "用户对象id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long userId;
+
+    @ApiModelProperty(value = "用户名称")
+    private String userName;
+
     @ApiModelProperty(value = "类别,LOGIN:登录,LOGOUT:退出以及数据库DDL和DML操作")
     private LogTypeEnum type;
 
@@ -38,6 +45,12 @@ public class SysLog implements Serializable {
     @ApiModelProperty(value = "内容")
     private String content;
 
+    @ApiModelProperty(value = "请求的url")
+    private String url;
+
+    @ApiModelProperty(value = "参数")
+    private String args;
+
     @ApiModelProperty(value = "更改前内容")
     private String updateBeforeObj;
 
@@ -47,6 +60,13 @@ public class SysLog implements Serializable {
     @ApiModelProperty(value = "创建时间")
     private Long createTime;
 
+    @ApiModelProperty(value = "方法运行时间")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long runTime;
+
+    @ApiModelProperty(value = "运行状态")
+    private String runStatus;
+
     public Long getId() {
         return id;
     }
@@ -55,6 +75,22 @@ public class SysLog implements Serializable {
         this.id = id;
     }
 
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
     public LogTypeEnum getType() {
         return type;
     }
@@ -87,6 +123,22 @@ public class SysLog implements Serializable {
         this.content = content;
     }
 
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getArgs() {
+        return args;
+    }
+
+    public void setArgs(String args) {
+        this.args = args;
+    }
+
     public String getUpdateBeforeObj() {
         return updateBeforeObj;
     }
@@ -110,4 +162,20 @@ public class SysLog implements Serializable {
     public void setCreateTime(Long createTime) {
         this.createTime = createTime;
     }
+
+    public Long getRunTime() {
+        return runTime;
+    }
+
+    public void setRunTime(Long runTime) {
+        this.runTime = runTime;
+    }
+
+    public String getRunStatus() {
+        return runStatus;
+    }
+
+    public void setRunStatus(String runStatus) {
+        this.runStatus = runStatus;
+    }
 }

+ 17 - 1
sop-business/src/main/java/com/qmth/sop/business/mapper/SysLogMapper.java

@@ -1,7 +1,11 @@
 package com.qmth.sop.business.mapper;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.sop.business.bean.result.SysLogResult;
 import com.qmth.sop.business.entity.SysLog;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * <p>
@@ -12,5 +16,17 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  * @since 2023-08-01
  */
 public interface SysLogMapper extends BaseMapper<SysLog> {
-
+    /**
+     * 日志分页查询
+     *
+     * @param iPage     分页参数
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @param content   内容
+     * @return 分页结果
+     */
+    IPage<SysLogResult> page(@Param("iPage") Page<SysLogResult> iPage,
+                             @Param("startTime") Long startTime,
+                             @Param("endTime") Long endTime,
+                             @Param("content") String content);
 }

+ 11 - 1
sop-business/src/main/java/com/qmth/sop/business/mapper/SysUserRoleMapper.java

@@ -1,7 +1,11 @@
 package com.qmth.sop.business.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.sop.business.entity.SysRole;
 import com.qmth.sop.business.entity.SysUserRole;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * <p>
@@ -12,5 +16,11 @@ import com.qmth.sop.business.entity.SysUserRole;
  * @since 2023-07-17
  */
 public interface SysUserRoleMapper extends BaseMapper<SysUserRole> {
-
+    /**
+     * 根据用户id查询角色集合
+     *
+     * @param userId 用户id
+     * @return 角色集合
+     */
+    List<SysRole> listRoleByUserId(@Param("userId") Long userId);
 }

+ 15 - 0
sop-business/src/main/java/com/qmth/sop/business/service/SysLogService.java

@@ -1,7 +1,11 @@
 package com.qmth.sop.business.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.sop.business.bean.result.SysLogResult;
 import com.qmth.sop.business.entity.SysLog;
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * <p>
@@ -13,4 +17,15 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface SysLogService extends IService<SysLog> {
 
+    /**
+     * 日志分页查询
+     *
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @param content    内容
+     * @param pageNumber 分页页数
+     * @param pageSize   分页容量
+     * @return 分页结果
+     */
+    IPage<SysLogResult> page(Long startTime, Long endTime, String content, int pageNumber, int pageSize);
 }

+ 11 - 0
sop-business/src/main/java/com/qmth/sop/business/service/SysUserRoleService.java

@@ -2,9 +2,12 @@ package com.qmth.sop.business.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.sop.business.bean.result.MenuResult;
+import com.qmth.sop.business.entity.SysRole;
 import com.qmth.sop.business.entity.SysUser;
 import com.qmth.sop.business.entity.SysUserRole;
 
+import java.util.List;
+
 /**
  * <p>
  * 用户和角色关联表 服务类
@@ -22,6 +25,14 @@ public interface SysUserRoleService extends IService<SysUserRole> {
      */
     MenuResult listByUserId();
 
+    /**
+     * 根据用户id查询该用户所包含的角色集合
+     *
+     * @param userId 用户id
+     * @return 角色集合
+     */
+    List<SysRole> listRoleByUserId(Long userId);
+
     /**
      * 新增用户权限
      *

+ 11 - 0
sop-business/src/main/java/com/qmth/sop/business/service/impl/SysLogServiceImpl.java

@@ -1,9 +1,13 @@
 package com.qmth.sop.business.service.impl;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.sop.business.bean.result.SysLogResult;
 import com.qmth.sop.business.entity.SysLog;
 import com.qmth.sop.business.mapper.SysLogMapper;
 import com.qmth.sop.business.service.SysLogService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.sop.common.contant.SystemConstant;
 import org.springframework.stereotype.Service;
 
 /**
@@ -17,4 +21,11 @@ import org.springframework.stereotype.Service;
 @Service
 public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements SysLogService {
 
+    @Override
+    public IPage<SysLogResult> page(Long startTime, Long endTime, String content, int pageNumber, int pageSize) {
+        if (content != null && content.length() > 0) {
+            content = SystemConstant.translateSpecificSign(content);
+        }
+        return this.baseMapper.page(new Page<>(pageNumber, pageSize), startTime, endTime, content);
+    }
 }

+ 7 - 0
sop-business/src/main/java/com/qmth/sop/business/service/impl/SysUserRoleServiceImpl.java

@@ -3,6 +3,7 @@ package com.qmth.sop.business.service.impl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.sop.business.bean.result.MenuResult;
 import com.qmth.sop.business.cache.CommonCacheService;
+import com.qmth.sop.business.entity.SysRole;
 import com.qmth.sop.business.entity.SysUser;
 import com.qmth.sop.business.entity.SysUserRole;
 import com.qmth.sop.business.mapper.SysUserRoleMapper;
@@ -12,6 +13,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.util.List;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -40,6 +42,11 @@ public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleMapper, SysUs
         return commonCacheService.userMenuCache(sysUser.getId());
     }
 
+    @Override
+    public List<SysRole> listRoleByUserId(Long userId) {
+        return this.baseMapper.listRoleByUserId(userId);
+    }
+
     /**
      * 新增用户权限
      *

+ 12 - 1
sop-business/src/main/resources/db/log/caozixuan_update_log.sql

@@ -1 +1,12 @@
-
+-- 2023.8.7 日志管理表字段更改
+ALTER TABLE `sys_log` ADD COLUMN `user_id` bigint(0) NOT NULL COMMENT '用户id' AFTER `id`;
+
+ALTER TABLE `sys_log` ADD COLUMN `user_name` varchar(100) NULL DEFAULT NULL COMMENT '用户名称' AFTER `user_id`;
+
+ALTER TABLE `sys_log` ADD COLUMN `url` varchar(64) NULL DEFAULT NULL COMMENT '请求的url' AFTER `content`;
+
+ALTER TABLE `sys_log` ADD COLUMN `args` mediumtext NULL COMMENT '请求的参数' AFTER `url`;
+
+ALTER TABLE `sys_log` ADD COLUMN `run_time` bigint(0) NULL DEFAULT NULL COMMENT '请求的响应时间' AFTER `create_time`;
+
+ALTER TABLE `sys_log` ADD COLUMN `run_status` varchar(64) NULL DEFAULT NULL COMMENT '请求的结果' AFTER `run_time`;

+ 18 - 0
sop-business/src/main/resources/mapper/SysLogMapper.xml

@@ -2,4 +2,22 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.qmth.sop.business.mapper.SysLogMapper">
 
+    <select id="page" resultType="com.qmth.sop.business.bean.result.SysLogResult">
+        SELECT
+            content, create_time AS createTime
+        FROM
+            sys_log
+        <where>
+            <if test="startTime != null">
+                AND create_time > #{startTime}
+            </if>
+            <if test="endTime != null">
+                AND #{endTime} > create_time
+            </if>
+            <if test="content != null and content != ''">
+                AND content LIKE CONCAT('%',#{content},'%')
+            </if>
+        </where>
+        ORDER BY create_time DESC
+    </select>
 </mapper>

+ 13 - 0
sop-business/src/main/resources/mapper/SysUserRoleMapper.xml

@@ -2,4 +2,17 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.qmth.sop.business.mapper.SysUserRoleMapper">
 
+    <select id="listRoleByUserId" resultType="com.qmth.sop.business.entity.SysRole">
+        SELECT
+            *
+        FROM
+            sys_role a
+        WHERE
+            EXISTS( SELECT
+                        1
+                    FROM
+                        sys_user_role b
+                    WHERE
+                        a.id = b.role_id AND b.user_id = #{userId})
+    </select>
 </mapper>

+ 22 - 0
sop-common/src/main/java/com/qmth/sop/common/contant/SystemConstant.java

@@ -82,6 +82,7 @@ public class SystemConstant {
     public static final int PAGE_SIZE_MAX = 500;
     public static final int PAGE_NUMBER_MIN = 1;
     public static final String STATIC = "static";
+    public static final String CATALOG_LINK = "->";
 
     /**
      * 表达式
@@ -124,6 +125,7 @@ public class SystemConstant {
     public static final String PREFIX_URL_DEVICE = "/sys/device";
     public static final String PREFIX_URL_DING_GROUP = "/sys/ding/group";
     public static final String PREFIX_URL_SUPPLIER = "/sys/supplier";
+    public static final String PREFIX_URL_LOG = "/sys/log";
 
     /**
      * 缓存配置
@@ -149,6 +151,7 @@ public class SystemConstant {
     public static final String HEADER_TIME = "time";
     public static final String HEADER_PLATFORM = "platform";
     public static final String HEADER_DEVICE_ID = "deviceId";
+    public static final String CURRENT_PRIVILEGE_ID = "privilegeId";
     public static final String TOKEN = "token";
     public static final String SIGN = "sign";
     public static final String LOG_ERROR = "请求出错:{}";
@@ -280,4 +283,23 @@ public class SystemConstant {
         LocalDateTime newDateTime = nowTime.plus(duration);
         return newDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
     }
+
+    /**
+     * 模糊查询时调用以去除符号"%","_"特殊字符对查询结果的影响
+     *
+     * @param param 要校验的参数
+     * @return 转译后的参数
+     */
+    public static String translateSpecificSign(String param) {
+        if (param == null) {
+            return null;
+        }
+        if (param.contains("%")) {
+            param = param.replaceAll("%", "\\\\%");
+        }
+        if (param.contains("_")) {
+            param = param.replaceAll("_", "\\\\_");
+        }
+        return param;
+    }
 }

+ 2 - 0
sop-common/src/main/java/com/qmth/sop/common/enums/ExceptionResultEnum.java

@@ -72,6 +72,8 @@ public enum ExceptionResultEnum {
 
     DEVICE_ID_INVALID(HttpStatus.UNAUTHORIZED, 4010002, "deviceId无效"),
 
+    PRIVILEGE_ID_INVALID(HttpStatus.UNAUTHORIZED, 4010002, "privilegeId无效"),
+
     TOKEN_INVALID(HttpStatus.UNAUTHORIZED, 4010003, "token无效"),
 
     TIME_INVALID(HttpStatus.UNAUTHORIZED, 4010004, "time无效"),

+ 20 - 6
sop-common/src/main/java/com/qmth/sop/common/enums/LogTypeEnum.java

@@ -8,18 +8,32 @@ package com.qmth.sop.common.enums;
  * @Date: 2022/1/24
  */
 public enum LogTypeEnum {
+    LOGIN("登录", true),
+    LOGOUT("退出", true),
+    EDIT("编辑", false),
+    ADD("新增", true),
+    DELETE("删除", true),
+    UPDATE("修改", true),
+    SEARCH("查询", true),
+    IMPORT("导入", true),
+    EXPORT("导出", true),
+    PUSH("推送", true),
+    PREVIEW("预览", true),
+    UN_KNOW("未知", false);
 
-    LOGIN("登录"),
+    private final String title;
+    private final boolean primary;
 
-    LOGOUT("退出");
-
-    private String title;
-
-    private LogTypeEnum(String title) {
+    LogTypeEnum(String title, boolean primary) {
         this.title = title;
+        this.primary = primary;
     }
 
     public String getTitle() {
         return title;
     }
+
+    public boolean isPrimary() {
+        return primary;
+    }
 }

+ 15 - 0
sop-common/src/main/java/com/qmth/sop/common/util/ServletUtil.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.qmth.boot.core.enums.Platform;
 import com.qmth.sop.common.contant.SystemConstant;
 import com.qmth.sop.common.enums.ExceptionResultEnum;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.web.context.request.RequestContextHolder;
@@ -257,4 +258,18 @@ public class ServletUtil {
     public static Object getRequestHeaderOrgIdNotVaild() {
         return getRequest().getHeader(SystemConstant.ORG_ID);
     }
+
+    /**
+     * 获取当前请求的菜单ID
+     */
+    public static Long getCurrentPrivilegeId() {
+        try {
+            HttpServletRequest request = getRequest();
+            String currentPrivilegeId = request.getHeader(SystemConstant.CURRENT_PRIVILEGE_ID);
+            return StringUtils.isBlank(currentPrivilegeId) ? null : Long.valueOf(currentPrivilegeId);
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+            throw ExceptionResultEnum.PRIVILEGE_ID_INVALID.exception();
+        }
+    }
 }

+ 28 - 2
sop-server/src/main/java/com/qmth/sop/server/api/SysLogController.java

@@ -1,10 +1,22 @@
 package com.qmth.sop.server.api;
 
 
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.sop.business.bean.result.SysLogResult;
+import com.qmth.sop.business.service.SysLogService;
+import com.qmth.sop.common.contant.SystemConstant;
+import com.qmth.sop.common.util.Result;
+import com.qmth.sop.common.util.ResultUtil;
+import io.swagger.annotations.*;
 import org.springframework.web.bind.annotation.RequestMapping;
-
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+
 /**
  * <p>
  * 系统日志 前端控制器
@@ -13,8 +25,22 @@ import org.springframework.web.bind.annotation.RestController;
  * @author wangliang
  * @since 2023-08-01
  */
+@Api(tags = "日志管理前端控制器")
 @RestController
-@RequestMapping("/sys-log")
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_LOG)
 public class SysLogController {
+    @Resource
+    private SysLogService sysLogService;
+
+    @ApiOperation(value = "日志管理-查询")
+    @RequestMapping(value = "/page", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = SysLogResult.class)})
+    public Result findLogPage(@ApiParam(value = "起始时间") @RequestParam(required = false) Long startTime,
+                              @ApiParam(value = "截止时间") @RequestParam(required = false) Long endTime,
+                              @ApiParam(value = "内容") @RequestParam(required = false) String content,
+                              @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                              @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
 
+        return ResultUtil.ok(sysLogService.page(startTime, endTime, content, pageNumber, pageSize));
+    }
 }