spring-data-aop 进行切面编程日志记录

spring-data-aop

用途主要是记录日志和做切面增强
项目demo: https://github.com/woyaochengweidaniu/spring

项目启动直接访问接口即可在控制台看到效果--------------------

依赖

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lcm</groupId>
    <artifactId>aop</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>aop</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.1.6.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.5.11</version>
        </dependency>
        <!-- 解析 UserAgent 信息 -->
        <dependency>
            <groupId>eu.bitwalker</groupId>
            <artifactId>UserAgentUtils</artifactId>
            <version>1.21</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.1.6.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


切点可以用注解 也可以用表达式

1创建注解
package com.lcm.aop.annon;


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


/**
 * 创建注解
 * RetentionPolicy.RUNTIME   生命周期   运行时
 *ElementType.METHOD   标记在什么地方    方法上
 *
 * @author lcm
 * @date created in 2019 7 11
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OpLog {

    String operation() default "";

    String target() default "";
}

创建切面

package com.lcm.aop.aspectj;


import com.lcm.aop.annon.OpLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * <p>进行注解式切面编程</p>
 * @author lcm
 * @date created in 2019 7 11
 *
 */
@Slf4j
@Aspect
@Component
public class OpreationLog {


    /**
     *<p>只需要在方法上添加注解即可</p>
     */
    @Pointcut("@annotation(com.lcm.aop.annon.OpLog)")
    public void operation(){}


    /**
     * <p>带有log的注解并且切入点是operation  返回的是Object</p>
     * @param joinPoint
     * @param opLog
     * @param o
     */
    @AfterReturning(value = "operation()&&@annotation(opLog)",returning = "o")
    public void AfterReturning(JoinPoint joinPoint, OpLog opLog, Object o){

        log.info("操作类型:{}",opLog.operation());
        log.info("操作目标:{}",opLog.target());
        log.info("返回对象:{}",o);

        Object[] args = joinPoint.getArgs();
        for (Object object:args) {

            log.info("参数:{}",object);

        }


    }
}

创建service

package com.lcm.aop.service;

import com.lcm.aop.annon.OpLog;
import org.springframework.stereotype.Service;

/**
 * @author lcm
 */
@Service
public class TestSerivce {


    @OpLog(operation = "删除",target = "订单")
    public Object delete(String id){
        System.out.println(id);
        return "success";

    }

}

创建controller

package com.lcm.aop.api;

import com.lcm.aop.service.TestSerivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author lcm
 */
@RestController
public class ApiController {

    @Autowired
    private TestSerivce serivce;

    /**
     * 测试方法
     *
     * @param id 测试参数
     */
    @GetMapping("/test2")
    public Object test2(String  id) {
        Object delete = serivce.delete(id);
        return delete;
    }

}

2使用表达式进行切点切入

package com.lcm.aop.aspectj;

import cn.hutool.json.JSONUtil;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
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.util.Map;
import java.util.Objects;

/**
 * @author lcm
 * <P>记录切面日志</P>
 * @date created in 2019 7 11
 * @author lcm
 * @deprecated 切面不仅可以做日志 还可以做方法增强
 *
 */
@Aspect
@Component
@Slf4j
public class AopLog {
    private static final String START_TIME = "request-start";

    /**
     * 切入点
     */
    @Pointcut("execution(public * com.lcm.aop.controller.*Controller.*(..))")
    public void log() {

    }

    /**
     * 前置操作
     *
     * @param point 切入点
     */
    @Before("log()")
    public void beforeLog(JoinPoint point) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();

        log.info("【请求 URL】:{}", request.getRequestURL());
        log.info("【请求 IP】:{}", request.getRemoteAddr());
        log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());

        Map<String, String[]> parameterMap = request.getParameterMap();
        log.info("【请求参数】:{},", JSONUtil.toJsonStr(parameterMap));
        Long start = System.currentTimeMillis();
        request.setAttribute(START_TIME, start);
    }

    /**
     * 环绕操作
     *
     * @param point 切入点
     * @return 原方法返回值
     * @throws Throwable 异常信息
     */
    @Around("log()")
    public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
        Object result = point.proceed();
        log.info("【返回值】:{}", JSONUtil.toJsonStr(result));
        return result;
    }

    /**
     * 后置操作
     */
    @AfterReturning("log()")
    public void afterReturning() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();

        Long start = (Long) request.getAttribute(START_TIME);
        Long end = System.currentTimeMillis();
        log.info("【请求耗时】:{}毫秒", end - start);

        String header = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(header);
        log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header);
    }
}


创建controller

package com.lcm.aop.controller;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.lcm.aop.service.TestSerivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 测试 Controller
 * </p>
 *
 * @package: com.xkcoding.log.aop.controller
 * @description: 测试 Controller
 * @author: yangkai.shen
 * @date: Created in 2018/10/1 10:10 PM
 * @copyright: Copyright (c) 2018
 * @version: V1.0
 * @modified: yangkai.shen
 */
@RestController
public class TestController {
	@Autowired
	private TestSerivce serivce;

	/**
	 * 测试方法
	 *
	 * @param who 测试参数
	 * @return {@link Dict}
	 */
	@GetMapping("/test1")
	public Dict test1(String who) {
		return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who);
	}



}


启动项目然后访问端口 如果端口号指定了,就按照指定的端口号访问

浏览器输入:http://localhost:8081/test1
浏览器输入:http://localhost:8081/test2

posted @ 2019-07-11 16:18  懵懂小子  阅读(571)  评论(0编辑  收藏  举报