作为一个小外包...,记录一下工作中常用的一些方法(tools),以便后续使用。
如果有小伙伴看,欢迎指点。切记:不要指指点点。
操作日志表结构
-- mysql 8.0 操作日志表结构
CREATE TABLE `sys_op_log`
(
`id` varchar(40) NOT NULL COMMENT '主键',
`op_user_id` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '操作人id\n',
`op_user_name` varchar(65) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '操作人账号',
`url` varchar(255) DEFAULT NULL COMMENT '访问路径',
`ip` varchar(255) DEFAULT NULL COMMENT '客户端ip',
`module` varchar(255) DEFAULT NULL COMMENT '所属模块',
`type` varchar(255) DEFAULT NULL COMMENT '请求类型',
`status` tinyint DEFAULT NULL COMMENT '1成功,0失败',
`title` varchar(255) DEFAULT NULL COMMENT '日志标题',
`message` text COMMENT '成功或失败的信息',
`op_time` datetime DEFAULT NULL COMMENT '操作时间',
`request_param` varchar(2000) DEFAULT NULL COMMENT '请求参数\n',
`request_body` varchar(2000) DEFAULT NULL COMMENT '请求body',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_by` varchar(40) DEFAULT NULL COMMENT '创建人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_by` varchar(40) DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='系统操作日志表';
注解:
package log;
import java.lang.annotation.*;
/**
* @author OutResource Boy
* @date 2023/8/17 22:43
*/
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OpLog {
/**
* 操作模块
*/
String module() default "";
/**
* 操作标题
*/
String title() default "";
/**
* 是否使用了body参数
*/
boolean useBody() default false;
/**
* 注解:body参数位于方法的第几位
*/
int bodyIndex() default 0;
}
opLog status 相关常量
package log;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* opLog status 相关常量
* @author OutResource Boy
* @date 2023/8/18 10:58
*/
@AllArgsConstructor
public enum OpLogEnum {
/**
* 成功
*/
SUCCESS(1, "成功"),
/**
* 失败
*/
FAIL(0, "失败");
@Getter
private final Integer FLAG;
@Getter
private final String DESC;
}
Aspect
package log;
import java.util.Date;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import utils.GlobalWebVarUtil;
import utils.SnowFlakeIdGenerateUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @author OutResource Boy
* 来自:ruoyi
* 重要依赖:hu-tool
* @date 2023/8/17 22:43
*/
@Aspect
@Component
public class OpLogAspect {
/**
* 处理完请求后执行
*
* @param opLog 操作日志
* @param jsonResult json结果
*/
@AfterReturning(pointcut = "@annotation(opLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, OpLog opLog, Object jsonResult) {
handleLog(joinPoint, opLog, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param e 异常
* @param opLog 操作日志
*/
@AfterThrowing(pointcut = "@annotation(opLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, OpLog opLog, Exception e) {
handleLog(joinPoint, opLog, e, null);
}
/**
* 处理日志
*
* @param joinPoint 连接点
* @param opLog 操作日志注解
* @param e 异常
* @param jsonResult json结果
*/
private void handleLog(JoinPoint joinPoint, OpLog opLog, Exception e, Object jsonResult) {
try {
// 记录到数据库时,return的数据 或者 异常的 限制长度
int msgMaxSize = 500;
// 1、生成日志Id
String id = SnowFlakeIdGenerateUtils.getSnowFlakeId();
// 2、操作人Id:这个需要获取当前登录的用户,这里不设置
String opId = StrUtil.EMPTY;
// 3、和操作人Id一样
String opName = StrUtil.EMPTY;
// 4、获取请求Uri
HttpServletRequest request = GlobalWebVarUtil.getRequest();
String requestUri = request.getRequestURI();
// 5、获取请求者IP地址
String ip = ServletUtil.getClientIP(request);
// 6、获取请求模块
String module = opLog.module();
// +1、请求方式
String requestMethod = request.getMethod();
// 7、获取请求主题
String title = opLog.title();
// 8、获取请求Param参数
Map<String, String[]> parameterMap = request.getParameterMap();
// 处理成json串
String requestParam = JSONUtil.toJsonPrettyStr(parameterMap);
// 9、获取Body参数--> 这个不能从request中获取,因为request的body只能被读取一次,所有采用从方法的形参中读取
String bodyParam = StrUtil.EMPTY;
if (opLog.useBody()) {
Object[] args = joinPoint.getArgs();
bodyParam = JSONUtil.toJsonPrettyStr(args[opLog.bodyIndex()]);
}
// 10、处理记录的message、状态
String message;
int status;
if (ObjectUtil.isNull(e)) {
status = OpLogEnum.SUCCESS.getFLAG();
String resString = JSONUtil.toJsonPrettyStr(jsonResult);
message = StrUtil.length(resString) > msgMaxSize ? StrUtil.sub(resString, 0, msgMaxSize) : resString;
} else {
status = OpLogEnum.FAIL.getFLAG();
String resString = JSONUtil.toJsonPrettyStr(e);
message = StrUtil.length(resString) > msgMaxSize ? StrUtil.sub(resString, 0, msgMaxSize) : resString;
}
// 记录日志
SysOpLog sysOpLog = new SysOpLog();
sysOpLog.setId(id);
sysOpLog.setOpId(opId);
sysOpLog.setOpName(opName);
sysOpLog.setUrl(requestUri);
sysOpLog.setIp(ip);
sysOpLog.setModule(module);
sysOpLog.setType(requestMethod);
sysOpLog.setStatus(status);
sysOpLog.setTitle(title);
sysOpLog.setMessage(message);
sysOpLog.setOpTime(new Date());
sysOpLog.setRequestParam(requestParam);
sysOpLog.setRequestBody(bodyParam);
// --- 下面这几个我觉得放在mybatis拦截器里面比较好,这里就不设置了 --- //
sysOpLog.setCreateTime(new Date());
sysOpLog.setCreateBy("");
sysOpLog.setUpdateTime(new Date());
sysOpLog.setUpdateBy("");
}catch (Exception exp){
// 打一下异常..
}
}
}
其他小工具
package utils;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
/**
* 雪花id生成工具
*
* @author OutResource Boy
* @date 2023/6/28 17:06
*/
public class SnowFlakeIdGenerateUtils {
public static String getSnowFlakeId(){
//参数1为终端ID, 参数2为数据中心ID
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
return snowflake.nextIdStr();
}
}
package utils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* 获取Request
* @author OutResource Boy
* @date 2023/07/07
*/
public class GlobalWebVarUtil {
/**
* 得到HttpServletRequest对象
*/
public static HttpServletRequest getRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return requestAttributes != null ? ((ServletRequestAttributes) requestAttributes).getRequest() : null;
}
/**
* 设置父线程requestAttributes共享 当异步执行的DAO方法需要记录日志时,需要先调用此方法设置
*/
public static void setParentRequestShare() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes, true);
}
}
}
完整代码在这:GIT