Spring?spel獲取自定義注解參數(shù)值方式
spel獲取自定義注解參數(shù)值
1.注解類
package com.xxx.mall.order.service.component;?
import java.lang.annotation.*;
?
/**
?* 庫存不足等信息監(jiān)控
?* Created by xdc on 2019/4/16 15:43
?*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface StockWarnCollect {
?
? ? /** 客戶id */
? ? String customerId();
?
? ? /** 來源 */
? ? String source();
?
? ? /** 請求類型 1:詳情頁 2:購物車去結算 3:提交訂單 */
? ? String pageType();
}2.注解使用
@Override
@StockWarnCollect(customerId = "#customerId", source = "#source", pageType = "2")
public Map<String, Object> validateCarts(Long customerId, Set<Long> 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;
/**
* 下單失敗、庫存監(jiān)控
* Created by xdc on 2019/4/16 15:45
*/
@Aspect
@Component
@Slf4j
public 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.parseExpression(customerIdSpel);
Long customerId = expression.getValue(context, Long.class);
expression = parser.parseExpression(sourceSpel);
Short source = expression.getValue(context, Short.class);
log.info("collectStockWarn customerId:{}, source:{}", customerId, source);
// 業(yè)務邏輯處理
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,因為它可以在運行時查詢和操作數(shù)據(jù),尤其是數(shù)組列表型數(shù)據(jù),因此可以縮減代碼量,優(yōu)化代碼結構。個人認為很有用。
1 語法說明
1.1 SpEL 字面量:
- 整數(shù):#{8}
- 小數(shù):#{8.8}
- 科學計數(shù)法:#{1e4}
- String:可以使用單引號或者雙引號作為字符串的定界符號。
- Boolean:#{true}
1.2 SpEL引用bean , 屬性和方法:
- 引用其他對象:#{car}
- 引用其他對象的屬性:#{car.brand}
- 調(diào)用其它方法 , 還可以鏈式操作:#{car.toString()}
- 調(diào)用靜態(tài)方法靜態(tài)屬性:#{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能修飾成員變量和方法形參
? ? //#{}內(nèi)就是表達式的內(nèi)容
? ? @Value("#{表達式}")
? ? public String arg;2.2 <bean>配置
<bean id="xxx" class="com.java.XXXXX.xx">
? ? <!-- 同@Value,#{}內(nèi)是表達式的值,可放在property或constructor-arg內(nèi) -->
? ? <property name="arg" value="#{表達式}">
</bean>2.3 代碼塊中使用
public class SpELTest {?
? ? public static void main(String[] args) {
?
? ? ? ? //創(chuàng)建ExpressionParser解析表達式
? ? ? ? ExpressionParser parser = new SpelExpressionParser();
? ? ? ? //表達式放置
? ? ? ? Expression exp = parser.parseExpression("表達式");
? ? ? ? //執(zhí)行表達式,默認容器是spring本身的容器:ApplicationContext
? ? ? ? Object value = exp.getValue();
? ? ? ??
? ? ? ? /**如果使用其他的容器,則用下面的方法*/
? ? ? ? //創(chuàng)建一個虛擬的容器EvaluationContext
? ? ? ? StandardEvaluationContext ctx = new StandardEvaluationContext();
? ? ? ? //向容器內(nèi)添加bean
? ? ? ? BeanA beanA = new BeanA();
? ? ? ? ctx.setVariable("bean_id", beanA);
? ? ? ??
? ? ? ? //setRootObject并非必須;一個EvaluationContext只能有一個RootObject,引用它的屬性時,可以不加前綴
? ? ? ? ctx.setRootObject(XXX);
? ? ? ??
? ? ? ? //getValue有參數(shù)ctx,從新的容器中根據(jù)SpEL表達式獲取所需的值
? ? ? ? Object value = exp.getValue(ctx);
? ? }
}4 #{…}和${…}
- #{…} 用于執(zhí)行SpEl表達式,并將內(nèi)容賦值給屬性
- ${…} 主要用于加載外部屬性文件中的值
- #{…} 和${…} 可以混合使用,但是必須#{}外面,${}在里面
4.1 ${…}用法
{}里面的內(nèi)容必須符合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:調(diào)用字符串Hello World的concat方法
? ? @Value("#{'Hello World'.concat('!')}")
? ? private String helloWorld;
?
? ? // SpEL: 調(diào)用字符串的getBytes方法,然后調(diào)用length屬性
? ? @Value("#{'Hello World'.bytes.length}")
? ? private String helloWorldbytes;4.3 ${…}和#{…}混合使用
${...}和#{...}可以混合使用,如下文代碼執(zhí)行順序:通過${server.name}從屬性文件中獲取值并進行替換,然后就變成了 執(zhí)行SpEL表達式{‘server1,server2,server3’.split(‘,’)}。
// SpEL: 傳入一個字符串,根據(jù)","切分后插入列表中, #{}和${}配置使用(注意單引號,注意不能反過來${}在外面,#{}在里面)
? ? @Value("#{'${server.name}'.split(',')}")
? ? private List<String> servers;在上文中在#{}外面,${}在里面可以執(zhí)行成功,那么反過來是否可以呢${}在外面,#{}在里面,如代碼
// SpEL: 注意不能反過來${}在外面,#{}在里面,這個會執(zhí)行失敗
? ? @Value("${#{'HelloWorld'.concat('_')}}")
? ? private List<String> servers2;答案是不能。因為spring執(zhí)行${}是時機要早于#{}。在本例中,Spring會嘗試從屬性中查找#{‘HelloWorld’.concat(‘_’)},那么肯定找不到,由上文已知如果找不到,然后報錯。所以${}在外面,#{}在里面是非法操作
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java實現(xiàn)音頻轉(zhuǎn)文本的示例代碼(語音識別)
Java中實現(xiàn)音頻轉(zhuǎn)文本通常涉及使用專門的語音識別服務,本文主要介紹了Java實現(xiàn)音頻轉(zhuǎn)文本的示例代碼(語音識別),具有一定的參考價值,感興趣的可以了解一下2024-05-05
Spring?Boot存在路徑遍歷漏洞CVE-2021-22118的問題解析
CVE-2021-22118?是一個在?Spring?Boot?中發(fā)現(xiàn)的漏洞,該漏洞關系到?Spring?Boot?的開發(fā)者工具(Devtools)中的遠程更新(Remote?Update)功能,這篇文章主要介紹了Spring?Boot存在路徑遍歷漏洞CVE-2021-22118,需要的朋友可以參考下2023-09-09
SpringBoot2.X Kotlin系列之數(shù)據(jù)校驗和異常處理詳解
這篇文章主要介紹了SpringBoot 2.X Kotlin系列之數(shù)據(jù)校驗和異常處理詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04
深入理解Java基礎之try-with-resource語法糖
這篇文章主要介紹了深入理解Java基礎之try-with-resource語法糖,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-02-02

