Spring MVC集成velocity扩展_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Spring MVC集成velocity扩展

Spring MVC集成velocity扩展

 2013/7/23 18:40:28  liufei.fir  程序员俱乐部  我要评论(0)
  • 摘要:本文主要讲述通过扩展SpringMVC集成velocity这一部分的功能,实现类似于webx的规约配置1、扩展velocity的视图扩展点:velocity的screen模板自动选择同名的layout模板,如果没有选择默认的layout模板,并注入除screen和layout之外的在模板文件根路径下的control工具bean,control可以作为公共课复用的模板,该bean和模板所在的文件名同名(这一点相对于webx是比较灵活的)。packageorg.christ.matrix
  • 标签:MVC Spring
本文主要讲述通过扩展Spring MVC集成velocity这一部分的功能,实现类似于webx的规约配置

1、扩展velocity的视图

扩 展点:velocity的screen模板自动选择同名的layout模板,如果没有选择默认的layout模板,并注入除screen和layout之 外的在模板文件根路径下的control工具bean,control可以作为公共课复用的模板,该bean和模板所在的文件名同名(这一点相对于 webx是比较灵活的)。
class="java" name="code">
package org.christ.matrix.template.velocity;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.tools.Scope;
import org.apache.velocity.tools.Toolbox;
import org.apache.velocity.tools.ToolboxFactory;
import org.apache.velocity.tools.config.XmlFactoryConfiguration;
import org.apache.velocity.tools.view.ViewToolContext;
import org.christ.matrix.template.TemplateVariable;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.support.ServletContextResource;
import org.springframework.web.servlet.view.velocity.VelocityToolboxView;

/**
 * 扩展velocity的视图解析器。
 * <p>
 * 自动匹配到Layout并扩展相关模板工具的Velocity视图。
 * 
 * @author 刘飞 E-mail:liufei_it@126.com
 * @version 1.0
 * @since 2013-7-1 上午11:06:59
 */
public class VelocityTemplateLayoutView extends VelocityToolboxView implements DefaultVelocityConfigurer {

	/** 模板文件的根路径目录 */
	protected String templates = null;
	/** screen模板解析的视图目录 */
	protected String screen = null;
	/** layout模板解析的视图目录 */
	protected String layout = null;

	/** velocity模板默认加载的layout模板 */
	protected String defaultLayoutTemplate = null;
	/** screen模板key */
	protected String screenTemplateKey = null;

	/** 本次请求对应的视图名称 */
	protected String viewName = null;
	/** 模板对应的扩展名称 */
	protected String suffix = null;

	protected List<Toolbox> toolboxs = new ArrayList<Toolbox>();

	@Override
	protected void doRender(Context context, HttpServletResponse response) throws Exception {
		Template screenTemplate = getTemplate();
		// 同名的layout
		String layoutTemplateURL = SYSTEM_SEPARATOR + templates + SYSTEM_SEPARATOR + layout + SYSTEM_SEPARATOR
				+ viewName + suffix;
		Template layoutTemplate = safeLoadLayoutTemplate(layoutTemplateURL);
		if (layoutTemplate == null) {// 默认的layout
			layoutTemplateURL = SYSTEM_SEPARATOR + templates + SYSTEM_SEPARATOR + layout + SYSTEM_SEPARATOR
					+ defaultLayoutTemplate;
			layoutTemplate = safeLoadLayoutTemplate(layoutTemplateURL);
		}
		if (layoutTemplate == null) {// 没有找到layout就只解析screen
			mergeTemplate(screenTemplate, context, response);
		} else {
			context.put(screenTemplateKey, templateRender(context, screenTemplate));
			mergeTemplate(layoutTemplate, context, response);
		}
	}

