1. 程式人生 > >Velocity編碼式渲染模板

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;
	}
	


網上找了一圈參考資料: