spring mvc整合velocity源码分析

一、首先复习下velocity模板的使用

package com.springmvc.controller;

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

public class VelocityTest {

	public static void main(String[] args) throws Exception {

		VelocityContext context = new VelocityContext();
		fillData(context);
		
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));

		new VelocityEngine().getTemplate("/src/main/resources/test.vm").merge(context, writer);

		writer.flush();
		writer.close();

	}
	
	static void fillData(VelocityContext context){
		//填充list
		List<String> list = new ArrayList<String>();
		list.add("list-a");
		list.add("list-b");
		list.add("list-c");
		context.put("list", list);
		//填充map
		Map<String, String> map = new LinkedHashMap<String, String>();
		map.put("key1", "map-val1");
		map.put("key2", "map-val2");
		map.put("key3", "map-val3");
		context.put("map", map);
		//填充JavaBean
		List<User> userList = new ArrayList<User>();
		userList.add(new User("username1", 18))	;
		userList.add(new User("username2", 19));
		context.put("userlist", userList);
	}

}
package com.springmvc.controller;

public class User {

	private String name;

	private int age;
	
	public User(){
		
	}
	
	public User(String name, int age){
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

/src/main/resources/test.vm文件:

list:
	#foreach($str in $list)
    	${str}
    #end

map:
    #foreach($ma in $map.entrySet())
    	$!{ma.key}      ${ma.value}
    #end

bean:
    #foreach($user in $userlist)
	    $!{user.name}
	    $!{user.age}
    #end

控制台输出:

list:
	    	list-a
        	list-b
        	list-c
    
map:
        	key1      map-val1
        	key2      map-val2
        	key3      map-val3
    
bean:
    	    username1
	    18
    	    username2
	    19

二、SpringMVC整合velocity

1.首先看下springMVC整合velocity的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

	<!-- 扫描controller -->
	<context:component-scan base-package="com.springmvc.controller" />

	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
	
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
		<property name="messageConverters">
			<list>
				<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
			</list>
		</property>
	</bean>

	<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
		<property name="cache" value="true" />
		<property name="prefix" value="" />
		<property name="suffix" value=".vm" />
		<property name="contentType">
			<value>text/html;charset=UTF-8</value>
		</property>
	</bean>

	<bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
		<property name="resourceLoaderPath" value="/WEB-INF/velocity/" />
		<property name="velocityProperties">
			<props>
				<prop key="input.encoding">utf-8</prop>
				<prop key="output.encoding">utf-8</prop>
			</props>
		</property>
	</bean>

</beans>

其中类VelocityViewResolver是velocity的视图解析类,用于生成velocity视图类,该类最调用velocity的api解析vm文件,并将Controler传入的map对象(模型)传入velocity,类VelocityConfigurer是velocity的配置类。

1)DispatcherServlet取得ModelAndView:

由SpringMVC的核心DispatcherServlet收到请求,其service方法经过一层层调用,找到请求处理适配器HandlerAdapter(本例中是RequestMappingHandlerAdapter),调用对应的类的相应方法,最终得到一个ModelAndView类。



2)取得VelocityViewResolver:

DispatcherServlet继续调用processDispatchResult方法,该方法调用void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) 方法,render方法调用resolveViewName方法,该方法取得配置中的VelocityViewResolver,

3) VelocityView视图类的生成:

VelocityViewResolver调用基类的

AbstractUrlBasedView buildView(String viewName)

------>AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());

        方法,生成VelocityView类。

其中viewClass是VelocityViewResolver在构造方法中调用父类的方法setViewClass初始化的。

	public VelocityViewResolver() {
		setViewClass(requiredViewClass());
	}

	/**
	 * Requires {@link VelocityView}.
	 */
	@Override
	protected Class requiredViewClass() {
		return VelocityView.class;
	}

4) velocity页面渲染:

VelocityView类调用父类的render方法,方法签名是:

public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception

        render方法调用VelocityView实现的renderMergedTemplateModel方法:

	@Override
	protected void renderMergedTemplateModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		exposeHelpers(model, request);

		Context velocityContext = createVelocityContext(model, request, response);
		exposeHelpers(velocityContext, request, response);
		exposeToolAttributes(velocityContext, request);

		doRender(velocityContext, response);
	}

        renderMergedTemplateModel方法继续调用doRender方法:

	protected void doRender(Context context, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("Rendering Velocity template [" + getUrl() + "] in VelocityView '" + getBeanName() + "'");
		}
		mergeTemplate(getTemplate(), context, response);
	}
        其中mergeTemplate方法实现如下:

	protected void mergeTemplate(
			Template template, Context context, HttpServletResponse response) throws Exception {

		try {
			template.merge(context, response.getWriter());
		}
		catch (MethodInvocationException ex) {
			Throwable cause = ex.getWrappedThrowable();
			throw new NestedServletException(
					"Method invocation failed during rendering of Velocity view with name '" +
					getBeanName() + "': " + ex.getMessage() + "; reference [" + ex.getReferenceName() +
					"], method '" + ex.getMethodName() + "'",
					cause==null ? ex : cause);
		}
	}
        以上的步骤简要概括如下:

i)通过createVelocityContext方法生成VelocityContext对象,其构造参数是Map model;

ii)通过getTemplate方法取得Template对象,该对象是使用VelocityEngine的getTemplate方法生成,而VelocityEngine则是VelocityView(实现了ApplicationContextAware接口)通过spring容器经VelocityConfigurer取得,VelocityEngine是VelocityConfigurer类在afterPropertiesSet中初始化的成员变量。

iii)通过template.merge(context, response.getWriter())方法将页面通过response的writer进行输出。

至此,整个velocity渲染的过程结束。

总结:

1.springMVC和velocity整合点是在DispatcherServlet的resolveViewName方法,通过spring配置中的的ViewResolver类,生成velocity的视图类VelocityView(包含视图模板的文件名),视图的渲染是在该类中进行的;

        2.通过springMVC的Controller生成的ModelMap对象创建velocity的Context对象;

        3.VelocityView实现了ApplicationContextAware接口,通过Spring容器,经spring配置文件中定义的VelocityConfig的实现,得到VelocityEngine,VelocityEngine生成Template对象。

        4.通过VelocityView得到视图对应的文件名,通过HttpServletResponse对象得到输出Writer,调用Template的merge( Context context, Writer writer)方法,输出页面。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值