自定义注解

1.元注解

java有四种元注解:@Retention、@Inherited、@Documented、@Target,他们是注解的注解

        ①@Retention是注解的保留策略,共有三种

            @Retention(RetentionPolicy.SOURCE)   注解仅存在于源码中,在class字节码文件中不包含

    @Retention(RetentionPolicy.CLASS)     默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得

 @Retention(RetentionPolicy.RUNTIME)  注解会在class字节码文件中存在,在运行时可以通过反射获取到

②@Inherited表示该注解可以被继承

@Documented表示一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。

        ④   @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)                   包

2.注解参数支持的数据类型:

    1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)

       2.String类型

    3.Class类型

    4.enum类型

    5.Annotation类型

    6.以上所有类型的数组

Annotation类型中的参数只能用public或者默认的default修饰。如果只有一个参数,最好把参数名称设为 value,这样在使用注解时,参数直接写即可。


下面是一个自定义注解的应用场景:使用自定义注解和拦截器处理权限问题:

  1. 自定义一个权限注解,有角色和权限两个属性

@Document
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PermissionAnnotation {
    String roles();
    String permissions();
}

    2.在controller中使用注解,并为每一个方法设置需要校验的角色和权限

@RestController
public class UserController {
    @Autowired
    private UserService userService;


    @PermissionAnnotation(roles = "admin", permissions = "user:insert")
    @RequestMapping("insert")
    public String insert(){
        User user = new User(3,"三上悠亚",20);
        userService.insert(user);
        return "插入成功";
    }

    @PermissionAnnotation(roles = "admin",permissions = "user:delete")
    @RequestMapping("delete")
    public String delete(){
        userService.delete();
        return "删除成功";
    }

    @PermissionAnnotation(roles = "admin",permissions = "user:update")
    @RequestMapping("update")
    public String update(){
        userService.update();
        return "修改成功";
    }

    @PermissionAnnotation(roles = "visitor",permissions = "user:find")
    @RequestMapping("find")
    public String find(){
        List<User> byId = userService.findByName("铃木心春");
        return "查询成功成功";
    }

    @PermissionAnnotation(roles = "visitor",permissions = "user:find")
    @RequestMapping("findOne")
    public String findById(){
        User user = userService.findById(1);
        return "查询单个成功";
    }
}

3.自定义一个拦截器,在拦截器中获取注解的信息,并完成校验

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    if(!(handler instanceof HandlerMethod)){
        return false;
    }
    HandlerMethod  handlerMethod= (HandlerMethod) handler;
    Method method = handlerMethod.getMethod();
    String name = method.getName();
    PermissionAnnotation annotation = method.getAnnotation(PermissionAnnotation.class);
    String permissions = annotation.permissions();
    String roles = annotation.roles();
    //模拟从数据库查询出当前登录用户的角色和权限(实际应从数据库中查询用户对应的角色和权限)
    String currentPer = "user:insert";
    String currentRol = "admin";
    if(!permissions.equals(currentPer)||!roles.equals(currentRol)){
        response.getWriter().write("permission denied");
        return false;
    }
    return true;

4.验证结果

当访问insert接口时,程序正常执行返回最终结果。

当访问其他接口时,页面显示permission denied。


自定义注解配合spring aop实现统一处理缓存

再介绍一个应用场景。在开发中经常要把查出来的数据存入redis缓存。但是这些写入缓存的代码和业务逻辑并没有太大的关系,如果可以将这些重复的、和业务无关的代码统一抽取出来。

首先创建一个自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
@Documented
public @interface RedisAnnotation {

}

其次准备好一个RedisClient类。然后使用spring aop  配置切点,使用环绕通知将返回结果进行切面处理

@Aspect
@Component
public class RedisAspect {
    @Autowired
    private RedisClient redisClient;
    
    //监控被RedisAnotation标记的方法(@annotation:用于匹配当前执行方法持有指定注解的方法;)
    @Pointcut("@annotation(RedisAnnotation)")
    public void setJoinPoint(){}

    @Around(value = "setJoinPoint()")//环绕通知=前置通知+目标方法执行+后置通知
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){
        Object result = null;
        try {
            //执行目标方法
            result = proceedingJoinPoint.proceed();
            //获取被注解标记的方法参数
            Object[] args = proceedingJoinPoint.getArgs();
            redisClient.set(result.getClass().getName()+"-"+args[0],result);
        }catch (Throwable e) {

        }
        return result;
    }
}

最后是一段业务代码

@Override
@RedisAnnotation
public List<User> findByName(String name) {
    Criteria criteria = Criteria.where("name").is("三上悠亚");
    Query query = Query.query(criteria);
    List<User> list = mongoTemplate.find(query, User.class);
   return list;
}

由于findByName方法被注解RedisAnnotation标记,此方法的返回结果会被aop切面获取到,从而进行redis缓存处理。

这样的话通过注解实现优化代码的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值