千家信息网

怎么用Spring的spel获取自定义注解参数值

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,这篇文章主要介绍了怎么用Spring的spel获取自定义注解参数值的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么用Spring的spel获取自定义注解参数值文章都会有
千家信息网最后更新 2025年01月19日怎么用Spring的spel获取自定义注解参数值

这篇文章主要介绍了怎么用Spring的spel获取自定义注解参数值的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么用Spring的spel获取自定义注解参数值文章都会有所收获,下面我们一起来看看吧。

spel获取自定义注解参数值

1.注解类

package com.xxx.mall.order.service.component; import java.lang.annotation.*; /** * 库存不足等信息监控 * Created by xdc on 2019/4/16 15:43 */@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})@Documentedpublic @interface StockWarnCollect {     /** 客户id */    String customerId();     /** 来源 */    String source();     /** 请求类型 1:详情页 2:购物车去结算 3:提交订单 */    String pageType();}

2.注解使用

@Override@StockWarnCollect(customerId = "#customerId", source = "#source", pageType = "2")public Map validateCarts(Long customerId, Set userSelectedIds, Short source, JSONArray couponInfo){    // 省略}

3.aop中处理

import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang.exception.ExceptionUtils;import org.apache.commons.lang3.StringUtils;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.core.LocalVariableTableParameterNameDiscoverer;import org.springframework.expression.EvaluationContext;import org.springframework.expression.Expression;import org.springframework.expression.ExpressionParser;import org.springframework.expression.spel.standard.SpelExpressionParser;import org.springframework.expression.spel.support.StandardEvaluationContext;import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 下单失败、库存监控 * Created by xdc on 2019/4/16 15:45 */@Aspect@Component@Slf4jpublic class StockWarnCollectAop {     @Pointcut(value = "@annotation(com.xxx.mall.order.service.component.StockWarnCollect)")    public void collectStockWarn(){}     @Around(value = "collectStockWarn()")    public Object around(ProceedingJoinPoint pjp) throws Throwable {         Method targetMethod = this.getTargetMethod(pjp);        StockWarnCollect stockWarnCollect = targetMethod.getAnnotation(StockWarnCollect.class);         // spel信息        String customerIdSpel = stockWarnCollect.customerId();        String sourceSpel = stockWarnCollect.source();        Integer pageType = null;  // 操作类型,纯字符串        if (StringUtils.isNotBlank(stockWarnCollect.pageType())) {            pageType = Integer.valueOf(stockWarnCollect.pageType());        }         // 客户id、来源解析        ExpressionParser parser = new SpelExpressionParser();        LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();        String[] params = discoverer.getParameterNames(targetMethod);         Object[] args = pjp.getArgs();         EvaluationContext context = new StandardEvaluationContext();        for (int len = 0; len < params.length; len++) {            context.setVariable(params[len], args[len]);        }        Expression expression = parser.parse_Expression(customerIdSpel);        Long customerId = expression.getValue(context, Long.class);         expression = parser.parse_Expression(sourceSpel);        Short source = expression.getValue(context, Short.class);        log.info("collectStockWarn customerId:{}, source:{}", customerId, source);         // 业务逻辑处理        Object result = null;        try {            result = pjp.proceed();        } catch (Throwable e) {            log.info("collectStockWarn watchs creating order errorMsg:{}", ExceptionUtils.getStackTrace(e));            if (e instanceof MallException) {             } else {    // 未知错误                        }             throw e;        }         try {            if (result != null) {                        }        } catch (Exception e) {            log.error("collectStockWarn process error, errorMsg:{}", ExceptionUtils.getStackTrace(e));        }         return result;     }     /**     * 获取目标方法     */    private Method getTargetMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {        Signature signature = pjp.getSignature();        MethodSignature methodSignature = (MethodSignature)signature;        Method agentMethod = methodSignature.getMethod();        return pjp.getTarget().getClass().getMethod(agentMethod.getName(),agentMethod.getParameterTypes());    }}

spel在注解中的使用

SpEL(Spring Expression Language),即Spring表达式语言,是比JSP的EL更强大的一种表达式语言。为什么要总结SpEL,因为它可以在运行时查询和操作数据,尤其是数组列表型数据,因此可以缩减代码量,优化代码结构。个人认为很有用。

1 语法说明

1.1 SpEL 字面量:

  • 整数:#{8}

  • 小数:#{8.8}

  • 科学计数法:#{1e4}

  • String:可以使用单引号或者双引号作为字符串的定界符号。

  • Boolean:#{true}

1.2 SpEL引用bean , 属性和方法:

  • 引用其他对象:#{car}

  • 引用其他对象的属性:#{car.brand}

  • 调用其它方法 , 还可以链式操作:#{car.toString()}

  • 调用静态方法静态属性:#{T(java.lang.Math).PI}

1.3 SpEL支持的运算符号:

  • 算术运算符:+,-,*,/,%,^(加号还可以用作字符串连接)

  • 比较运算符:< , > , == , >= , <= , lt , gt , eg , le , ge

  • 逻辑运算符:and , or , not , |

  • if-else 运算符(类似三目运算符):?:(temary), ?:(Elvis)

  • 正则表达式:#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}'}

2. 基本用法

SpEL有三种用法:

1. 是在注解@Value中;

2. 在XML配置中;

3. 代码块中使用Expression。

2.1 @Value

    //@Value能修饰成员变量和方法形参    //#{}内就是表达式的内容    @Value("#{表达式}")    public String arg;

2.2 配置

        

2.3 代码块中使用

public class SpELTest {     public static void main(String[] args) {         //创建ExpressionParser解析表达式        ExpressionParser parser = new SpelExpressionParser();        //表达式放置        Expression exp = parser.parse_Expression("表达式");        //执行表达式,默认容器是spring本身的容器:ApplicationContext        Object value = exp.getValue();                /**如果使用其他的容器,则用下面的方法*/        //创建一个虚拟的容器EvaluationContext        StandardEvaluationContext ctx = new StandardEvaluationContext();        //向容器内添加bean        BeanA beanA = new BeanA();        ctx.setVariable("bean_id", beanA);                //setRootObject并非必须;一个EvaluationContext只能有一个RootObject,引用它的属性时,可以不加前缀        ctx.setRootObject(XXX);                //getValue有参数ctx,从新的容器中根据SpEL表达式获取所需的值        Object value = exp.getValue(ctx);    }}

4 #{…}和${…}

  • #{…} 用于执行SpEl表达式,并将内容赋值给属性

  • ${…} 主要用于加载外部属性文件中的值

  • #{…} 和${…} 可以混合使用,但是必须#{}外面,${}在里面

4.1 ${…}用法

{}里面的内容必须符合SpEL表达式,通过@Value("${spelDefault.value}")可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,则会报错。可以通过赋予默认值解决这个问题,如@Value("${spelDefault.value:127.0.0.1}")

// 如果属性文件没有spelDefault.value,则会报错    //  @Value("${spelDefault.value}")    //  private String spelDefault2;     // 使用default.value设置值,如果不存在则使用默认值    @Value("${spelDefault.value:127.0.0.1}")    private String spelDefault;

4.2 #{…}用法

这里只演示简单用法

    // SpEL:调用字符串Hello World的concat方法    @Value("#{'Hello World'.concat('!')}")    private String helloWorld;     // SpEL: 调用字符串的getBytes方法,然后调用length属性    @Value("#{'Hello World'.bytes.length}")    private String helloWorldbytes;

4.3 ${…}和#{…}混合使用

${...}和#{...}可以混合使用,如下文代码执行顺序:通过${server.name}从属性文件中获取值并进行替换,然后就变成了 执行SpEL表达式{‘server1,server2,server3’.split(‘,’)}。

// SpEL: 传入一个字符串,根据","切分后插入列表中, #{}和${}配置使用(注意单引号,注意不能反过来${}在外面,#{}在里面)    @Value("#{'${server.name}'.split(',')}")    private List servers;

在上文中在#{}外面,${}在里面可以执行成功,那么反过来是否可以呢${}在外面,#{}在里面,如代码

// SpEL: 注意不能反过来${}在外面,#{}在里面,这个会执行失败    @Value("${#{'HelloWorld'.concat('_')}}")    private List servers2;

答案是不能。因为spring执行${}是时机要早于#{}。在本例中,Spring会尝试从属性中查找#{‘HelloWorld’.concat(‘_’)},那么肯定找不到,由上文已知如果找不到,然后报错。所以${}在外面,#{}在里面是非法操作

关于"怎么用Spring的spel获取自定义注解参数值"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"怎么用Spring的spel获取自定义注解参数值"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。

表达式 属性 注解 方法 参数 字符 字符串 容器 运算 代码 内容 文件 运算符 反过来 引号 知识 混合 配置 上文 从属性 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 同时数据库 江苏信息化软件开发服务价格 北京百卓网络技术 中国网络技术有有限公司电话 网络卡顿无法连接服务器 软件开发税收优惠政策是什么 印尼服务器维护管理工资 python连接数据库卡住 数据库删除数据保留一部分数据 dellt110服务器显卡驱动 数据库删除表内容语句 银川oa软件开发公司 谦乐网络技术有限公司招聘 科技部无线网络安全自查 职业生涯规划软件开发 国家网络安全保护中心 把主机做成局域网服务器 互联网时代科技引领安保行业 数据库课程设计社区管理 连接对方服务器超时 未来科技互联网淘汰 网络安全手抄报文字内容90字 网站模版怎么上传服务器 网络安全责任制考核办法 数据库错误请联系系统管理员 红桥区数据网络技术售后服务 服务器返回信息错误啥意思 36岁学网络安全 tbc怀旧服服务器人口状况 网络安全管理遵循原则
0