Velocity編碼式渲染模板
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 [email protected]
*
*/
@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 [email protected]
*
*/
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;
}
網上找了一圈參考資料: