Velocity与Struts 1.* -- VM展示

在Struts中有两种使用Velocity的方法,一种是利用Velocity的vm模板进行页面展示,一种则是利用Velocity来生成静态页面。以下介绍在Struts 1.*版本中使用Velocity的vm模板显示。

在Struts 1.*版本中,并未支持对vm模板的显示,所以当ActionForward指向一个vm模板时,只会将模板中的Velocit语句当做普通字符内容显示出来,而不对其中的Velocity语句进行任何解析及赋值。所以在Struts 1.*版本中使用Velocity,需要在web.xml中配置VelocityViewServlet,以处理后缀为.vm的模板文件。

在web.xml中进行如下配置:
<servlet>
	<servlet-name>velocity</servlet-name>
	<servlet-class>
org.apache.velocity.tools.view.servlet.VelocityViewServlet
</servlet-class>
	<init-param>
		<param-name>org.apache.velocity.toolbox</param-name>
		<param-value>/WEB-INF/toolbox.xml</param-value>
	</init-param>
	<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>velocity</servlet-name>
	<url-pattern>*.vm</url-pattern>
</servlet-mapping>

这样当ActionForward指向一个后缀为vm的模板时,该Servlet便会进行对vm模板的解析及赋值工作。
在web.xml中配置Struts 1.2的ActionServlet步骤省略。

vm模板:namelist.vm
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
	<title>StrutsSample_1</title>
</head>
<body>
	<h3>StrutsSample</h3>
	<table width="400" border="1">
		#foreach($name in $list)
		<tr> <td>$name</td> </tr>
		#end
	</table>
</body>
</html>


Struts Action
public class StrutsSample extends DispatchAction {
	public ActionForward showNameList(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		ActionForward forward = new ActionForward();
		ActionMessages errors = new ActionMessages();
		List<String> list = new ArrayList<String>();
		String name = null;
		for(int i=0;i<20;i++){
			name = "Hoffman "+i+" Name";
			list.add(name);
		}
		request.setAttribute("list", list);
		if (!errors.isEmpty()) {
			saveErrors(request, errors);
			forward = new ActionForward(mapping.getInput());
		} else {
			forward = new ActionForward("/namelist.vm");
		}
		return forward;
	}
}

这里需要注意forward = new ActionForward("/namelist.vm");这句,因为在velocity.properties中已经配置了模板存放位置,所以这里直接可以指定模板名称。需要注意的是这里和Servlet中应用不同,Servlet是通过getTemplate("sample.vm")来获取模板,而Struts则是通过转发,所以模板前需要加上/。关于在servlet中使用velocity,请参考本博客的《Velocity简单示例源码解析》一文)

Struts配置
<struts-config>
	<action-mappings>
		<action path="/StrutsSample" parameter="dispatch" scope="request"
				type="com.mixele.velocity.struts.StrutsSample" validate="true">
			<forward name="namelist" path="/templates/namelist.vm"  redirect="false"/>	
		</action>	
	</action-mappings>
</struts-config>


浏览器输入:http://localhost:8080/Mixele_Velocity/StrutsSample.do?dispatch=showNameList
便可看到处理结果。

在Struts的Action中,只做了对用户请求的处理,以及回复工作,和vm模板解析相关的所有工作,由VelocityViewServlet完成。
在web.xml中配置VelocityViewServlet后,当系统启动时,VelocityViewServlet类会初始化。

VelocityViewServlet初始化过程
public void init(ServletConfig config) throws ServletException {
	super.init(config);
	initVelocity(config); //初始化Velocity
	initToolbox(config); //初始化Servlet的toolbox
	//当Velocity初始化后,可以获取以下这些(默认内容类型、模板字符编码)
	defaultContentType = RuntimeSingleton.getString(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
	String encoding = RuntimeSingleton.getString(
			RuntimeSingleton.OUTPUT_ENCODING, DEFAULT_OUTPUT_ENCODING);
	if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding)) {
		int index = defaultContentType.lastIndexOf("charset");
		if (index < 0) {
			defaultContentType += "; charset=" + encoding;
		} else {
			Velocity.warn("VelocityViewServlet: Charset was already "
					+ "specified in the Content-Type property.  "
					+ "Output encoding property will be ignored.");
		}
	}
	Velocity.info("VelocityViewServlet: Default content-type is: " + defaultContentType);
}

