springboot-aop面向切面编程
需求:
项目中需要记录用户操作信息,例如用户登陆系统后做了那些操作,需要有具体的日志记录。
解决办法:
1、编写操作记录日志业务类,在使用的方法中调用(一般记录方式)。
2、使用面向切面方式记录日志,例如针对某些业务处理方法进行日志记录。
3、通过注解方式,在调用的业务方法上增加日志类注解。
推荐使用第二、第三中方式,使用灵活,如果不需要日志记录,将切面取消即可,第一种不够灵活。一些介绍使用注解方式编写日志记录。
项目结构如下:
在pom.xml导入依赖包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.springboot</groupId>
<artifactId>springboot-aop</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-aop</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- log4j 日志记录 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
<!--aop依赖包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 引入mybatis 数据库操作包 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 引入mybatis 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在application.properties配置文件中增加数据库连接
#server.port=8090
#标示使用的是mysql/oracle/sqlserver
datasource.type=mysql
#mysql数据连接
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
#spring.datasource.max-active=20
#spring.datasource.max-idle=8
#spring.datasource.min-idle=8
#spring.datasource.initial-size=20
#mybatis 配置
# 配置映射文件加载
mybatis.mapper-locations=classpath*:mapper/**/*.xml
# 实体类通过别名使用
#mybatis.type-aliases-package=
自定义注解类
package com.example.springboot.aop.annotation;
import java.lang.annotation.*;
/**
*自定义注解 拦截Controller
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemControllerLog {
String LogAction() default "";
String LogContent() default "";
int ModuleID() default 0;
}
实体类
package com.example.springboot.aop.entity;
public class SystemLogModel {
private String LogAction;
private String LogContent;
private String FlagID;
private String FlagName;
private String LogIP;
private String TimeFlag;
private int ModuleID;
自定义切面类
package com.example.springboot.aop.aspect;
import com.example.springboot.aop.annotation.SystemControllerLog;
import com.example.springboot.aop.dao.SystemLogMapper;
import com.example.springboot.aop.entity.SystemLogModel;
import org.aspectj.lang.JoinPoint;
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.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 切点类
*/
@Aspect
@Component
public class SystemLogAspect {
// 本地异常日志记录对象
private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);
@Autowired
private SystemLogMapper systemLogMapper;
// Controller层切点,针对在业务模块标注SystemControllerLog注解记录日志
@Pointcut("@annotation( com.example.springboot.aop.annotation.SystemControllerLog )")
public void controllerAspect() {
}
/**
* 前置通知 用于拦截Controller层记录用户的操作
*
* @param joinPoint 切点
*/
@Before("controllerAspect()")
public void doBefore(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
try {
// 请求的IP
String logIP = request.getHeader("X-Real-IP");
// if (StringUtils.isEmpty(logIP)) {
// logIP = request.getRemoteAddr();
// }
String userID = request.getParameter("UserID");
String userName = request.getParameter("UserName");
// if (StringUtils.isEmpty(userID) || StringUtils.isEmpty(userName)) {
// logger.debug("操作日志-->日志添加:用户名或用户ID为空,返回不添加日志!");
// return;
// }
SystemLogModel slm = getControllerMethodDescription(joinPoint);
slm.setLogIP(logIP);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss");
String date = dateFormat.format(new Date());
slm.setTimeFlag(date);
slm.setFlagID(userID);
slm.setFlagName(userName);
// *========控制台输出=========*//
logger.debug("=====注解参数获取开始=====");
logger.debug("请求方法:"
+ (joinPoint.getTarget().getClass().getName() + "."
+ joinPoint.getSignature().getName() + "()"));
logger.debug("操作模块:" + slm.getModuleID());
logger.debug("操作方法:" + slm.getLogAction());
logger.debug("操作内容:" + slm.getLogContent());
logger.debug("请求IP:" + slm.getLogIP());
logger.debug("FlagID:" + slm.getFlagID());
logger.debug("FlagName:" + slm.getFlagName());
// *========数据库日志=========*//
int res = systemLogMapper.saveOrUpdate(slm);
if (res > 0) {
logger.info(">>>>>>>>保存日志成功");
}
} catch (Exception e) {
// 记录本地异常日志
logger.error("前置通知异常,保存日志异常信息:{}", e.getMessage());
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static SystemLogModel getControllerMethodDescription(
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();
String description = "";
SystemControllerLog log;
SystemLogModel logM = new SystemLogModel();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
log = method.getAnnotation(SystemControllerLog.class);
logM.setModuleID(log.ModuleID());
logM.setLogAction(log.LogAction());
logM.setLogContent(log.LogContent());
break;
}
}
}
return logM;
}
}
mapper接口
package com.example.springboot.aop.dao;
import com.example.springboot.aop.entity.SystemLogModel;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SystemLogMapper {
//保存日志
public int saveOrUpdate(SystemLogModel systemLogModel);
}
mapper配置文件
<?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.example.springboot.aop.dao.SystemLogMapper">
<insert id="saveOrUpdate" parameterType="com.example.springboot.aop.entity.SystemLogModel">
insert into test_system_Operation_log(FlagID,FlagName,LogAction,LogContent,LogIP,ModuleID,TimeFlag)
values(#{FlagID},#{FlagName},#{LogAction},#{LogContent},#{LogIP},#{ModuleID},#{TimeFlag})
</insert>
</mapper>
创建controller类
package com.example.springboot.aop.controller;
import com.example.springboot.aop.annotation.SystemControllerLog;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @desc aop测试日志记录
* @Author wangsh
* @date 2018/5/7 20:57
*/
@RestController
@RequestMapping("/aop")
public class AopController {
@SystemControllerLog(LogAction = "查询", ModuleID = 12, LogContent = "测试aop示例")
@ResponseBody
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
创建启动服务类
package com.example.springboot.aop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
//配置扫描指定的包及包下的所以子集
@ComponentScan("com.example.springboot.aop")
@SpringBootApplication
public class SpringbootAopApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootAopApplication.class, args);
}
}
启动服务测试
浏览器访问: http://localhost:8080//aop/hello
查看数据库记录:
以上就是aop切面及注解的使用。
---------------------
作者:1057718341_h
来源:CSDN
原文:https://blog.csdn.net/seashouwang/article/details/80232811
版权声明:本文为博主原创文章,转载请附上博文链接!
springboot-aop面向切面编程的更多相关文章
- 基于SpringBoot AOP面向切面编程实现Redis分布式锁
基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式 ...
- 极简SpringBoot指南-Chapter05-SpringBoot中的AOP面向切面编程简介
仓库地址 w4ngzhen/springboot-simple-guide: This is a project that guides SpringBoot users to get started ...
- Spring Boot2(六):使用Spring Boot整合AOP面向切面编程
一.前言 众所周知,spring最核心的两个功能是aop和ioc,即面向切面和控制反转.本文会讲一讲SpringBoot如何使用AOP实现面向切面的过程原理. 二.何为aop aop全称Aspec ...
- 浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~
简介 我们都知道,Spring 框架作为后端主流框架之一,最有特点的三部分就是IOC控制反转.依赖注入.以及AOP切面.当然AOP作为一个Spring 的重要组成模块,当然IOC是不依赖于Spring ...
- AOP 面向切面编程, Attribute在项目中的应用
一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...
- AOP面向切面编程的四种实现
一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...
- Javascript aop(面向切面编程)之around(环绕)
Aop又叫面向切面编程,其中“通知”是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被 ...
- Method Swizzling和AOP(面向切面编程)实践
Method Swizzling和AOP(面向切面编程)实践 参考: http://www.cocoachina.com/ios/20150120/10959.html 上一篇介绍了 Objectiv ...
- [转] AOP面向切面编程
AOP面向切面编程 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...
- C# AOP 面向切面编程之 调用拦截
有时候我们需要在代码中对方法调用进行拦截,并修改参数和返回值,这种操作叫做AOP(面向切面编程) 不过需要注意的是,AOP的效率很慢,在需要高效率场合慎用. 以下是C#的AOP方法: 首先建立一个控制 ...
随机推荐
- 要过年啦,用canvas做了个烟火效果
声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢! 要过年了,过年想到的就是放烟火啦....于是就用canvas写了个放烟火的效果,鼠标点击也会产生烟火,不过不要产生太多烟火哦,一个烟火散出 ...
- python之property属性
Property的概念:property是一种特殊的属性,访问它时会执行一段功能(函数),然后返回值. import math class Circle: def __init__(self,radi ...
- C_狐狸和兔子的故事
题目描述 围绕着山顶有10个洞,一只狐狸和一只兔子各住一个洞.狐狸总想吃掉兔子.一天兔子对狐狸说:“你想吃我有一个条件,先把洞从1-10编上号,你从10号洞出发,先到1号洞找我:第二次隔1个洞找我,第 ...
- 宿主机系统 Deepin 15.4,解决 Virtualbox 5.1 中 XP虚拟机无法使用 USB设备(如:U盘、罗技优联接收器等)的问题
软件环境 宿主机系统:Deepin 15.4.1, 虚拟机软件:VirtualBox 5.1 虚拟机系统:XP 操作步骤如下: (1) 安装 Virtualbox Extension Pack 进入 ...
- ASP.NET WebApi 基于分布式Session方式实现Token签名认证
一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...
- 第六周周赛——AK机会不易得,好好把握题解(出自HDU5650,codeforces 616A,624A,659A,655A,658A)
A题: A题题目链接 题目描写叙述: 位运算 TimeLimit:1000MS MemoryLimit:65536KB 64-bit integer IO format:%I64d Problem ...
- angularjs自定义filter
angular.Module API Overview Methods info([info]); provider(name, providerType); factory(name, provid ...
- shouldComponentUpdate 是做什么的,(react 性能优化是哪个周期函数?)
shouldComponentUpdate询问组件是否需要更新的一个钩子函数,判断数据是否需要重新渲染,返回一个布尔值.默认的返回值是true,需要重新render().若如果返回值是false则不触 ...
- reStructuredText语法简单说明
reStructuredText 是扩展名为.rst的纯文本文件,含义为"重新构建的文本"",也被简称为:RST或reST. 官方网址: http://docutils. ...
- LeetCode: Gray Code [089]
[题目] The gray code is a binary numeral system where two successive values differ in only one bit. Gi ...