使用aop切面编写日志模块
我们先自定义一个注解(一个有关自定义注解的LJ文章 https://www.cnblogs.com/guomie/p/10824973.html)
/**
*
* 自定义日志注解
* Retention(RetentionPolicy.RUNTIME) 生命周期永远不会被丢弃
* Target(ElementType.METHOD) 作用于方法上
* Documented
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation { // 描述
String actiondese() default ""; //类型
public enum Logtype {ADD,UPDATE,DEL,SET,LOGIN,LOGOUT,MESSAGE}; Logtype actionvalue() default Logtype.ADD;
}
我们编写一个切面类
@Aspect
@Component
public class LogAop {
@Autowired
private RedisService redisService; @Autowired
private LogService logService; // 切点
// @Pointcut("execution(* com.monitoring.controller..*.*(..))")
@Pointcut("@annotation(com.annotations.LogAnnotation)")
private void controllerAspect() {} //增强
@Around("controllerAspect()")
public Object log(ProceedingJoinPoint pjp )throws Throwable{ //先运行目标方法
Object object = pjp.proceed(); //获取request
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest(); // 拦截当前方法的对象
Object target = pjp.getTarget();
// 获取正在拦截方法名称
String methodName = pjp.getSignature().getName();
// 获取方法的参数
Object[] args = pjp.getArgs();
// 获取请求的路径
// String requestURI = request.getRequestURI(); // 拦截的放参数类型
Signature sig = pjp.getSignature();
MethodSignature msig = null;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
msig = (MethodSignature) sig;
Class[] parameterTypes = msig.getMethod().getParameterTypes(); Method method = null;
String actionType = "07";
String actionDesc = "";
try { // 获取当前方法
method = target.getClass().getMethod(methodName, parameterTypes); } catch (NoSuchMethodException | SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} if (null != method) { // 获取方法上的注解
LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
if(null == annotation) {
return object;
}
// 获取注解上的信息
actionDesc = annotation.actiondese();
// 获取类型
Logtype actionvalue = annotation.actionvalue(); switch (actionvalue) {
case ADD:
actionType = "00";
break;
case UPDATE:
actionType = "01";
break;
case DEL:
actionType = "02";
break;
case SET:
actionType = "03";
break;
case LOGIN:
actionType = "04";
break;
case LOGOUT:
actionType = "05";
break;
case MESSAGE:
actionType = "06";
break;
default:
actionType = "07";
break;
}
} // 获取访问真实IP
String internetIp = request.getHeader("x-forwarded-for");
if (internetIp == null || internetIp.length() == 0 || "unknown".equalsIgnoreCase(internetIp)) {
internetIp = request.getHeader("Proxy-Client-IP");
}
if (internetIp == null || internetIp.length() == 0 || "unknown".equalsIgnoreCase(internetIp)) {
internetIp = request.getHeader("WL-Proxy-Client-IP");
}
if (internetIp == null || internetIp.length() == 0 || "unknown".equalsIgnoreCase(internetIp)) {
internetIp = request.getRemoteAddr();
if (internetIp.equals("127.0.0.1") || internetIp.equals("0:0:0:0:0:0:0:1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
internetIp = inet.getHostAddress();
} }
//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (internetIp != null && internetIp.length() > 15) { // "***.***.***.***".length() = 15
if (internetIp.indexOf(",") > 0) {
internetIp = internetIp.substring(0, internetIp.indexOf(","));
}
} // 创建日志对象用于保存
BsUserLog4j log = new BsUserLog4j();
BsUserInfo user = JsonUtils.jsonToPojo(redisService.get(args[0].toString()), BsUserInfo.class) ; //用户登出
if(actionType == "04") {
//删除缓存中的token值
redisService.del(args[0].toString());
System.out.println("已删除缓存中token值");
}
//设置时间
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String actionTime=sdf.format(new Date()); // 设置log信息并保存数据库
log.setLogId(new BigDecimal(IDUtils.genId()));
log.setUsername(user.getUsername());
log.setActionType(actionType);
log.setActionTime(actionTime);
log.setActionDesc(actionDesc);
log.setInternetIp(internetIp); //添加日志到数据库
logService.addLog(log);
System.out.println("添加日志: " + log.toString()); //最后返回目标方法
return object;
}
}
在配置里里面配置有关aop的配置
<beans xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd" <beans> <!-- 自动为@aspectJ切面bean创建代理,true表示使用CGLib来创建 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
controller层代码
@LogAnnotation(actiondese="用户登录",actionvalue=Logtype.LOGIN)
@RequestMapping("/loginTest")
@ResponseBody
public CarResult loginTest(HttpServletResponse response,HttpServletRequest request, String name,String pas,String phoneNumer){}
其中还会遇到一些问题
1. error at ::0 formal unbound in pointcut
当出现这个错误的时候 表示你的通知方法得带上参数 比如
但是 request 不能通过参数传递进来 只能通过下面方式来获取
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
2.目标方法不执行
这时候我们需要先执行目标方法,然后再讲目标方法通过返回值返回出去
使用aop切面编写日志模块的更多相关文章
- Logstash+ Kafka基于AOP 实时同步日志到es
Logstash是一个开源数据收集引擎,具有实时管道功能.Logstash可以动态地将来自不同数据源的数据统一起来,并将数据标准化到你所选择的目的地,logstash丰富的插件(logstash-in ...
- SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Asp ...
- 十:SpringBoot-配置AOP切面编程,解决日志记录业务
SpringBoot-配置AOP切面编程,解决日志记录业务 1.AOP切面编程 1.1 AOP编程特点 1.2 AOP中术语和图解 2.SpringBoot整合AOP 2.1 核心依赖 2.2 编写日 ...
- Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入
首选需要参考的是:[参考]http://www.cnblogs.com/guokai870510826/p/5977948.html http://www.cnblogs.com/guokai8 ...
- 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- Spring Boot 2.0 教程 | AOP 切面统一打印请求日志
欢迎关注微信公众号: 小哈学Java 文章首发于个人网站 https://www.exception.site/springboot/spring-boot-aop-web-request 本节中,您 ...
- Springboot项目使用aop切面保存详细日志到ELK日志平台
上一篇讲过了将Springboot项目中logback日志插入到ELK日志平台,它只是个示例.这一篇来看一下实际使用中,我们应该怎样通过aop切面,拦截所有请求日志插入到ELK日志系统.同时,由于往往 ...
- Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志
其实,小哈在之前就出过一篇关于如何使用 AOP 切面统一打印请求日志的文章,那为什么还要再出一篇呢?没东西写了? 哈哈,当然不是!原因是当时的实现方案还是存在缺陷的,原因如下: 不够灵活,由于是以所有 ...
- Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId
一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...
随机推荐
- 02. JVM运行机制
JVM运行机制 JVM启动流程 JVM基本结构 内存模型 编译和解释运行的概念 一.JVM启动流程
- hdu 2063 过山车 (二分图,最大匹配)
过山车Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...
- Python3.7.1学习(三)求两个list的差集、并集与交集
在python3.7.1对列表的处理中,会经常使用到Python求两个list的差集.交集与并集的方法. 下面就以实例形式对此加以分析. # 求两个list的差集.并集与交集# 一.两个list差集# ...
- arm下dlsym返回的符号地址居然不是偶对齐的。
我们都知道在写汇编函数过程都会偶对齐,而gcc编译器都会将函数编译为cpu字长对齐的地址.arm指令集是固定32位指令长度,thumb指令集是固定16位指令长度, 但是运行在arm下的程序,dlsym ...
- .NET进阶篇06-async异步、thread多线程3
知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 梯子 一.任务Task1.启动任务2.阻塞延续3.任务层次结构4.枚举参数5.任务取消6.任务结果7.异常二.并行Parallel1.Paral ...
- element 根据某多个属性合并列
日常渲染 methods: { arraySpanMethod({ row, column, rowIndex, columnIndex }) { // 没办法循环判断具体是那一列 所以就只好写了多个 ...
- springboot+logback日志输出企业实践(下)
目录 1.引言 2. 输出 logback 状态数据 3. logback 异步输出日志 3.1 异步输出配置 3.2 异步输出原理 4. springboot 多环境下 logback 配置 5. ...
- Golang 指针理解
目录 0x00 指针地址和指针类型 0x01 从指针获取指针指向的值 0x02 使用指针修改值 0x03 返回函数中局部变量 0x04 使用 new() 创建指针 0x05 flag包的指针技术 0x ...
- 2019 ICPC Asia Nanjing Regional K. Triangle
题目:在直角坐标系中给定 p1,p2,p3构成三角形,给定p4可能在三角形边上也可能不在, 问能不能在三角形上找出p5,使得线段p4p5,平分三角形(p4必须在三角形上).不能则输出-1. 思路:四个 ...
- linux系统资源查看常用命令
1.vmstat vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写,可对操作系统的虚拟内存.进程.IO读写.CPU活动等进行监视.它是对系统的整体情况进行统计, ...