#自定义注解实现接口权限控制
##一、自定义注解介绍
1.官方描述
An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.
- 注解是一种元数据形式。即注解是属于java的一种数据类型,和类、接口、数组、枚举类似。
- 注解用来修饰,类、方法、变量、参数、包。
- 注解不会对所修饰的代码产生直接的影响
2.注解使用范围
- 为编译器提供信息 - 注解能被编译器检测到错误或抑制警告
- 编译时和部署时的处理 - 软件工具能处理注解信息从而生成代码,XML文件等等
- 运行时的处理 - 有些注解在运行时能被检测到。
3.注解使用步骤
- 定义注解
- 配置注解-把标记打在需要用到的程序代码中;
- 解析注解——在编译期或运行时检测到标记,并进行特殊操作。
4.基本语法
- 关键字@interface,@Retention,@Target,@Documented,@Inherited
eg:@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
@Documented
@Inherited
public @interface ModulePermission {
public int moduleIdPos() default 0;
public int moduleCodePos() default -1;
}
其中@Target表示作用于哪些java元素上
@Retention表示注解的生命力,常用开发中用到的是RetentionPolicy.RUNTIME,表示可以再运行期加载该注解,可以通过反射获取该注解,并得到其属性- 注意事项
- 1.访问修饰符必须为public,不写默认为public
- 2.该元素的类型只能是基本数据类型
- 3.default代表默认值,值必须和第2点定义的类型一致
- 4.如果没有默认值,代表后续使用注解时必须给该类型元素赋值。
##二、代码实例
使用自定义注解对环保相关接口进行权限控制,即若不配置相关接口权限,则该接口不能访问
1.注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
@Documented
@Inherited
public @interface ModulePermission {
public int moduleIdPos() default 0;
public int moduleCodePos() default -1;
}
注解定义如上:自定义注解名称为@ModulePermission,定义了两int类型属性,分别为 moduleIdPos(),moduleCodePos();
2.注解使用
- 由上述注解定义可知,注解应用于java方法上,如下为环保接口中的告警日志查询接口
[外链图片转存失败(img-BkyH9hsm-1562566147920)(0611-1.png)]
设定了moduleCodePos
3.注解解析,使用aop对注解进行解析
private static final Logger logger = LoggerFactory.getLogger(EpModulePermissionAop.class);
@Order(1)
@Around("@annotation(cn.com.egova.ep.base.moduleright.aop.ModulePermission)")
public Object setLog(ProceedingJoinPoint joinPoint) throws Throwable {
try {
String roleEnable = SysConfigUtils.getSysConfigStrValue(
"EP_MODULE_RIGHT_ROLE_ENABLE", "0");
if ("0".equals(roleEnable)) {
return joinPoint.proceed();
}
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Method method = ms.getMethod();
ModulePermission mp = method.getAnnotation(ModulePermission.class);
int idPos = mp.moduleIdPos();
int codePos = mp.moduleCodePos();
Object[] args = joinPoint.getArgs();
Integer humanID = SessionUtils.getHumanSession().getHumanID();
String moduleCode;
Integer moduleID = null;
if (codePos != -1) {
moduleCode = (String) args[codePos];
List<EpModule> modules = epModuleDao.queryByWhere(" moduleCode = ?",moduleCode);
if(CollectionUtils.isNotEmpty(modules)){
moduleID = modules.get(0).getModuleID();
}
} else{
moduleID = (int) args[idPos];
EpModule module = epModuleDao.findById(moduleID);
moduleCode = module.getModuleCode();
}
boolean hasRight = epModuleRightManager.hasModuleRight(humanID,
moduleID);
if (!hasRight) {
// 无访问权限时处理返回值
Class<?> clazz = method.getReturnType();
if (clazz == null) {
return null;
} else if (clazz == ResultInfo.class) {
ResultInfo resultInfo = new ResultInfo(false);
resultInfo.setMessage("无"+moduleCode+"访问权限!");
return resultInfo;
} else if (clazz == BaseResultInfo.class) {
@SuppressWarnings("rawtypes")
BaseResultInfo resultInfo = new BaseResultInfo(false);
resultInfo.setMessage("无"+moduleCode+"访问权限!");
return resultInfo;
} else {
return clazz.newInstance();
}
}
}catch (Exception e) {
logger.error("处理模块访问权限时发生错误!参数:joinPoint={}",joinPoint, e);
return null;
}
return joinPoint.proceed();
}
- 如上aop所示,将注解@ModulePermission设为aop pointcut
- 在代码逻辑中获取接口注解值,并得到相应的模块编码
- 然后通过在表中查询,该人员是否拥有模块权限
- 若拥有权限,则调用joinPoint.proceed(),进行正常的业务逻辑处理,若无权限,则抛出异常