Spring AOP
OOP缺陷:在我们日常开发中常见Controller------>Service------>Dao------>数据库 自上而下的调用方式 这之中存在许多的缺陷和不足,我们在记录某个方法的操作详情时候,每个方法都要写对应的操作与业务逻辑结合,导致代码很臃肿耦合度很高。这个时候SpringAOP应运而生来解决我们出现的问题。
AOP应用场景:日志操作记录,权限,事务
日志操作记录
1.第一步倒入相应的maven坐标在IDEA环境中如果出现aspectjweaver对应的maven倒入不进来的话建议手动导入具体步骤如下
1)下载jar包: http://mvnrepository.com/artifact/org.aspectj/aspectjweaver
2)倒入jar包: mvn install:install-file -Dfile=D:\psas_mvn\repository\org\aspectwever\aspectjweaver-1.9.4.jar -DgroupId=org.aspectj -DartifactId=aspectjweaver -Dversion=1.9.4 -Dpackaging=jar 路径替换成你自己的路径就可以了
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.16</version>
</dependency>
<!-- aspectj支持 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
2.自定义注解 方面对不同的控制层Controller进行日志操作
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ControllerLog {
String value() default "";
String type() default "";
}
3.切面编程核心逻辑处理
@Aspect
@Component
public class LogAspect {
// Controller层切点(声明切入点)
@Pointcut("@annotation( com.unicom.tancms.config.ControllerLog)")
public void controllerAspect() {
}
/**
* 前置通知 用于拦截Controller层记录用户的操作
* @param joinPoint 切点
*/
@Before("controllerAspect()")
public void doBefore(JoinPoint joinPoint) {
getLog(joinPoint, null);
}
private ActionLog getLog(JoinPoint joinPoint, Throwable e){
HttpServletRequest request = getRequest();
HttpSession session = request.getSession();
// 读取session中的用户
User user = (User) session.getAttribute("user");
String userName=user.getRealName();//用户的真实姓名
ActionLog log = new ActionLog();
if(StringUtils.isNotBlank(userName)) {
log.setUserName(userName);
}
log.setLogIp(IpUtil.getIpAdd(request));
log.setUserId(user.getUserId());
//log.setContent((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
//操作类型
//操作URL
log.setOperatorUrl(request.getRequestURI());
//操作时间
log.setOperatorTime(new Date());
try {
if(null == e){
ControllerLog logAnnotation = getControllerAnnotation(joinPoint);
log.setContent(logAnnotation.value());
log.setOperatorType(logAnnotation.type()+"");
}
// 保存数据库
logService.insertOperatorLog(log);
} catch (Exception ex) {
// 记录本地异常日志
logger.error("==异常通知异常==");
logger.error("异常信息:{}", ex.getMessage());
}
return log;
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
* @param joinPoint 切点
* @throws Exception
*/
@SuppressWarnings("rawtypes")
public static ControllerLog getControllerAnnotation(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
ControllerLog logAnnotation = null;
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
logAnnotation = method.getAnnotation(ControllerLog.class);
break;
}
}
}
return logAnnotation;
}
public static HttpServletRequest getRequest() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request;
}
}
@ControllerLog(value="查询数据",type="4") 可以对Controller进行控制哪个方法加日志记录
@Autowired
private TbUserService tbUserService;
@RequestMapping(value="/getPhoneMess",method= RequestMethod.POST)
@ControllerLog(value="查询数据",type="4")
public PageResult getPhoneMess(@RequestBody Map<String,Object> pageParams) {
PageResult tbUserResult = tbUserService.getAllUser(pageParams);
return tbUserResult;
}
4.注意,在SpringBoot项目中启动类要将该@EnableAspectJAutoProxy(proxyTargetClass = true)注解加如否则会报错代码如下:
@SpringBootApplication
@ComponentScan(basePackages ={"cn"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringBootDemo {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo.class);
}
}