原创

SpringBoot 系列教程(十九):基于SpringBoot自定义注解和AOP实现日志记录

版权声明: 本文为博主原创文章,转载请注明原文出处!
本文链接:https://thinkingcao.blog.csdn.net/article/details/86615088

目的: 以SpringBoot项目为基础,定义写入日志注解@InsertLog,当项目启动了访问controller时,在标注了注解@InsertLog的controller方法上,将会执行“写入日志到数据库”操作;

实现:定义切面LogAspect,实现自定义注解的生效;

一、环境准备

   开发工具        IntelliJ IDEA 2018.2.3 x64

   JDK版本         1.8

   Maven版本     apache-maven-3.5.0

   Spring Boot :   (v2.1.0.RELEASE)

二、创建SpringBoot项目aspect_log_demo

 第1步、项目目录结构     

 第2步、新建注解包名com.thinkingcao.annotation,定义注解@InsertLog

package com.thinkingcao.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @创建者 caowencao
 * @描述 自定义注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Inherited
@Documented
public @interface InsertLog {
    String logStr() default "日志操作";
}

第3步、新建实体类包名com.thinkingcao.model,创建一个entity为User

package com.thinkingcao.model;

/**
 * @创建者 caowencao
 * @描述 用户
 */
public class User {

    private String name;
    private int age;
    private String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

第4步、在实体类包名中定义返回数据封装实体类Result

package com.thinkingcao.model;

public class Result {

    private int code;
    private String msg;
    private Object data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

第5步、新建service类包名com.thinkingcao.service,定义UserService类

package com.thinkingcao.service;

import com.thinkingcao.model.Result;
import com.thinkingcao.model.User;
import com.thinkingcao.utils.LogUtils;
import com.thinkingcao.utils.ResultUtils;
import javassist.NotFoundException;
import org.springframework.stereotype.Service;

@Service
public class UserService {

//    @Log(logStr = "添加一个用户")
//    public Result add(User user) {
//        return ResultUtils.success();
//    }

    //@Log
    public Result add(User user) throws NotFoundException {
        if (user.getAge() < 18) {
            LogUtils.get().setLog("添加用户失败,因为用户未成年");
            return ResultUtils.error("未成年不能注册");
        }
        if ("男".equalsIgnoreCase(user.getSex())) {
            LogUtils.get().setLog("添加用户失败,因为用户是个男的");
            return ResultUtils.error("男性不能注册");
        }

       // LogUtils.get().setLog("添加用户成功,是一个" + user.getAge() + "岁的美少女");

        return ResultUtils.success();
    }

}

第6步、新建controller类包名com.thinkingcao.controller,定义UserController类

package com.thinkingcao.controller;

import com.thinkingcao.annotation.InsertLog;
import com.thinkingcao.model.Result;
import com.thinkingcao.model.User;
import com.thinkingcao.service.UserService;
import javassist.NotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    UserService mUserService;

    @PostMapping("/add")
    @InsertLog(logStr = "打印微信日志")
    public Result add(User user) throws NotFoundException {
        return mUserService.add(user);
    }
}

第7步、新建切面包名com.thinkingcao.aspect ,定义切面LogAspect

package com.thinkingcao.aspect;

import com.thinkingcao.annotation.InsertLog;
import com.thinkingcao.utils.AnnotationUtils;
import javassist.NotFoundException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.StringUtils;

@Component
@Aspect
public class LogAspect {

    private Logger logger = LoggerFactory.getLogger(LogAspect.class);

    @Pointcut("execution(* com.thinkingcao.controller..*(..))")
    private void pointcut() {
    }

    @After(value = "pointcut()")
    public void After(JoinPoint joinPoint) throws NotFoundException, ClassNotFoundException {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        //Object[] args = joinPoint.getArgs();
        //Class<?> targetClass = Class.forName(className);
        //Method[] methods = targetClass.getMethods();
        //for (Method method : methods) {
        //    if (method.getName().equalsIgnoreCase(methodName)) {
        //        Class<?>[] clazzs = method.getParameterTypes();
        //        if (clazzs.length == args.length) {
        //            InsertLog logAnnotation = method.getAnnotation(InsertLog.class);
        //            if (logAnnotation != null) {
        //                String logStr = logAnnotation.logStr();
        //                logger.error("获取日志:" + logStr);
        //                // 数据库记录操作...
        //                break;
        //            }
        //        }
        //    }
        //}
        String logStr = AnnotationUtils.get().getAnnotatioinFieldValue(className, methodName, InsertLog.class.getName(), "logStr");
        if (!StringUtils.isEmpty(logStr)) {
            logger.debug("获取日志:" + logStr);
            // 数据库记录日志操作...
        }
    }
}

第8步、新建Utils包名com.thinkingcao.utils,定义AnnotationUtils、LogUtils、ResultUtils

   (1)、AnnotationUtils

package com.thinkingcao.utils;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ConstPool;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;

/**
 * @创建者 caowencao
 * @描述 注解中属性修改、查看工具
 */
public class AnnotationUtils {

