spring的aop注解(java自定义注解)

这个AOP使用分享里,结合用到的还有自定义注解做切点、环绕增强拦截方法、请求参的截取。我们先了解下AOP,已经知道的,直接往后拖。AOP,面向切面编程。OOP,面向对象编程。个人鄙见:在OOP模式编程的时候,有时候很多的对象都需要添加一些公共的行为的时候,也许你会想到继承啊、提抽象啊、实现接口啊等等。没错,这是给很多对象添加公共行为的一个表现,其实就是多态嘛。但是这种…

大家好,又见面了,我是你们的朋友全栈君。

前言:

该篇以记录接口调用的传入参数日志为场景,来介绍下使用自定义注解作为切点,AOP切面方式去记录每个接口的传入参数以及可扩展的业务处理。

 

正文:

项目目录:

spring的aop注解(java自定义注解)

 

先是创建自定义注解, LogTrack:

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

/**
 * @Author : JCccc
 * @CreateTime : 2020/4/13
 * @Description :
 **/

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogTrack {
    String value() default "logTracking";
}

上面的自定义注解,我只用了一个默认参,所以不用命名,写value就可以。

 

然后写切点对应的代码,LogTrackAspect:

用到了fastjson,导入依赖:
 

        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>

 

/**
 * @Author : JCccc
 * @CreateTime : 2020/4/13
 * @Description :
 **/

@Component
@Aspect
public class LogTrackAspect  {
    private static final Logger log = LoggerFactory.getLogger(LogTrackAspect.class);



    //这里需要注意了,这个是将自己自定义注解作为切点的根据,路径一定要写正确了
    @Pointcut(value = "@annotation(com.jc.mytest.aop.logRecord.LogTrack)")
    public void access() {

    }

    //进来切点世界,先经过的第一个站
    @Before("access()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {


        System.out.println("-aop 日志记录启动-" + new Date());


    }


    //环绕增强,是在before前就会触发
    @Around("@annotation(logTrack)")
    public Object around(ProceedingJoinPoint pjp, LogTrack logTrack) throws Throwable {
        System.out.println("-aop 日志环绕阶段-" + new Date());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

//        GET 请求其实可以从request里获取出参数
//       Map<String,String[]> map=request.getParameterMap();
//        System.out.println("获取参数:"+map.get("username")[0])

        String url = request.getRequestURL().toString();
        String ip = IpUtil.getIpAddr(request);
        String logTrackValue = logTrack.value();
        Object[] pipArrary = pjp.getArgs();
        if (pipArrary.length>1){ //多参,不是Map/JsonObject方式
            List<Object> argList = new ArrayList<>();
            for (Object arg : pjp.getArgs()) {
          // request/response无法使用toJSON
            if (arg instanceof HttpServletRequest) {
                       argList.add("request");
                 } else if (arg instanceof HttpServletResponse) {
                  argList.add("response");
                 } else {
                    argList.add(JSON.toJSON(arg));
            }
            }
         Signature signature = pjp.getSignature();
         MethodSignature methodSignature = (MethodSignature) signature;
        // 参数名数组
        String[] parameterNames = ((MethodSignature) signature).getParameterNames();
            System.out.println("参数名数组:"+new ArrayList(Arrays.asList(parameterNames)));
            System.out.println("参数是:"+argList.toString());
            System.out.println("logTrackValue:"+logTrackValue);
            System.out.println("url:"+url);
            System.out.println("ip:"+ip);
            return pjp.proceed();
            
        }

        Object param =  pipArrary[0];
        System.out.println("logTrackValue:"+logTrackValue);
        System.out.println("url:"+url);
        System.out.println("ip:"+ip);
        System.out.println("param:"+param.toString());
        return pjp.proceed();

    }


    //进来切点这,最后经过的一个站,也是方法正常运行结束后
    @After("access()")
    public void after(JoinPoint joinPoint) {
        System.out.println("-aop 日志记录结束-" + new Date());
    }

}

ps:return pjp.proceed(); 这个是从切点的环绕增强里面脱离出来,接下来会进入before阶段 ,然后回到接口,再回来after阶段。

所以扩展业务逻辑处理的话,可以放在return pjp.proceed();这行代码之前,例如判断用户密码是否正确;判断用户权限等等。

 

接下来是在Controller编写接口,并用上自定义注解,MyTestController:

/**
 * @Author : JCccc
 * @CreateTime : 2020/3/27
 * @Description :
 **/

@Controller
@RequestMapping("/test")
public class MyTestController {

