Parcourir la source

1.授权菜单只查询启用菜单。
2.添加日志管理

leihy il y a 2 ans
Parent
commit
e7f520f141
32 fichiers modifiés avec 1101 ajouts et 27 suppressions
  1. 1 0
      build.gradle
  2. 29 0
      src/main/groovy/com/jd/brume/common/annotation/Log.java
  3. 229 0
      src/main/groovy/com/jd/brume/common/aspect/LogAspect.java
  4. 72 0
      src/main/groovy/com/jd/brume/common/enums/Module.groovy
  5. 27 0
      src/main/groovy/com/jd/brume/common/enums/OpertateStatus.groovy
  6. 78 0
      src/main/groovy/com/jd/brume/common/enums/OpertateType.groovy
  7. 5 0
      src/main/groovy/com/jd/brume/controller/ConfigController.groovy
  8. 9 0
      src/main/groovy/com/jd/brume/controller/CorpController.groovy
  9. 60 0
      src/main/groovy/com/jd/brume/controller/LogController.groovy
  10. 133 2
      src/main/groovy/com/jd/brume/controller/LoginController.groovy
  11. 8 0
      src/main/groovy/com/jd/brume/controller/MenuButtonController.groovy
  12. 15 3
      src/main/groovy/com/jd/brume/controller/MenuController.groovy
  13. 5 1
      src/main/groovy/com/jd/brume/controller/MySmsController.groovy
  14. 9 1
      src/main/groovy/com/jd/brume/controller/RoleController.groovy
  15. 12 0
      src/main/groovy/com/jd/brume/controller/ServiceController.groovy
  16. 9 2
      src/main/groovy/com/jd/brume/controller/SmsController.groovy
  17. 12 0
      src/main/groovy/com/jd/brume/controller/UserController.groovy
  18. 4 4
      src/main/groovy/com/jd/brume/entity/LogEntity.groovy
  19. 4 4
      src/main/groovy/com/jd/brume/entity/func/LogFunc.java
  20. 14 0
      src/main/groovy/com/jd/brume/mapper/LogMapper.groovy
  21. 14 0
      src/main/groovy/com/jd/brume/service/LogService.groovy
  22. 19 0
      src/main/groovy/com/jd/brume/service/impl/LogServiceImpl.groovy
  23. 198 0
      src/main/groovy/com/jd/brume/util/IpUtils.java
  24. 20 3
      src/main/groovy/com/jd/brume/util/TokenUtil.groovy
  25. 17 0
      src/main/groovy/com/jd/brume/vo/LogVo.groovy
  26. 1 0
      src/main/resources/mapper/MenuMapper.xml
  27. 9 0
      src/main/resources/static/web/js/api/index.api.js
  28. 9 0
      src/main/resources/static/web/js/api/log.api.js
  29. 10 5
      src/main/resources/static/web/js/index.js
  30. 41 0
      src/main/resources/static/web/js/log.js
  31. 2 2
      src/main/resources/static/web/js/login.js
  32. 26 0
      src/main/resources/static/web/view/log.html

+ 1 - 0
build.gradle

