QLexpress实现Spring的融合–Set方法注入
对于qlExpress脚本引擎来说,能否调用spring bean的方法?怎么调用?是一个非常常见的问题。本文章主要讲述我是如何实现Spring注入属性(Set方法)与QLexpress组件的融合,请阅读下面的案例。
第一步:定义变量并进行变量的封装
这里我创建了UserDo对变量进行封装,保证代码的灵活性。详细代码如下:
public class UserDO {
private String nick;
private Long userId;
private Date gmtCreate;
private String position;
private Double salary;
public String getNick() {
return nick;
}
public void setNick(String nick) {
this.nick = nick;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Date getGmtCreate() {
return gmtCreate;
}
public void setGmtCreate(Date gmtCreate) {
this.gmtCreate = gmtCreate;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
}
第二步:利用Set方法向Spring容器内注入Bean属性
这里采用的是利用Set方法将属性注入到Spring容器中,Spring配置文件会自动配置属性注入,代码如下:
public class BizLogicBean {
public UserDO getUserInfo(String nick) {
if (nick.equals("小王")) {
UserDO userDO = new UserDO();
userDO.setNick(nick);
userDO.setGmtCreate(new Date());
userDO.setUserId(10086L);
userDO.setPosition("salesman");
userDO.setSalary(5000.0);
return userDO;
} else if (nick.equals("马总")) {
UserDO userDO = new UserDO();
userDO.setNick(nick);
userDO.setGmtCreate(new Date());
userDO.setUserId(1L);
userDO.setPosition("boss");
userDO.setSalary(999999999999.0);
return userDO;
}
return null;
}
}
第三步:获取Spring容器中的属性值
紧接着上一步,获取到Spring容器中的属性值,代码如下:
public class QLExpressContext extends HashMap<String, Object> implements IExpressContext<String, Object> {
private final ApplicationContext applicationContext;
public QLExpressContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public QLExpressContext(Map<String, Object> properties, ApplicationContext applicationContext) {
super(properties);
this.applicationContext = applicationContext;
}
/**
* 抽象方法:根据名称从属性列表中提取属性值
*/
@Override
public Object get(Object name) {
Object result;
result = super.get(name);
try {
if (result == null && this.applicationContext != null
&& this.applicationContext.containsBean((String)name)) {
// 如果在Spring容器中包含bean,则返回String的Bean
result = this.applicationContext.getBean((String)name);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
}
第四步:通过扩展IExpressContext->QLExpressContext,打通spring容器
这一步是关键,通过runner初始化获取到spring容器中的属性值,代码如下:
public class QlExpressUtil implements ApplicationContextAware {
private static final ExpressRunner runner;
static {
runner = new ExpressRunner();
}
private static boolean isInitialRunner = false;
private ApplicationContext applicationContext;// spring上下文
/**
* @param statement 执行语句
* @param context 上下文
* @throws Exception
*/
@SuppressWarnings("unchecked")
public Object execute(String statement, Map<String, Object> context) throws Exception {
initRunner(runner);
IExpressContext expressContext = new QLExpressContext(context, applicationContext);
return runner.execute(statement, expressContext, null, true, false);
}
private void initRunner(ExpressRunner runner) {
if (isInitialRunner) {
return;
}
synchronized (runner) {
if (isInitialRunner) {
return;
}
try {
runner.addFunctionOfServiceMethod("读取用户信息", applicationContext.getBean("bizLogicBean"), "getUserInfo",
new Class[] {String.class}, null);
runner.addMacro("判定用户是否vip", "userDO.salary>200000");
} catch (Exception e) {
throw new RuntimeException("初始化失败表达式", e);
}
}
isInitialRunner = true;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
第五步:测试是否成功引用到spring容器中的Bean属性
利用Junit对代码块进行测试,代码如下:
public class SpringDemoTest extends UnitilsJUnit4 {
@SpringBeanByName
private QlExpressUtil qlExpressUtil;
@Test
public void testScript() throws Exception {
String express = ""
+ "if(bizLogicBean.getUserInfo(nick)!=null) {"
+ " userDO = bizLogicBean.getUserInfo(nick);"
+ " if(userDO.salary>20000 && userDO.salary<20000) {"
+ " System.out.println('高级客户:'+userDO.nick);"
+ " } else if(userDO.salary>=200000) {"
+ " System.out.println('vip客户:'+userDO.nick);"
+ " } else {"
+ " System.out.println('普通客户:'+userDO.nick);"
+ " }"
+ "} else {"
+ " System.out.println('用户信息不存在');"
+ "}";
Map<String, Object> context = new HashMap<>();
context.put("nick", "马总");
qlExpressUtil.execute(express, context);
context.put("nick", "小王");
qlExpressUtil.execute(express, context);
context.put("nick", "XXX");
qlExpressUtil.execute(express, context);
}
@Test
public void testScript2() throws Exception {
String express = ""
+ "userDO = 读取用户信息(nick);"
+ "if(userDO != null) {"
+ " if(判定用户是否vip)"//直接中文代码,这就很好理解了!!
+ " System.out.println('vip客户:' + nick);"
+ "} else {"
+ " System.out.println('用户信息不存在,nick:' + nick);"
+ "}";
Map<String, Object> context = new HashMap<>();
context.put("nick", "马总");
qlExpressUtil.execute(express, context);
context.put("nick", "小王");
qlExpressUtil.execute(express, context);
context.put("nick", "XXX");
qlExpressUtil.execute(express, context);
}
}
testScript测试结果:
testScript2测试结果:
PS:小编是引用GitHub上面的源码举例,希望大家能够理解其中的原理,有问题请联系QQ:1443497132