注解继承,动态修改注解属性值,BeanPostProcessor应用,自定义shiro授权注解属性值。

  一个Web项目,想做一个默认通用接口的功能。父类BaseController有默认的对外接口(/page,/list,/detail,/update等)以及默认的实现。已经实现,(继承shiro,需要接口访问权限功能)但是shiro的授权(@RequiresPermissions)不能自定义了。想着利用Spring的BeanPostProcessor给ControllerBean的API方法的授权做动态修改。但实际并不能如此只能另寻他法了。

//父类定义默认对外接口,以及方法实现
public class BaseController<T extends BaseService,M extends BaseModel> {
    @GetMapping("/page")
    @RequiresPermissions(":read")
    public Object defaultPage(ModelMap modelMap, @RequestParam Map<String, Object> param) {
        service.beforePage(param);
        return setSuccessModelMap(modelMap, service.getPage(param,service.pageHandler()));
    }
    @GetMapping("/list")
    @RequiresPermissions(":read")
    public Object defaultList(ModelMap modelMap, @RequestParam Map<String, Object> param) {
        service.beforeList(param);
        return setSuccessModelMap(modelMap, service.getList(param,service.listHandler()));
    }
    
    @GetMapping("/detail")
    @RequiresPermissions(":read")
    public Object defaultDetail(ModelMap modelMap, Long id) {
        service.beforeDetail(id);
        M t= (M) service.getById(id);
        return setSuccessModelMap(modelMap,service.afterDetail(t));
    }
    @PostMapping("/update")
    @RequiresPermissions(":update")
    public Object defaultUpdate(ModelMap modelMap, M param) {
        if(param==null||param.getId()==null){
            service.beforeAdd(param);
            M t= (M) service.update(param);
            return setSuccessModelMap(modelMap, service.afterAdd(t));
        }else{
            service.beforeUpdate(param);
            M t= (M)service.update(param);
            return setSuccessModelMap(modelMap, service.afterUpdate(t));
        }
    }
    @DeleteMapping("/delete")
    @RequiresPermissions(":del")
    public Object defaultDelete(ModelMap modelMap, Long id) {
        return setSuccessModelMap(modelMap, service.delete(id));
    }
    @DeleteMapping("/del")
    @RequiresPermissions(":del")
    public Object defaultDel(ModelMap modelMap, Long id) {
        return setSuccessModelMap(modelMap, service.del(id));
    }
    @DeleteMapping("/deletes")
    @RequiresPermissions(":del")
    public Object defaultDeletes(ModelMap modelMap, String ids) {
        service.deletes(ids);
        return setSuccessModelMap(modelMap);
    }
}

//授权动态修改
@Component
public class DefaultRequiresPermissionPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class clazz=bean.getClass();
        MController mapping= (MController) clazz.getAnnotation(MController.class);
        if(mapping!=null){
            String[] roots=mapping.value();
            if(roots.length>0){
                String rootUrl= Stream.of(roots).collect(Collectors.joining()).substring(1);
                List<String> defaultMethods= Arrays.asList("defaultPage","defaultList","defaultDetail","defaultUpdate","defaultDelete","defaultDel","defaultDeletes");
                Stream.of(clazz.getMethods())
                        .filter(method -> defaultMethods.contains(method.getName()))
                        .forEach(method -> {
                            RequiresPermissions pageAnnotation= method.getAnnotation(RequiresPermissions.class);
                            InvocationHandler pageHandler= Proxy.getInvocationHandler(pageAnnotation);
                            try {
                                Field pageField = pageHandler.getClass().getDeclaredField("memberValues");
                                pageField.setAccessible(true);
                                Map pageMap= (Map) pageField.get(pageHandler);
                                String[] pageValues= (String[]) pageMap.get("value");
                                pageValues[0]=rootUrl+pageValues[0];
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        });
            }
        }
        return bean;
    }
}
//自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RestController
@RequestMapping
public @interface MController {
    @AliasFor(annotation = RequestMapping.class)
    String[] value() default {};
    //String[] exclude() default {};
}

  实验中授权确实修改了,但发现所有的Controller的默认接口的权限都是同一个,意识到其实修改的自始至终都是父类方法中的注解。如是做了以下测试:

//注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Temp {
    String value();
}

//父类
public class Animal{
	@Temp("animal")
	public void eat(){}
}

//子类A
public class Dog extends Animal {
}

//子类B
public class Cat extends Animal {
}

//临时工具方法
//获取对象某方法上某注解的value值
public static <T extends Annotation> String getAnnotationValue(Object obj, Class<T> annotationType, String methodName) throws Exception {
   	Method method=obj.getClass().getMethod(methodName);
    T annotation=method.getAnnotation(annotationType);
    InvocationHandler handler=Proxy.getInvocationHandler(annotation);
    Field field=handler.getClass().getDeclaredField("memberValues");
    field.setAccessible(true);
    Map map= (Map) field.get(handler);
    Object value=map.get("value");
    if(value==null)return null;
    return value.toString();
}

//设置对象某方法上某注解的value值
 public static <T extends Annotation> void setAnnotationValue(Object obj,Class<T> annotationType,String methodName,String value)throws Exception{
     Method method=obj.getClass().getMethod(methodName);
     T annotation=method.getAnnotation(annotationType);
     InvocationHandler handler=Proxy.getInvocationHandler(annotation);
     Field field=handler.getClass().getDeclaredField("memberValues");
     field.setAccessible(true);
     Map map= (Map) field.get(handler);
     map.put("value",value);
 }

//测试方法
@Test
public void test(){
	Dog dog=new Dog();
	Cat cat=new Cat();
	System.out.println("dog value:"+getAnnotationValue(dog,Temp.class,"eat"));
	System.out.println("cat value:"+getAnnotationValue(cat,Temp.class,"eat"));
	setAnnotationValue(dog,Temp.class,"eat","dog");
	System.out.println("dog value:"+getAnnotationValue(dog,Temp.class,"eat"));
	System.out.println("cat value:"+getAnnotationValue(cat,Temp.class,"eat"));
}

//结果
dog value:animal
cat value:animal
dog value:dog
cat value:dog

//A类重写父类方法
public class Dog extends Animal {
    @Override
    @Temp("animal")
    public void eat() {
        super.eat();
    }
}

//结果
dog value:animal
cat value:animal
dog value:dog
cat value:animal

总结

  父类方法的注解有默认值,该类有多个子类。其中一个子类修改了该注解的值,则所有其他子类该方法的值也发生变化,子类不重写的前提下。已通过自定义注解实现

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值