自定义注解

简介: 本文介绍Spring中自定义注解的实现,结合AOP完成日志记录,并通过@Login注解与过滤器实现登录控制,涵盖注解定义、元注解说明及实际应用场景,展示其在日志、权限等场景的扩展用途。

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月前
|
存储 关系型数据库 索引
聚簇索引及其优缺点
聚簇索引是一种数据存储方式,InnoDB通过主键构建B+树组织数据,叶子节点即数据页。若无主键,则选非空唯一索引或隐式创建主键。辅助索引(二级索引)需两次查找:先查主键值,再查数据行。优点是查询快,尤其主键排序与范围查询;缺点是插入依赖顺序,更新主键代价高,且易引发页分裂。
|
3月前
|
关系型数据库 应用服务中间件 Nacos
Nacos配置中心
本章介绍Nacos配置中心的实现,涵盖配置管理、热更新、共享配置及优先级规则,并演示Nacos集群搭建与高可用部署,帮助掌握微服务环境下配置统一管理的核心技能。
|
3月前
|
JSON 安全 Java
SpringBoot鉴权
本文介绍基于Spring Security与JWT实现客户端Token认证的完整方案,涵盖登录鉴权、Token生成与验证、角色权限控制等细节。通过自定义过滤器与认证组件,结合Redis或数据库可扩展实现高效安全的无状态认证体系,适用于Spring Boot微服务架构。
|
3月前
|
存储 缓存 Java
SpringBoot自动装配机制
本章深入解析SpringBoot自动装配机制,从@SpringBootApplication注解入手,剖析其组合注解原理。重点讲解@EnableAutoConfiguration如何通过@AutoConfigurationPackage实现包扫描、通过AutoConfigurationImportSelector加载spring.factories中的自动配置类,结合@Conditional条件注解实现智能化配置。同时解析@ComponentScan组件过滤机制及自定义排除方式,揭示SpringBoot“约定优于配置”的底层实现逻辑。(238字)
|
存储 人工智能 运维
阿里云 Tair 基于 3FS 工程化落地 KVCache:企业级部署、高可用运维与性能调优实践
阿里云 Tair KVCache 团队联合硬件团队对 3FS 进行深度优化,通过 RDMA 流量均衡、小 I/O 调优及全用户态落盘引擎,提升 4K 随机读 IOPS 150%;增强 GDR 零拷贝、多租户隔离与云原生运维能力,构建高性能、高可用、易管理的 KVCache 存储底座,助力 AI 大模型推理降本增效。
|
3月前
|
人工智能 安全 前端开发
AgentScope Java v1.0 发布,让 Java 开发者轻松构建企业级 Agentic 应用
AgentScope 重磅发布 Java 版本,拥抱企业开发主流技术栈。
3457 54
|
3月前
|
监控 Java 调度
定时任务概述
定时任务是基于时间表达式调度执行的任务,适用于对账、提醒、订单超时等场景。实现方式包括单体架构的轮询、Timer、ScheduledExecutorService、Quartz、SpringTask,以及分布式架构下的TBSchedule、Elastic-Job、XXL-JOB等方案,解决集群重复执行、动态调整、故障转移与监控问题。(238字)
|
3月前
|
存储 负载均衡 Java
Nacos注册中心
本文详细介绍Nacos的安装部署、服务注册与发现、分级模型、负载均衡策略、权重控制、环境隔离及临时/持久化实例等核心功能,涵盖Spring Cloud Alibaba整合实践。通过实操演示,帮助开发者快速掌握Nacos在微服务架构中的应用,助力高效构建配置管理与服务治理体系。(238字)
|
3月前
|
负载均衡 算法 架构师
Ribbon负载均衡
本节深入讲解Ribbon实现客户端负载均衡的原理,解析@LoadBalanced注解的作用机制,介绍负载均衡分类、算法及Ribbon自定义策略与饥饿加载优化,帮助读者全面掌握Ribbon在Spring Cloud中的应用与底层逻辑。(238字)
|
3月前
|
关系型数据库 MySQL Java
SpringCloud工程部署启动
本教程介绍SpringCloud微服务工程搭建与部署,支持完整导入或从零构建。创建user-service与order-service模块,配置数据库及依赖,实现RestTemplate远程调用,解决跨服务数据获取问题,帮助理解微服务拆分与通信机制。(239字)

热门文章

最新文章