Java代码中使用JSP/JSF表达式语言EL

JSP/JSF中的“EL”有很多版本,Tomcat对应的EL版本如下:
Java代码中使用JSP/JSF表达式语言EL_第1张图片
  • 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();
    }
}

你可能感兴趣的:(java)