    private static AnnotationUtils mInstance;

    public AnnotationUtils() {
    }

    public static AnnotationUtils get() {
        if (mInstance == null) {
            synchronized (AnnotationUtils.class) {
                if (mInstance == null) {
                    mInstance = new AnnotationUtils();
                }
            }
        }
        return mInstance;
    }

    /**
     * 修改注解上的属性值
     *
     * @param className  当前类名
     * @param methodName 当前方法名
     * @param annoName   方法上的注解名
     * @param fieldName  注解中的属性名
     * @param fieldValue 注解中的属性值
     * @throws NotFoundException
     */
    public void setAnnotatioinFieldValue(String className, String methodName, String annoName, String fieldName, String fieldValue) throws NotFoundException {
        ClassPool classPool = ClassPool.getDefault();
        CtClass ct = classPool.get(className);
        CtMethod ctMethod = ct.getDeclaredMethod(methodName);
        MethodInfo methodInfo = ctMethod.getMethodInfo();
        ConstPool constPool = methodInfo.getConstPool();
        AnnotationsAttribute attr = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.visibleTag);
        Annotation annotation = attr.getAnnotation(annoName);
        if (annotation != null) {
            annotation.addMemberValue(fieldName, new StringMemberValue(fieldValue, constPool));
            attr.setAnnotation(annotation);
            methodInfo.addAttribute(attr);
        }
    }

    /**
     * 获取注解中的属性值
     *
     * @param className  当前类名
     * @param methodName 当前方法名
     * @param annoName   方法上的注解名
     * @param fieldName  注解中的属性名
     * @return
     * @throws NotFoundException
     */
    public String getAnnotatioinFieldValue(String className, String methodName, String annoName, String fieldName) throws NotFoundException {
        ClassPool classPool = ClassPool.getDefault();
        CtClass ct = classPool.get(className);
        CtMethod ctMethod = ct.getDeclaredMethod(methodName);
        MethodInfo methodInfo = ctMethod.getMethodInfo();
        AnnotationsAttribute attr = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.visibleTag);
        String value = "";
        if (attr != null) {
            Annotation an = attr.getAnnotation(annoName);
            if (an != null)
                value = ((StringMemberValue) an.getMemberValue(fieldName)).getValue();
        }
        return value;
    }

}

 (2)、LogUtils

package com.thinkingcao.utils;

import com.thinkingcao.annotation.InsertLog;
import javassist.NotFoundException;

/**
 * @创建者 caowencao
 * @描述 日志修改工具
 */
public class LogUtils {

    private static LogUtils mInstance;

    private LogUtils() {
    }

    public static LogUtils get() {
        if (mInstance == null) {
            synchronized (LogUtils.class) {
                if (mInstance == null) {
                    mInstance = new LogUtils();
                }
            }
        }
        return mInstance;
    }

    public void setLog(String logStr) throws NotFoundException {
        String className = Thread.currentThread().getStackTrace()[2].getClassName();
        String name = Thread.currentThread().getStackTrace()[0].getClassName();
        String name1 = Thread.currentThread().getStackTrace()[1].getClassName();
        String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
        AnnotationUtils.get().setAnnotatioinFieldValue(className, methodName, InsertLog.class.getName(), "logStr", logStr);
    }
}

 (3)、ResultUtils

package com.thinkingcao.utils;

import com.thinkingcao.model.Result;

public class ResultUtils {

    public static Result success() {
        return success(null);
    }

    public static Result success(Object data) {
        Result result = new Result();
        result.setCode(200);
        result.setMsg("成功");
        result.setData(data);
        return result;
    }

    public static Result error() {
        return error("失败");
    }

    public static Result error(String msg) {
        Result result = new Result();
        result.setCode(400);
        result.setMsg(msg);
        return result;
    }


}

二、创建SpringBoot应用启动类AspectLogDemoApplication

package com.thinkingcao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AspectLogDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(AspectLogDemoApplication.class, args);
	}
}

三、创建配置文件application.yml

server:
  port: 8787   ##端口号

logging:
  level:
    com.thinkingcao : debug   ##日志级别debug

spring:
  mvc:
    static-path-pattern: /images/**    ##静态资源访问路径
  resources:
    static-locations: file:D://Images//壁纸/   ##外部静态资源位置(磁盘)

   在resources下新建static文件夹,static文件夹下新建images文件夹,存储一张图片20190123115705.jpg,提供静态资源直接访问

 在上面application.yml中配置了访问本地磁盘图片,所以这里来访问一下

 

四、启动项目,演示通过注解插入操作日志到数据库

PostMan测试:

 

响应结果示例:

注: 到此为止,自定义注解示例已完成,此示例仅供本人学习喜好记录博客使用,有错误请指出,不喜勿喷;

 

文章最后发布于: 2019-01-23 17:55:30
展开阅读全文
0 个人打赏
私信求帮助

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览