	@Override
	protected Context createVelocityContext(Map<String, Object> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ViewToolContext context = new ViewToolContext(getVelocityEngine(), request, response, getServletContext());
		context.putAll(model);

		if (!CollectionUtils.isEmpty(toolboxs)) {// 注入模板工具
			for (Toolbox toolbox : toolboxs) {
				context.addToolbox(toolbox);
			}
		}

		Map<String, Object> templateVariables = getApplicationContext().getBeansWithAnnotation(TemplateVariable.class);

		if (templateVariables != null && templateVariables.size() > 0) {
			for (Map.Entry<String, Object> e : templateVariables.entrySet()) {// 注入自定义工具
				context.put(e.getKey(), e.getValue());
			}
		}

		Map<String, VelocityTemplateController> controls = getApplicationContext().getBeansOfType(
				VelocityTemplateController.class, true, false);
		if (controls != null && controls.size() > 0) {// 注入control
			for (Map.Entry<String, VelocityTemplateController> e : controls.entrySet()) {
				String name = e.getKey();
				VelocityTemplateController controller = e.getValue();
				controller.setContext(context);
				controller.setVelocityEngine(getVelocityEngine());
				context.put(name, controller);
			}
		}

		return context;
	}

	/**
	 * 初始化工作。
	 * 
	 * @throws Exception
	 */
	protected void init() throws Exception {
		if (StringUtils.isBlank(templates)) {
			templates = DEFAULT_TEMPLATES;
		}
		if (StringUtils.isBlank(screen)) {
			screen = DEFAULT_SCREEN;
		}
		if (StringUtils.isBlank(layout)) {
			layout = DEFAULT_LAYOUT;
		}

		if (StringUtils.isBlank(defaultLayoutTemplate)) {
			defaultLayoutTemplate = DEFAULT_LAYOUT_TEMPLATE;
		}
		if (StringUtils.isBlank(suffix)) {
			suffix = DEFAULT_SUFFIX;
		}
		if (StringUtils.isBlank(screenTemplateKey)) {
			screenTemplateKey = DEFAULT_SCREEN_TEMPLATE_KEY;
		}

		if (StringUtils.isNotBlank(getToolboxConfigLocation())) {
			// 扩展使用velocity tools 2.0
			try {
				XmlFactoryConfiguration configuration = new XmlFactoryConfiguration();
				ServletContextResource resource = new ServletContextResource(getServletContext(),
						getToolboxConfigLocation());
				configuration.read(resource.getURL());
				ToolboxFactory factory = configuration.createFactory();
				if (factory.hasTools(Scope.APPLICATION)) {
					Toolbox applicationTool = factory.createToolbox(Scope.APPLICATION);
					if (applicationTool != null) {
						toolboxs.add(applicationTool);
					}
				}
				if (factory.hasTools(Scope.REQUEST)) {
					Toolbox requestTool = factory.createToolbox(Scope.REQUEST);
					if (requestTool != null) {
						toolboxs.add(requestTool);
					}
				}
				if (factory.hasTools(Scope.SESSION)) {
					Toolbox sessionTool = factory.createToolbox(Scope.SESSION);
					if (sessionTool != null) {
						toolboxs.add(sessionTool);
					}
				}
			} catch (Exception e) {
				logger.error(String.format("init toolbox [%s] error.", getToolboxConfigLocation()), e);
			}
		}
	}

	/**
	 * 安全的校验并获取layout模板。
	 * 
	 * @param layoutURL
	 * @return
	 */
	protected Template safeLoadLayoutTemplate(String layoutURL) {
		try {
			return getTemplate(layoutURL);
		} catch (Exception e) {
			if (logger.isDebugEnabled()) {
				logger.debug("Loading Layout Template: " + layoutURL, e);
			}
		}
		return null;
	}