    @ResponseBody
    @GetMapping("/testGet1")
    @LogTrack("testGet1 接口")
    public void testGet1(@RequestParam("userId") String userId, @RequestParam("toUserId") String toUserId) {

        System.out.println("已经进入GET测试接口,参数userId:" + userId+  "参数toUserId:"+toUserId);
    }


    @ResponseBody
    @GetMapping("/testGet2")
    @LogTrack("testGet2 接口")
    public void testGet2(@RequestParam Map map) {

        System.out.println("已经进入GET测试接口,参数:" + map.get("userId"));
    }

    @ResponseBody
    @PostMapping("/testPost1")
    @LogTrack("testPost1 接口")
    public void testPost1(@RequestBody Map map) {

        System.out.println("已经进入POST测试接口,参数:" + map.toString());
    }

    @ResponseBody
    @PostMapping("/testPost2")
    @LogTrack("testPost2 接口")
    public void testPost2(@RequestBody JSONObject jsonObject) {

        System.out.println("已经进入POST测试接口,参数:" + jsonObject.toString());
    }

}

然后我们来运行一下,看看控制台,就知道整个切点以及环绕的流程了: 

 

首先是测试GET方式的接口,通过@RequestParam单个参数获取的情况:
spring的aop注解(java自定义注解)

调用接口:

spring的aop注解(java自定义注解)

运行结果:

 spring的aop注解(java自定义注解)

 

接下来还是GET方式 ,通过Map去接收多参:

spring的aop注解(java自定义注解)

调用接口:

spring的aop注解(java自定义注解)

运行结果:

spring的aop注解(java自定义注解)

 

然后是调用Post请求:

spring的aop注解(java自定义注解)

 

spring的aop注解(java自定义注解)

 

ps: 如果发现按照上面配置了,但是aop切点的方法好像没触发,
那么可以试试

1.检查jar包是否有导入正确

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.9</version>
        </dependency>

2.在启动类上加上注解@EnableAspectJAutoProxy  这个其实springboot是默认帮我们已经开启为true状态的。

 

 

 

 

本篇使用到的一些工具类:

IpUtil:

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

/**
 * @Author : JCccc
 * @CreateTime : 2018-11-23
 * @Description :
 * @Point: Keep a good mood
 **/
public class IpUtil {
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress = inet.getHostAddress();
                }
            }
            // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress="";
        }
        // ipAddress = this.getRequest().getRemoteAddr();

        return ipAddress;
    }
}

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/129170.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • windows下安装emscripten python下载安装

    windows下安装emscripten python下载安装目录1.在电脑上安装配置好git和python2.新建个文件夹,用于放置emscripten3.在文件夹中,右键,gitbashhere4.从git上克隆出emscripten5.进入下载完的emsdk文件夹6.下载完查看是否更新emsdk7.安装最新的emsdk并配置全局的环境变量8.如果上一步安装成功,激活9.应用环境变量10.检验是否安装成功…

  • Python终将成为最火爆的编程语言,因为它是属于大众的「建议收藏」

    Python终将成为最火爆的编程语言,因为它是属于大众的「建议收藏」很多培训机构宣称py是人工智能必备的编程语言,打着速成的旗号来引诱学者学习python。事实却并不是这样的,万丈高台平地起,不论你想从事怎样的编程工作,都是从最基本的编程技巧开始的;Python并不适合所有人,如果你是一个编程类专业的学生,适度了解python是有必要的(python的第三方库的爆发造就了不少C/C++程序员的就业),但如果你作为一个非编程类专业但又需要了解编程的人…

  • java 读写文件的两种方式

    java 读写文件的两种方式1.情景展示在实际开发过程中,对于文件的读写操作也是经常碰到的,如何用java完成对文件的准确无误的读写呢?2.场景分析在java中,我们可以通过数据流(二进制)来完成对文件的操作;其中,数据

  • centos7放行1521端口

    centos7放行1521端口[root@localhost~]#firewall-cmd–zone=public–add-port=1521/tcp–permanentsuccess[root@localhost~]#firewall-cmd–reloadsuccess转载于:https://www.cnblogs.com/yongestcat/p/115434…

  • asp.net(C#)中Repeater嵌套绑定Repeater[通俗易懂]

    asp.net(C#)中Repeater嵌套绑定Repeater[通俗易懂]Repeater嵌套Repeater的结构:一般写过的都能看懂吧privatevoidRpTypeBind(){//GetQuestionTypeAndCount()返回一个datatablethis.rptypelist.DataSource=LiftQuestionCtr.GetQuestionTypeAndCount(

  • 十天冲刺-07

    十天冲刺-07

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号