SpringBoot第二十五篇:SpringBoot与AOP
作者:追梦1819
原文:https://www.cnblogs.com/yanfei1819/p/11457867.html
版权声明:本文为博主原创文章,转载请附上博文链接!
引言
作者在实际项目中碰到一个问题,就是需要在系统中加入操作日志功能。但是目前系统开发已经接近尾声,功能接口达到一百几十个。
如果按照新手的思维(项目组中有人就这样提建议),但是这样的话,工作量之大、冗余代码之多,可想而知。对于这种需求,我们应该考虑到 Java 的面向切面编程思想,使用 Spring AOP。下面,阐述在 SpringBoot 中使用 AOP。
在项目中的使用
为了演示更加完整的功能,此处我将我在实际项目中的需求抽取出来:将整个系统中的操作记录(比例数据的增、删、改、登录、退出等)入库。
为了演示实际的应用场景,本处代码不做专门的 demo 处理。将本人在真实项目中的实际代码展示出来,以便读者做更好的理解。
以下是核心代码:
package com.sunwin.aspect;
import com.sunwin.common.ErrorCode;
import com.sunwin.db.dao.ActionLogDao;
import com.sunwin.db.dto.ActionLogDTO;
import com.sunwin.exception.BusinessException;
import com.sunwin.util.DateUtil;
import com.sunwin.util.IPUtil;
import com.sunwin.util.UserUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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 java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by 追梦1819 on 2019-07-08.
*/
@Aspect
@Component
public class LogAspect {
@Autowired
private ActionLogDao actionLogDao;
private final static Logger logger = LoggerFactory.getLogger(LogAspect.class);
// ..表示包及子包 该方法代表controller层的所有方法
@Pointcut(
"execution(public * com.sunwin.web.controller.*.add*(..)) || " +
"execution(public * com.sunwin.web.controller.*.insert*(..)) || " +
"execution(public * com.sunwin.web.controller.*.update*(..)) || " +
"execution(public * com.sunwin.web.controller.*.delete*(..))||" +
// "execution(public * com.sunwin.web.controller.*.login*(..))"+
"execution(public * com.sunwin.web.controller.*.logout*(..))"
)
public void controllerMethod() {
}
@Pointcut("execution(public * com.sunwin.web.controller.*.login*(..))")
public void afterController() {
}
@After("afterController()")
public void afterLogRequestInfo(JoinPoint joinPoint) throws Exception {
common(joinPoint);
}
@Before("controllerMethod()")
public void LogRequestInfo(JoinPoint joinPoint) throws Exception {
common(joinPoint);
}
// aop业务处理逻辑
private void common(JoinPoint joinPoint) throws BusinessException {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
StringBuffer requestLog = new StringBuffer();
requestLog.append("请求信息:")
.append("URL = {" + request.getRequestURI() + "},\t")
.append("HTTP_METHOD = {" + request.getMethod() + "},\t")
.append("IP = {" + request.getRemoteAddr() + "},\t")
.append("CLASS_METHOD = {" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + "}\t");
ActionLogDTO actionLog = new ActionLogDTO();
actionLog.setContent("调用信息是:" + requestLog);
String ip = IPUtil.getLocalIPAddress();
actionLog.setIp(ip);
String user = UserUtil.getUser() == null ? "" : UserUtil.getUser();
actionLog.setOperator(user);
SimpleDateFormat format = new SimpleDateFormat(DateUtil.DateFormat_yyyyMMddHHmmss);
String now = format.format(new Date());
actionLog.setActionDate(now);
String name = joinPoint.getSignature().getName();
// 类型、操作时间、操作者、内容、ip
// 操作类型:1-登录;2-退出;3-新增;4-编辑;5-删除;99-未知
if (name.startsWith("delete")) { // 删
actionLog.setActionType(5);
} else if (name.startsWith("update")) { // 改
actionLog.setActionType(4);
} else if (name.startsWith("add") || name.startsWith("insert")) { // 增
actionLog.setActionType(3);
} else if (name.startsWith("login")) {
actionLog.setActionType(1);
} else if (name.startsWith("logout")) {
actionLog.setActionType(2);
} else {
actionLog.setActionType(99);
}
int count = actionLogDao.insert(actionLog);
if (count < 1) {
throw new BusinessException(ErrorCode.INSERT_ERROR);
}
}
}
以上是项目中的部门真实代码。读者需要关注的有以下几点:
- 注解:@Aspect、@Pointcut、@After、@Before;
- 拦截的方法命名规则要统一,比如新增时 addXXX 或者 insertXXX,更新是 updateXXX 或者 editXXX,查询是 queryXXX 或者 selectXXX ,删除是 deleteXXX 等;
- 处理相关的业务逻辑,比如,数据入库,导出日志文件等等;
- 需要理解 Spring aop 中的相关概念,比如切点、切面、增强/通知等。SpringBoot Aop 还是对 Spring Aop 的封装。
下面是本项目中的日志展示效果:
总结
本文希望传到的不仅仅是一个解决方案,更希望传达一种思想。在需求实现时,多思考,而不是在没有思考的前提下,就横冲直撞,胡写一通。正如方腾飞所说,聪明人的几个特质:
1、问题是什么?
2、解决方案有哪些?
3、哪一个方案是所有方案中的捷径?
![](https://img2018.cnblogs.com/blog/1183871/201910/1183871-20191015115013786-523924507.png)
SpringBoot第二十五篇:SpringBoot与AOP的更多相关文章
- SpringBoot第二十四篇:应用监控之Admin
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11457867.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 前一章(S ...
- 第二十五章 springboot + hystrixdashboard
注意: hystrix基本使用:第十九章 springboot + hystrix(1) hystrix计数原理:附6 hystrix metrics and monitor 一.hystrixdas ...
- SpringBoot第十五篇:swagger构建优雅文档
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11007470.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 前面的十四 ...
- SpringBoot非官方教程 | 第二十五篇:2小时学会springboot
转载请标明出处: http://blog.csdn.net/forezp/article/details/61472783 本文出自方志朋的博客 一.什么是spring boot Takes an o ...
- SpringBoot | 第二十五章:日志管理之自定义Appender
前言 前面两章节我们介绍了一些日志框架的常见配置及使用实践.一般上,在开发过程中,像log4j2.logback日志框架都提供了很多Appender,基本上可以满足大部分的业务需求了.但在一些特殊需求 ...
- SpringBoot第二十二篇:应用监控之Actuator
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11226397.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 很多文章都 ...
- 第二十五篇:在SOUI中做事件分发处理
不同的SOUI控件可以产生不同的事件.SOUI系统中提供了两种事件处理方式:事件订阅 + 事件处理映射表(参见第八篇:SOUI中控件事件的响应) 事件订阅由于直接将事件及事件处理函数连接,不存在事件分 ...
- Python之路(第二十五篇) 面向对象初级:反射、内置方法
[TOC] 一.反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它 ...
- flask第二十五篇——控制语句
有兴趣的请加船长公众号:自动化测试实战 先和大家强调一个发邮件的问题 # coding: utf-8 import smtplib from email.mime.text import MIMETe ...
随机推荐
- PAT 天梯杯 L3-008. 喊山 bfs
L3-008. 喊山 时间限制 150 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂 ...
- MyCat数据库的基础配置及使用
一.为什么需要分布式数据据库 随着计算机和信息技术的迅猛发展,行业应用系统的规模迅速扩大,行业应用所产生的数据量呈爆炸式增长,动辄达到数百TB甚至数百PB的规模,已远远超出传统计算技术和信息系统的处理 ...
- 【Nginx】四层负载均衡配置
一.概述 二.配置 2.1 环境准备 2.2 安装及配置 1).下载Nginx 2).下载nginx_tcp_proxy_module 插件 3).编译Nginx 4).修改Nginx.conf配置文 ...
- 章节十六、8-ITestResult接口
一.ITestResult:该接口就像一个监听器,能够监听每个方法执行后的状态(是否成功)并将结果返回给我们. package testclasses1; import org.testng.anno ...
- 史上最全面的SignalR系列教程-目录汇总
1.引言 最遗憾的不是把理想丢在路上,而是理想从未上路. 每一个将想法变成现实的人,都值得称赞和学习. 致正在奔跑的您! 2.SignalR介绍 SignalR实现服务器与客户端的实时通信 ,她是一个 ...
- 纯css实现乌云密布的天气图标
效果 效果如下 实现思路 使用box-shadow属性画几个灰色的圆,将这些圆错落的组合在一起,形成乌云图案 after伪元素写乌云下的投影 增加动画 dom结构 用两个嵌套的div容器,父容器来 ...
- Java测试(二)
一.选择题(每题2分,共40分) 1.下面哪个是Java语言中正确的标识符(C ) a) 3com b)import c)that d)this 2.下面哪个语句 ...
- 理解 Spring 注解编程模型
理解 Spring 注解编程模型 Spring 中有一个概念叫「元注解」(Meta-Annotation),通过元注解,实现注解的「派生性」,官方的说法是「Annotation Hierarchy」. ...
- vue入门之创建第一个实例,挂载点、模板和实例之间的关系
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 使用Spreadsheet导出表格时,设置样式
$spreadsheet = new Spreadsheet();// 初始化 $spreadsheet->createSheet();// 添加一个sheet ...