	@Override
	public final void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		try {
			init();
		} catch (Exception e) {
			logger.error("VelocityTemplateLayoutView#init error.", e);
		}
	}

	@Override
	public boolean checkResource(Locale locale) throws Exception {

		if (StringUtils.isBlank(templates)) {
			if (logger.isErrorEnabled()) {
				logger.error("Property 'templates' is required.");
			}
			throw new IllegalArgumentException("Property 'templates' is required.");
		}
		if (StringUtils.isBlank(screen)) {
			if (logger.isErrorEnabled()) {
				logger.error("Property 'screen' is required.");
			}
			throw new IllegalArgumentException("screen 'screen' is required.");
		}
		if (StringUtils.isBlank(layout)) {
			if (logger.isErrorEnabled()) {
				logger.error("Property 'layout' is required.");
			}
			throw new IllegalArgumentException("screen 'layout' is required.");
		}

		if (StringUtils.isBlank(defaultLayoutTemplate)) {
			if (logger.isErrorEnabled()) {
				logger.error("Property 'defaultLayoutTemplate' is required.");
			}
			throw new IllegalArgumentException("screen 'defaultLayoutTemplate' is required.");
		}
		if (StringUtils.isBlank(suffix)) {
			if (logger.isErrorEnabled()) {
				logger.error("Property 'suffix' is required.");
			}
			throw new IllegalArgumentException("screen 'suffix' is required.");
		}
		if (StringUtils.isBlank(screenTemplateKey)) {
			if (logger.isErrorEnabled()) {
				logger.error("Property 'screenTemplateKey' is required.");
			}
			throw new IllegalArgumentException("screen 'screenTemplateKey' is required.");
		}

		if (StringUtils.isBlank(viewName)) {
			if (logger.isErrorEnabled()) {
				logger.error("Property 'viewName' is required.");
			}
			throw new IllegalArgumentException("screen 'viewName' is required.");
		}

		return super.checkResource(locale);
	}

	/**
	 * 渲染一个模板。
	 * 
	 * @param context
	 * @param template
	 * @return
	 */
	protected String templateRender(Context context, Template template) {
		if (template == null || context == null) {
			return null;
		}
		try {
			StringWriter sw = new StringWriter();
			template.merge(context, sw);
			return sw.toString();
		} catch (Exception e) {
			logger.error(String.format("Template[%s] Render Error.", template.getName()), e);
		}
		return null;
	}

	/**
	 * @return the templates
	 */
	public String getTemplates() {
		return templates;
	}

	/**
	 * @param templates
	 *            the templates to set
	 */
	public void setTemplates(String templates) {
		this.templates = templates;
	}

	/**
	 * @return the screen
	 */
	public String getScreen() {
		return screen;
	}

	/**
	 * @param screen
	 *            the screen to set
	 */
	public void setScreen(String screen) {
		this.screen = screen;
	}

	/**
	 * @return the layout
	 */
	public String getLayout() {
		return layout;
	}

	/**
	 * @param layout
	 *            the layout to set
	 */
	public void setLayout(String layout) {
		this.layout = layout;
	}

	/**
	 * @return the defaultLayoutTemplate
	 */
	public String getDefaultLayoutTemplate() {
		return defaultLayoutTemplate;
	}

	/**
	 * @param defaultLayoutTemplate
	 *            the defaultLayoutTemplate to set
	 */
	public void setDefaultLayoutTemplate(String defaultLayoutTemplate) {
		this.defaultLayoutTemplate = defaultLayoutTemplate;
	}

	/**
	 * @return the viewName
	 */
	public String getViewName() {
		return viewName;
	}

	/**
	 * @param viewName
	 *            the viewName to set
	 */
	public void setViewName(String viewName) {
		this.viewName = viewName;
	}

	/**
	 * @return the suffix
	 */
	public String getSuffix() {
		return suffix;
	}

	/**
	 * @param suffix
	 *            the suffix to set
	 */
	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}

	/**
	 * @return the screenTemplateKey
	 */
	public String getScreenTemplateKey() {
		return screenTemplateKey;
	}

	/**
	 * @param screenTemplateKey
	 *            the screenTemplateKey to set
	 */
	public void setScreenTemplateKey(String screenTemplateKey) {
		this.screenTemplateKey = screenTemplateKey;
	}
}


