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、哪一个方案是所有方案中的捷径?

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 ...
随机推荐
- SpringCloud学习笔记(1):Eureka注册中心
简介 Eureka是Netflix开源的基于rest的服务治理方案,分为Server端和Client端,Server端为注册中心,其他微服务通过Client端连接Server端进行服务的注册和发现. ...
- 获取mysql自主生成的主键
一.sql语句 CREATE TABLE `testgeneratedkeys` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) ...
- 松软科技课堂:SQL-SELECT-INTO语句
SQL SELECT INTO 语句可用于创建表的备份复件. SELECT INTO 语句 SELECT INTO 语句从一个表中选取数据,然后把数据插入另一个表中. SELECT INTO 语句常用 ...
- charles 禁用Cookies /Block Cookies Settings
本文参考:charles 禁用Cookies 禁用cookies/Block Cookies Settings 功能:阻止发送和接收Cookie 禁用Cookie工具 禁用Cookie工具阻止发送和接 ...
- 01.Django基础一之web框架的本质
一 web框架的本质及自定义web框架 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,基于请求做出响应,客户都先请求,服务端做出对应的响 ...
- Java开发者薪资最低?程序员只能干到30岁?国外真的没有996?Intellij真的比Eclipse受欢迎?
Stack Overflow作为全球最大的程序设计领域的问答网站,每年都会出据一份开发者调查报告.近日,Stack Overflow公布了其第9次年度开发者调查报告(https://insights. ...
- ThinkPHP 5.x远程命令执行漏洞复现
ThinkPHP 5.x远程命令执行漏洞复现 一.漏洞描述 2018年12月10日,ThinkPHP官方发布了安全更新,其中修复了ThinkPHP5框架的一个高危漏洞: https://blog.th ...
- Android的有序广播和无序广播(解决安卓8.0版本之后有序广播的接收问题)
前言 Google从Android8.0版本开始,对在清单文件中静态注册广播做了限制. *** 特殊广播(动态注册广播接收者) 说:有序广播和无序广播之前,咱们先来说下Android中一些特殊的广播如 ...
- 微信小程序全局变量的设置、使用、修改
1. 全局变量的设置 在miniprogram > app.js 文件中设置,globalData对象就是存储全局变量的. App({ globalData: { hasLogin: false ...
- [AWS] Lambda by Python
当前统治数据分析的语言还是Python,还是暂时走:Python + GPU的常规路线好了. numba, pyculib (分装了cublas) Ref: 使用 Python 构建 Lambda 函 ...