Spring3 表达式语言(SpEL)介绍

Spring SpEL 表达式语言 Spring也有自己的EL,叫Spring Expression Language,简称SpEl。其可以在程序中单独使用,也可以在Spring应用中进行bean定义时使用。其核心是org.springframework.expression.Expression接口,Spring使用该接口来表示EL中的表达式。通过Expression接口的系列getValue()方法我们可以获取对应Expression在特定EvaluationContext下的值,也可以通过其系列setValue()方法来设值。 阅读详情

http://leeyee.github.io/blog/2011/06/19/spring-expression-language/


Spring Expression Language (SpEL)语言支持在运行时操作和查询对象,其语法类似统一的EL语言,但是SpEL提供了额外的功能。SpEL支持以下功能:

使用SpEl进行表达式操作,基本操作如下:

第一步,构建解析

   
  1. ExpressionParser parser = new SpelExpressionParser();

第二步,使用表达式进行解析

   
  1. Expression exp = parser.parseExpression( SpEl);

第三步,获取结果

   
  1. exp.getValue()

2.1 文本表达式

文本表达式支持字符表达式、日期、数字(正数、实数及十六进制数)、布尔类型及null.其中字符表达式需要用单引号声明。

对数字支持负数、指数及小数。默认情况下实数使用Double.parseDouble()进行表达式类型转换

   
  1. String[] lELs = { "'hello SpEL'", "1.028E+7", "0x12EF", "true", "null" };
  2. assertEquals("hello SpEL",
  3. exp.parseExpression(lELs[0]).getValue(String.class));
  4. assertEquals(new Double(10280000), exp.parseExpression(lELs[1])
  5. .getValue(Double.class));
  6. assertEquals(new Integer(4847),
  7. exp.parseExpression(lELs[2]).getValue(Integer.class));
  8. assertTrue(exp.parseExpression(lELs[3]).getValue(Boolean.class));
  9. assertNull(exp.parseExpression(lELs[4]).getValue());

2.2 属性、数组、列表、字典(map)及索引

在表达式中访问类属性时直接使用属性名,属性名首字母大小写均可。

访问数组时可以使用[index]进行元素对象范围。

访问列表时,可直接使用类表的方法,通过点操作符

   
  1. // 属性测试。time为SpElUtil类Date型数据,这里调用Date的属性Year
  2. assertEquals(new Integer(2011), exp.parseExpression("time.Year + 1900")
  3. .getValue(secontext, Integer.class));
  4. // 属性测试。innerClass为SpElUtil类中引入的其他类。
  5. assertEquals(29,
  6. exp.parseExpression("innerClass.age").getValue(secontext));
  7. // 设置SpElUtil类的numbers属性
  8. spel.setNumbers(Arrays.asList(2, 3, 4, 5, 6, 7, 9));
  9. // 访问对象属性数组通过索引
  10. assertEquals(2, exp.parseExpression("numbers[0]").getValue(secontext));
  11. // 访问map
  12. assertEquals("string1",
  13. exp.parseExpression("maps[1]")
  14. .getValue(secontext, String.class));

2.3 内置列表

列表可以直接表示在表达式中使用{}符号表达。{}本身代表一个空的list

   
  1. // 构造list
  2. List<String> nums = (List<String>) exp.parseExpression(
  3. "{'a','b','c','d'}").getValue();
  4. assertEquals(Arrays.asList("a", "b", "c", "d"), nums);
  5. // 构造List<List<>>
  6. List listOfLists = (List) exp.parseExpression("{ {1,2},{3,4} }")
  7. .getValue(secontext);
  8. assertEquals(Arrays.asList(1, 2), listOfLists.get(0));

2.4 数组构造(spring3.0.3中会抛出异常)

可以通过熟悉的java语法在表达是语言中定义。但目前不支持定义一个初始化的多维数组

   
  1. // 创建没有初始值的数组
  2. int[] a = (int[]) exp.parseExpression("new int[4]").getValue();
  3. assertEquals(4, a.length);
  4. // 创建带有初始值的数组
  5. int[] b = (int[]) exp.parseExpression("new int[4]{1,2,3,4}").getValue();
  6. assertEquals(3, b[2]);
  7. // 创建二维数组
  8. int[][] c = (int[][]) exp.parseExpression("new int[4][5]").getValue();
  9. assertEquals(4, c.length);
  10. assertEquals(5, c[0].length);

2.5 方法调用

表达式中的方法调用遵循java语法。

   
  1. assertEquals(
  2. "abC2def",
  3. exp.parseExpression("'abcdef'.replace('c','C2')").getValue(
  4. String.class));
  5. // 自定义类方法测试
  6. assertFalse(exp.parseExpression("innerClass.isGt30ForAge()").getValue(
  7. secontext, Boolean.class));
  8. spel.getInnerClass().setAge(34);
  9. assertTrue(exp.parseExpression("innerClass.isGt30ForAge()").getValue(
  10. secontext, Boolean.class));