@@ -25,6 +25,7 @@ jar{
 dependencies {
 	implementation 'org.springframework.boot:spring-boot-gradle-plugin:1.5.3.RELEASE'
 	implementation 'org.springframework.boot:spring-boot-starter-web'
+	implementation 'org.springframework.boot:spring-boot-starter-aop'
 	implementation 'org.codehaus.groovy:groovy'
 	implementation 'com.baomidou:mybatis-plus-boot-starter:3.5.3'
 	implementation 'mysql:mysql-connector-java'

+ 29 - 0
src/main/groovy/com/jd/brume/common/annotation/Log.java

@@ -0,0 +1,29 @@
+package com.jd.brume.common.annotation;
+
+import com.jd.brume.common.enums.Module;
+import com.jd.brume.common.enums.OpertateType;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 自定义操作日志记录注解
+ *
+ *
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Log
+{
+    /**
+     * 模块
+     */
+    Module title() default Module.OTHER;
+
+    /**
+     * 功能
+     */
+    OpertateType opertateType() default OpertateType.OTHER;
+}

+ 229 - 0
src/main/groovy/com/jd/brume/common/aspect/LogAspect.java

@@ -0,0 +1,229 @@
+package com.jd.brume.common.aspect;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONObject;
+import com.jd.brume.common.annotation.Log;
+import com.jd.brume.common.enums.OpertateStatus;
+import com.jd.brume.entity.LogEntity;
+import com.jd.brume.service.LogService;
+import com.jd.brume.util.TokenUtil;
+import com.jd.brume.util.IpUtils;
+import io.spring.gradle.dependencymanagement.org.codehaus.plexus.util.StringUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+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.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.HandlerMapping;
+import com.alibaba.fastjson.JSON;
+
+/**
+ * 操作日志记录处理
+ *
+ */
+@Aspect
+@Component
+class LogAspect
+{
+    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
+
+    @Resource
+    private LogService logService;
+
+    @Resource
+    private HttpServletRequest request;
+
+    // 配置织入点
+    @Pointcut("@annotation(com.jd.brume.common.annotation.Log)")
+    public void logPointCut()
+    {
+    }
+
+    /**
+     * 处理完请求后执行
+     *
+     * @param joinPoint 切点
+     */
+    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
+    {
+        handleLog(joinPoint, null, jsonResult);
+    }
+
+    /**
+     * 拦截异常操作
+     *
+     * @param joinPoint 切点
+     * @param e 异常
+     */
+    @AfterThrowing(value = "logPointCut()", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Exception e)
+    {
+        handleLog(joinPoint, e, null);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
+    {
+        try
+        {
+            // 获得注解
+            Log controllerLog = getAnnotationLog(joinPoint);
+            if (controllerLog == null)
+            {
+                // 未配置注解
+                return;
+            }
+
+            JSONObject jsonObj = (JSONObject)TokenUtil.getParamStr(new String[] { "userId", "userName"}, request);
+            if(jsonObj == null){
+                // token为空
+                return;
+            }
+
+            LogEntity log = new LogEntity();
+            // 操作人id
+            Integer userId = jsonObj.getInt("userId", 0);
+            log.setOpertateId(userId);
+
+            // 操作ip
+            String ip = IpUtils.getIpAddr(request);
+            log.setOpertateIp(ip);
+
+            // 操作类型
+            // 获取注解中对方法的描述信息 用于Controller层注解
+            log.setOpertateType(controllerLog.opertateType().getValue());
+
+            // 操作人
+            String userName = jsonObj.getStr("userName", "");
+            log.setOpertateName(userName);
+
+            // 操作时间
+            log.setOpertateTime(DateUtil.date());
+
+            // 模块
+            // 获取注解中对方法的描述信息 用于Controller层注解
+            log.setOpertateModule(controllerLog.title().getValue());
+
+
+
+            if (e != null)
+            {
+                // 操作状态:失败、成功
+                log.setOpertateStatus(OpertateStatus.FAIL.getValue());
+
+                // 描述
+                log.setOpertateDesc(StringUtils.substring(e.getMessage(), 0, 1000));
+            }else{
+
+                // 操作状态:失败、成功
+                log.setOpertateStatus(OpertateStatus.SUCCESS.getValue());
+
+                // 描述, 成功无描述
+                log.setOpertateDesc("");
+
+            }
+
+            // 创建时间
+            log.setCreateTime(DateUtil.date());
+
+            // 操作参数
+            setRequestValue(joinPoint, request, log);
+
+            // 返回参数
+            log.setNewMsg(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 1000));
+            //log.setNewMsg("");
+
+            // 保存日志
+            logService.save(log);
+        }
+        catch (Exception exp)
+        {
+            // 记录本地异常日志
+            log.error("==前置通知异常==");
+            log.error("异常信息:{}", exp.getMessage());
+            exp.printStackTrace();
+        }
+    }
+
+    /**
+     * 获取请求的参数,放到log中
+     *
+     * @param log 操作日志
+     * @throws Exception 异常
+     */
+    private void setRequestValue(JoinPoint joinPoint, HttpServletRequest request, LogEntity log) throws Exception
+    {
+        String requestMethod = request.getMethod();
+        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
+        {
+            String params = argsArrayToString(joinPoint.getArgs());
+            log.setOldMsg(StringUtils.substring(params, 0, 1000));
+        }
+        else
+        {
+            Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
+            log.setOldMsg(StringUtils.substring(paramsMap.toString(), 0, 1000));
+        }
+    }
+
+    /**
+     * 是否存在注解,如果存在就获取
+     */
+    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
+    {
+        Signature signature = joinPoint.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+
+        if (method != null)
+        {
+            return method.getAnnotation(Log.class);
+        }
+        return null;
+    }
+
+    /**
+     * 参数拼装
+     */
+    private String argsArrayToString(Object[] paramsArray)
+    {
+        String params = "";
+        if (paramsArray != null && paramsArray.length > 0)
+        {
+            for (int i = 0; i < paramsArray.length; i++)
+            {
+                if (!isFilterObject(paramsArray[i]))
+                {
+                    Object jsonObj = JSON.toJSON(paramsArray[i]);
+                    params += jsonObj.toString() + " ";
+                }
+            }
+        }
+        return params.trim();
+    }
+
+    /**
+     * 判断是否需要过滤的对象。
+     *
+     * @param o 对象信息。
+     * @return 如果是需要过滤的对象,则返回true;否则返回false。
+     */
+    public boolean isFilterObject(final Object o)
+    {
+        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
+    }
+}

+ 72 - 0
src/main/groovy/com/jd/brume/common/enums/Module.groovy

@@ -0,0 +1,72 @@
+package com.jd.brume.common.enums
+
+/**
+ * 功能模块
+ *
+ * @Description
+ * @Author leihy
+ * @Date 2023/4/4 10:05
+ * */
+enum Module {
+
+    /**
+     * 其它
+     */
+    OTHER("其它"),
+    /**
+     * 登录管理
+     */
+    LOGIN("登录管理"),
+
+    /**
+     * 日志管理
+     */
+    LOG("日志管理"),
+
+    /**
+     * 用户管理
+     */
+    USER("用户管理"),
+
+    /**
+     * 菜单管理
+     */
+    MENU("菜单管理"),
+
+    /**
+     * 按钮管理
+     */
+    BUTTON("按钮管理"),
+
+    /**
+     * 角色管理
+     */
+    ROLE("角色管理"),
+
+    /**
+     * 单位管理
+     */
+    CORP("单位管理"),
+
+    /**
+     * 短信配置
+     */
+    CONFIG("短信配置"),
+
+    /**
+     * 短信用户管理
+     */
+    SMS("短信用户管理"),
+
+    /**
+     * 业务管理
+     */
+    SERVICE("业务管理")
+
+    String value
+
+    Module(String value){
+        setValue(value)
+    }
+
+}

+ 27 - 0
src/main/groovy/com/jd/brume/common/enums/OpertateStatus.groovy

@@ -0,0 +1,27 @@
+package com.jd.brume.common.enums
+
+/**
+ * TODO
+ *
+ * @Description
+ * @Author leihy
+ * @Date 2023/4/3 17:14
+ * */
+enum OpertateStatus {
+
+    /**
+     * 成功
+     */
+    SUCCESS("成功"),
+
+    /**
+     * 失败
+     */
+    FAIL("失败")
+
+    String value
+
+    OpertateStatus(String value){
+        setValue(value)
+    }
+}

+ 78 - 0
src/main/groovy/com/jd/brume/common/enums/OpertateType.groovy

@@ -0,0 +1,78 @@
+package com.jd.brume.common.enums
+
+/**
+ * 操作类型
+ */
+public enum OpertateType
+{
+    /**
+     * 其它
+     */
+    OTHER("其它"),
+
+    /**
+     * 登录
+     */
+    LOGIN("登录"),
+
+    /**
+     * 登出
+     */
+    LOGOUT("登出"),
+
+    /**
+     * 查询
+     */
+    SELECT("查询"),
+
+    /**
+     * 新增
+     */
+    INSERT("新增"),
+
+    /**
+     * 修改
+     */
+    UPDATE("修改"),
+
+    /**
+     * 删除
+     */
+    DELETE("删除"),
+
+    /**
+     * 导出
+     */
+    EXPORT("导出"),
+
+    /**
+     * 发送
+     */
+    SEND("发送"),
+
+    /**
+     * 受理
+     */
+    CASE("受理"),
+
+    /**
+     * 退回
+     */
+    BACK("退回"),
+
+    /**
+     * 补齐换证
+     */
+    USE("补齐换证"),
+
+    /**
+     * 办结
+     */
+    COMPLETION("办结")
+
+    String value
+
+    OpertateType(String value){
+        setValue(value)
+    }
+}

+ 5 - 0
src/main/groovy/com/jd/brume/controller/ConfigController.groovy

@@ -2,6 +2,9 @@ package com.jd.brume.controller
 
 
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 import com.jd.brume.entity.ConfigEntity
 import com.jd.brume.service.ConfigService
 import com.jd.brume.util.Result
@@ -30,6 +33,7 @@ class ConfigController {
 	 * @param deptId
 	 * @return
 	 */
+	@Log(title = Module.CONFIG, opertateType = OpertateType.SELECT)
 	@GetMapping('one')
 	def getConfig() {
 		return new Result().ok(configService.getOne(null))
@@ -42,6 +46,7 @@ class ConfigController {
 	 * @param corVo
 	 * @return
 	 */
+	@Log(title = Module.CONFIG, opertateType = OpertateType.UPDATE)
 	@PostMapping('update')
 	def updateConfig(@Validated(UpdateGroup) ConfigVo configVo) {
 		def wrapper = new UpdateWrapper<ConfigEntity>()

+ 9 - 0
src/main/groovy/com/jd/brume/controller/CorpController.groovy

@@ -1,5 +1,8 @@
 package com.jd.brume.controller
 
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 import com.jd.brume.entity.func.UserFunc
 import com.jd.brume.service.UserService
 
@@ -47,6 +50,7 @@ class CorpController {
 	 * @param corVo
 	 * @return
 	 */
+	@Log(title = Module.CORP, opertateType = OpertateType.SELECT)
 	@GetMapping('paging')
 	def getCorpPaging(@Validated(PagingGroup) CorpVo corVo) {
 		Wrapper<CorpEntity> wrapper = Wrappers.lambdaQuery()
@@ -67,6 +71,7 @@ class CorpController {
 	 * @param deptId
 	 * @return
 	 */
+	@Log(title = Module.CORP, opertateType = OpertateType.SELECT)
 	@GetMapping('one')
 	def getCorp(@NotNull Integer deptId) {
 		return new Result().ok(corpService.getById(deptId))
@@ -77,6 +82,7 @@ class CorpController {
 	 * @param deptId
 	 * @return
 	 */
+	@Log(title = Module.CORP, opertateType = OpertateType.DELETE)
 	@DeleteMapping('delete')
 	def deleteCorp(@NotNull Integer deptId) {
 		def count = userService.count(Wrappers.lambdaQuery().eq(UserFunc.deptId(),deptId))
@@ -91,6 +97,7 @@ class CorpController {
 	 * @param corVo
 	 * @return
 	 */
+	@Log(title = Module.CORP, opertateType = OpertateType.INSERT)
 	@PostMapping('save')
 	def saveCorp(@Validated(SaveGroup) CorpVo corVo) {
 		def count = corpService.count(Wrappers.lambdaQuery().eq(CorpFunc.deptName(), corVo.deptName))
@@ -103,6 +110,7 @@ class CorpController {
 	 * @param corVo
 	 * @return
 	 */
+	@Log(title = Module.CORP, opertateType = OpertateType.UPDATE)
 	@PostMapping('update')
 	def updateCorp(@Validated(UpdateGroup) CorpVo corVo) {
 		def count = corpService.count(Wrappers.lambdaQuery().and({i -> i.eq(CorpFunc.deptName(), corVo.deptName)
@@ -116,6 +124,7 @@ class CorpController {
 	 * 初始化
 	 * @return
 	 */
+	@Log(title = Module.CORP, opertateType = OpertateType.SELECT)
 	@GetMapping('init')
 	def init() {
 		return new Result().ok([type: dictService.getDictByType(Constant.CORP_TYPE)])

+ 60 - 0
src/main/groovy/com/jd/brume/controller/LogController.groovy

@@ -0,0 +1,60 @@
+package com.jd.brume.controller
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper
+import com.baomidou.mybatisplus.core.toolkit.StringUtils
+import com.baomidou.mybatisplus.core.toolkit.Wrappers
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
+import com.jd.brume.entity.CorpEntity
+import com.jd.brume.entity.func.LogFunc
+import com.jd.brume.service.LogService
+import com.jd.brume.util.Result
+import com.jd.brume.util.ResultEnum
+import com.jd.brume.vo.LogVo
+import com.jd.brume.vo.group.PagingGroup
+import org.springframework.validation.annotation.Validated
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+
+import javax.annotation.Resource
+
+/**
+ * 系统日志
+ *
+ * @Description
+ * @Author leihy
+ * @Date 2023/4/3 16:10
+ * */
+@Validated
+@RestController
+@RequestMapping('log')
+class LogController {
+
+    @Resource
+    LogService logService
+
+
+    /**
+     * 分页查询
+     * @param logVo
+     * @return
+     */
+    @Log(title = Module.LOG, opertateType = OpertateType.SELECT)
+    @GetMapping('paging')
+    def getLogPaging(@Validated(PagingGroup) LogVo logVo) {
+        Wrapper<CorpEntity> wrapper = Wrappers.lambdaQuery()
+        if (StringUtils.isNotBlank(logVo.queryVal)) {
+            wrapper.and({i -> i.like(StringUtils.isNotBlank(logVo.queryVal), LogFunc.opertateName(), logVo.queryVal).or()
+                    .like(StringUtils.isNotBlank(logVo.queryVal), LogFunc.opertateType(), logVo.queryVal).or()
+                    .like(StringUtils.isNotBlank(logVo.queryVal), LogFunc.opertateModule(), logVo.queryVal)})
+        }
+        def count = logService.count(wrapper)
+        if (count == 0) return new Result().msg(ResultEnum.NO_DATA_TABLE)
+        wrapper.orderByDesc(LogFunc.createTime())
+        def data = logService.page(new Page(logVo.page, logVo.limit, count), wrapper)
+        return new Result().layTable([list: data.records, count: data.total])
+    }
+}

+ 133 - 2
src/main/groovy/com/jd/brume/controller/LoginController.groovy

@@ -1,5 +1,15 @@
 package com.jd.brume.controller
 
+import cn.hutool.core.date.DateUtil
+import cn.hutool.json.JSONObject
+import cn.hutool.json.JSONUtil
+import com.jd.brume.common.enums.OpertateStatus
+import com.jd.brume.common.enums.OpertateType
+import com.jd.brume.common.enums.Module
+import com.jd.brume.entity.LogEntity
+import com.jd.brume.service.LogService
+import com.jd.brume.util.IpUtils
+
 import javax.annotation.Resource
 
 import org.springframework.validation.annotation.Validated
@@ -17,12 +27,21 @@ import com.jd.brume.vo.group.LoginGroup
 
 import cn.hutool.core.codec.Base64
 
+import javax.servlet.http.HttpServletRequest
+
 @RestController
 @RequestMapping('login')
 class LoginController {
 	
 	@Resource
 	UserService userService
+
+	@Resource
+	LogService logService
+
+
+	@Resource
+	HttpServletRequest request
 	
 	/**
 	 * 登录
@@ -42,7 +61,119 @@ class LoginController {
 		if (Base64.decodeStr(userVo.password) != SMUtil.sm2Decrypt(user.password)) return new Result().msg(101, '密码错误')
 		
 		def token = TokenUtil.create(user)
+
+		def result = [token: token,userId : user.getUserId(),
+					  roleId : user.getRoleId(),deptId : user.getDeptId(),
+					  userName : user.getUserName(),phone : user.getPhone()];
+
+		try {
+			LogEntity log = new LogEntity();
+			// 操作人id
+			log.setOpertateId(user.getUserId());
+
+			// 操作ip
+			String ip = IpUtils.getIpAddr(request);
+			log.setOpertateIp(ip);
+
+			// 操作类型
+			// 获取注解中对方法的描述信息 用于Controller层注解
+			log.setOpertateType(OpertateType.LOGIN.getValue());
+
+			// 操作人
+			log.setOpertateName(user.getUserName());
+
+			// 操作时间
+			log.setOpertateTime(DateUtil.date());
+
+			// 模块
+			// 获取注解中对方法的描述信息 用于Controller层注解
+			log.setOpertateModule(Module.LOGIN.getValue());
+
+			// 操作状态:失败、成功
+			log.setOpertateStatus(OpertateStatus.SUCCESS.getValue());
+
+			// 描述, 成功无描述
+			log.setOpertateDesc("");
+
+			// 创建时间
+			log.setCreateTime(DateUtil.date());
+
+			// 操作参数
+			log.setOldMsg(JSONUtil.parse(userVo).toString());
+
+			// 返回参数
+			log.setNewMsg(JSONUtil.parse(result).toString());
+			//log.setNewMsg("");
+
+			// 保存日志
+			logService.save(log);
+		}catch(Exception e){
+			e.printStackTrace()
+		}
+
+
+
 		
-		return new Result().ok([token: token,userId : user.getUserId(),roleId : user.getRoleId(),deptId : user.getDeptId(),userName : user.getUserName(),phone : user.getPhone()])
+		return new Result().ok(result)
+	}
+
+
+	@PostMapping('logout')
+	def logout() {
+
+		try {
+			JSONObject jsonObj = (JSONObject)TokenUtil.getParamStr(new String[] { "userId", "userName"}, request);
+			if(jsonObj == null){
+				jsonObj = new JSONObject();
+			}
+			LogEntity log = new LogEntity();
+			// 操作人id
+			Integer userId = jsonObj.getInt("userId", 0);
+			log.setOpertateId(userId);
+
+			// 操作ip
+			String ip = IpUtils.getIpAddr(request);
+			log.setOpertateIp(ip);
+
+			// 操作类型
+			// 获取注解中对方法的描述信息 用于Controller层注解
+			log.setOpertateType(OpertateType.LOGOUT.getValue());
+
+			// 操作人
+			String userName = jsonObj.getStr("userName", "");
+			log.setOpertateName(userName);
+
+			// 操作时间
+			log.setOpertateTime(DateUtil.date());
+
+			// 模块
+			// 获取注解中对方法的描述信息 用于Controller层注解
+			log.setOpertateModule(Module.LOGIN.getValue());
+
+			// 操作状态:失败、成功
+			log.setOpertateStatus(OpertateStatus.SUCCESS.getValue());
+
+			// 描述, 成功无描述
+			log.setOpertateDesc("");
+
+			// 创建时间
+			log.setCreateTime(DateUtil.date());
+
+			// 操作参数
+			log.setOldMsg("{}");
+
+			// 返回参数
+			log.setNewMsg("{}");
+			//log.setNewMsg("");
+
+			// 保存日志
+			logService.save(log);
+		}catch(Exception e){
+			e.printStackTrace()
+		}
+
+		String access_token = request.getHeader("access-token");
+		TokenUtil.clean(access_token);
+		return new Result().ok([]);
 	}
-}
+}

+ 8 - 0
src/main/groovy/com/jd/brume/controller/MenuButtonController.groovy

@@ -1,5 +1,8 @@
 package com.jd.brume.controller
 
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 import com.jd.brume.service.MenuService
 import com.jd.brume.service.RoleMenuService
 
@@ -55,6 +58,7 @@ class MenuButtonController {
 	 * @param menuButtonVo
 	 * @return
 	 */
+	@Log(title = Module.BUTTON, opertateType = OpertateType.SELECT)
 	@GetMapping('paging')
 	def getMenuButtonPaging(@Validated(PagingGroup) MenuButtonVo menuButtonVo) {
 		Wrapper<MenuButtonEntity> wrapper = Wrappers.lambdaQuery()
@@ -73,6 +77,7 @@ class MenuButtonController {
 	 * @param menuButtonVo
 	 * @return
 	 */
+	@Log(title = Module.BUTTON, opertateType = OpertateType.INSERT)
 	@PostMapping('save')
 	def saveMenuButton(@Validated(SaveGroup) MenuButtonVo menuButtonVo) {
 		def count = menuButtonService.count(Wrappers.lambdaQuery().eq(MenuButtonFunc.btnTag(), menuButtonVo.btnTag)
@@ -86,6 +91,7 @@ class MenuButtonController {
 	 * @param menuButtonVo
 	 * @return
 	 */
+	@Log(title = Module.BUTTON, opertateType = OpertateType.UPDATE)
 	@PostMapping('update')
 	def updateMenuButton(@Validated(UpdateGroup) MenuButtonVo menuButtonVo) {
 		def count = menuButtonService.count(Wrappers.lambdaQuery().or({it.eq(MenuButtonFunc.btnTag(), menuButtonVo.btnTag)
@@ -98,6 +104,7 @@ class MenuButtonController {
 	/**
 	 * 删除按钮
 	 */
+	@Log(title = Module.BUTTON, opertateType = OpertateType.DELETE)
 	@DeleteMapping('delete')
 	def deleteMenuButton(@NotNull Integer btnId) {
 		def count = roleMenuService.count(Wrappers.lambdaQuery().apply(" FIND_IN_SET({0}, button_ids)", btnId))
@@ -116,6 +123,7 @@ class MenuButtonController {
 	 * @param btnId
 	 * @return
 	 */
+	@Log(title = Module.BUTTON, opertateType = OpertateType.SELECT)
 	@GetMapping('one')
 	def getMenuButton(@NotNull Integer btnId) {
 		return new Result().ok(menuButtonService.getById(btnId))

+ 15 - 3
src/main/groovy/com/jd/brume/controller/MenuController.groovy

@@ -1,5 +1,8 @@
 package com.jd.brume.controller
 
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 import com.jd.brume.entity.UserEntity
 import com.jd.brume.entity.func.CorpFunc
 import com.jd.brume.entity.func.RoleMenuFunc
@@ -68,6 +71,7 @@ class MenuController {
 	 * @param menuVo
 	 * @return
 	 */
+	@Log(title = Module.MENU, opertateType = OpertateType.SELECT)
 	@GetMapping('paging')
 	def getMenuPaging(@Validated(PagingGroup) MenuVo menuVo) {
 		Wrapper<MenuEntity> wrapper = Wrappers.lambdaQuery()
@@ -87,6 +91,7 @@ class MenuController {
 	 * 获取初始化参数
 	 * @return
 	 */
+	@Log(title = Module.MENU, opertateType = OpertateType.SELECT)
 	@GetMapping('init')
 	def init() {
 		// 获取所有上级菜单
@@ -109,6 +114,7 @@ class MenuController {
 	 * @param status
 	 * @return
 	 */
+	@Log(title = Module.MENU, opertateType = OpertateType.UPDATE)
 	@PostMapping('changeStatus')
 	def changeStatus(@NotNull Integer menuId, @NotNull Integer status) {
 		return new Result().ok(menuService.update(Wrappers.lambdaUpdate().set(MenuFunc.menuStatus(), status).eq(MenuFunc.menuId(), menuId)))
@@ -119,6 +125,7 @@ class MenuController {
 	 * @param menuId
 	 * @return
 	 */
+	@Log(title = Module.MENU, opertateType = OpertateType.SELECT)
 	@GetMapping('one')
 	def getOne(@NotNull Integer menuId) {
 		return new Result().ok(menuService.getById(menuId))
@@ -129,6 +136,7 @@ class MenuController {
 	 * @param menuVo
 	 * @return
 	 */
+	@Log(title = Module.MENU, opertateType = OpertateType.INSERT)
 	@PostMapping('save')
 	def saveMenu(@Validated(SaveGroup) MenuVo menuVo) {
 		def count = menuService.count(Wrappers.lambdaQuery().eq(MenuFunc.menuName(), menuVo.menuName))
@@ -142,6 +150,7 @@ class MenuController {
 	 * @param menuVo
 	 * @return
 	 */
+	@Log(title = Module.MENU, opertateType = OpertateType.UPDATE)
 	@PostMapping('update')
 	def updateMenu(@Validated(UpdateGroup) MenuVo menuVo) {
 		def count = menuService.count(Wrappers.lambdaQuery().eq(MenuFunc.menuName(), menuVo.menuName).ne(MenuFunc.menuId(), menuVo.menuId))
@@ -155,6 +164,7 @@ class MenuController {
 	 * @param menuId
 	 * @return
 	 */
+	@Log(title = Module.MENU, opertateType = OpertateType.DELETE)
 	@DeleteMapping('delete')
 	def deleteMenu(@NotNull Integer menuId) {
 		def count = roleMenuService.count(Wrappers.lambdaQuery().eq(RoleMenuFunc.menuId(), menuId))
@@ -168,18 +178,20 @@ class MenuController {
 	 * 获取树形菜单
 	 * @return
 	 */
+	@Log(title = Module.MENU, opertateType = OpertateType.SELECT)
 	@GetMapping('tree')
 	def getMenuTree() {
-		def menu = menuService.query().list()
+		def menu = menuService.lambdaQuery().eq(MenuFunc.menuStatus(), 1).list()
 		def button = menuButtonService.query().list()
 		return new Result().ok(LayTreeUtil.getTree(menu, button))
 	}
 
+	@Log(title = Module.MENU, opertateType = OpertateType.SELECT)
 	@GetMapping('userTree')
 	def getMenuUserTree(@NotNull Integer userId) {
-		def id = userService.getById(userId)
+		def user = userService.getById(userId)
 
-		def menu = menuService.queryList(id.getRoleId())
+		def menu = menuService.queryList(user.getRoleId())
 		return new Result().ok(LayTreeUtil.getMenuUserTree(menu))
 	}
 }

+ 5 - 1
src/main/groovy/com/jd/brume/controller/MySmsController.groovy

@@ -1,5 +1,8 @@
 package com.jd.brume.controller
 
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 import org.springframework.web.bind.annotation.GetMapping
 import org.springframework.web.bind.annotation.RequestMapping
 import org.springframework.web.bind.annotation.RestController
@@ -9,7 +12,8 @@ import com.jd.brume.util.SmsUtil
 @RestController
 @RequestMapping('mysms')
 class MySmsController {
-	
+
+	@Log(title = Module.SMS, opertateType = OpertateType.SEND)
 	@GetMapping('send')
 	def send() {
 		SmsUtil.sendSms('http://173.10.3.103:8081/sms/sendSms', "13594570020", "测试短信")

+ 9 - 1
src/main/groovy/com/jd/brume/controller/RoleController.groovy

@@ -1,5 +1,8 @@
 package com.jd.brume.controller
 
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 import com.jd.brume.entity.func.UserFunc
 import com.jd.brume.service.UserService
 
@@ -54,6 +57,7 @@ class RoleController {
 	 * @param roleVo
 	 * @return
 	 */
+	@Log(title = Module.ROLE, opertateType = OpertateType.SELECT)
 	@GetMapping('paging')
 	def getRolePaging(@Validated(PagingGroup) RoleVo roleVo) {
 		Wrapper<RoleEntity> wrapper = Wrappers.lambdaQuery()
@@ -70,6 +74,7 @@ class RoleController {
 	 * @param roleId
 	 * @return
 	 */
+	@Log(title = Module.ROLE, opertateType = OpertateType.DELETE)
 	@DeleteMapping('delete')
 	def deleteRole(@NotNull Integer roleId) {
 		def count = userService.count(Wrappers.lambdaQuery().eq(UserFunc.roleId(), roleId))
@@ -78,7 +83,8 @@ class RoleController {
 		}
 		return new Result().ok(roleService.removeById(roleId))
 	}
-	
+
+	@Log(title = Module.ROLE, opertateType = OpertateType.SELECT)
 	@GetMapping('one')
 	def getRole(@NotNull Integer roleId) {
 		return new Result().ok([role: roleService.getById(roleId), menus: roleMenuService.lambdaQuery().eq(RoleMenuFunc.roleId(), roleId).list()])
@@ -89,6 +95,7 @@ class RoleController {
 	 * @param roleVo
 	 * @return
 	 */
+	@Log(title = Module.ROLE, opertateType = OpertateType.INSERT)
 	@PostMapping('save')
 	def saveRole(@Validated(SaveGroup) RoleVo roleVo) {
 		def count = roleService.count(Wrappers.lambdaQuery().eq(RoleFunc.roleName(), roleVo.roleName))
@@ -115,6 +122,7 @@ class RoleController {
 	 * @param roleVo
 	 * @return
 	 */
+	@Log(title = Module.ROLE, opertateType = OpertateType.UPDATE)
 	@PostMapping('update')
 	def updateRole(@Validated(UpdateGroup) RoleVo roleVo) {
 		def count = roleService.count(Wrappers.lambdaQuery().eq(RoleFunc.roleName(), roleVo.roleName).ne(RoleFunc.roleId(), roleVo.roleId))

+ 12 - 0
src/main/groovy/com/jd/brume/controller/ServiceController.groovy

@@ -1,6 +1,9 @@
 package com.jd.brume.controller
 
 import com.alibaba.fastjson.JSON
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 
 import java.util.zip.ZipEntry
 import java.util.zip.ZipOutputStream
@@ -75,6 +78,8 @@ class ServiceController {
 	@Resource
 	private SmsRecordService smsRecordService
 
+
+	@Log(title = Module.SERVICE, opertateType = OpertateType.SEND)
 	@GetMapping('sendMsg')
 	def send(String url, String phone, String msg) {
 		return SmsUtil.sendSms(url, phone, msg)
@@ -83,6 +88,7 @@ class ServiceController {
 	/**
 	 * 待办
 	 */
+	@Log(title = Module.SERVICE, opertateType = OpertateType.SELECT)
 	@GetMapping('paging')
 	def getDealtPaging(@Validated(PagingGroup) ServiceVo serviceVo, HttpServletRequest req) {
 		// 查询单位前缀
@@ -97,6 +103,7 @@ class ServiceController {
 	 * @param req
 	 * @return
 	 */
+	@Log(title = Module.SERVICE, opertateType = OpertateType.SELECT)
 	@GetMapping('dealt/init')
 	def init(HttpServletRequest req) {
 		CorpEntity corp = corpService.lambdaQuery().eq(CorpFunc.deptId(), TokenUtil.getParams('deptId', req)).one()
@@ -109,6 +116,7 @@ class ServiceController {
 	 * @param id
 	 * @return
 	 */
+	@Log(title = Module.SERVICE, opertateType = OpertateType.EXPORT)
 	@GetMapping('download')
 	def download(@NotNull Integer id, @NotBlank String serviceId, @NotBlank String type, HttpServletResponse response) {
 		try {
@@ -131,6 +139,7 @@ class ServiceController {
 	 * @param req
 	 * @return
 	 */
+	@Log(title = Module.SERVICE, opertateType = OpertateType.CASE)
 	@PostMapping('dealt/case')
 	def dealtCase(@NotNull Integer id, HttpServletRequest req) {
 		JSONObject obj = TokenUtil.getParamStr(['userId', 'deptId'], req)
@@ -151,6 +160,7 @@ class ServiceController {
 	 * @param req
 	 * @return
 	 */
+	@Log(title = Module.SERVICE, opertateType = OpertateType.BACK)
 	@PostMapping('dealt/back')
 	def dealtBack(@NotNull Integer id, HttpServletRequest req) {
 		JSONObject obj = TokenUtil.getParamStr(['userId', 'deptId'], req)
@@ -167,6 +177,7 @@ class ServiceController {
 	 * @param req
 	 * @return
 	 */
+	@Log(title = Module.SERVICE, opertateType = OpertateType.USE)
 	@PostMapping('dealt/use')
 	def dealtUse(@NotNull Integer id, HttpServletRequest req) {
 		JSONObject obj = TokenUtil.getParamStr(['userId', 'deptId'], req)
@@ -188,6 +199,7 @@ class ServiceController {
 	 * @param req
 	 * @return
 	 */
+	@Log(title = Module.SERVICE, opertateType = OpertateType.COMPLETION)
 	@PostMapping('dealt/completion')
 	def dealtCompletion(@NotNull Integer id, HttpServletRequest req) {
 		JSONObject obj = TokenUtil.getParamStr(['userId', 'deptId'], req)

+ 9 - 2
src/main/groovy/com/jd/brume/controller/SmsController.groovy

@@ -3,6 +3,9 @@ package com.jd.brume.controller
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 import com.jd.brume.entity.SmsEntity
 import com.jd.brume.entity.UserEntity
 import com.jd.brume.entity.func.SmsFunc
@@ -40,6 +43,7 @@ class SmsController {
 	 * @param deptId
 	 * @return
 	 */
+	@Log(title = Module.SMS, opertateType = OpertateType.SELECT)
 	@GetMapping('one')
 	def getSmsOne(@NotNull Integer id) {
 		def sms = smsService.getById(id)
@@ -55,10 +59,11 @@ class SmsController {
 
 
 	/**
-	 * 保存菜单信息
-	 * @param menuVo
+	 * 保存配置信息
+	 * @param smsVo
 	 * @return
 	 */
+	@Log(title = Module.SMS, opertateType = OpertateType.INSERT)
 	@PostMapping('save')
 	def saveSms(@Validated(SaveGroup) SmsVo smsVo) {
 		def count = smsService.count(Wrappers.lambdaQuery().eq(SmsFunc.userId(), smsVo.userId))
@@ -71,6 +76,7 @@ class SmsController {
 	 * @param menuVo
 	 * @return
 	 */
+	@Log(title = Module.SMS, opertateType = OpertateType.SELECT)
 	@GetMapping('paging')
 	def getSmsPaging(@Validated(PagingGroup) SmsVo smsVo) {
 		return  smsService.Paging(smsVo)
@@ -83,6 +89,7 @@ class SmsController {
 	 * @param corVo
 	 * @return
 	 */
+	@Log(title = Module.SMS, opertateType = OpertateType.UPDATE)
 	@PostMapping('update')
 	def updateConfig(@Validated(UpdateGroup) SmsVo smsVo) {
 		return new Result().ok(smsService.updateById(new SmsEntity(id: smsVo.id,userId: smsVo.userId,status: smsVo.status)))

+ 12 - 0
src/main/groovy/com/jd/brume/controller/UserController.groovy

@@ -1,6 +1,9 @@
 package com.jd.brume.controller
 
 import cn.hutool.core.codec.Base64
+import com.jd.brume.common.annotation.Log
+import com.jd.brume.common.enums.Module
+import com.jd.brume.common.enums.OpertateType
 
 import javax.annotation.Resource
 import javax.validation.constraints.NotNull
@@ -57,6 +60,7 @@ class UserController {
 	 * @param userVo
 	 * @return
 	 */
+	@Log(title = Module.USER, opertateType = OpertateType.SELECT)
 	@GetMapping('paging')
 	def getUserPaging(@Validated(PagingGroup) UserVo userVo) {
 		Wrapper<UserEntity> wrapper = Wrappers.lambdaQuery()
@@ -69,6 +73,7 @@ class UserController {
 		def data = userService.page(new Page(userVo.page, userVo.limit, count), wrapper)
 		return new Result().layTable([list: data.records, count: data.total])
 	}
+	@Log(title = Module.USER, opertateType = OpertateType.SELECT)
 	@GetMapping('list')
 	def getUserList() {
 		return new Result().ok(userService.query().list())
@@ -79,6 +84,7 @@ class UserController {
 	 * @param saveUserVo
 	 * @return
 	 */
+	@Log(title = Module.USER, opertateType = OpertateType.INSERT)
 	@PostMapping('save')
 	def saveUser(@Validated(SaveGroup) UserVo userVo) {
 		if (userVo.password != userVo.repeatPass) return new Result().msg(100, '密码输入不一致')
@@ -95,6 +101,7 @@ class UserController {
 	 * @param userVo
 	 * @return
 	 */
+	@Log(title = Module.USER, opertateType = OpertateType.UPDATE)
 	@PostMapping('update')
 	def updateUser(@Validated(UpdateGroup) UserVo userVo) {
 		if (StrUtil.isNotBlank(userVo.password)) {
@@ -116,6 +123,7 @@ class UserController {
 	 * @param userId
 	 * @return
 	 */
+	@Log(title = Module.USER, opertateType = OpertateType.DELETE)
 	@DeleteMapping('delete')
 	def deleteUser(@NotNull Integer userId) {
 		return new Result().ok(userService.removeById(userId))
@@ -126,6 +134,7 @@ class UserController {
 	 * @param userId
 	 * @return
 	 */
+	@Log(title = Module.USER, opertateType = OpertateType.SELECT)
 	@GetMapping('one')
 	def getUserById(@NotNull Integer userId) {
 		return new Result().ok(userService.lambdaQuery().select(UserSelect.one).eq(UserFunc.userId(), userId).one())
@@ -135,6 +144,7 @@ class UserController {
 	 * 初始化信息
 	 * @return
 	 */
+	@Log(title = Module.USER, opertateType = OpertateType.SELECT)
 	@GetMapping('init')
 	def init() {
 		return new Result().ok([
@@ -148,6 +158,7 @@ class UserController {
 	 * @param userVo
 	 * @return
 	 */
+	@Log(title = Module.USER, opertateType = OpertateType.UPDATE)
 	@PostMapping('updatePwd')
 	def updatePwd(@Validated(UpdatePwdGroup) UserVo userVo) {
 		if (StrUtil.isNotBlank(userVo.password)) {
@@ -173,6 +184,7 @@ class UserController {
 	 * @param userVo
 	 * @return
 	 */
+	@Log(title = Module.USER, opertateType = OpertateType.UPDATE)
 	@PostMapping('updateTel')
 	def updateTel(@Validated(UpdateTelGroup) UserVo userVo) {
 		userVo.phone = Base64.decodeStr(userVo.phone);

+ 4 - 4
src/main/groovy/com/jd/brume/entity/LogEntity.groovy

@@ -13,8 +13,8 @@ class LogEntity {
 	Integer opertateId
 	
 	String opertateIp
-	
-	Integer opertateType
+
+	String opertateType
 	
 	String opertateName
 	
@@ -23,8 +23,8 @@ class LogEntity {
 	String opertateModule
 	
 	String opertateDesc
-	
-	Integer opertateStatus
+
+	String opertateStatus
 	
 	String oldMsg
 	

+ 4 - 4
src/main/groovy/com/jd/brume/entity/func/LogFunc.java

@@ -22,8 +22,8 @@ public class LogFunc {
 		return f;
 	}
 
-	public static SFunction<LogEntity, Integer> opertateType() {
-		SFunction<LogEntity, Integer> f = LogEntity::getOpertateType;
+	public static SFunction<LogEntity, String> opertateType() {
+		SFunction<LogEntity, String> f = LogEntity::getOpertateType;
 		return f;
 	}
 
@@ -47,8 +47,8 @@ public class LogFunc {
 		return f;
 	}
 
-	public static SFunction<LogEntity, Integer> opertateStatus() {
-		SFunction<LogEntity, Integer> f = LogEntity::getOpertateStatus;
+	public static SFunction<LogEntity, String> opertateStatus() {
+		SFunction<LogEntity, String> f = LogEntity::getOpertateStatus;
 		return f;
 	}
 

+ 14 - 0
src/main/groovy/com/jd/brume/mapper/LogMapper.groovy

@@ -0,0 +1,14 @@
+package com.jd.brume.mapper
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper
+import com.jd.brume.entity.LogEntity
+
+/**
+ * 系统日志
+ *
+ * @Description
+ * @Author leihy
+ * @Date 2023/4/3 15:57
+ **/
+interface LogMapper extends BaseMapper<LogEntity> {
+}

+ 14 - 0
src/main/groovy/com/jd/brume/service/LogService.groovy

@@ -0,0 +1,14 @@
+package com.jd.brume.service
+
+import com.baomidou.mybatisplus.extension.service.IService
+import com.jd.brume.entity.LogEntity
+
+/**
+ * 系统日志
+ *
+ * @Description
+ * @Author leihy
+ * @Date 2023/4/3 15:59
+ **/
+interface LogService  extends IService<LogEntity> {
+}

+ 19 - 0
src/main/groovy/com/jd/brume/service/impl/LogServiceImpl.groovy

@@ -0,0 +1,19 @@
+package com.jd.brume.service.impl
+
+import org.springframework.stereotype.Service
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
+import com.jd.brume.entity.LogEntity
+import com.jd.brume.mapper.LogMapper
+import com.jd.brume.service.LogService
+
+/**
+ * 系统日志
+ *
+ * @Description
+ * @Author leihy
+ * @Date 2023/4/3 16:01
+ **/
+@Service
+class LogServiceImpl extends ServiceImpl<LogMapper, LogEntity> implements LogService {
+}

+ 198 - 0
src/main/groovy/com/jd/brume/util/IpUtils.java

@@ -0,0 +1,198 @@
+package com.jd.brume.util;
+
+import cn.hutool.core.util.EscapeUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HTMLFilter;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 获取IP方法
+ * 
+ * @author ruoyi
+ */
+public class IpUtils
+{
+    public static String getIpAddr(HttpServletRequest request)
+    {
+        if (request == null)
+        {
+            return "unknown";
+        }
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("X-Forwarded-For");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("X-Real-IP");
+        }
+
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getRemoteAddr();
+        }
+        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : new HTMLFilter().filter(ip);
+    }
+
+    public static boolean internalIp(String ip)
+    {
+        byte[] addr = textToNumericFormatV4(ip);
+        return internalIp(addr) || "127.0.0.1".equals(ip);
+    }
+
+    private static boolean internalIp(byte[] addr)
+    {
+        if (ObjectUtil.isNull(addr) || addr.length < 2)
+        {
+            return true;
+        }
+        final byte b0 = addr[0];
+        final byte b1 = addr[1];
+        // 10.x.x.x/8
+        final byte SECTION_1 = 0x0A;
+        // 172.16.x.x/12
+        final byte SECTION_2 = (byte) 0xAC;
+        final byte SECTION_3 = (byte) 0x10;
+        final byte SECTION_4 = (byte) 0x1F;
+        // 192.168.x.x/16
+        final byte SECTION_5 = (byte) 0xC0;
+        final byte SECTION_6 = (byte) 0xA8;
+        switch (b0)
+        {
+            case SECTION_1:
+                return true;
+            case SECTION_2:
+                if (b1 >= SECTION_3 && b1 <= SECTION_4)
+                {
+                    return true;
+                }
+            case SECTION_5:
+                switch (b1)
+                {
+                    case SECTION_6:
+                        return true;
+                }
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 将IPv4地址转换成字节
+     * 
+     * @param text IPv4地址
+     * @return byte 字节
+     */
+    public static byte[] textToNumericFormatV4(String text)
+    {
+        if (text.length() == 0)
+        {
+            return null;
+        }
+
+        byte[] bytes = new byte[4];
+        String[] elements = text.split("\\.", -1);
+        try
+        {
+            long l;
+            int i;
+            switch (elements.length)
+            {
+                case 1:
+                    l = Long.parseLong(elements[0]);
+                    if ((l < 0L) || (l > 4294967295L)) {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
+                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 2:
+                    l = Integer.parseInt(elements[0]);
+                    if ((l < 0L) || (l > 255L)) {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l & 0xFF);
+                    l = Integer.parseInt(elements[1]);
+                    if ((l < 0L) || (l > 16777215L)) {
+                        return null;
+                    }
+                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 3:
+                    for (i = 0; i < 2; ++i)
+                    {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L)) {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    l = Integer.parseInt(elements[2]);
+                    if ((l < 0L) || (l > 65535L)) {
+                        return null;
+                    }
+                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 4:
+                    for (i = 0; i < 4; ++i)
+                    {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L)) {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    break;
+                default:
+                    return null;
+            }
+        }
+        catch (NumberFormatException e)
+        {
+            return null;
+        }
+        return bytes;
+    }
+
+    public static String getHostIp()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostAddress();
+        }
+        catch (UnknownHostException e)
+        {
+        }
+        return "127.0.0.1";
+    }
+
+    public static String getHostName()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostName();
+        }
+        catch (UnknownHostException e)
+        {
+        }
+        return "未知";
+    }
+}

+ 20 - 3
src/main/groovy/com/jd/brume/util/TokenUtil.groovy

@@ -20,7 +20,7 @@ class TokenUtil {
 	static def create(UserEntity user) {
 		RedisUtil redis = ContextUtil.getBean(RedisUtil)
 		def time = System.currentTimeMillis()
-		def data = [userId: user.userId, account: user.account, deptId: user.deptId, roleId: user.roleId, loginTime: time,
+		def data = [userId: user.userId, account: user.account, userName: user.userName, deptId: user.deptId, roleId: user.roleId, loginTime: time,
 					sign: IdUtil.randomUUID(), time: time]
 		def token = SMUtil.sm2Encrypt(JSONUtil.toJsonStr(data))
 		redis.set(Constant.REDIS_TOKEN_SORT.concat(Base64.getEncoder().encodeToString(user.account.getBytes())), token, expireTime)
@@ -51,6 +51,21 @@ class TokenUtil {
 		}
 	}
 
+
+	static Map<String,Object> clean(String token) {
+		try {
+
+			def json = JSONUtil.parseObj(SMUtil.sm2Decrypt(token))
+			RedisUtil redis = ContextUtil.getBean(RedisUtil)
+			def key = Constant.REDIS_TOKEN_SORT.concat(Base64.getEncoder().encodeToString(json.getStr('account').getBytes()))
+			if (!redis.hasKey(key)) return [status: false, msg: 'token过期']
+			redis.delete(key)
+			return [status: true]
+		} catch (Exception e) {
+			return [status: false, msg: 'token清除失败']
+		}
+	}
+
 	/**
 	 * 获取参数
 	 * @param name
@@ -59,11 +74,12 @@ class TokenUtil {
 	 */
 	static def getParams(String name, HttpServletRequest request) {
 		def token = request.getHeader('access-token')
-		if (!token) return null
+		if (!token || token == "null") return null
 		try {
 			def json = JSONUtil.parseObj(SMUtil.sm2Decrypt(token))
 			RedisUtil redis = ContextUtil.getBean(RedisUtil)
 			def key = Constant.REDIS_TOKEN_SORT.concat(Base64.getEncoder().encodeToString(json.getStr('account').getBytes()))
+			if(!redis.hasKey(key)) return null
 			def obj = JSONUtil.parseObj(SMUtil.sm2Decrypt(redis.get(key)))
 			return obj.get(name)
 		} catch (Exception e) {
@@ -73,11 +89,12 @@ class TokenUtil {
 
 	static def getParamStr( name, HttpServletRequest request) {
 		def token = request.getHeader('access-token')
-		if (!token) return null
+		if (!token || token == "null") return null
 		try {
 			def json = JSONUtil.parseObj(SMUtil.sm2Decrypt(token))
 			RedisUtil redis = ContextUtil.getBean(RedisUtil)
 			def key = Constant.REDIS_TOKEN_SORT.concat(Base64.getEncoder().encodeToString(json.getStr('account').getBytes()))
+			if(!redis.hasKey(key)) return null
 			def obj = JSONUtil.parseObj(SMUtil.sm2Decrypt(redis.get(key)))
 			JSONObject params = new JSONObject()
 			for (item in name) {

+ 17 - 0
src/main/groovy/com/jd/brume/vo/LogVo.groovy

@@ -0,0 +1,17 @@
+package com.jd.brume.vo
+
+import com.jd.brume.vo.group.SaveGroup
+import com.jd.brume.vo.group.UpdateGroup
+
+import javax.validation.constraints.NotBlank
+
+/**
+ * 系统日志
+ *
+ * @Description
+ * @Author leihy
+ * @Date 2023/4/3 16:27
+ * */
+class LogVo extends PagingVo {
+
+}

+ 1 - 0
src/main/resources/mapper/MenuMapper.xml

@@ -18,6 +18,7 @@
 		FROM `t_role_menu` trm
 		    LEFT JOIN t_menu tm ON tm.menu_id = trm.menu_id
 		    WHERE trm.role_id = #{roleId}
+		    and tm.menu_status = 1
 		order by tm.menu_sort
 	</select>
 </mapper>

+ 9 - 0
src/main/resources/static/web/js/api/index.api.js

@@ -29,6 +29,15 @@ layui.define(['jquery', 'ajax'], (exports) => {
 					fun(json)
 				}
 			})
+		},
+		logout: (params) => {
+			ajax.post({
+				url: '/login/logout',
+				data: params.data,
+				success: (json) => {
+					params.fun(json)
+				}
+			})
 		}
 	}
 	

+ 9 - 0
src/main/resources/static/web/js/api/log.api.js

@@ -0,0 +1,9 @@
+layui.define(['jquery', 'ajax'], (exports) => {
+	const ajax = layui.ajax
+	const $ = layui.jquery
+	
+	const api = {
+	}
+	
+	exports('api', api)
+})

+ 10 - 5
src/main/resources/static/web/js/index.js

@@ -13,13 +13,18 @@ layui.config({
 	const form = layui.form;
 	const customUtil = layui.customUtil;
 	const userId = sessionStorage.getItem('login-userId');
-	const userName = sessionStorage.getItem('login-userName');
-	const phone = sessionStorage.getItem('login-phone');
+	const userName = decodeURIComponent(atob(sessionStorage.getItem('login-userName')));
+	const phone = decodeURIComponent(atob(sessionStorage.getItem('login-phone')));
 	$("#indexUserName").text(userName);
 
 	$('#loginBack').on('click', () => {
-		localStorage.clear();
-		window.location = constants.LOGIN_PATH;
+		layui.api.logout({
+			data : {},
+			fun : (json) => {
+				localStorage.clear();
+				window.location = constants.LOGIN_PATH;
+			}
+		})
 	})
 
 	$('#updatePwd').on('click', () => {
@@ -99,7 +104,7 @@ layui.config({
 					setTimeout( () => {
 						layer.closeAll();
 					},1500)
-					sessionStorage.setItem('login-phone',data.field.phone);
+					sessionStorage.setItem('login-phone',btoa(encodeURIComponent(data.field.phone)));
 				}
 				customUtil.refush(json.code == constants.SUCCESS_CODE, '保存成功', json.msg)
 			}

+ 41 - 0
src/main/resources/static/web/js/log.js

@@ -0,0 +1,41 @@
+layui.config({
+  base: '../js/module/'
+}).extend({
+	'constants': '{/}../js/util/constants',
+	'ajax': '{/}../js/util/ajax',
+	'customUtil': '{/}../js/util/util',
+	'api': '{/}../js/api/log.api'
+}).use(['jquery', 'layer', 'form', 'api', 'constants', 'customUtil'], () => {
+	initTable()
+	initClick()
+})
+
+const initTable = () => {
+	layui.customUtil.table({
+		elem: '#table',
+		url: '/log/paging',
+		cols: [[
+			{type: 'numbers', title: '序号'},
+			{field: 'opertateIp', title: '操作ip'},
+			{field: 'opertateName', title: '操作人'},
+			{field: 'createTime', title: '操作时间'},
+			{field: 'opertateModule', title: '模块'},
+			{field: 'opertateDesc', title: '描述'},
+			{field: 'opertateType', title: '操作类型'},
+			{field: 'opertateStatus', title: '操作状态'},
+			{field: 'oldMsg', title: '操作参数'},
+			{field: 'newMsg', title: '返回参数'}
+		]]
+	})
+}
+
+const initClick = () => {
+	const $ = layui.jquery
+	
+	$('.brume-main').on('click', '.search', () => {
+		layui.table.reload('table', {
+			where: {queryVal: $('input[name="search"]').val()},
+			page: { curr: 1 }
+		})
+	})
+}

+ 2 - 2
src/main/resources/static/web/js/login.js

@@ -48,8 +48,8 @@ const click = () => {
 					sessionStorage.setItem('login-userId', json.result.userId)
 					sessionStorage.setItem('login-deptId', json.result.deptId)
 					sessionStorage.setItem('login-roleId', json.result.roleId)
-					sessionStorage.setItem('login-userName', json.result.userName)
-					sessionStorage.setItem('login-phone', json.result.phone)
+					sessionStorage.setItem('login-userName', btoa(encodeURIComponent(json.result.userName)))
+					sessionStorage.setItem('login-phone', btoa(encodeURIComponent(json.result.phone)))
 					window.location.href = '../index.html'
 				} else {
 					layui.layer.msg(json.msg, {icon: 5})

+ 26 - 0
src/main/resources/static/web/view/log.html

@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<title>日志管理</title>
+		<link rel="stylesheet" href="../js/lib/layui-v2.7.6/layui/css/layui.css" />
+		<link rel="stylesheet" href="../css/main.css"/>
+	</head>
+	<body>
+		<div class="brume-main">
+			<div class="layui-row">
+				<div class="fast-float-right layui-form">
+					<div class="layui-input-inline">
+						<input placeholder="请输入操作人/操作类型/模块" type="text" name="search" autocomplete="off" class="layui-input">
+					</div>
+					<button type="button" class="layui-btn layui-btn-normal search">
+						<i class="layui-icon layui-icon-search"></i>
+					</button>
+				</div>
+			</div>
+			<table id="table" class="layui-hide" lay-filter="table"></table>
+		</div>
+	</body>
+	<script src="../js/lib/layui-v2.7.6/layui/layui.js"></script>
+	<script src="../js/log.js"></script>
+</html>