Velocity通常作为页面前端的模板渲染引擎,在spring中配置好就OK了。在某些特殊情况下也会需要使用编码式方式调用它,小试了一把。
过于简单,就直接贴代码了。
import java.io.StringWriter;
import java.util.Date;
import junit.framework.TestCase;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import com.xxx.common.lang.util.DateUtil;
/**
*
*
* @author Lucas
*
*/
public class VelocityProgramaticCallTest extends TestCase {
public void testVelocity() {
Velocity.init();
Template template = Velocity.getTemplate("src/test/resources/vm/helloworld.vm");
VelocityContext context = new VelocityContext();
StringWriter writer = new StringWriter();
context.put("username", "麦子");
context.put("companyName", "Easylife ltd.");
context.put("now", DateUtil.simpleDate(new Date()));
template.merge(context, writer);
System.out.println(writer.toString());
}
}
helloworld.vm
<html>
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
hello,dear $username
<br />
Welcome to our website.Hope you have a great time.
<br />
$companyName
$now
</body>
</html>
通常,我们会在应用中使用自定义的一些工具类来完成特殊的展示需求,比如,用DateUtil来格式化日期,用StringUtil来处理字符串等等。以下代码加入了此类功能
注意前提是系统中加载了spring并且是文本环境,并在文件中配置了velocityConfig.当然其实其他系统方式也是一致的。
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.tools.ToolContext;
import org.apache.velocity.tools.ToolManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.velocity.VelocityConfig;
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
import com.xxx.common.lang.util.StringUtil;
import com.xxx.common.enums.EasylifeExceptionEnum;
import com.xxx.common.exception.BusinessException;
/**
*
*
* @author lvchen@yiji.com
*
*/
@Component
public class VelocityParser {
@Autowired
private VelocityConfig velocityConfig;
/**
* 使用velocity引擎解析指定路径下的文件模板
* @param templateFilePath 模板文件路径
* @param params 参数
* @return 解析后的结果
*/
public String parse(String templateFilePath, Map<String, Object> params, HttpServletRequest req) {
String parsed = null;
if (StringUtil.isEmpty(templateFilePath)) {
throw new BusinessException(EasylifeExceptionEnum.INVALID_ARGUMENT_EXCEPTION, "模板路径为空");
}
try {
VelocityEngine velocityEngine = velocityConfig.getVelocityEngine();
ToolManager toolManager = new ToolManager();
String realPath = req.getServletContext().getRealPath("/");
toolManager.configure(realPath + "WEB-INF\\config\\velocity-toolbox.xml");
ToolContext toolContext = toolManager.createContext();
StringWriter sw = new StringWriter();
VelocityContext velocityContext = new VelocityContext(params, toolContext);
velocityEngine.mergeTemplate(templateFilePath, "UTF-8", velocityContext, sw);
parsed = sw.toString();
} catch (Exception e) {
throw new BusinessException(e, EasylifeExceptionEnum.EXECUTE_FAIL);
}
return parsed;
}
}
顺便说说解决这个问题中遇到的坑和感悟吧。
1.最为光火的问题是,我按照官方的方式编写了上面的代码,但是无论如何不生效。看了半天spring配置文件中配置的org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver和org.springframework.web.servlet.view.velocity.VelocityConfigurer源码都得不到任何有用信息。之后我联想到系统启动时报的warning,toolbox的配置格式已经是deprecated的了,于是就把toolbox的格式配置改了,就成功了。汗啊~
2.关于上面提到的两个组件VelocityLayoutViewResolver和VelocityConfigurer。VelocityConfigurer是一个用来配置velocity的配置器,启动时会被调用,而VelocityLayoutViewResolver推测是在resolve模板的时候才会使用到,而toolbox这个玩意儿不是在系统启动的时候初始化velocityEngine时加载的而是在resolve的时候再添加进去的。
后续:
修改了toolbox.xml之后编码式调用可以使用自定义的工具类了,但是页面渲染又不行了。google一番,发现spring竟然不支持最新的toolbox,需要自定义一个velocityview来覆盖才可以...我这里继承了VelocityLayoutView,是为了实现layout。
贴出代码:
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
import org.apache.velocity.tools.config.ConfigurationUtils;
import org.apache.velocity.tools.config.FactoryConfiguration;
import org.apache.velocity.tools.view.ViewToolContext;
import org.apache.velocity.tools.view.ViewToolManager;
import org.springframework.web.servlet.view.velocity.VelocityLayoutView;
/**
*
*
* @author lvchen@yiji.com
*
*/
public class VelocityUpgradedToolBoxView extends VelocityLayoutView {
private static final String TOOL_MANAGER_KEY = ViewToolManager.class.getName();
/**
* @param model
* @param request
* @param response
* @return
* @throws Exception
* @see org.springframework.web.servlet.view.velocity.VelocityToolboxView#createVelocityContext(java.util.Map,
* javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
@Override
protected Context createVelocityContext(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
ServletContext application = getServletContext();
ViewToolManager toolManager = (ViewToolManager) application.getAttribute(TOOL_MANAGER_KEY);
if (toolManager == null) {
toolManager = createToolManager(getVelocityEngine(), getToolboxConfigLocation(),
application);
application.setAttribute(TOOL_MANAGER_KEY, toolManager);
}
ViewToolContext toolContext = toolManager.createContext(request, response);
if (model != null) {
toolContext.putAll(model);
}
return toolContext;
}
private ViewToolManager createToolManager(VelocityEngine velocity, String toolFile,
ServletContext application) {
ViewToolManager toolManager = new ViewToolManager(application, false, false);
toolManager.setVelocityEngine(velocity);
// generic & view tools config
FactoryConfiguration config = ConfigurationUtils.getVelocityView();
// user defined tools config
if (toolFile != null) {
FactoryConfiguration userConfig = ConfigurationUtils.load(application
.getRealPath(toolFile));
config.addConfiguration(userConfig);
}
toolManager.configure(config);
return toolManager;
}
网上找了一圈参考资料:
1.关于velocity代码概念,介绍的稍微详细点的:velocity官方开发者介绍(英文)
4.stackoverflow上关于调用新的velocityView的讨论