欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring boot使用自定义注解+AOP实现对Controller层方法的日志记录

程序员文章站 2022-06-17 13:03:43
...

1.创建一个spring boot项目,导入maven依赖:

	<dependencies>
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>2.8.6</version>
		</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

2.自定义RecordLog注解:

import java.lang.annotation.*;

@Target(ElementType.METHOD) // 此注解适用于方法上
@Retention(RetentionPolicy.RUNTIME) // 此注解不仅被保存到class文件中,jvm加载class文件之后依然存在
@Documented
/**
 * 用于标识方法需要记录日志
 */
public @interface RecordLog {
    /**
     * 方法描述
     *
     * @return
     */
    String desc() default "";
}

3.定义一个IP工具类获取访问的ip地址:

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @ClassName: IPUtil
 * @Description:获取ip地址工具类
 * @author: jinghx
 * @date: 2020/5/26 16:28
 */
public class IPUtil {
    private IPUtil() {
    }

    /**
     * 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址;
     *
     * @param request
     * @return
     */
    public final static String getIpAddress(HttpServletRequest request) throws UnknownHostException {
        // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } else if (ip.length() > 15) {
            String[] ips = ip.split(",");
            for (int index = 0; index < ips.length; index++) {
                String strIp = (String) ips[index];
                if (!("unknown".equalsIgnoreCase(strIp))) {
                    ip = strIp;
                    break;
                }
            }
        }
        if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            // 根据网卡取本机配置的IP
            ip = getLocalIp();
        }
        return ip;
    }

    /**
     * 获取本机IP
     */
    public static String getLocalIp() throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getLocalHost();
        String ip = inetAddress.getHostAddress().toString();//获得本机Ip
        return ip;
    }
}

4.编码实现切面类:

/**
 * @ClassName: LogAspect
 * @Description: 日志切面
 * @author: jinghx
 * @date: 2020/5/26 15:42
 */
@Aspect // 标识这是一个切面类
@Component // 把切面类加入到IOC容器中
public class LogAspect {

    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
    /**
     * 切入点表达式
     */
    public static final String exp = "@annotation(com.learn.annotation.RecordLog)"; // "execution(* com.learn.controller..*(..))";

    /**
     * 定义切入点
     */
    @Pointcut(exp)
    public void logAspect() {
    }

    /**
     * 切面方法(环绕通知)
     *
     * @param joinPoint
     * @return
     * @throws Exception
     */
    @Around("logAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis(); // 开始时间
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        // 获取方法描述
        String methodDesc = methodSignature.getMethod().getAnnotation(RecordLog.class).desc();
        // 获取Request对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        log.info("-----------开始访问方法:" + LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "-------------");
        // 方法描述
        log.info("方法描述:{}", methodDesc);
        // 请求url
        log.info("请求url:{}", request.getRequestURL().toString());
        // 请求类型
        log.info("请求类型:{}", request.getMethod());
        // 请求方法
        log.info("请求方法:{}.{}", signature.getDeclaringTypeName(), methodSignature.getName());
        // 请求IP
        log.info("请求IP:{}", IPUtil.getIpAddress(request));
        // 请求参数
        log.info("请求参数:{}", new Gson().toJson(joinPoint.getArgs()));

        Object result = joinPoint.proceed();

        // 请求耗时
        log.info("请求耗时:{}ms", System.currentTimeMillis() - startTime);
        // 请求返回
        log.info("请求返回:{}", new Gson().toJson(result));
        log.info("------------------请求结束-----------------------");
        return result;
    }

}

5.编写一个Controller类进行测试:

/**
 * @ClassName: UserController
 * @Description: 用户Controller
 * @author: jinghx
 * @date: 2020/5/26 15:38
 */
@RestController
public class UserController {

    @GetMapping("/hello")
    @RecordLog(desc = "这个一个用于问好的方法")
    public String sayHello(String name) {
        return "hello," + name + "!";
    }

}

最终项目结构:
spring boot使用自定义注解+AOP实现对Controller层方法的日志记录
启动项目,在浏览器中输入:http://localhost:8080/hello?name=德玛西亚

日志输出:
spring boot使用自定义注解+AOP实现对Controller层方法的日志记录