2.6 操作符

2.6.1 关系操作符

支持eq("==")、ne("!=")、le("<=")、lt("<")、gt(">")、ge(">=")、div("/")、mod("%")、not("!")、正则表达式及instanceof操作

   
  1. assertTrue(exp.parseExpression("1 == 1").getValue(Boolean.class));
  2. assertTrue(exp.parseExpression("1 eq 1").getValue(Boolean.class));
  3. assertTrue(exp.parseExpression("1 > -1").getValue(Boolean.class));
  4. assertTrue(exp.parseExpression("1 gt -1").getValue(Boolean.class));
  5. assertTrue(exp.parseExpression("'a' < 'b'").getValue(Boolean.class));
  6. assertTrue(exp.parseExpression("'a' lt 'b'").getValue(Boolean.class));
  7. assertTrue(exp.parseExpression(
  8. " new Integer(123) instanceof T(Integer) ").getValue(
  9. Boolean.class));
  10. assertTrue(exp.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'")
  11. .getValue(Boolean.class));

2.6.2 逻辑操作符

逻辑操作符支持and,or,not

   
  1. assertTrue(exp.parseExpression("true and true").getValue(Boolean.class));

2.6.3 数学运算操作符

加法运算符可以用于数字,字符串和日期。减法可以用在数字和日期。乘法和除法只能用于对数字。其他受支持的数学运算是模数(%)和指数幂(^)。运行顺序按标准运算符优先级执行

   
  1. assertEquals(25.0,
  2. exp.parseExpression("1 + 2 * 8 div 4 mod 2 + 2 ^ 3 * 3e0")
  3. .getValue());

2.7 赋值操作

通过赋值操作进行属性设置。通常是调用setValue方法,但也可以在调用getValue时设置。

   
  1. Date oldDate = spel.getTime();// 获取当前time属性值
  2. exp.parseExpression("time").setValue(secontext, new Date(113, 2, 25)); // 为time属性重新赋值
  3. Date newDate = spel.getTime();// 获取赋值后的time属性值
  4. assertEquals(2013,
  5. exp.parseExpression("time.Year + 1900").getValue(secontext));
  6. assertNotSame(oldDate, newDate);
  7. // 或者使用下属方法赋值
  8. assertEquals("abc",
  9. exp.parseExpression("Name = 'abc'").getValue(secontext));

2.8 类型

