SpEL表达式
Spring Expression Language
前言
Spring Expression Language,Spring Framework的核心技术之一,支持在运行时查询和操作对象图;最特别的是方法调用与字符串模板功能.
Spring表达式语言Spring3.0提供的最强大的功能, 可以通过运行期间执行的表达式将值装配到我们的属性 或 构造函数 之中。
一、SpEL是什么?
SpEL 全称是Spring Expression Language。是Spring Framework的核心技术之一。使用AOP +SpEL表达式来实现接口权限的控制。
二、使用步骤
1.自定义权限注解
代码如下(示例):
@Target({ ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PreAuth {
String value();
}
2.定义切面类
代码如下(示例):
@Aspect
@Component
public class AuthorAspect{...}
3.指定注解为切点,形成切面(增强通知)
代码如下(示例):
@Around("@annotation(com.shop.annotation.PreAuth) || " + "@within(com.shop.annotation.PreAuth)")
public Object preAuth(ProceedingJoinPoint point) throws Throwable {
//连接点 + SpEl表达式实现
Boolean flag = this.handleAuth(point);
if ( flag ) {
return point.proceed();
}
throw new AdminGlobalException("Request_REJECT");
}
4.SpEl表达式代码实现
代码如下(示例):
private boolean handleAuth(ProceedingJoinPoint point) {
//三目运算也是SpEl表达式的基本
MethodSignature ms = point.getSignature() instanceof MethodSignature? (MethodSignature) point.getSignature():null;
Method method = ms.getMethod();
// 读取权限注解,优先方法上,没有则读取类
PreAuth preAuth = ClassUtil.getAnnotation(method, PreAuth.class);
// 判断表达式
String condition = preAuth.value();
if (StringUtils.isNotBlank(condition)) {
// 方法参数值
Object[] args = point.getArgs();
//1.构造一个解析器
ExpressionParser expressionPparser= new SpelExpressionParser();
//2.其次解析器解析字符串表达式
Expression expression = expressionParser.parseExpression(condition);
//3.构造上下文
StandardEvaluationContext context = this.getEvaluationContext(method, args);
//4.最后根据上下文得到表达式运算后的值
return expression.getValue(context, Boolean.class);
}
return false;
}```
----------------------------------------------------------------------------------
```java
private StandardEvaluationContext getEvaluationContext(Method method, Object[] args) {
//3.1 初始化Spring el表达式上下文,并设置 AuthFun 权限按钮类
StandardEvaluationContext context = new StandardEvaluationContext(new AuthFun());
//3.2设置表达式支持spring bean
context.setBeanResolver(new BeanFactoryResolver(SpringContextUtils.applicationContext));
for (int i = 0; i < args.length; i++) {
//读取方法参数
MethodParameter methodParam = ClassUtil.getMethodParameter(method, i);
// 3.3设置方法 参数名和值 为spel变量
context.setVariable(methodParam.getParameterName(), args[i]);
}
return context;
}
5.ClassUtil的依赖包
<dependency>
<groupId>net.dreamlu</groupId>
<artifactId>mica-ip2region</artifactId>
<version>2.5.6</version>
</dependency>
6.SpringContextUtils获取上下文
@Component
public class SpringContextUtils implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class<? extends Object> getType(String name) {
return applicationContext.getType(name);
}
}
6.AuthFun类 权限控制类
public class AuthFun {
/**
* 判断角色是否具有接口权限
*
* @return {boolean}
*/
public boolean permissionAll() {
//TODO 全部接口权限
return true;
}
/**
* 判断角色是否具有接口权限
*
* @param permission 权限编号,对应菜单的MENU_CODE
* @return {boolean}
*/
public boolean hasPermission(String permission) {
//TODO 全部接口权限
return true;
}
/**
* 放行所有请求
*
* @return {boolean}
*/
public boolean permitAll() {
// TODO 全部接口权限
return true;
}
/**
* 只有超管角色才可访问
*
* @return {boolean}
*/
public boolean denyAll() {
return hasRole(SysTypeEnum.ADMIN.name());
}
/**
* 是否已授权
*
* @return {boolean}
*/
public boolean hasAuth() {
SysUserAuthVO sysUser = SecurityUtils.getSysUser();
if(sysUser == null ){
// TODO 返回异常提醒
return false;
}else{
return true;
}
}
/**
* 是否有时间授权
*
* @param start 开始时间
* @param end 结束时间
* @return {boolean}
*/
public boolean hasTimeAuth(Integer start, Integer end) {
Integer hour = DateUtil.hour(new Date(), true);
return hour >= start && hour <= end;
}
/**
* 判断是否有该角色权限
*
* @param role 单角色
* @return {boolean}
*/
public boolean hasRole(String role) {
return hasAnyRole(role);
}
/**
* 判断是否具有所有角色权限
*
* @param role 角色集合
* @return {boolean}
*/
public boolean hasAllRole(String... role) {
for (String r : role) {
if (!hasRole(r)) {
return false;
}
}
return true;
}
/**
* 判断是否有该角色权限
*
* @param role 角色集合
* @return {boolean}
*/
public boolean hasAnyRole(String... role) {
//获取当前登录用户
SysUserAuthVO user = SecurityUtils.getSysUser();
if (user == null) {
return false;
}
String userRole = user.getUsername();
if (StringUtils.isBlank(userRole)) {
return false;
}
String[] roles = (String[]) user.getAuthorities().toArray();
for (String r : role) {
if (CollectionUtil.contains(Arrays.asList(roles), r)) {
return true;
}
}
return false;
}
}
总结
利用aop + spel表达式 结合项目实现接口权限控制,实际功能根据自己需要进行扩展.本人在此记录一下我在项目里测试的代码.
项目里的接口权限的控制 实际是用 org.springframework.security 框架实现的,这个框架自带的功能;