2、扩展velocity模板解析器来完成上述的规约配置。
/**
 * E-Mail : liufei_it@126.com, liufeiit@gmail.com, wb-liufei@taobao.com
 * QQ : 970275153
 */
package org.christ.matrix.template.velocity;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.christ.matrix.template.TemplateViewResolver;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.io.ClassRelativeResourceLoader;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.context.support.ServletContextResourceLoader;
import org.springframework.web.servlet.view.AbstractUrlBasedView;
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;

/**
 * 模板视图布局规则:
 * <p>
 * 指定模板文件的根路径目录,在该目录的子目录下指定一个目录作为screen模板解析的视图目录
 * <p>
 * 在该目录的子目录下指定一个目录作为layout模板解析的视图目录
 * <p>
 * 其余的子目录下的模板直接用其目录名称作为control对象直接引用即可。
 * 
 * @author 刘飞 E-mail:liufei_it@126.com
 * @version 1.0
 * @since 2013-6-30 下午01:36:58
 */
public class VelocityTemplateLayoutViewResolver extends VelocityViewResolver implements TemplateViewResolver,
		DefaultVelocityConfigurer {
	/** 加载control模板文件的编码 */
	protected String encoding = null;
	/** 模板文件的根路径目录 */
	protected String templates = null;
	/** screen模板解析的视图目录 */
	protected String screen = null;
	/** layout模板解析的视图目录 */
	protected String layout = null;

	/** velocity模板默认加载的layout模板 */
	protected String defaultLayoutTemplate = null;
	/** screen模板key */
	protected String screenTemplateKey = null;

	/** 资源加载器。 */
	protected ResourceLoader resourceLoader = new DefaultResourceLoader();
	/** {@link #templates} 下的control目录 */
	protected final List<File> controls = new ArrayList<File>();
	
	/** velocity模板contentType */
	protected String contentType = null;
	/** 约定:模板缓存上限,为-1的时候表示关闭,不配置的话默认是2048 */
	protected Integer cacheLimit = null;

	@Override
	protected Class<?> requiredViewClass() {
		return VelocityTemplateLayoutView.class;
	}

	@Override
	protected AbstractUrlBasedView buildView(String viewName) throws Exception {
		VelocityTemplateLayoutView view = VelocityTemplateLayoutView.class.cast(super.buildView(viewName));
		view.setCacheTemplate(true);
		view.setContentType(contentType);
		view.setTemplates(templates);
		view.setScreen(screen);
		view.setLayout(layout);
		view.setEncoding(encoding);
		view.setViewName(viewName);
		view.setSuffix(getSuffix());
		view.setScreenTemplateKey(screenTemplateKey);
		view.setDefaultLayoutTemplate(defaultLayoutTemplate);
		return view;
	}

	protected void controlBeanRegistry(BeanDefinitionRegistry registry) throws Exception {
		if (controls == null || controls.isEmpty()) {
			logger.debug("没有control需要配置.");
			return;
		}
		for (File controlFile : controls) {
			String absolutePath = controlFile.getAbsolutePath();
			String name = controlFile.getName();
			try {
				RootBeanDefinition controlBean = getDefaultRootBeanDefinition(VelocityTemplateController.class,
						"模板引擎扩展的control:" + name);
				MutablePropertyValues propertyValues = new MutablePropertyValues();
				propertyValues.addPropertyValue("encoding", encoding);
				/** 将control的绝对路径赋予 */
				propertyValues.addPropertyValue("control", SYSTEM_SEPARATOR + templates + SYSTEM_SEPARATOR + name
						+ SYSTEM_SEPARATOR);
				controlBean.setPropertyValues(propertyValues);
				registry.registerBeanDefinition(name, controlBean);
				logger.error(String.format("Registry control Named[%s] for template directory[%s] success.", name,
						absolutePath));
			} catch (Exception e) {
				logger.error(String.format("Registry control Named[%s] for template directory[%s] error.", name,
						absolutePath));
			}
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if (StringUtils.isBlank(templates)) {
			templates = DEFAULT_TEMPLATES;
		}
		if (StringUtils.isBlank(screen)) {
			screen = DEFAULT_SCREEN;
		}
		if (StringUtils.isBlank(layout)) {
			layout = DEFAULT_LAYOUT;
		}
		if (StringUtils.isBlank(encoding)) {
			encoding = DEFAULT_ENCODING;
		}

		if (StringUtils.isBlank(defaultLayoutTemplate)) {
			defaultLayoutTemplate = DEFAULT_LAYOUT_TEMPLATE;
		}
		if (StringUtils.isBlank(screenTemplateKey)) {
			screenTemplateKey = DEFAULT_SCREEN_TEMPLATE_KEY;
		}
		
		if (StringUtils.isEmpty(contentType)) {
			contentType = DEFAULT_CONTENT_TYPE;
		}
		
		if (StringUtils.isBlank(getSuffix())) {//默认配置
			setSuffix(DEFAULT_SUFFIX);
		}
		
		setPrefix(SYSTEM_SEPARATOR + templates + SYSTEM_SEPARATOR + screen + SYSTEM_SEPARATOR);// 设置prefix

		if (cacheLimit == null) {
			cacheLimit = CACHE_LIMIT;
		}
		if(cacheLimit != null && cacheLimit > 0) {
			setCacheLimit(cacheLimit);
			setCache(true);
		} else {
			setCache(false);
		}
		
		try {
			/** 模板根路径 */
			File templates = getTemplatesSource(SYSTEM_SEPARATOR + this.templates + SYSTEM_SEPARATOR);
			if (templates != null && templates.isDirectory()) {
				/** 过滤根路径下的control目录 */
				File[] controlTemplates = templates.listFiles(new FilenameFilter() {
					public boolean accept(File dir, String name) {
						if (StringUtils.equalsIgnoreCase(name, screen) || StringUtils.equalsIgnoreCase(name, layout)) {
							return false;
						}
						return true;
					}
				});
				if (ArrayUtils.isNotEmpty(controlTemplates)) {
					controls.addAll(Arrays.asList(controlTemplates));
				}
			}
		} catch (Exception e) {
			logger.error("加载control异常", e);
		}
	}
	
	/**
	 * 获取模板根路径文件。
	 * 
	 * @param templates
	 * @return
	 */
	protected File getTemplatesSource(String templatesPath) {
		File templates = null;
		try {
			templates = resourceLoader.getResource(templatesPath).getFile();
			if(templates != null) {
				return templates;
			}
		} catch (Exception e) {
			logger.warn(String.format("[%s] trying loading resource [%s] failure.", resourceLoader.getClass().getSimpleName(), templatesPath), e);
		}
		try {
			templates = new ServletContextResourceLoader(getServletContext()).getResource(templatesPath).getFile();
			if(templates != null) {
				return templates;
			}
		} catch (Exception e) {
			logger.error(String.format("[%s] trying loading resource [%s] failure.", ServletContextResourceLoader.class.getSimpleName(), templatesPath), e);
		}
		try {
			templates = new ClassRelativeResourceLoader(getClass()).getResource(templatesPath).getFile();
			if(templates != null) {
				return templates;
			}
		} catch (Exception e) {
			logger.error(String.format("[%s] trying loading resource [%s] failure.", ClassRelativeResourceLoader.class.getSimpleName(), templatesPath), e);
		}
		
		logger.error(String.format("trying loading resource [%s] failure.", templatesPath));
		return null;
	}

	/**
	 * 在这里将注入和各个目录对应的control
	 */
	@Override
	public final void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		try {
			if (beanFactory instanceof BeanDefinitionRegistry) {
				controlBeanRegistry(BeanDefinitionRegistry.class.cast(beanFactory));
			} else {
				logger.warn("ConfigurableListableBeanFactory can't be cast to BeanDefinitionRegistry.");
			}
			postProcessBeanFactory0(beanFactory);
		} catch (Exception e) {
			logger.error("注入和各个目录对应的control异常", e);
		}
	}

	/**
	 * 基础的RootBeanDefinition定义。
	 * 
	 * @param clazz
	 * @param description
	 * @return
	 */
	protected RootBeanDefinition getDefaultRootBeanDefinition(Class<?> clazz, String description) {
		RootBeanDefinition beanDefinition = new RootBeanDefinition(clazz);
		beanDefinition.setAbstract(false);
		beanDefinition.setAutowireCandidate(true);
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
		beanDefinition.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		beanDefinition.setDescription(description);
		beanDefinition.setLazyInit(false);
		beanDefinition.setScope(AbstractBeanDefinition.SCOPE_SINGLETON);
		return beanDefinition;
	}

	protected void postProcessBeanFactory0(ConfigurableListableBeanFactory beanFactory) throws Exception {
	}

	@Override
	public void setTemplates(String templates) {
		this.templates = templates;

	}

	@Override
	public void setScreen(String screen) {
		this.screen = screen;
	}

	@Override
	public void setLayout(String layout) {
		this.layout = layout;

	}

	/**
	 * @param resourceLoader
	 *            the resourceLoader to set
	 */
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

	/**
	 * @param encoding
	 *            the encoding to set
	 */
	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	/**
	 * @return the defaultLayoutTemplate
	 */
	public String getDefaultLayoutTemplate() {
		return defaultLayoutTemplate;
	}

	/**
	 * @param defaultLayoutTemplate
	 *            the defaultLayoutTemplate to set
	 */
	public void setDefaultLayoutTemplate(String defaultLayoutTemplate) {
		this.defaultLayoutTemplate = defaultLayoutTemplate;
	}

	/**
	 * @return the screenTemplateKey
	 */
	public String getScreenTemplateKey() {
		return screenTemplateKey;
	}

	/**
	 * @param screenTemplateKey
	 *            the screenTemplateKey to set
	 */
	public void setScreenTemplateKey(String screenTemplateKey) {
		this.screenTemplateKey = screenTemplateKey;
	}

	/**
	 * @return the encoding
	 */
	public String getEncoding() {
		return encoding;
	}

	/**
	 * @return the templates
	 */
	public String getTemplates() {
		return templates;
	}

	/**
	 * @return the screen
	 */
	public String getScreen() {
		return screen;
	}

	/**
	 * @return the layout
	 */
	public String getLayout() {
		return layout;
	}

	/**
	 * @return the resourceLoader
	 */
	public ResourceLoader getResourceLoader() {
		return resourceLoader;
	}
}

