自定义注解

简介: 本文介绍如何在Spring项目中实现自定义注解,结合AOP完成日志记录,并通过过滤器实现登录权限控制。涵盖注解定义、元注解说明、切面编程及实际应用场景,展示其在日志、验证、权限等场景的扩展用途,帮助提升代码可读性与维护性。(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);
}

相关文章
|
机器学习/深度学习 算法
【Matlab智能算法】PSO优化(双隐层)BP神经网络算法
【Matlab智能算法】PSO优化(双隐层)BP神经网络算法
|
8月前
|
机器学习/深度学习 数据采集 调度
bp神经网络电力系统短期负荷预测
bp神经网络电力系统短期负荷预测
321 60
|
6月前
|
存储 分布式计算 调度
云计算核心技术
云计算作为IT领域的热门技术,融合网格计算与虚拟化,通过资源池和分布式存储提供高效计算与存储服务。其架构涵盖物理资源、资源池、管理中间件及SOA构建层,关键技术包括虚拟化、海量数据处理、资源调度、服务管理及云平台,旨在实现低成本、高可靠、可扩展的服务交付。
602 0
云计算核心技术
|
6月前
|
存储 安全 Java
Java集合框架(一):List接口及其实现类剖析
本文深入解析Java中List集合的实现原理,涵盖ArrayList的动态数组机制、LinkedList的链表结构、Vector与Stack的线程安全性及其不推荐使用的原因,对比了不同实现的性能与适用场景,帮助开发者根据实际需求选择合适的List实现。
|
12月前
|
Cloud Native 关系型数据库 分布式数据库
客户说|信美相互人寿携手阿里云PolarDB,引领保险IFRS17场景创新
客户说|信美相互人寿携手阿里云PolarDB,引领保险IFRS17场景创新
318 2
|
运维 监控 安全
实时计算 Flink 版最佳实践测评
本文介绍了结合电商平台用户行为数据的实时计算Flink版实践,涵盖用户行为分析、标签画像构建、业务指标监控和数据分析预测等场景。文章还对比了实时计算Flink版与其他引擎及自建Flink集群在稳定性、性能、开发运维和安全能力方面的差异,分析了其成本与收益。最后,文章评估了实时计算Flink版的产品内引导、文档帮助、功能满足情况,并提出了针对不同业务场景的改进建议和与其他产品的联动可能性。
360 2
|
机器学习/深度学习 数据挖掘 PyTorch
🚀PyTorch实战宝典:从数据分析小白到深度学习高手的飞跃之旅
【7月更文挑战第29天】在数据驱动的世界里, **PyTorch** 作为深度学习框架新星, 凭借其直观易用性和高效计算性能, 助力数据分析新手成为深度学习专家。首先, 掌握Pandas、Matplotlib等工具进行数据处理和可视化至关重要。接着, 安装配置PyTorch环境, 学习张量、自动求导等概念。通过构建简单线性回归模型, 如定义 `nn.Module` 类、设置损失函数和优化器, 进行训练和测试, 逐步过渡到复杂模型如CNN和RNN的应用。不断实践, 你将能熟练运用PyTorch解决实际问题。
331 1
|
存储 搜索推荐 算法
ICLR 2024:UTS提出全新联邦推荐算法
【2月更文挑战第17天】ICLR 2024:UTS提出全新联邦推荐算法
582 2
ICLR 2024:UTS提出全新联邦推荐算法
|
机器学习/深度学习 人工智能 自然语言处理
python量化学习路线
python量化学习路线
1035 10