通过特殊的T操作符可以用来指定一个java.lang.Class的实例。在实例话对象的静态方法将会被调用。

   
  1. Class dateClass = exp.parseExpression("T(java.util.Date)").getValue(Class.class);
  2. assertEquals("java.util.Date", dateClass.getName());
  3. assertTrue(exp
  4. .parseExpression(
  5. "T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
  6. .getValue(Boolean.class));

2.9 构造器

构造器通过new操作被调用。在new操作时需要指明类的完全类名(包括包路径)

   
  1. SpelTestInnerClass spt = exp
  2. .parseExpression(
  3. "new leeyee.study.spring3.bean.SpelTestInnerClass('constructTest',23)")
  4. .getValue(SpelTestInnerClass.class);

2.10 变量

变量可以通过 #变量名 在表达式中被引用。变量通过StandardEvaluationContext类的setVariable方法进行设置

   
  1. List<Integer> list = new ArrayList<Integer>();
  2. list.addAll(Arrays.asList(2, 3, 4, 5, 6, 7, 9));
  3. secontext.setVariable("list", list);
  4. List<Integer> vList = (List<Integer>) exp.parseExpression("#list")
  5. .getValue(secontext);
  6. assertEquals(vList, list);

2.10.1  #this变量

变量#this被定义为当前操作对象的引用。

   
  1. List<Integer> nums = (List<Integer>) exp.parseExpression(
  2. "#list.?[#this >5]").getValue(secontext); // 获取值大于5的元素集合
  3. assertEquals(nums, Arrays.asList(6, 7, 9));

2.11 用户自定义函数

你可以扩展SpEL通过注册自定义函数。注册后的函数可以在表达式中通过其名称进行调用。函数的注册是通过StandardEvaluationContext类的registerFunction方法进行声明

   
  1. context.registerFunction("len", SpElUtil.class.getDeclaredMethod("len",
  2. new Class[] { String.class }));
  3. assertEquals(3, exp.parseExpression("#len('abc')").getValue(context));

2.12 三元操作

   
  1. assertTrue(exp.parseExpression(" true ? true :false").getValue(
  2. Boolean.class));

2.13 Elvis操作

Elvis操作是一个短的三元操作符语法,通常在Groovy语言中使用。

Note: Elvis操作在表达式中可以用来生成默认值,当被访问属性为空时。比如@Value

   
  1. @Value("#systemPro['mail.port'] ? : 25}")
  2. // 当mail.port为空时将默认为25
  3. Expression ex = exp.parseExpression("name?:'name is null'");
  4. assertEquals("override", ex.getValue(secontext, String.class));
  5. spel.setName(null);
  6. assertEquals("name is null", ex.getValue(secontext, String.class));
  7. spel.setName("override");

2.14 安全导航操作

该操作是为避免空指针异常。他是来自Groovy语言的。典型的当你有一个指向对象的引用,在你访问其方法或属性时,可能需要验证该对象的方法或属性是否为空,为了避免验证,使用安全导航操作将简单的返回null而不是空指针异常。

   
  1. assertEquals("innerClass", exp.parseExpression("innerClass?.name")
  2. .getValue(secontext, String.class));
  3. spel.setInnerClass(null);
  4. // 使用这种表达式可以避免抛出空指针异常
  5. assertNull(exp.parseExpression("innerClass?.name").getValue(secontext,
  6. String.class));

2.15 集合选择

选择是一个强大的表达式语言属性,可以使用选择表达式过滤源集合,从而生成一个新的符合选择条件的集合

选择的语法为?[selectionExpression]。他将过滤集合并且返回一个新的集合(原集合的子集)。选择语句也可用在Map中,过滤keySet及valueSet分别使用key和value关键字。另外:选择语法中,选择符合条件的结果集的第一个元素的语法为 ^[selectionExpression],选择最后一个元素的语法为$[selectionExpression]

   
  1. spel.setNumbers(Arrays.asList(2, 3, 4, 5, 6, 7, 9));
  2. List<Integer> nums = (List<Integer>) exp.parseExpression(
  3. "numbers.?[#this >5]").getValue(secontext);
  4. assertEquals(nums, Arrays.asList(6, 7, 9));
  5. // 获取第一个元素
  6. assertEquals(6,
  7. exp.parseExpression("numbers.^[#this > 5]").getValue(secontext));
  8. // 获取最后一个元素
  9. assertEquals(9,
  10. exp.parseExpression("numbers.$[#this > 5]").getValue(secontext));
  11. Map<Integer, String> maps = (Map<Integer, String>) exp.parseExpression(
  12. "maps.?[value == 'string3' ]").getValue(secontext);
  13. Map<Integer, String> tmap = new HashMap<Integer, String>();
  14. tmap.put(3, "string3");
  15. assertEquals(maps, tmap);
  16. Map<Integer, String> mapk = (Map<Integer, String>) exp.parseExpression(
  17. "maps.?[key > 2 and key < 4 ]").getValue(secontext);
  18. assertEquals(mapk, tmap);

2.16 集合投影

语法![projectionExpression]判断集合中每个元素是否符合语法要求

   
  1. assertEquals(Arrays.asList(5, 6, 7, 8, 9), exp
  2. .parseExpression("numbers.![#this+3]").getValue(secontext));

2.17 模板表达式

表达式模板允许混合文字表达式,一个或多个值计算块。每一个值计算块被声明通过可被自定义的前缀和后缀,一般选择使用#{}作为一个定界符。

   
  1. assertEquals(
  2. " this is a test 4",
  3. exp.parseExpression(" this is a test #{ maps.![key].get(3)}",
  4. new TemplateParserContext()).getValue(secontext,
  5. String.class));

一大段测试用例:

   
  1. import static org.junit.Assert.*;
  2. import java.util.*;
  3. import org.junit.*;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.expression.Expression;
  6. import org.springframework.expression.ExpressionParser;
  7. import org.springframework.expression.common.TemplateParserContext;
  8. import org.springframework.expression.spel.standard.SpelExpressionParser;
  9. import org.springframework.expression.spel.support.StandardEvaluationContext;
  10. import study.spring.context.factory.ApplicationContextFactory;
  11. public class SpElUtilTest {
  12. // spring配置文件上下文
  13. ApplicationContext context = null;
  14. // spring el测试辅助类
  15. SpElUtil spel = null;
  16. // 表达式解析对象
  17. ExpressionParser exp = null;
  18. // 标准赋值上下文
  19. StandardEvaluationContext secontext;
  20. @Before
  21. public void setUp() throws Exception {
  22. context = ApplicationContextFactory.createInstance();
  23. spel = context.getBean(SpElUtil.class);
  24. secontext = new StandardEvaluationContext(spel);
  25. exp = new SpelExpressionParser();
  26. }
  27. @After
  28. public void tearDown() throws Exception {
  29. context = null;
  30. spel = null;
  31. secontext = null;
  32. exp = null;
  33. }
  34. /**
  35. * 文字表达式测试用例
  36. *
  37. * @throws Exception
  38. */
  39. @Test
  40. public void testSpELLiteralExpression() throws Exception {
  41. // 定义各种文字表达式
  42. String[] lELs = { "'hello SpEL'", "1.028E+7", "0x12EF", "true", "null" };
  43. assertEquals("hello SpEL",
  44. exp.parseExpression(lELs[0]).getValue(String.class));
  45. assertEquals(new Double(10280000), exp.parseExpression(lELs[1])
  46. .getValue(Double.class));
  47. assertEquals(new Integer(4847),
  48. exp.parseExpression(lELs[2]).getValue(Integer.class));
  49. assertTrue(exp.parseExpression(lELs[3]).getValue(Boolean.class));
  50. assertNull(exp.parseExpression(lELs[4]).getValue());
  51. }
  52. /**
  53. * 访问属性、数组、集合和 map 测试
  54. *
  55. * @throws Exception
  56. */
  57. @Test
  58. public void testSpELProOrArrayOrIndexEtcExpression() throws Exception {
  59. // 属性测试。time为SpElUtil类Date型数据,这里调用Date的属性Year
  60. assertEquals(new Integer(2011), exp.parseExpression("time.Year + 1900")
  61. .getValue(secontext, Integer.class));
  62. // 属性测试。innerClass为SpElUtil类中引入的其他类。
  63. assertEquals(29,
  64. exp.parseExpression("innerClass.age").getValue(secontext));
  65. // 设置SpElUtil类的numbers属性
  66. spel.setNumbers(Arrays.asList(2, 3, 4, 5, 6, 7, 9));
  67. // 访问对象属性数组通过索引
  68. assertEquals(2, exp.parseExpression("numbers[0]").getValue(secontext));
  69. // 访问map
  70. assertEquals("string1",
  71. exp.parseExpression("maps[1]")
  72. .getValue(secontext, String.class));
  73. }
  74. /**
  75. * 内联list测试
  76. *
  77. * @throws Exception
  78. */
  79. @SuppressWarnings({ "unchecked", "rawtypes" })
  80. @Test
  81. public void testSpELInnerListExpression() throws Exception {
  82. // 构造list
  83. List<String> nums = (List<String>) exp.parseExpression(
  84. "{'a','b','c','d'}").getValue();
  85. assertEquals(Arrays.asList("a", "b", "c", "d"), nums);
  86. // 构造List<List<>>
  87. List listOfLists = (List) exp.parseExpression("{ {1,2},{3,4} }")
  88. .getValue(secontext);
  89. assertEquals(Arrays.asList(1, 2), listOfLists.get(0));
  90. }
  91. /**
  92. * Array 构造测试
  93. *
  94. * @throws Exception
  95. */
  96. @Test
  97. public void testSpELArrayConstructionExcpression() throws Exception {
  98. // 创建没有初始值的数组
  99. int[] a = (int[]) exp.parseExpression("new int[4]").getValue();
  100. assertEquals(4, a.length);
  101. // 创建带有初始值的数组
  102. int[] b = (int[]) exp.parseExpression("new int[4]{1,2,3,4}").getValue();
  103. assertEquals(3, b[2]);
  104. // 创建二维数组
  105. int[][] c = (int[][]) exp.parseExpression("new int[4][5]").getValue();
  106. assertEquals(4, c.length);
  107. assertEquals(5, c[0].length);
  108. }
  109. /**
  110. * 方法表达式测试
  111. *
  112. * @throws Exception
  113. */
  114. @Test
  115. public void testSpELMethodExcpression() throws Exception {
  116. // String.replace方法测试
  117. assertEquals(
  118. "abC2def",
  119. exp.parseExpression("'abcdef'.replace('c','C2')").getValue(
  120. String.class));
  121. // 自定义类方法测试
  122. assertFalse(exp.parseExpression("innerClass.isGt30ForAge()").getValue(
  123. secontext, Boolean.class));
  124. spel.getInnerClass().setAge(34);
  125. assertTrue(exp.parseExpression("innerClass.isGt30ForAge()").getValue(
  126. secontext, Boolean.class));
  127. }
  128. /**
  129. * 操作符、正则表达式测试
  130. *
  131. * @throws Exception
  132. */
  133. @Test
  134. public void testSpElOperatorAndRegExpression() throws Exception {
  135. // 关系操作
  136. assertTrue(exp.parseExpression("1 == 1").getValue(Boolean.class));
  137. assertTrue(exp.parseExpression("1 eq 1").getValue(Boolean.class));
  138. assertTrue(exp.parseExpression("1 > -1").getValue(Boolean.class));
  139. assertTrue(exp.parseExpression("1 gt -1").getValue(Boolean.class));
  140. assertTrue(exp.parseExpression("'a' < 'b'").getValue(Boolean.class));
  141. assertTrue(exp.parseExpression("'a' lt 'b'").getValue(Boolean.class));
  142. assertTrue(exp.parseExpression(
  143. " new Integer(123) instanceof T(Integer) ").getValue(
  144. Boolean.class));
  145. assertTrue(exp.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'")
  146. .getValue(Boolean.class));
  147. // 逻辑操作
  148. assertTrue(exp.parseExpression("true and true").getValue(Boolean.class));
  149. assertTrue(exp.parseExpression("true or false").getValue(Boolean.class));
  150. assertFalse(exp.parseExpression("innerClass.isGt30ForAge() and false ")
  151. .getValue(secontext, Boolean.class));
  152. assertFalse(exp.parseExpression("!innerClass.isGt30ForAge() and true ")
  153. .getValue(secontext, Boolean.class));
  154. assertTrue(exp.parseExpression("!false").getValue(Boolean.class));
  155. // 运算操作
  156. assertEquals(2, exp.parseExpression("1 + 1").getValue());
  157. assertEquals("ABab",
  158. exp.parseExpression("'AB' + 'ab'").getValue(String.class));
  159. assertEquals(25.0,
  160. exp.parseExpression("1 + 2 * 8 div 4 mod 2 + 2 ^ 3 * 3e0")
  161. .getValue());
  162. assertEquals(exp.parseExpression("1 + 2 * 8 / 4 % 2 + 2 ^ 3 ")
  163. .getValue(),
  164. exp.parseExpression("1 + 2 * 8 div 4 mod 2 + 2 ^ 3 ")
  165. .getValue());
  166. }
  167. /**
  168. * 赋值表达式测试
  169. *
  170. * @throws Exception
  171. */
  172. @SuppressWarnings("deprecation")
  173. @Test
  174. public void testSpelAssignmentExpression() throws Exception {
  175. Date oldDate = spel.getTime();// 获取当前time属性值
  176. exp.parseExpression("time").setValue(secontext, new Date(113, 2, 25)); // 为time属性重新赋值
  177. Date newDate = spel.getTime();// 获取赋值后的time属性值
  178. assertEquals(2013,
  179. exp.parseExpression("time.Year + 1900").getValue(secontext));
  180. assertNotSame(oldDate, newDate);
  181. // 或者使用下属方法赋值
  182. assertEquals("abc",
  183. exp.parseExpression("Name = 'abc'").getValue(secontext));
  184. // 还原time默认,避免后续测试错误
  185. spel.setTime(oldDate);
  186. spel.setName("override");
  187. }
  188. /**
  189. * 类型操作表达式测试
  190. *
  191. * @throws Exception
  192. */
  193. @SuppressWarnings("rawtypes")
  194. @Test
  195. public void testSpelTypesExpression() throws Exception {
  196. Class dateClass = exp.parseExpression("T(java.util.Date)").getValue(
  197. Class.class);
  198. assertEquals("java.util.Date", dateClass.getName());
  199. assertTrue(exp
  200. .parseExpression(
  201. "T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
  202. .getValue(Boolean.class));
  203. }
  204. /**
  205. * 构造函数调用测试
  206. *
  207. * @throws Exception
  208. */
  209. @Test
  210. public void testSpelConstructorsExpression() throws Exception {
  211. SpelTestInnerClass spt = exp
  212. .parseExpression(
  213. "new study.spring.beans.SpelTestInnerClass('constructTest',23)")
  214. .getValue(SpelTestInnerClass.class);
  215. assertEquals(23, spt.getAge());
  216. assertEquals("constructTest", spt.getName());
  217. }
  218. /**
  219. * 设置变量测试
  220. *
  221. * @throws Exception
  222. */
  223. @SuppressWarnings("unchecked")
  224. @Test
  225. public void testSpelVariablesExpression() throws Exception {
  226. List<Integer> list = new ArrayList<Integer>();
  227. list.addAll(Arrays.asList(2, 3, 4, 5, 6, 7, 9));
  228. secontext.setVariable("list", list);
  229. List<Integer> vList = (List<Integer>) exp.parseExpression("#list")
  230. .getValue(secontext);
  231. assertEquals(vList, list);
  232. List<Integer> nums = (List<Integer>) exp.parseExpression(
  233. "#list.?[#this >5]").getValue(secontext); // 获取值大于5的元素集合
  234. assertEquals(nums, Arrays.asList(6, 7, 9));
  235. }
  236. /**
  237. * 自定义函数表达式测试
  238. *
  239. * @throws Exception
  240. */
  241. @Test
  242. public void testSpelFunctionExpression() throws Exception {
  243. StandardEvaluationContext context = new StandardEvaluationContext();
  244. context.registerFunction("len", SpElUtil.class.getDeclaredMethod("len",
  245. new Class[] { String.class }));
  246. assertEquals(3, exp.parseExpression("#len('abc')").getValue(context));
  247. }
  248. @Test
  249. public void testSpelBeanExpression() throws Exception {
  250. }
  251. /**
  252. * 三元操作测试
  253. *
  254. * @throws Exception
  255. */
  256. @Test
  257. public void testSpelTernaryOperatorExpression() throws Exception {
  258. assertTrue(exp.parseExpression(" true ? true :false").getValue(
  259. Boolean.class));
  260. assertEquals("is true",
  261. exp.parseExpression(" 1 == 1 ? 'is true' :'is false'")
  262. .getValue(String.class));
  263. }
  264. /**
  265. * Elvis 操作测试
  266. *
  267. * @throws Exception
  268. */
  269. @Test
  270. public void testSpeleElvisOperatorExpression() throws Exception {
  271. Expression ex = exp.parseExpression("name?:'name is null'");
  272. assertEquals("override", ex.getValue(secontext, String.class));
  273. spel.setName(null);
  274. assertEquals("name is null", ex.getValue(secontext, String.class));
  275. spel.setName("override");
  276. }
  277. /**
  278. * 安全导航操作测试
  279. *
  280. * @throws Exception
  281. */
  282. @Test
  283. public void testSpelSafeNavOperatorExpression() throws Exception {
  284. assertEquals("innerClass", exp.parseExpression("innerClass?.name")
  285. .getValue(secontext, String.class));
  286. spel.setInnerClass(null);
  287. // 使用这种表达式可以避免抛出空指针异常
  288. assertNull(exp.parseExpression("innerClass?.name").getValue(secontext,
  289. String.class));
  290. }
  291. /**
  292. * 集合选择表达式测试
  293. *
  294. * @throws Exception
  295. */
  296. @SuppressWarnings("unchecked")
  297. @Test
  298. public void testSpelCollectionSelectExpression() throws Exception {
  299. spel.setNumbers(Arrays.asList(2, 3, 4, 5, 6, 7, 9));
  300. List<Integer> nums = (List<Integer>) exp.parseExpression(
  301. "numbers.?[#this >5]").getValue(secontext);
  302. assertEquals(nums, Arrays.asList(6, 7, 9));
  303. // 获取第一个元素
  304. assertEquals(6,
  305. exp.parseExpression("numbers.^[#this > 5]").getValue(secontext));
  306. // 获取最后一个元素
  307. assertEquals(9,
  308. exp.parseExpression("numbers.$[#this > 5]").getValue(secontext));
  309. Map<Integer, String> maps = (Map<Integer, String>) exp.parseExpression(
  310. "maps.?[value == 'string3' ]").getValue(secontext);
  311. Map<Integer, String> tmap = new HashMap<Integer, String>();
  312. tmap.put(3, "string3");
  313. assertEquals(maps, tmap);
  314. Map<Integer, String> mapk = (Map<Integer, String>) exp.parseExpression(
  315. "maps.?[key > 2 and key < 4 ]").getValue(secontext);
  316. assertEquals(mapk, tmap);
  317. }
  318. /**
  319. * 投影表达式测试
  320. *
  321. * @throws Exception
  322. */
  323. @SuppressWarnings("unchecked")
  324. @Test
  325. public void testSpelProjectionExpression() throws Exception {
  326. spel.setNumbers(Arrays.asList(2, 3, 4, 5, 6));
  327. assertEquals(Arrays.asList(5, 6, 7, 8, 9),
  328. exp.parseExpression("numbers.![#this+3]").getValue(secontext));
  329. List<Integer> keys = (List<Integer>) exp.parseExpression("maps.![key]")
  330. .getValue(secontext);
  331. assertEquals(keys, Arrays.asList(1, 2, 3, 4));
  332. List<String> mapv = (List<String>) exp.parseExpression("maps.![value]")
  333. .getValue(secontext);
  334. assertEquals(mapv,
  335. Arrays.asList("string1", "string2", "string3", "String4"));
  336. List<Boolean> mapK = (List<Boolean>) exp.parseExpression(
  337. "maps.![key > 2 and value !='String4']").getValue(secontext);
  338. assertEquals(mapK, Arrays.asList(false, false, true, false));
  339. }
  340. /**
  341. * 模板语言测试
  342. *
  343. * @throws Exception
  344. */
  345. @Test
  346. public void testSpelTemplate() throws Exception {
  347. assertEquals(
  348. " this is a test 4",
  349. exp.parseExpression(" this is a test #{ maps.![key].get(3)}",
  350. new TemplateParserContext()).getValue(secontext,
  351. String.class));
  352. }
  353. }

【网络安全 | 渗透工具】密码字典生成工具crunch、cupp安装使用教程 Crunch是一个常用的密码破解工具,它可以根据指定的字符集、长度和模式生成各种可能的密码并进行暴力破解。同时,Crunch可以将生成的密码保存到文件中,以便在破解工具中使用。在进行渗透测试时,手动收集密码字典是十分耗时的,利用密码字典生成工具可以大幅缩短时间,提高爆破宽度。 阅读详情

相关推荐

【数字电源/MATLAB+PLECS】如何进行 Buck 数字电源仿真(二)PLECS 搭建开环 Buck 功率级

本文介绍了如何在PLECS中搭建开环Buck功率级模型,验证数字电源设计的基本思路。重点内容包括: 明确开发顺序:先开环验证功率级,再闭环设计控制器 搭建关键组件:输入电源、PWM模块、MOSFET开关、续流二极管、LC滤波电路及负载 设置初始参数:24V输入、12V输出、200kHz开关频率、22μH电感、100μF电容 测量关键波形:MOSFET Vds验证开关动作、电感电流纹波和输出电压稳态值 提供完整仿真模型和GitHub资源,便于读者复现验证 文章强调通过开环测试先确保功率级正确性,为后续闭环控制

weixin_43234123的博客 1218

spring el 三元表达式

前言 spring 5.0.6.RELEASE 三元表达式 spring el 的三元表达式提供了一个简便的写法,可以省略true的值,如下: ExpressionParser parser = new SpelExpressionParser(); String name = parser.parseExpression("name?:'Unknown'").getValue(String.class); System.out.println(name); // 'Unknown' 参考 htt

sayyy的专栏 1511

【学习记录】IIC驱动ICM42670+卡尔曼滤波+四元数姿态角解算

ICM42670陀螺仪可以使用iic驱动,单片机平台使用GD32f305VE。

liarsup的博客 8267

Spring SpEL表达式

Spring Expression Language (SpEL)语言支持在运行时操作和查询对象,其语法类似统一的EL语言,但是SpEL提供了额外的功能。SpEL支持以下功能: 文本表达式布尔类和关系操作正则表达式类表达式访问属性、数组、集合和map方法调用关系操作赋值操作调用构造函数Bean 引用数组构造内联list三元操作变量用户自定义函数集合投影集合选择模板表达式 使用SpEl进行表

fangchao3652 1144

Moveit Servo学习

MoveIt Servo功能与配置指南 摘要:本文介绍了MoveIt Servo的功能特性,包括支持关节速度、末端执行器速度和位置控制,以及安全功能如奇点检查、碰撞检测等。通过示例展示了如何运行伺服控制demo,详细解析了关键节点和话题。最后以睿尔曼rml_63机器人为例,讲解了如何自定义伺服配置文件,包括环境设置、输入输出参数配置、平滑滤波器和规划场景监控等关键配置项。文章提供了从基础使用到自定义机器人配置的完整指导,帮助开发者实现高效的实时运动控制。

Fisher的博客 1174

单片机控制双向可控硅的5种实用触发电路设计(附完整电路图)

本文深入解析了单片机控制双向可控硅的5种实用触发电路设计,涵盖从基础隔离到复杂负载驱动的实战方案。重点探讨了光电耦合器选型、过零检测同步、RC吸收电路精密计算以及应对感性负载和高噪声环境的加固策略,并提供了完整的电路图与调试避坑指南,旨在帮助开发者实现安全可靠的交流负载控制。

joy55的博客 2210

SpEL表达式

概观 Spring Expression Language(缩写为SpEL)是一种强大的表达式语言。在Spring产品组合中,它是表达式计算的基础。它支持在运行时查询和操作对象图,它可以与基于XML和基于注解的Spring配置还有bean定义一起使用。由于它能够在运行时动态分配值,因此可以为我们节省大量Java代码。 项目设置 对于Maven项目,应使用以下依赖项: 前两个依赖项 ...

HELLOW,文浩 2407

【碳排放数据集】全球近实时网格化二氧化碳排放数据集GRACED

【碳排放数据集】全球近实时网格化二氧化碳排放数据集GRACED

WW、forever的博客 146

Spring 表达式语言之 SpEL 语法

5.3 SpEL语法 5.3.1 基本表达式 一、字面量表达式: SpEL支持的字面量包括:字符串、数字类型(int、long、float、double)、布尔类型、null类型。 类型 示例 字符串 String str1 = parser.parseExpression(“‘Hello World!’”).getValue(String.class); Strin

夜-feng的专栏 1万+

YOLO+OpenClaw缺陷检测智能体 | 低代码工业质检自动化方案 | 含YOLO模型训练/智能体集成/任务全流程,支持离线日报/预警/趋势分析,解决实时性瓶颈问题(下篇)

某PCB板制造商需要对生产线上的PCB板进行缺陷检测,主要检测划痕、凹坑、污渍和裂纹等缺陷。原有人工检测方式效率仅为200件/小时,漏检率达5%,且检测人员长期工作易疲劳。

qq_36130719的博客 206

simulink的Sine Wave 模块详解

模块是 Simulink 中的一个信号源模块,用于生成正弦波信号。该模块可以根据设定的幅值、频率、相位和偏移量,在仿真过程中产生周期性的正弦波形。模块都能提供强有力的支持。通过深入了解其参数的影响及结合 MATLAB 脚本的应用,读者可以更加有效地利用这一模块进行仿真和研究。此外,通过实际应用场景的扩展以及常见问题解答部分的帮助,能够更好地掌握。模块是一个非常实用的工具,适用于需要生成正弦波信号的各种场景。模块的参数,可以进一步增强学习体验。模块参数的影响,下面我们将详细探讨每个参数如何影响仿真结果。

xiaoheshang_123的博客 1052

Spring框架学习--基础的SPEL表达式

Spring 3引入了Spring表达式语言(Spring Expression Language, 简称为SpEL) , 它能够以一种强大和简洁的方式将值装配到bean属性和构造器参数中, 在这个过程中所使用的表达式会在运行时计算得到值。 SpEL拥有很多特性, 包括: 1.使用bean的ID来引用bean; 2.调用方法和访问对象的属性; 3.对值进行算术、...

满屏尽是白日梦,记下梦中刃 2291

通用抓取————6D位姿估计

这意味着算法在没有物体的先验知识(如 CAD 模型)的情况下,依然能够通过神经网络捕捉物体的外观、形状和几何特征,生成相关的 6D 位姿估计。通过输入物体类别的描述,算法能够推断出该类别物体的位姿和尺度,无需特定物体的 CAD 模型。在这个坐标空间中,物体的位姿和尺度都是已知的,基于这个标准化表示,算法可以对输入图像中的物体进行 6D 位姿和尺寸的估计。○优势: ICP 是一种非常有效的位姿优化算法,特别适合精细调整物体的位姿,确保最终估计的位姿与真实物体的点云或模型高度一致。

具身机器人和通用AI 2380

Java中的SpEL表达式

Spring 3引入了Spring表达式语言( Spring Expression Language,SpEL),它能够以一种强大和简洁的方式将值装配到bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到值 SpEL拥有很多特性,包括: 使用bean的ID来引用bean 调用方法和访问对象的属性 对值进行算术、关系和逻辑运算 正则表达式匹配 集合操作 SpEL基础表达式 表示字面值 表示是浮点值 #{3.1415} 数值还可以使用科学记数法的方式进行表示 #{9.87E4} 表达式计

Mr. Xu的博客 3351

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Spring表达式语言SpEL简介

Spring3引入了Spring表达式语言(Spring Expression Language,SpEL)。 SpEL有很多特性,比较常用的包括: 1、使用bean的id来引用bean, 下面这个例子就是将卧室这个bean通过SpEL注入到house这个bean的bedroom属性中。       2、访问对象的属性和调用方法, 增加一个snoopy

达叔 1679

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Spring3.1——Spring表达式语言SpEL

创建步骤:      (1)创建ExpressionParser对象。表达式解析器。      (2)调用ExpressionParser对象的parseExpresssion方法解析字符串,得到Expression对象。      (3)调用Expression对象的getValue()方法,即可得到表达式的值。 eg1:基本语法 eg2:变量语法

ack_Finding的博客 503

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Spring之SpEL

前言Spring3引入了Spring表达式语言(SpEL),可以像jsp中的el表达式一样,在运行期动态执行,从而得到需要的值。 SpEL的特性包括: - 使用Bean的ID来引用Bean - 调用方法和访问对象的属性 - 对值进行算术、关系和逻辑运算 - 正则表达式匹配 - 集合操作字面值字面值是最简单的SpEL表达式。一个简单的SpEL表达式如下:<bean id="emp

stream的专栏 3259

Spring 3.0参考手册之SpEL

Spring 3.0 RC1发布,一些新特性很吸引人,看了一下Reference,顺便翻译了SpEL这节,水平有限,还望指教。 Spring 3.0 Reference:http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/index.html Part III 核心技术 6...

mmdev 239

Spring_表达式语言SpEl

Spring3引入了Spring表达式语言(Spring Expression Language,SpEL)。SpEL是一种强大的、简洁的装配Bean的方式,它通过运行期执行的表达式将值装配到Bean的属性或构造器参数中。1.字面值①我们可以在元素的value属性中使用#{}界定符将值装配到Bean的属性中。<property name="count" value="#{5}" />②浮点型数字一样

故园 454

Spring学习笔记--Spring表达式语言SpEL

Spring3引入了Spring表达式语言(Spring Expression Language,SpEL)。SpEL是一种强大的、简洁的装配Bean的方式,它通过运行期执行的表达式将值装配到Bean的属性或构造器参数中。字面值我们可以在&lt;property&gt;元素的value属性中使用#{}界定符将值装配到Bean的属性中。 &lt;property name="count" va...

weixin_34184158的博客 272

Spring 3.0参考之SpEL

Spring 3.0 RC1发布,一些新特性很吸引人,看了一下Reference,顺便翻译了SpEL这节,水平有限,还望指教。 Spring 3.0 Reference:http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/index.html    排版过的见:http://blog...

iteye_10762的博客 157

Spring表达式语言SpEL简单介绍

Spring3引入了Spring表达式语言(Spring Expression Language,SpEL)。 SpEL有非常多特性。比較经常使用的包含: 1、使用bean的id来引用bean, 以下这个样例就是将卧室这个bean通过SpEL注入到house这个bean的bedroom属性中。 &lt;bean id="bedroom" class="go.de...

weixin_34143774的博客 102
上一篇: EhCache介绍
下一篇: 脏读、不可重复读 共享锁、悲观锁 和 事务五种隔离级别
ppby2002
博客等级 码龄23年 65粉丝 104原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值