自定义注解

简介: 本文介绍如何在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);
}

相关文章
|
固态存储 安全 Java
Maven settings.xml 最全配置详解:从入门到精通
本文深入讲解了 Maven settings.xml 的完整配置项,包含本地仓库路径、镜像源配置、代理设置、认证信息、Profile 多环境切换等核心内容。通过 10 个实战案例展示了企业级配置最佳实践,提供可直接使用的配置文件模板。掌握这些技能,你将能够轻松应对团队标准化、私服集成、多环境部署等场景。适合 Java 开发者、DevOps 工程师阅读。
Maven settings.xml 最全配置详解:从入门到精通
|
9月前
|
监控 安全 数据安全/隐私保护
泄密事件高发频发,DLP/EDR/VDI等传统安全手段失效了吗?
近期台积电、华为等企业频发员工手机偷拍泄密事件,暴露传统DLP、EDR等安全体系在应对屏幕拍照泄露时的盲区。尽管部署多重防护,仍难阻“人”的主动泄密。新型“电-光-电”跨媒介隐形水印技术应运而生,通过无感嵌入、精准溯源,有效震慑内部泄密行为。该技术可与DLP、EDR协同,补齐“最后一公里”防护短板,构建事前预防、事中控制、事后溯源的纵深防御体系。安全无银弹,唯有传统手段与创新科技联动,方能筑牢数据防线。
394 26
|
8月前
|
SQL Java 数据库连接
持久层框架MyBatisPlus
MyBatisPlus是MyBatis的增强工具,简化单表CRUD操作,无需编写XML,通过BaseMapper、条件构造器、分页插件等实现高效开发,支持自定义SQL、逻辑删除、枚举与JSON处理,提升开发效率。
|
8月前
|
存储 缓存 负载均衡
Nacos注册中心
本文详细介绍Nacos的安装部署、服务注册与发现、分级模型、负载均衡策略、权重控制、环境隔离及实例类型等核心功能,涵盖从入门到实战的全流程,助力掌握Nacos在微服务架构中的应用,实现高效服务治理与配置管理。
|
8月前
|
机器学习/深度学习 人工智能 测试技术
DeepSeek-R1 与 OpenAI o3 的启示:Test-Time Compute 技术不再迷信参数堆叠
2025年,AI告别“参数内卷”,迎来Test-Time Compute范式革命。模型不再依赖训练时的“烘焙”智能,而是通过推理阶段的思考、验证与优化,在数学、逻辑等任务中实现质的飞跃。DeepSeek-R1与OpenAI o3证明:让小模型“多想一会儿”,效果远超盲目堆参数。Best-of-N+验证机制让普通开发者也能复现高精度推理,算力成本可控。未来AI产品核心不再是模型大小,而是可配置的“Inference Budget”。
733 14
DeepSeek-R1 与 OpenAI o3 的启示:Test-Time Compute 技术不再迷信参数堆叠
|
8月前
|
人工智能 NoSQL 前端开发
Chap03. SpringAI
SpringAI整合主流大模型,支持多模态、函数调用与RAG,提供统一API简化开发。通过ChatClient封装对话流程,结合Prompt工程、工具调用和知识库扩展,可快速构建智能客服、聊天机器人等应用,助力Java开发者高效集成AI能力。
1086 0
|
8月前
|
缓存 NoSQL Java
微服务高频面试题
本课程系统讲解微服务架构核心知识,涵盖SpringBoot与SpringCloud应用、Nacos注册与配置中心、OpenFeign远程调用、Sentinel熔断限流、Gateway网关鉴权、分布式事务Seata、RabbitMQ消息队列、Elasticsearch搜索及Redis缓存等技术,结合实战场景解析服务治理、数据同步与高并发处理方案。
|
8月前
|
NoSQL Redis Docker
Redis集群搭建
Redis主从实现读写分离,提升并发能力;哨兵保障高可用,自动故障转移;分片集群则解决海量数据存储与高并发写入问题,三者结合构建高性能、高可用的Redis分布式架构。
|
机器学习/深度学习 搜索推荐 算法
跨平台电商整合:API如何帮助打通多店铺运营
在多平台电商运营中,商家常面临库存不同步、订单分散等问题。API技术作为“数据管道”,可通过标准化协议打通系统,实现库存同步、订单整合与智能分配,大幅提升效率。例如,某服装企业借助API将订单处理时间缩短70%。实施API有云端SaaS和定制开发两种方案,分别适合中小商家与复杂业务流。未来,随着GraphQL等新技术发展,API将进一步支持智能库存预测、跨平台用户画像及自动化营销联动。总之,API如同电商的“神经网络”,是提升运营效率与构建竞争壁垒的核心战略资产。