Spring AOP接口请求记录数据库
AboutChristopher 人气:01.引入AOP依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2.创建日志记录表
DROP TABLE IF EXISTS `rule_operate_log`; CREATE TABLE `rule_operate_log` ( id INT(11) NOT NULL AUTO_INCREMENT COMMENT '日志id', path VARCHAR(4000) NULL DEFAULT NULL COMMENT '接口地址', http_method VARCHAR(32) NULL DEFAULT NULL COMMENT '请求方法', status_code VARCHAR(32) NULL DEFAULT NULL COMMENT '请求返回状态码', create_time_char VARCHAR(32) NULL DEFAULT NULL COMMENT '日志时间', create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '日志时间戳', ip varchar(200) NULL DEFAULT NULL COMMENT '请求ip', params mediumtext NULL COMMENT '请求参数', result mediumtext NULL COMMENT '返回值', exception mediumtext NULL COMMENT '接口异常', user_id VARCHAR(32) NULL DEFAULT NULL COMMENT '操作用户', user_account VARCHAR(32) NULL DEFAULT NULL COMMENT '操作用户账号', user_name VARCHAR(200) NULL DEFAULT NULL COMMENT '操作用户名称', user_org_id VARCHAR(32) NULL DEFAULT NULL COMMENT '操作用户机构id', user_org_name VARCHAR(200) NULL DEFAULT NULL COMMENT '操作用户机构名称', operate_name VARCHAR(200) NULL DEFAULT NULL COMMENT '操作名称', operate_position VARCHAR(200) NULL DEFAULT NULL COMMENT '操作位置', log_type VARCHAR(32) NULL DEFAULT NULL COMMENT '日志类型 error:错误日志 operate:操作日志', category_id VARCHAR(32) NULL DEFAULT NULL COMMENT '分类机构id', cost INT(11) NULL DEFAULT NULL COMMENT '接口耗时', PRIMARY KEY (id) ) COMMENT = '操作日志表';
3.日志实体类
import java.util.Date; public class RuleOperateLog { /** * id */ private Integer id; /** * 接口地址 */ private String path; /** * 请求方法 */ private String httpMethod; /** * 请求返回状态码 */ private String statusCode; /** * 日志时间 */ private String createTimeChar; /** * 日志时间戳 */ private Date createTime; /** * 请求ip */ private String ip; /** * 请求参数 */ private String params; /** * 返回值 */ private String result; /** * 接口异常 */ private String exception; /** * 操作用户 */ private String userId; /** * 操作用户账号 */ private String userAccount; /** * 操作用户名称 */ private String userName; /** * 操作用户机构 */ private String userOrgId; /** * 操作用户机构名称 */ private String userOrgName; /** * 操作名称 */ private String operateName; /** * 操作位置 */ private String operatePosition; /** * 日志类型 */ private String logType; /** * 分类机构id */ private String categoryId; /** * 请求耗时 */ private Integer cost; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getHttpMethod() { return httpMethod; } public void setHttpMethod(String httpMethod) { this.httpMethod = httpMethod; } public String getStatusCode() { return statusCode; } public void setStatusCode(String statusCode) { this.statusCode = statusCode; } public String getCreateTimeChar() { return createTimeChar; } public void setCreateTimeChar(String createTimeChar) { this.createTimeChar = createTimeChar; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getParams() { return params; } public void setParams(String params) { this.params = params; } public String getResult() { return result; } public void setResult(String result) { this.result = result; } public String getException() { return exception; } public void setException(String exception) { this.exception = exception; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUserAccount() { return userAccount; } public void setUserAccount(String userAccount) { this.userAccount = userAccount; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserOrgId() { return userOrgId; } public void setUserOrgId(String userOrgId) { this.userOrgId = userOrgId; } public String getUserOrgName() { return userOrgName; } public void setUserOrgName(String userOrgName) { this.userOrgName = userOrgName; } public String getOperateName() { return operateName; } public void setOperateName(String operateName) { this.operateName = operateName; } public String getOperatePosition() { return operatePosition; } public void setOperatePosition(String operatePosition) { this.operatePosition = operatePosition; } public String getLogType() { return logType; } public void setLogType(String logType) { this.logType = logType; } public String getCategoryId() { return categoryId; } public void setCategoryId(String categoryId) { this.categoryId = categoryId; } public Integer getCost() { return cost; } public void setCost(Integer cost) { this.cost = cost; } }
4.Dao+Mapper+service
import com.xxx.xxx.xxx.entity.RuleOperateLog; /** * 操作日志(RuleOperateLog)表数据库访问层 * * @author hx * @since 2022-08-23 */ public interface RuleOperateLogDao { /** * 新增数据 * * @param operateLog * @return */ int insert(RuleOperateLog operateLog); }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xxx.xxx.xxx.dao.RuleOperateLogDao"> <resultMap type="com.xxx.xxx.xxx.entity.RuleOperateLog" id="RuleOperateLogMap"> <result property="id" column="id" jdbcType="INTEGER"/> <result property="path" column="path" jdbcType="VARCHAR"/> <result property="httpMethod" column="http_method" jdbcType="VARCHAR"/> <result property="statusCode" column="status_code" jdbcType="VARCHAR"/> <result property="createTimeChar" column="create_time_char" jdbcType="VARCHAR"/> <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/> <result property="ip" column="ip" jdbcType="VARCHAR"/> <result property="params" column="params" jdbcType="VARCHAR"/> <result property="result" column="result" jdbcType="VARCHAR"/> <result property="exception" column="exception" jdbcType="VARCHAR"/> <result property="userId" column="user_id" jdbcType="VARCHAR"/> <result property="userAccount" column="user_account" jdbcType="VARCHAR"/> <result property="userName" column="user_name" jdbcType="VARCHAR"/> <result property="userOrgId" column="user_org_id" jdbcType="VARCHAR"/> <result property="userOrgName" column="user_org_name" jdbcType="VARCHAR"/> <result property="operateName" column="operate_name" jdbcType="VARCHAR"/> <result property="operatePosition" column="operate_position" jdbcType="VARCHAR"/> <result property="logType" column="log_type" jdbcType="VARCHAR"/> <result property="categoryId" column="category_id" jdbcType="VARCHAR"/> <result property="cost" column="cost" jdbcType="INTEGER"/> </resultMap> <insert id="insert" keyProperty="id" useGeneratedKeys="true"> insert into rule_operate_log (id, path, http_method, status_code, create_time_char, create_time, ip, params, result, exception, user_id, user_account, user_name, user_org_id, user_org_name, operate_name, operate_position, log_type, category_id, cost) values (#{id}, #{path}, #{httpMethod}, #{statusCode}, #{createTimeChar}, #{createTime}, #{ip}, #{params}, #{result}, #{exception},#{userId}, #{userAccount}, #{userName}, #{userOrgId}, #{userOrgName}, #{operateName}, #{operatePosition}, #{logType}, #{categoryId}, #{cost}) </insert> </mapper>
import com.xxx.xxx.xxx.entity.RuleOperateLog; /** * 操作日志(RuleOperateLog)表服务接口 * * @author hx * @since 2022-08-23 */ public interface RuleOperateLogService { /** * 保存日志 * * @param ruleOperateLog * @return */ void saveLog(RuleOperateLog ruleOperateLog); }
import com.xxx.xxx.xxx.dao.RuleOperateLogDao; import com.xxx.xxx.xxx.entity.RuleOperateLog; import com.xxx.xxx.xxx.service.RuleOperateLogService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 操作日志(RuleOperateLog)表服务实现类 * * @author hx * @since 2022-08-23 */ @Service("RuleOperateLogService") public class RuleOperateLogServiceImpl implements RuleOperateLogService { @Autowired private RuleOperateLogDao operateLogDao; @Override public void saveLog(RuleOperateLog ruleOperateLog) { operateLogDao.insert(ruleOperateLog); } }
5.自定义注解
import java.lang.annotation.*; @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface LogResource { /** * 服务名称 * @return */ String name(); /** * 操作位置描述 * @return */ String position() default ""; /** * 日志类型 * @return */ String logType() default ""; }
6.操作日志切面类
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; import com.com.xxx.xxx.xxx.annotation.LogResource; import com.com.xxx.xxx.xxx.constants.LogTypeConstants; import com.com.xxx.xxx.xxx.entity.RuleOperateLog; import com.com.xxx.xxx.xxx.service.RuleOperateLogService; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; /** * 操作日志切面类 * * @author hx * @since 2022-08-23 */ @Aspect @Component public class OperateLogAspect { @Autowired private RuleOperateLogService operateLogService; //扫描使用@LogResource注解的方法 @Pointcut("@annotation(com.com.xxx.xxx.xxx.annotation.LogResource)") public void logPointCut() { }; @Around("logPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { Date startTime = new Date(); String exception = null; String result = null; try { Object obj = point.proceed(); if (obj != null) { result = JSONObject.toJSONString(obj); } return obj; } catch (Exception e) { //请求时报错 exception = e.toString(); throw e; } finally { //操作和报错日志都记录 HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); int statusCode = response.getStatus(); if (exception != null) { /** CHECKSTYLE:OFF:MagicNumber */ statusCode = 500; /** CHECKSTYLE:ON:MagicNumber */ } syncSaveLog(point, startTime, new Date(), exception, result, statusCode); } } @Async void syncSaveLog(ProceedingJoinPoint joinPoint, Date startTime, Date endTime, String exception, String result, int statusCode) { RuleOperateLog log = new RuleOperateLog(); try { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); LogResource annotation = method.getAnnotation(LogResource.class); if (annotation != null) { //注解上的描述 log.setOperateName(annotation.name()); } Date nowDate = new Date(); log.setCreateTimeChar(new SimpleDateFormat("yyyyMMddhhmmss").format(nowDate)); log.setCreateTime(nowDate); //入参 if (joinPoint.getArgs() != null) { try { log.setParams(JSONObject.toJSONString(joinPoint.getArgs(), SerializerFeature.IgnoreNonFieldGetter)); } catch (Exception e) { e.printStackTrace(); } } Long cost = endTime.getTime() - startTime.getTime(); log.setCost(cost.intValue()); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); if (request != null) { log.setUserName(request.getHeader(HttpHeaders.USER_AGENT)); log.setPath(request.getRequestURI()); log.setHttpMethod(request.getMethod()); log.setIp(request.getRemoteAddr()); } log.setStatusCode(String.valueOf(statusCode)); log.setResult(result); /** CHECKSTYLE:OFF:MagicNumber */ if (statusCode > 400 && exception != null) { log.setException(exception); log.setLogType(LogTypeConstants.ERROR); } else { log.setLogType(LogTypeConstants.OPERATE); } /** CHECKSTYLE:ON:MagicNumber */ operateLogService.saveLog(log); } catch (Exception e) { e.printStackTrace(); } /* //启动一个线程,执行报错日志防止影响主请求 new Thread() { @Override public void run() { try { //保存到数据库 operLogMapper.insertOper(operLog); } catch (Exception e) { e.printStackTrace(); } } }.start();*/ } }
7.使用
加载全部内容