/** 初始化Velocity */
protected void initVelocity(ServletConfig config) throws ServletException {
	Velocity.setApplicationAttribute(SERVLET_CONTEXT_KEY, getServletContext());
	// default to servletlogger, which logs to the servlet engines log
	Velocity.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
			ServletLogger.class.getName());
	// by default, load resources with webapp resource loader
	Velocity.setProperty(RuntimeConstants.RESOURCE_LOADER, "webapp");
	Velocity.setProperty("webapp.resource.loader.class", WebappLoader.class.getName());
	// Try reading an overriding Velocity configuration
	try {
		ExtendedProperties p = loadConfiguration(config); //读取配置文件(velocity.properties)
		Velocity.setExtendedProperties(p);
	} catch (Exception e) {
		……源码省略……
	}
	try {
		Velocity.init(); //now all is ready - init Velocity
	} catch (Exception e) {
		getServletContext().log(
				"VelocityViewServlet: PANIC! unable to init() - " + e);
		throw new ServletException(e);
	}
}

/** 读取Velocity配置文件velocity.properties中的配置
 * 若该文件不存在,使用默认配置,即org/apache/velocity/tools/view/servlet/velocity.properties */
protected ExtendedProperties loadConfiguration(ServletConfig config) throws IOException {
	ServletContext servletContext = config.getServletContext();
	//获取Velocity文件的路径
	String propsFile = config.getInitParameter(INIT_PROPS_KEY);
	if (propsFile == null || propsFile.length() == 0) {
		propsFile = servletContext.getInitParameter(INIT_PROPS_KEY);
	}
	ExtendedProperties p = new ExtendedProperties();
	if (propsFile != null) {
		p.load(servletContext.getResourceAsStream(propsFile));
		Velocity.info("VelocityViewServlet: Custom Properties File: " + propsFile);
	} else {
		Velocity.info("VelocityViewServlet: No custom properties found. "
				+ "Using default Velocity configuration.");
	}
	return p;
}

/** 读取Velocity Tools配置文件toolbox.xml中的配置
 * 若该文件不存在,使用Velocity Tools的默认配置 */
protected void initToolbox(ServletConfig config) throws ServletException {
	ServletContext servletContext = config.getServletContext();
	/* 检查Servlet配置中关于toolbox的配置(即/WEB-INF/toolbox.xml) */
	String file = config.getInitParameter(TOOLBOX_KEY);
	System.out.println("VelocityViewServlet == initToolbox == file = "+file);
	/* check the servlet context for a toolbox */
	if (file == null || file.length() == 0) {
		file = servletContext.getInitParameter(TOOLBOX_KEY);
	}
	/* if we have a toolbox, get a manager for it */
	if (file != null) {
		toolboxManager = ServletToolboxManager.getInstance(servletContext, file);
	} else {
		Velocity.info("VelocityViewServlet: No toolbox entry in configuration.");
	}
}

和在Servlet中使用Velocity一样,只是在初始化的过程中增加了读取Velocity Tools配置文件的步骤。
当Action跳转打到VM文件时,VelocityViewServlet类会对VM类型文件进行解析和赋值处理。
过程如下:
doGet() --> doRequest() --> createContext() --> setContentType() --> handleRequest() --> getTemplate() --> mergeTemplate() --> getResponseWriter() --> requestCleanup()

doGet():复写的HttpServlet方法,以获取用户的request
doRequest():这是处理vm的主要方法,在其中调用了以下方法:
createContext() – 获取Velocity的上下文
setContentType() – 设置HttpServletResponse的内容类型
handleRequest() – 使用模板处理请求(这个方法通过模板路径返回一个模板对象)
mergeTemplate() – 将模板和嵌入模板中的值合并
requestCleanup() – 应该是资源回收的方法,不过源码里是个空方法
通过以上的方法,VelocityViewServlet类对vm的解析赋值完成。

你可能感兴趣的:(xml,Web,servlet,struts,velocity)