1 @Target({ElementType.PARAMETER, ElementType.METHOD}) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 public @interface Log { 5 6 /** 7 * 是否记录日志 true记录 false不记录 8 **/ 9 public boolean record() default true; 10 11 /** 12 * 要执行的具体操作比如:添加用户 13 **/ 14 public String operationName() default ""; 15 16 /** 17 * 模块 18 */ 19 String title() default ""; 20 21 /** 22 * 是否保存请求的参数 23 */ 24 boolean isSaveRequestData() default true; 25 }
/** * @author Leon */ @Aspect @Component // bean容器的组件注解。虽然放在contrller包里,但它不是控制器。如果注入service,但我们又没有放在service包里 @Order(3) // 有多个日志时,ORDER可以定义切面的执行顺序(数字越大,前置越后执行,后置越前执行) public class WebLogAspect { //定义日志记录器 private Logger logger = LoggerFactory.getLogger(WebLogAspect.class); @Autowired private ILogsService logsService; @Pointcut("@within(com.**.config.AxpectLog.Log) || @annotation(com.**.config.AxpectLog.Log)") public void weblog() { } /** *功能描述 方法的返回值注入给ret * @author qqg * @date * @param joinPoint ret * @return */ @AfterReturning(returning = "ret", pointcut = "weblog()") public void doafter(JoinPoint joinPoint,Object ret) { try { //获得注解 Log controllerLog = getAnnotationLog(joinPoint); //获取servlet请求对象---因为这不是控制器,这里不能注入HttpServletRequest,但springMVC本身提供ServletRequestAttributes可以拿到 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String accessToken = AccountTokenUtil.getToken(request); if (StringUtils.isNotBlank(accessToken)) { Map map = RedisUtil.getJsonToMap(accessToken); if (map.containsKey("userInfo")) { JSONObject obj = (JSONObject) map.get("userInfo"); String operationName=controllerLog.operationName();//获取模块名称 //是否需要记录日志 boolean isRecord=controllerLog.record(); if(isRecord){ //日志记录操作 } } } } catch (Exception e) { // 记录本地异常日志 logger.error("记录日志异常"+e.getMessage().toString()); e.printStackTrace(); } } /** * 是否存在注解,如果存在就获取 */ private static Log getAnnotationLog(JoinPoint joinPoint) throws Exception { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); if (method != null) { return method.getAnnotation(Log.class); } return null; } }
方法上添加@Log注解即可 @Log(operationName = "添加数据字典") 本例为 @AfterReturning 后置 在方法执行完后记录
PS:
下方内容转载自https://blog.csdn.net/qq_38431927/article/details/77507543
版权声明:本文为CSDN博主「Holy灬繁星」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
Spring AOP编程
切面(Aspect):简单的理解就是把那些与核心业务无关的代码提取出来,进行封装成一个或几个模块用来处理那些附加的功能代码。(如日志,事务,安全验证)我们把这个模块的作用理解为一个切面,其实切面就是我们写一个类,这个类中的代码原来是在业务模块中完成的,现在单独成一个或几个类。在业务模块需要的时候才织入。
连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点总是代表一个方法的执行。通过声明一个JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。
切入点(Pointcut):本质上是一个捕获连接点的结构。在AOP中,可以定义一个pointcut,来捕获相关方法的调用
织入(Weaving):把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。这些可以在编译时,类加载时和运行时完成。Spring和其它纯Java AOP框架一样,在运行时完成织入。
通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
通知的类型:
前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
后置通知(After(finally)advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。