自定义注解

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 本文介绍如何在Spring项目中实现自定义注解,结合AOP完成日志记录与权限控制。通过定义注解、使用@Target和@Retention等元注解,并配合切面或过滤器,实现日志增强、登录鉴权等功能,提升代码可读性与复用性。(238字)

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 merchantsInfoDtos = new ArrayList<>();
merchantsInfoDtos = historyTradeService.filter(companyId, code);
return ok("查询成功", merchantsInfoDtos);
}

相关文章
|
3月前
|
监控 安全 数据安全/隐私保护
泄密事件高发频发,DLP/EDR/VDI等传统安全手段失效了吗?
近期台积电、华为等企业频发员工手机偷拍泄密事件,暴露传统DLP、EDR等安全体系在应对屏幕拍照泄露时的盲区。尽管部署多重防护,仍难阻“人”的主动泄密。新型“电-光-电”跨媒介隐形水印技术应运而生,通过无感嵌入、精准溯源,有效震慑内部泄密行为。该技术可与DLP、EDR协同,补齐“最后一公里”防护短板,构建事前预防、事中控制、事后溯源的纵深防御体系。安全无银弹,唯有传统手段与创新科技联动,方能筑牢数据防线。
166 26
|
2月前
|
机器学习/深度学习 人工智能 测试技术
DeepSeek-R1 与 OpenAI o3 的启示:Test-Time Compute 技术不再迷信参数堆叠
2025年,AI告别“参数内卷”,迎来Test-Time Compute范式革命。模型不再依赖训练时的“烘焙”智能,而是通过推理阶段的思考、验证与优化,在数学、逻辑等任务中实现质的飞跃。DeepSeek-R1与OpenAI o3证明:让小模型“多想一会儿”,效果远超盲目堆参数。Best-of-N+验证机制让普通开发者也能复现高精度推理,算力成本可控。未来AI产品核心不再是模型大小,而是可配置的“Inference Budget”。
206 14
DeepSeek-R1 与 OpenAI o3 的启示:Test-Time Compute 技术不再迷信参数堆叠
|
2月前
|
缓存 NoSQL Java
微服务高频面试题
本课程系统讲解微服务架构核心知识,涵盖SpringBoot与SpringCloud应用、Nacos注册与配置中心、OpenFeign远程调用、Sentinel熔断限流、Gateway网关鉴权、分布式事务Seata、RabbitMQ消息队列、Elasticsearch搜索及Redis缓存等技术,结合实战场景解析服务治理、数据同步与高并发处理方案。
|
8月前
|
机器学习/深度学习 搜索推荐 算法
跨平台电商整合:API如何帮助打通多店铺运营
在多平台电商运营中,商家常面临库存不同步、订单分散等问题。API技术作为“数据管道”,可通过标准化协议打通系统,实现库存同步、订单整合与智能分配,大幅提升效率。例如,某服装企业借助API将订单处理时间缩短70%。实施API有云端SaaS和定制开发两种方案,分别适合中小商家与复杂业务流。未来,随着GraphQL等新技术发展,API将进一步支持智能库存预测、跨平台用户画像及自动化营销联动。总之,API如同电商的“神经网络”,是提升运营效率与构建竞争壁垒的核心战略资产。
201 0
|
8月前
|
人工智能 JSON 数据格式
VTJ 上线 AI 识别 Sketch 和 Figma 设计稿
VTJ的AI助手支持通过识别Sketch和Figma设计稿的元数据,高精度还原设计图。用户可使用官方插件导出json格式的元数据文件。对于Sketch,下载并安装vtj-sketch-plugin后,选中图层导出;Figma则需安装vtj-figma-plugin,通过插件完成元数据导出。最后,在VTJ设计器中上传json文件,借助AI实现设计图的高效还原。
262 0
|
10月前
|
运维 监控 算法
基于 Python 迪杰斯特拉算法的局域网计算机监控技术探究
信息技术高速演进的当下,局域网计算机监控对于保障企业网络安全、优化资源配置以及提升整体运行效能具有关键意义。通过实时监测网络状态、追踪计算机活动,企业得以及时察觉潜在风险并采取相应举措。在这一复杂的监控体系背后,数据结构与算法发挥着不可或缺的作用。本文将聚焦于迪杰斯特拉(Dijkstra)算法,深入探究其在局域网计算机监控中的应用,并借助 Python 代码示例予以详细阐释。
255 6
|
11月前
|
存储 索引 容器
课时15:字典的介绍
字典是一种映射数据结构,与列表不同,它通过键值对存储对象,查询效率更高。字典的每个元素由唯一键(Key)和对应的值(Value)组成,称为键值对。键必须是不可变对象(如字符串、数字),且不能重复。字典适合快速查找特定信息,而列表则按索引访问元素,查询性能较低。以下是创建字典及获取值的示例代码: 字典提供了一种高效、灵活的方式来组织和访问数据。
|
Kubernetes 持续交付 Docker
探索DevOps实践:利用Docker与Kubernetes实现微服务架构的自动化部署
【10月更文挑战第18天】探索DevOps实践:利用Docker与Kubernetes实现微服务架构的自动化部署
371 2
|
运维 监控 网络安全
自动化运维:使用Python脚本简化日常任务
【8月更文挑战第3天】在本文中,我们将探讨如何通过编写简单的Python脚本来优化和自动化常见的系统运维任务。文章将展示具体的代码示例,并解释如何在真实环境中应用这些脚本以提升效率和减少人为错误。
308 6