重新定义的解析器接口
/**
 * E-Mail : liufei_it@126.com, liufeiit@gmail.com, wb-liufei@taobao.com
 * QQ : 970275153
 */
package org.christ.matrix.template;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;

/**
 * 模板视图布局规则:
 * <p>
 * 指定模板文件的根路径目录,在该目录的子目录下指定一个目录作为screen模板解析的视图目录
 * <p>
 * 在该目录的子目录下指定一个目录作为layout模板解析的视图目录
 * <p>
 * 其余的子目录下的模板直接用其目录名称作为control对象直接引用即可。
 * 
 * @author 刘飞 E-mail:liufei_it@126.com
 * @version 1.0
 * @since 2013-6-30 上午11:58:41
 */
public interface TemplateViewResolver extends BeanFactoryPostProcessor, InitializingBean {

	/**
	 * 指定模板文件的根路径目录.
	 * 
	 * @param templates
	 */
	void setTemplates(String templates);

	/**
	 * 指定{@link #setTemplate(String)}一个目录作为screen模板解析的视图目录.
	 * 
	 * @param screen
	 */
	void setScreen(String screen);

	/**
	 * 指定{@link #setTemplate(String)}一个目录作为layout模板解析的视图目录
	 * 
	 * @param layout
	 */
	void setLayout(String layout);
}



发表评论
用户名: 匿名