Spring AOP实现接口请求记录到数据库的示例代码
作者:AboutChristopher 发布时间:2023-08-15 19:14:05
标签:Spring,AOP,接口请求,数据库
1.引入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.使用
来源:https://www.cnblogs.com/huangxuannn/p/16730848.html
0
投稿
猜你喜欢
- 实现的效果图:自定义Fragment继承BottomSheetDialogFragment重写它的三个方法:onCreateDialog()
- Java HashSetHashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。HashSet 允许有 null 值。
- 一、Monkey 是什么?Monkey 就是SDK中附带的一个工具。二、Monkey 测试的目的?:该工具用于进行压力测试。 然后开发人员结
- 仅供学习交流,禁止商业用途。如侵害利益,联系必删!前言最近一位小伙伴钟爱二次元文化,于是找到半次元这个app,但是很快他就遇到了问题。一、案
- 逆时针画圆弧,原理:将360度分割成36份,分别标出每10度角度时的坐标点,然后将每个点连接起来。 #include <io
- MediaQuery通常情况下,不会直接将MediaQuery当作一个控件,而是使用MediaQuery.of获取当前设备的信息,用法如下:
- [LeetCode] 2. Add Two Numbers 两个数字相加You are given two non-empty&n
- 概述:App几乎都离不开与服务器的交互,本文主要讲解了flutter网络请求三种方式 flutter自带的HttpClient、 第三方库h
- 1.引言在开发中,拖放是一种比较常见的手势操作,使用它能够让应用的交互更加地便捷和友好,本文将简要介绍如何为Android中的View添加拖
- 获取和释放 monitor 锁的时机本文我们研究下 synchronized 背后的 monitor 锁。我们都知道,最简单的同步方式就是利
- java缓冲流本身不具IO功能,只是在别的流上加上缓冲提高效率,像是为别的流装上一种包装。当对文件或其他目标频繁读写或操作效率低,效能差。这
- 本文实例讲述了Android TextView中文字通过SpannableString设置属性的方法。分享给大家供大家参考,具体如下:在An
- 一、介绍在实际的软件项目开发过程中,我可以很负责任的跟大家说,如果你真的实际写代码的时间超过5年,你对增删改查这类简单的功能需求开发,可以说
- 1、JavaBean介绍 * JavaBean的定义:JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)
- 本文实例讲述了C#获取网页源代码的方法。分享给大家供大家参考。具体如下:public string GetPageHTML(string u
- Android 集成FlutterFlutter 作为 Google 开源的新一代跨平台、高性能 UI 框架,旨在帮助开发者高效地构建出跨平
- 我们在学习接口的时候。能够在里面做一些方法的调用。不过今天所要讲的JDBC,虽然也是连接数据库的一种接口,不过与类接口有着很大的区别,大家要
- ObjectMapper 忽略字段大小写核心代码:ObjectMapper mapper = new ObjectMapper();mapp
- 有时候,我们需要制作一个Word模板文档,然后发给用户填写,但我们希望用户只能在指定位置填写内容,其他内容不允许编辑和修改。这时候我们就可以
- C# 关于Invoke首先说下,invoke和begininvoke的使用有两种情况:control中的invoke、begininvoke