springboot aop+@interface实现日志记录
一、基本概念
1、自定义注解
自定义注解我们必须了解四个元注解,什么是元注解?元注解指作用于注解之上的元数据或者元信息,简单通俗的讲,元注解就是注解的注解 .
Documented与Inherited是典型的标识性注解,也就是说在注解内部并没有成员变量,没有成员变量的注解称为标识注解
Documented
指明拥有这个注解的元素可以被javadoc此类的工具文档化。这种类型应该用于注解那些影响客户使用带注释的元素声明的类型。如果一种声明使用Documented进行注解,这种类型的注解被作为被标注的程序成员的公共API 。
Inherited
指明该注解类型被自动继承。如果用户在当前类中查询这个元注解类型并且当前类的声明中不包含这个元注解类型,那么也将自动查询当前类的父类是否存在Inherited元注解,这个动作将被重复执行知道这个标注类型被找到,或者是查询到顶层的父类。
具体请查看:https://blog.csdn.net/ab411919134/article/details/81252516
Retention
指明在什么级别显示此注解
Retention主要的参数类型包括以下几种:
RetentionPolicy.SOURCE 注解存在于源代码中,编译时会被抛弃
RetentionPolicy.CLASS 注解会被编译到class文件中,但是JVM会忽略
RetentionPolicy.RUNTIME JVM会读取注解,同时会保存到class文件中
Target
指明该类型的注解可以注解的程序元素的范围
Target主要的参数类型包括以下几种:
ElementType.TYPE 用于类,接口,枚举但不能是注解
ElementType.FIELD 作用于字段,包含枚举值
ElementType.METHOD 作用于方法,不包含构造方法
ElementType.PARAMETER 作用于方法的参数
ElementType.CONSTRUCTOR 作用于构造方法
ElementType.LOCAL_VERIABLE 作用于本地变量或者catch语句
ElementType.ANNOTATION_TYPE 作用于注解
ElementType.PACKAGE 作用于包
2、@ControllerAdvice 注解
在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中
二、完整示例
1、工程结构
2、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.aop.demo</groupId>
<artifactId>aop-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring切面aop依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies> </project>
3、新建启动类
package com.aop.demo; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; /**
* @author Administrator
* @date 2018/08/18
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
4、自定义异常类
package com.aop.demo.exception; /**
* @author Administrator
* @date 2018/08/18
*/
public class OperateException extends RuntimeException{ public Integer errorCode;
public String errorMessage; public OperateException(Integer errorCode, String errorMessage){
this.errorCode = errorCode;
this.errorMessage = errorMessage;
} public Integer getErrorCode() {
return errorCode;
} public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
} public String getErrorMessage() {
return errorMessage;
} public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
5、自定义异常处理类,使用了@ControllerAdvice,来捕捉全局异常
package com.aop.demo.exception; import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap;
import java.util.Map; /**
* @author Administrator
* @date 2018/08/18
*/
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String,Object> exceptionProcess(Exception e){
Map<String,Object> map = new HashMap<String, Object>();
if(e instanceof OperateException){
OperateException myException = (OperateException) e;
System.out.println(myException.getErrorCode()+": "+ myException.getErrorMessage());
map.put(myException.getErrorCode().toString(),myException.getErrorMessage());
return map;
}else {
System.out.println("");
map.put("505","系统级错误");
return map;
}
}
}
6、引入aop来处理方法,执行前,执行中,执行后的动作。这里只是在控制台打印信息
1)定义了一个切入点:logwrite(),对com.aop.demo.controller里面的所有方法有效
举例说明execution表达式:
任意公共方法的执行:
execution(public * *(..))
任何一个以“set”开始的方法的执行:
execution(* set*(..))
AccountService 接口的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
定义在service包里的任意方法的执行:
execution(* com.xyz.service.*.*(..))
定义在service包和所有子包里的任意类的任意方法的执行:
execution(* com.xyz.service..*.*(..))
定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:
execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
package com.aop.demo.aspect; import com.aop.demo.controller.MyController;
import com.aop.demo.exception.MyExceptionHandler;
import com.aop.demo.model.LogWrite;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
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.lang.reflect.Method; /**
* @author Administrator
* @date 2018/08/20
*/
@Aspect
@Component
public class HttpAspect { @Autowired
private MyExceptionHandler myExceptionHandler; @Pointcut("execution(public * com.aop.demo.controller.*.*(..))")
public void logwrite(){ } @Before("logwrite()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
System.out.println("===========================以下是Aspect的Before方法的执行结果==========================");
//url
System.out.println("url="+request.getRequestURL());
//method
System.out.println("method="+request.getMethod());
//ip
System.out.println("id="+request.getRemoteAddr());
//获取类名和方法名
System.out.println("class_method="+joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
//args[]
System.out.println("args="+joinPoint.getArgs()); for (Method method: MyController.class.getDeclaredMethods()) {
if(method.getName().equals(joinPoint.getSignature().getName())){
LogWrite logWrite = method.getAnnotation(LogWrite.class);
if(logWrite!=null){
System.out.println("Found LogWrite:"+logWrite.user()+" "+logWrite.action() +"处理中");
}
}
}
} @Around("logwrite()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
try {
result = proceedingJoinPoint.proceed();
return result;
} catch (Exception e) {
System.out.println("===========================以下是Aspect的doAround方法捕捉到的异常==========================");
for (Method method: MyController.class.getDeclaredMethods()) {
if(method.getName().equals(proceedingJoinPoint.getSignature().getName())){
LogWrite logWrite = method.getAnnotation(LogWrite.class);
if(logWrite!=null){
System.out.println("Found LogWrite:"+logWrite.user()+" "+logWrite.action() +"处理失败");
}
}
}
return myExceptionHandler.exceptionProcess(e);
}
} @AfterReturning(pointcut = "logwrite()",returning = "object")//打印输出结果
public void doAfterReturing(JoinPoint joinPoint,Object object){
System.out.println("===========================以下是Aspect的doAfterReturing方法的执行结果==========================");
for (Method method: MyController.class.getDeclaredMethods()) {
if(method.getName().equals(joinPoint.getSignature().getName())){
LogWrite logWrite = method.getAnnotation(LogWrite.class);
if(logWrite!=null){
System.out.println("Found LogWrite:"+logWrite.user()+" "+logWrite.action() +"处理完成");
}
}
}
System.out.println("response="+object.toString());
}
}
7、自定义注解
package com.aop.demo.model; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* @author Administrator
* @date 2018/08/18
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogWrite { public String user() default "adming"; public String action() default "create";
}
8、controller
package com.aop.demo.controller; import com.aop.demo.exception.OperateException;
import com.aop.demo.model.LogWrite;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; /**
* @author Administrator
* @date 2018/08/18
*/
@RestController
@RequestMapping("/test")
public class MyController { @RequestMapping(value = "/aopsuccess",method = RequestMethod.GET)
@LogWrite(user = "boshen",action = "excute aopsuccess")
public String testSucces(){
return "aopsuccess excute success";
} @RequestMapping(value = "/aoperror/{flag}",method = RequestMethod.GET)
@LogWrite(user = "boshen",action = "excute aoperror")
public String testError(@PathVariable String flag){
if(flag.equals("A")){
throw new OperateException(1001,"发生业务错误");
}
return "testError excute success";
}
}
说明:MyController类里面使用了自定义注解:@LogWrite,在HttpAspect 类里面,获取注解的内容得到user和action,打印到控制台上
9、用postman执行
控制台如下:
===========================以下是Aspect的Before方法的执行结果==========================
url=http://10.111.131.11:8084/aop-test/test/aopsuccess
method=GET
id=10.111.131.11
class_method=com.aop.demo.controller.MyController,testSucces
args=[Ljava.lang.Object;@3b3ffba0
Found LogWrite:boshen excute aopsuccess处理中
===========================以下是Aspect的doAfterReturing方法的执行结果==========================
Found LogWrite:boshen excute aopsuccess处理完成
response=aopsuccess excute success
控制台如下:
===========================以下是Aspect的Before方法的执行结果==========================
url=http://10.111.131.11:8084/aop-test/test/aoperror/A
method=GET
id=10.111.131.11
class_method=com.aop.demo.controller.MyController,testError
args=[Ljava.lang.Object;@67ca9239
Found LogWrite:boshen excute aoperror处理中
===========================以下是Aspect的doAround方法捕捉到的异常==========================
Found LogWrite:boshen excute aoperror处理失败
1001: 发生业务错误
===========================以下是Aspect的doAfterReturing方法的执行结果==========================
Found LogWrite:boshen excute aoperror处理完成
response={1001=发生业务错误}
springboot aop+@interface实现日志记录的更多相关文章
- springboot AOP全局拦截日志记录
@Aspect@Component@Slf4jpublic class WebLogAspect { @Pointcut("execution(public * com.we.control ...
- SpringBoot AOP处理请求日志处理打印
SpringBoot AOP处理请求日志处理打印 @Slf4j @Aspect @Configuration public class RequestAopConfig { @Autowired pr ...
- 在SpringBoot中用SpringAOP实现日志记录功能
背景: 我需要在一个SpringBoot的项目中的每个controller加入一个日志记录,记录关于请求的一些信息. 代码类似于: logger.info(request.getRequestUrl( ...
- 【SpringBoot】13. logback日志记录
logback日志记录 Spring Boot 1.5.19.RELEASE 1.导入相关jar包 在spring-boot-starter-web 中已经包含 2.添加logback.xml配置文件 ...
- spring aop 方法增加日志记录
使用场景: 1:调用外部接口时需要记录出参和入参. 2:分布式系统之间,调用各个系统之间需要记录日志,一旦出现了问题也可以找得到元数据 一言不合,上代码: # 枚举类 package xxxxxxxx ...
- Springboot AOP写操作日志 GET POST
pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- 使用SpringBoot AOP 记录操作日志、异常日志
平时我们在做项目时经常需要对一些重要功能操作记录日志,方便以后跟踪是谁在操作此功能:我们在操作某些功能时也有可能会发生异常,但是每次发生异常要定位原因我们都要到服务器去查询日志才能找到,而且也不能对发 ...
- 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...
- Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
本文梯子 本文3.0版本文章 代码已上传Github+Gitee,文末有地址 大神反馈: 零.今天完成的深红色部分 一.AOP 之 实现日志记录(服务层) 1.定义服务接口与实现类 2.在API层中添 ...
随机推荐
- NET Runtime version 2.0.50727.42 - 执行引擎错误 或者无法创建应用程序域
server2003操作系统 IIS运行应用程序报错,应用程序事件查看器详细: NET Runtime version 2.0.50727.42 - 执行引擎错误 或者无法创建应用程序域 解决方法:卸 ...
- 创建smartfroms页格式
1.输入TCODE:spad 2.页格式:完全管理 ---> 设备类型 ---> 页格式 ---> 创建 3.比如:长:24.2cm 宽:11.5cm 则设置:纸宽:115MM 纸 ...
- 集合 day8
一,集合. 集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的.以下是集合最重要的两点: 去重,把一个列表变成集合,就自动去重了. ...
- Soa思想分布式服务webservice WCF
什么是分布式事务 分布式事务就是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上.以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作组成,这 ...
- JAVA程序 从命令行接受多个数字,求和之后输出结果
源程序代码: public class sum{ public static void main(String[] args){ double[] a=new double[4]; a[0]=Doub ...
- PAT 1066 图像过滤(15)(代码)
1066 图像过滤(15 分) 图像过滤是把图像中不重要的像素都染成背景色,使得重要部分被凸显出来.现给定一幅黑白图像,要求你将灰度值位于某指定区间内的所有像素颜色都用一种指定的颜色替换. 输入格式: ...
- Centos7 开机启动命令行模式
1.在图形界面下单击鼠标右键,选择“Konsole”: 2. 获取当前系统启动模式,输入:systemctl get-default 3.查看配置文件, cat /etc/inittab 4.通过以上 ...
- GitHub上README.md教程 详情介绍 (修改图片连接地址错误)
最近对它的README.md文件颇为感兴趣.便写下这贴,帮助更多的还不会编写README文件的同学们. README文件后缀名为md.md是markdown的缩写,markdown是一种编辑博客的语言 ...
- 还没有写完准备弡上cpickle 还有字典
#!/usr/bin/python #Filename: cpickle.py import cPickle as p import os shoplistfile="shoplist.da ...
- 使用iTEXT库生成pdf
iTEXT下载地址 https://sourceforge.net/projects/itext/files/ 选择绿色的按钮,下载最新版本,解压后是一些jar包 为了使用方便,将文件夹放到JAVA_ ...