自定义注解

简介: 本文介绍如何在Spring框架中实现自定义注解,结合AOP与过滤器应用于日志记录、权限控制等场景,通过代码示例展示注解定义、元注解使用及拦截处理流程,涵盖从基础到进阶的完整实现步骤。

1.前言

自定义注解目前在我使用过的项目中,主要用用作日志丰富,参数处理,其核心还是借助于Spring的AOP进行实现,本文将结合具体代码演示简单的自定义注解实现流程。

2.实现

2.1 定义User

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String name;
}

2.2 定义UserDAO

@Component
public class UserDao {
    public User findUserById(Integer id) {
        if(id > 10) {
            return null;
        }
        return new User(id, "user-" + id);
    }
}

2.3 定义UserService

@Service
public class UserService {
    private final UserDao userDao;
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
    public User findUserById(Integer id) {
        return userDao.findUserById(id);
    }
}

2.4 定义Controller

@RequestMapping(value = "user/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public User findUser(@PathVariable("id") Integer id) {
    return userService.findUserById(id);
}

此时浏览器访问:http://{domain}/user/1即可出现对应效果

{
    "id": 1,
    "name": "user-1"
}

2.5 定义自定义注解

import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotation {
    String name() default "";
    String value() default "";
}

说明:

  • @interface 不是interface,是注解类  定义注解
  • Documented
  • 这个Annotation可以被写入javadoc  
  • @Retention
  • 修饰注解,是注解的注解,称为元注解
  • SOURCE,     // 编译器处理完Annotation后不存储在class中  
  • CLASS,       // 编译器把Annotation存储在class中,这是默认值  
  • RUNTIME  // 编译器把Annotation存储在class中,可以由虚拟机读取,反射需要
  • @Target
  • 注解的作用目标
  • @Target(ElementType.TYPE)                                           //接口、类、枚举、注解
  • @Target(ElementType.FIELD)                                         //字段、枚举的常量
  • @Target(ElementType.METHOD)                                   //方法
  • @Target(ElementType.PARAMETER)                              //方法参数
  • @Target(ElementType.CONSTRUCTOR)                        //构造函数
  • @Target(ElementType.LOCAL_VARIABLE)                     //局部变量
  • @Target(ElementType.ANNOTATION_TYPE)                //注解
  • @Target(ElementType.PACKAGE)                                 //包    


  • 可以定义多个方法,每个方法在使用时参照下面的Controller使用即可,实际就是类似于@PostMapping这样的注解中使用过的value,method,produces等,如下:

2.6 AOP+Controller使用自定义注解

@CustomAnnotation(name = "findUser", value = "根据ID查找用户")
@RequestMapping(value = "user/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public User findUser(@PathVariable("id") Integer id) {
    return userService.findUserById(id);
}
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class TestLogAspect {
    @Pointcut("@annotation(cn.test.CustomAnnotation)")
    private void pointcut() {}
    @Before("pointcut() && @annotation(annotation)")
    public void advice(JoinPoint joinPoint, CustomAnnotation annotation) {
        System.out.println(
            "类名:["
            + joinPoint.getSignature().getDeclaringType().getSimpleName()
            + "],方法名:[" + joinPoint.getSignature().getName()
            + "]-日志内容-[" + annotation.value() + ", "+annotation.name()+ "]");
    }
}

3.总结

自定义注解其核心是借助于:@Target 和 @Rentention,@Documented组合实现,其实现还是需要依赖于Spring的AOP进行具体体现,除了上面的用作日志拦截,还可以自定义:数据验证注解,权限注解,缓存注解等多种用途,但其实现基本都遵循上述步骤。

4.自定义注解+过滤器实现登陆相关

4.1 定义自定义注解@Login

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.zhicall.majordomo.core.common.enums.YesOrNo;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
  YesOrNo value();
}

4.2 过滤器匹配

package com.zhicall.majordomo.core.security.interceptor;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.alibaba.fastjson.JSON;
import com.zhicall.care.realtime.util.ResultMessageBuilder;
import com.zhicall.care.realtime.util.ResultMessageBuilder.ResultMessage;
import com.zhicall.care.system.basic.BeanFactory;
import com.zhicall.majordomo.core.common.constant.GlobalCst;
import com.zhicall.majordomo.core.common.enums.YesOrNo;
import com.zhicall.majordomo.core.security.annotation.Login;
import com.zhicall.majordomo.core.security.constant.Cst;
import com.zhicall.majordomo.core.security.util.UserAuthHelper;
public class UserLoginInterceptor extends HandlerInterceptorAdapter {
  @SuppressWarnings({ "unchecked", "rawtypes" })
  protected RedisTemplate<String, String> redisTemplate = (RedisTemplate) BeanFactory.getInstance().getBean("redisTemplate");
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    Login login = handlerMethod.getMethodAnnotation(Login.class);
    // 方法被 @Login(YesOrNo.No)标记 表示不需要登陆即可访问 否者都要登录
    if (login != null && YesOrNo.NO.equals(login.value())) {
      return true;
    }
    // 做鉴权
        ......
  }
}

