SpringBoot+MyBatis-Plus+MySQL实现AOP日志记录
创作时间:
作者:
@小白创作中心
SpringBoot+MyBatis-Plus+MySQL实现AOP日志记录
引用
CSDN
1.
https://blog.csdn.net/jql20182107/article/details/139417894
本文将详细介绍如何使用SpringBoot、MyBatis-Plus和MySQL实现AOP日志记录。文章将分为两部分:面向用户的日志记录和面向开发者的日志记录。通过本文的学习,读者将掌握如何在项目中实现日志记录功能,提高开发效率和代码质量。
1. 实现AOP记录面向用户的日志
1.1 添加依赖
在pom.xml文件中添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 整合mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- aop依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
1.2 修改配置文件
在application.properties文件中添加以下配置:
# 应用服务 WEB 访问端口
server.port=8080
#mysql数据库连接信息配置
#mysql驱动
spring.datasource.driverClassName=com.mysql.jdbc.Driver
#数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/log?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
#数据库用户名
spring.datasource.username=root
#数据库密码
spring.datasource.password=123456
spring.aop.auto=true
# mybatis-plus.configuration.map-underscore-to-camel-case=true
1.3 自定义注解
在启动类的同级包下新建一个config包,在这个包下新建一个名为Log的Annotation文件,文件内容如下:
元注解:用来对注解进行注解的注解类
@Target: 描述注解的使用范围,取值有ElementType.TYPE(类、接口、枚举类)、FIELD(成员变量)、METHOD(成员方法)等等;@Retention: 描述注解保留的时间范围,取值有三种:RetentionPolicy.SOURCE(源文件保留)、CLASS(编译期保留,默认值)、RUNTIME(运行期保留,可以通过反射获取注解信息);@Documented: 描述在使用javadoc工具为类生成帮助文档时是否要保留其注解信息。@Inherited: 使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解)。
1.4 准备数据库表以及实体类SysLog
@Data
//省去代码中大量的get()、 set()、 toString()等方法;
@TableName("sys_log")
//指定实体类和数据库表的映射关系。当实体类的类名在转成小写后和数据库表名相同时,可以不指定该注解。
public class SysLog implements Serializable {
@TableId(type = IdType.AUTO)
//指定实体类的某个属性为对应的主键
private Long id;
@TableField("user_id")
//如果我们开启了驼峰命名,就不用再指定value属性了
private Long userId;
@TableField("user_action")
private String userAction;
@TableField("create_time")
private Timestamp createTime;
}
1.5 创建SysLogMapper.class文件
@Mapper
public interface SysLogMapper extends BaseMapper<SysLog> {
}
1.6 创建Service日志接口ISysLogServcie.class以及实现类SysLogServiceImpl.class
public interface ISysLogServcie extends IService<SysLog> {
/**
* 插入日志
* @param entity
* @return
*/
int insertLog(SysLog entity);
}
@Service
public class SysLogServiceImpl extends ServiceImpl<SysLogMapper,SysLog> implements ISysLogServcie {
@Autowired
private SysLogMapper sysLogMapper;
@Override
public int insertLog(SysLog entity) {
return sysLogMapper.insert(entity);
}
}
1.7 AOP的切面和切点
将该类放在config包下,命名为LogAspect.java,内容如下:
@Aspect//这个注解表示将当前类视为一个切面类
@Component//将当前类交由Spring管理
public class LogAspect {
private final static Logger log= org.slf4j.LoggerFactory.getLogger(LogAspect.class);
@Autowired
private ISysLogServcie sysLogServcie;
@Pointcut("@annotation(com.dianxin.operationlog.config.Log)")
//切点表达式,定义我们的匹配规则,上边我们使用@Pointcut("@annotation(com.dianxin.operationlog.config.Log)")表示匹配带有我们自定义注解的方法。
public void pointcut(){}
@Around("pointcut()")
//@Around:环绕通知,可以在目标方法执行前后执行一些操作,以及目标方法抛出异常时执行的操作。
public Object around(ProceedingJoinPoint point){
Object result=null;
long beginTime= System.currentTimeMillis();
try {
log.info("我在目标方法之前执行");
result = point.proceed();
long endTime = System.currentTimeMillis();
insertLog(point,endTime-beginTime);
} catch (Throwable e) {
throw new RuntimeException(e);
}
return result;
}
private void insertLog(ProceedingJoinPoint point , long time){
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
SysLog sys_Log = new SysLog();
Log userAction = method.getAnnotation(Log.class);
if(userAction != null){
//注解上的描述
sys_Log.setUserAction(userAction.value());
}
String className = point.getTarget().getClass().getName();//类名
String methodName = signature.getName();//方法名
String args = Arrays.toString(point.getArgs());//请求的方法参数值
Long userid=1L;//应该从session中获取当前的登陆人id
sys_Log.setUserId(userid);
sys_Log.setCreateTime(new Timestamp(new Date().getTime()));
log.info("当前登陆人:{},类名:{},方法名:{},参数:{},执行时间:{}",userid,className,methodName,args,time);
sysLogServcie.insertLog(sys_Log);
}
}
1.8 测试控制器
在controller包下新建一个HomeController.java,内容如下:
@Controller
public class HomeController {
private final static Logger log = LoggerFactory.getLogger(HomeController.class);
@Autowired
private ISysLogServcie logServcie;
@RequestMapping("/aop")
@ResponseBody
@Log("测试aoplog")
public Object aop(String name,String nick){
Map<String,Object> map=new HashMap<>();
log.info("我被执行了!");
map.put("res","ok");
return map;
}
}
浏览器访问localhost:8080/aop?name=xfr&nick=eran,可以看到数据库成功插入以下数据:
2. 实现AOP记录面向开发者的日志
使用该方式的应用场景是在项目中出现了bug,想要知道前台的请求是否进入了控制器中,以及参数的获取情况。原理跟上边是一样的,只是切点的匹配规则变了而已,而且不用将日志记录到数据库。
2.1 修改LogAspect.java
@Aspect
@Component
public class LogAspect {
...
@Pointcut("execution(public * com.dianxin.operationlog.controller..*.*(..))")
//表示匹配com.dianxin.operationlog.controller包及其子包下的所有公有方法。
public void pointcutController(){}
@Before("pointcutController()")
//目标方法执行之前执行以下方法体的内容
public void around2(JoinPoint point){
String methodName = point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName();
String params = Arrays.toString(point.getArgs());
log.info("get in {} params :{}",methodName,params);
}
}
2.2 修改HomeController.java
@RequestMapping("/testaop3")
@ResponseBody
public Object testAop3(String name,String nick){
Map<String,Object> map = new HashMap<>();
map.put("res","ok");
return map;
}
热门推荐
真丝睡衣如何清洗?给您的终极指南
单相直流无刷电机驱动器:高效、静音与智能控制的未来趋势
Unity的粒子系统:功能、应用与优化技巧
《封神榜》中纣王昏庸无道、妲己祸乱朝纲,那真实历史是怎样的呢
新学期 交通安全体验课来啦!
想坚持养成好习惯?那就坚持21天
电动工具注塑模具镶件设计问题剖析与解决
老人多病用药指南:按时按顿标记好,注意存储要求
父亲如何通过建设花园为女儿提供深厚的支持与关怀
OSPF多区域部署指南:提升网络可扩展性与稳定性
年轻人的“小而美”婚礼火了
谷歌搜索算法内幕被扒,2500页巨细文件实名泄密,搜索排名谎言被揭穿
人性与社会冲突——《那些野兽》
哈丁战役:十字军与穆斯林力量的较量
会用AI才能多发论文,LLM助力科研效率提升,新研究登Nature子刊
自制有风险!这种酸奶火遍全网,有人吃后却进了医院,医生提醒
吴贤妃:朱祁钰生母,相传是朱瞻基庶婶婶,夺门之变后结局如何?
幼儿园“离园环节”标准化工作流程
哪吒到底在哪闹的海?揭秘神话背后的地理之谜
如何利用AI工具高效生成论文大纲与内容?
全国31省大学分布图一览
《庆余年第二季》:范闲的艰难蜕变之路
谈凤霞:一场儿童文学高标的探索之旅——漫谈国际安徒生奖评审
探寻吴冠中字画的市场价值:一平尺价格背后的艺术密码
古建屋面的传承与新生
2025年生肖运势测算全解析:五步找准吉凶方向
明朝时期常遇春是一种什么样的存在?他做出了哪些贡献?
全球AI发展新机遇:“人工智能技术及其应用进展”边会在巴黎举行
旅游打卡不再拍游客照,4个摄影小技巧,一看就会,帮你美出天际
VR棒棒糖来了!让你在虚拟世界品尝9种味道