JSP/JSF中的“EL”有很多版本,Tomcat对应的EL版本如下:
- EL2.1:JavaEE5/Tomcat6 (Unified EL:${}和#{}作用相同但不能混用)
- EL2.2:JavaEE6/Tomcat7
- EL3.0:JavaEE7/Tomcat8
从JavaEE5开始,EL的package使用javax.el.*。这个EL功能不仅可以使用在JSP/JSF中,也可以使用在所有的Java代码中,el-api.jar、jasper-el.jar可以在Tomcat的lib文件夹中找到,放入自己的工程中即可使用。
(1)EL2.2
这个版本的EL还不怎么支持独立程序使用,用起来也比较复杂。需要用到的几个类:ELContext、FunctionMapper、VariableMapper、ELResolver。
最简单的使用
// (1)Resolver、VariableMapper、FunctionMapper都使用默认实现
final CompositeELResolver resolver = new CompositeELResolver();
resolver.add(new ResourceBundleELResolver());
resolver.add(new MapELResolver());
resolver.add(new ListELResolver());
resolver.add(new ArrayELResolver());
resolver.add(new BeanELResolver());
final VariableMapper varMapper = new VariableMapperImpl();
final FunctionMapper funcMapper = new FunctionMapperImpl();
// (2)创建ELContext
ELContext elContext = new ELContext() {
@Override
public ELResolver getELResolver() {
return resolver;
}
@Override
public FunctionMapper getFunctionMapper() {
return funcMapper;
}
@Override
public VariableMapper getVariableMapper() {
return varMapper;
}
};
// (3)EL表达式工厂类
ExpressionFactory ef = ExpressionFactory.newInstance();
// (4)设置变量的值
varMapper.setVariable("foo", ef.createValueExpression("FOO", String.class));
MyBean myBean = new MyBean();
myBean.setX(1);
myBean.setY(2);
varMapper.setVariable("bar", ef.createValueExpression(myBean, myBean.getClass()));
// (5)读入EL表达式
String expression = "hello, ${foo}! ${bar.x + 234}";// 等价于"hello, #{foo}! #{bar.x + 234}"
ValueExpression ve = ef.createValueExpression(elContext, expression, String.class);
// (6)获取表达式的值
String ret = (String) ve.getValue(elContext);
System.out.println("result=" + ret);// result=hello, FOO! 235
// 更新变量值(对象实例的场合,原有实例的值也会被修改)
String expression2 = "${bar.x}";
ValueExpression ve2 = ef.createValueExpression(elContext, expression2, Object.class);
ve2.setValue(elContext, 123);
System.out.println("myBean.x=" + myBean.getX());// myBean.x=123
// 调用对象实例的方法
String expression31 = "${bar.mes('hello')}";
MethodExpression me1 = ef.createMethodExpression(elContext, expression31, Object.class, new Class[0]);
me1.invoke(elContext, new Object[0]);// mes=hello
String expression32 = "#{bar.mes}";
MethodExpression me2 = ef.createMethodExpression(elContext, expression32, Object.class, new Class[] {String.class});
me2.invoke(elContext, new Object[] {"hello"});// mes=hello
public class MyBean {
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void mes(String mes) {
System.out.println("mes=" + mes);
}
@Override
public String toString() {
return "(x: " + x + ", y:" + y + ")";
}
}
设置预定义变量
final CompositeELResolver resolver = new CompositeELResolver();
resolver.add(new ResourceBundleELResolver());
resolver.add(new MapELResolver());
resolver.add(new ListELResolver());
resolver.add(new ArrayELResolver());
resolver.add(new BeanELResolver());
resolver.add(new MyImplicitELResolver());// *****添加自定义Resolver*****
final VariableMapper varMapper = new VariableMapperImpl();
final FunctionMapper funcMapper = new FunctionMapperImpl();
ELContext elContext = new ELContext() {
@Override
public ELResolver getELResolver() {
return resolver;
}
@Override
public FunctionMapper getFunctionMapper() {
return funcMapper;
}
@Override
public VariableMapper getVariableMapper() {
return varMapper;
}
};
ExpressionFactory ef = ExpressionFactory.newInstance();
List<String> lst = Arrays.asList("aaa", "bbb", "ccc", "ddd");
varMapper.setVariable("list", ef.createValueExpression(lst, List.class));
// 包含预定义变量implicit的EL表达式
String expression = "${list[implicit.idx]}";
ValueExpression ve = ef.createValueExpression(elContext, expression, String.class);
// 设置预定义变量implicit的Context
ImplicitContext implicitContext = new ImplicitContext();
elContext.putContext(ImplicitContext.class, implicitContext);
for (int idx = 0; idx < lst.size(); idx++) {
implicitContext.put("idx", Integer.valueOf(idx));
String ret = (String) ve.getValue(elContext);
System.out.println("ret[" + idx + "]=" + ret);
}
// ret[0]=aaa
// ret[1]=bbb
// ret[2]=ccc
// ret[3]=ddd
public class ImplicitContext extends HashMap<String, Object> {}
public class MyImplicitELResolver extends ELResolver {
@Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
if (base == null) {
return String.class;
}
return null;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(
ELContext context, Object base) {
if (base != null) {
return Collections.<FeatureDescriptor>emptyList().iterator();
}
return null;
}
@Override
public Class<?> getType(ELContext context, Object base, Object property) {
if (base == null && property != null) {
String name = property.toString();
if ("implicit".equals(name)) {
context.setPropertyResolved(true);
return ImplicitContext.class;
}
}
return null;
}
@Override
public Object getValue(ELContext context, Object base, Object property) {
if (base == null && property != null) {
String name = property.toString();
if ("implicit".equals(name)) {
context.setPropertyResolved(true);
return context.getContext(ImplicitContext.class);
}
}
return null;
}
@Override
public boolean isReadOnly(ELContext context, Object base, Object property) {
return true;
}
@Override
public void setValue(ELContext context, Object base, Object property, Object value) {
throw new PropertyNotWritableException("base=" + base + "/property=" + property);
}
}
自定义函数
final CompositeELResolver resolver = new CompositeELResolver();
resolver.add(new ResourceBundleELResolver());
resolver.add(new MapELResolver());
resolver.add(new ListELResolver());
resolver.add(new ArrayELResolver());
resolver.add(new BeanELResolver());
final VariableMapper varMapper = new VariableMapperImpl();
// *****定义FunctionMapper*****
final FunctionMapper funcMapper = new FunctionMapper() {
private HashMap<String, Method> methods = new HashMap<String, Method>();
{
for (Method method : Math.class.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) {
String name = method.getName();
Class<?>[] params = method.getParameterTypes();
boolean accept = true;
if (params.length > 0) {
if (!params[0].isAssignableFrom(double.class)) {
accept = false;
}
}
if (accept) {
methods.put(name, method);
}
}
}
}
@Override
public Method resolveFunction(String prefix, String localName) {
if ("math".equals(prefix)) {
return methods.get(localName);
}
return null;
}
};
ELContext elContext = new ELContext() {
@Override
public ELResolver getELResolver() {
return resolver;
}
@Override
public FunctionMapper getFunctionMapper() {
return funcMapper;
}
@Override
public VariableMapper getVariableMapper() {
return varMapper;
}
};
ExpressionFactory ef = ExpressionFactory.newInstance();
varMapper.setVariable("a", ef.createValueExpression(10, Integer.class));
varMapper.setVariable("b", ef.createValueExpression(20, Integer.class));
String expression = "max=${math:max(a,b)}, min=${math:min(a,b)}";
ValueExpression ve = ef.createValueExpression(elContext, expression, String.class);
String ret = (String) ve.getValue(elContext);
System.out.println("ret=" + ret);// ret=max=20.0, min=10.0
(2)EL3.0
在最新版的EL3.0中,Java代码中可以通过ELProcessor来很简单的使用EL。
ELProcessor elProc = new ELProcessor();
// 设置变量
elProc.defineBean("foo", new BigDecimal("123"));
elProc.defineBean("bar", "brabrabra");
// 获取表达式的值getValue()
String expression = "bar += '☆' += foo"; // 不需要使用${}或#{}
String ret1 = (String)elProc.getValue(expression, String.class);
System.out.println("ret=" + ret1);// ret=brabrabra☆123
// 获取表达式的值eval()
Number ret2 = (Number)elProc.eval("foo + 1");
System.out.println("ret=" + ret2);// ret=124
// 变量的嵌套
elProc.setVariable("v1", "foo * 2");
Number ret3 = (Number)elProc.eval("v1 + 1");
System.out.println("ret=" + ret3);// ret=247
Number ret4 = (Number)elProc.eval("v1 + foo");
System.out.println("ret=" + ret4);// ret=369
// 给不存在的变量设置值
elProc.setValue("baz", "1234");
Number ret5 = (Number)elProc.eval("baz + 1");
System.out.println("ret=" + ret5);// ret=1235
// 设置其他类型的变量
elProc.eval("qux = [1,2,3,4]");
elProc.eval("map = {'a': 111, 'b': 222}");
System.out.println("qux=" + elProc.getValue("qux", Object.class));// qux=[1, 2, 3, 4]
System.out.println("map=" + elProc.getValue("map", Object.class));// map={b=222, a=111}
// 计算多个表达式
Integer ret6 = (Integer) elProc.getValue("x=1;y=2;z=x+y", Integer.class);
System.out.println("ret=" + ret6);// ret=3
// 静态变量
elProc.defineBean("Color", new ELClass(java.awt.Color.class));
Color color = (Color) elProc.eval("Color.red");
System.out.println("ret=" + color);// ret=java.awt.Color[r=255,g=0,b=0]
// 默认导入了「java.lang.*」
System.out.println("ret=" + elProc.eval("Math.random()"));
// 自定义函数
Method method = MyClass.class.getMethod("strJoin", new Class[] {String.class, List.class});
elProc.defineFunction("myFn", "join", method);
Object ret = elProc.eval("myFn:join(',', ['aaa', 'bbb', 'ccc', 123])");
System.out.println("ret=" + ret);// ret=aaa,bbb,ccc,123
// 计算lambda表达式
List<Integer> listdata = Arrays.asList(1, 2, 3, 4, 5, 6);
elProc.defineBean("list", listdata);
String lambda1 = "sum=0;list.stream().forEach(x->(sum=sum+x));sum";
Number ret8 = (Number) elProc.eval(lambda1);
System.out.println("ret=" + ret8.intValue());// ret=21
String lambda1b = "list.stream().sum()";
Number ret9 = (Number) elProc.eval(lambda1b);
System.out.println("ret=" + ret9.intValue());// ret=21
String lambda1c = "list.stream().reduce(0,(a,b)->a+b)";
Number ret10 = (Number) elProc.eval(lambda1c);
System.out.println("ret=" + ret10.intValue());// ret=21
public class MyClass {
public static String strJoin(String sep, List<Object> args) {
StringBuilder buf = new StringBuilder();
if (args != null) {
for (Object arg : args) {
if (buf.length() > 0) {
buf.append(sep);
}
buf.append(arg != null ? arg.toString() : "");
}
}
return buf.toString();
}
}