4.3 Controller中具体使用

@Login(YesOrNo.NO)
@RequestMapping(value = "/filter", method = RequestMethod.POST)
public @ResponseBody ResultMessageBuilder.ResultMessage filter(String companyId, String code) {
    List<TabInfoVo> merchantsInfoDtos = new ArrayList<>();
    merchantsInfoDtos = historyTradeService.filter(companyId, code);
    return ok("查询成功", merchantsInfoDtos);
}
相关文章
|
存储
若依框架 --- pdf文件上传预览功能实现
若依框架 --- pdf文件上传预览功能实现
1368 0
|
2月前
|
人工智能 安全 Java
Spring AI 核心架构、抽象模型与四大核心组件设计精髓
Spring AI 是 Spring 官方推出的 Java AI 应用开发框架,遵循“约定优于配置”等核心理念,提供统一 API 屏蔽多模型差异,支持 OpenAI、通义千问等厂商,集成 RAG、函数调用、结构化输出及企业级可观测性能力。
529 1
|
2月前
|
人工智能 JSON Java
【SpringAIAlibaba新手村系列】(6)PromptTemplate 提示词模板与变量替换
本章详解Spring AI的PromptTemplate提示词模板机制,涵盖变量替换、系统消息模板(SystemPromptTemplate)、外部文件加载等核心功能,助力实现提示词参数化、复用与动态组装,提升RAG、Agent及结构化输出场景下的开发效率与可维护性。
507 7
|
9月前
|
存储 人工智能 测试技术
如何使用LangChain的Python库结合DeepSeek进行多轮次对话?
本文介绍如何使用LangChain结合DeepSeek实现多轮对话,测开人员可借此自动生成测试用例,提升自动化测试效率。
2136 125
如何使用LangChain的Python库结合DeepSeek进行多轮次对话?
|
6月前
|
开发者
业务架构图
本文介绍了业务架构图的核心概念与绘制方法,涵盖业务定义、架构域分类、分层分模块分功能的要义,并结合实例说明其在产品设计中的应用价值。
|
10月前
|
数据采集 边缘计算 缓存
从流量到留量:ESA 安全加速守护零售行业交易全链路
零售业正经历数字技术驱动的深度变革,电商蓬勃发展,消费持续升级。阿里云边缘云推出零售交易行业解决方案,通过分布式边缘计算、智能路由与安全防护,助力企业应对跨地域交易挑战,实现安全高效发展。
547 14
|
6月前
|
负载均衡 应用服务中间件 Nacos
Nacos配置中心
本文详细介绍Nacos作为配置中心的实现原理与实战应用,涵盖配置管理、热更新、共享配置及优先级规则,并演示集群搭建与高可用部署,提升微服务架构下配置的动态管理能力。
|
6月前
|
JSON Dubbo Java
Feign远程调用
本文介绍了如何使用Feign替代RestTemplate实现更优雅的HTTP跨服务调用。通过引入Feign,解决传统方式中服务地址硬编码、代码可读性差等问题,并结合注册中心实现服务发现。文章详细讲解了Feign的集成步骤、自定义配置(如日志级别)、性能优化(如连接池)及最佳实践,包括接口抽取与模块复用方案,提升微服务间通信的可维护性和开发效率。
|
6月前
|
SpringCloudAlibaba Java Nacos
SpringCloud概述
Spring Cloud是微服务的统一解决方案,具备约定大于配置、组件丰富、开箱即用等特点。通过整合Netflix与Alibaba生态,形成完整技术栈,其中Spring Cloud Alibaba因Nacos、Sentinel等优秀组件成为主流选择。
|
9月前
|
人工智能 运维 中间件
CTI中间件:现代呼叫中心的核心开发平台
乐科CTI中间件助力企业高效构建智能呼叫中心,集成通信与业务系统,支持多协议、AI融合、高可用部署,广泛应用于客服、营销等场景,降低开发成本,提升运维效率。

热门文章

最新文章