最近遇到一个问题,是在SpringMVC+FreeMarker项目的使用了一个base参数,${base}可一直报没有此参数定义异常。在网上查了很多资料,说是可以直接使用。后面才发现这个参数是由Structs 传递给FreeMarker的。如果在系统中并没有使用Structs框架是没有这个参数的。
如果我们想通过这个参数取得程序的根路径,则需要自己写一个FreeMarker的解析器,进行设置这个参数。
代码如下:
<bean id="freemarkerViewResolver" class="com.onlineexam.exam.core.common.interceptor.SimpleFreeMarkerViewResolver">
<property name="suffix" value=".html"/>
<property name="prefix" value="/exam/"/>
<property name="contentType" value="text/html; charset=UTF-8"/>
<property name="exposeRequestAttributes" value="false"/>
<property name="exposeSessionAttributes" value="false"/>
<property name="exposeSpringMacroHelpers" value="true"/>
bean>
设置自己的视图解析器
com.onlineexam.exam.core.common.interceptor.SimpleFreeMarkerViewResolver 代码如下
package com.onlineexam.exam.core.common.interceptor;
import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
import org.springframework.web.servlet.view.AbstractUrlBasedView;
/**
* ViewResolver for SimpleFreeMarkerView
*
* Override buildView, if viewName start with / , then ignore prefix.
*/
public class SimpleFreeMarkerViewResolver extends AbstractTemplateViewResolver {
/**
* Set default viewClass
*/
public SimpleFreeMarkerViewResolver() {
setViewClass(SimpleFreeMarkerView.class);
}
/**
* if viewName start with / , then ignore prefix.
*/
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
AbstractUrlBasedView view = super.buildView(viewName);
// start with / ignore prefix
if (viewName.startsWith("/")) {
view.setUrl(viewName + getSuffix());
}
return view;
}
}
这个类里用了一个设置base参数的类 SimpleFreeMarkerView
package com.onlineexam.exam.core.common.interceptor;
import java.io.IOException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContextException;
import org.springframework.web.servlet.view.AbstractTemplateView;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
/**
* 轻量级的FreeemarkerView
*
* 不支持jsp标签、不支持request、session、application等对象,可用于前台模板页面。
*/
public class SimpleFreeMarkerView extends AbstractTemplateView {
/**
* 部署路径调用名称
*/
public static final String CONTEXT_PATH = "base";
private Configuration configuration;
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
protected Configuration getConfiguration() {
return this.configuration;
}
/**
* 自动检测FreeMarkerConfig
*
* @return
* @throws BeansException
*/
protected FreeMarkerConfig autodetectConfiguration() throws BeansException {
try {
return (FreeMarkerConfig) BeanFactoryUtils
.beanOfTypeIncludingAncestors(getApplicationContext(),
FreeMarkerConfig.class, true, false);
} catch (NoSuchBeanDefinitionException ex) {
throw new ApplicationContextException(
"Must define a single FreeMarkerConfig bean in this web application context "
+ "(may be inherited): FreeMarkerConfigurer is the usual implementation. "
+ "This bean may be given any name.", ex);
}
}
/**
* Invoked on startup. Looks for a single FreeMarkerConfig bean to find the
* relevant Configuration for this factory.
*
* Checks that the template for the default Locale can be found: FreeMarker
* will check non-Locale-specific templates if a locale-specific one is not
* found.
*
* @see freemarker.cache.TemplateCache#getTemplate
*/
protected void initApplicationContext() throws BeansException {
super.initApplicationContext();
if (getConfiguration() == null) {
FreeMarkerConfig config = autodetectConfiguration();
setConfiguration(config.getConfiguration());
}
checkTemplate();
}
/**
* Check that the FreeMarker template used for this view exists and is
* valid.
*
* Can be overridden to customize the behavior, for example in case of
* multiple templates to be rendered into a single view.
*
* @throws ApplicationContextException
* if the template cannot be found or is invalid
*/
protected void checkTemplate() throws ApplicationContextException {
try {
// Check that we can get the template, even if we might subsequently
// get it again.
getConfiguration().getTemplate(getUrl());
} catch (ParseException ex) {
throw new ApplicationContextException(
"Failed to parse FreeMarker template for URL [" + getUrl()
+ "]", ex);
} catch (IOException ex) {
throw new ApplicationContextException(
"Could not load FreeMarker template for URL [" + getUrl()
+ "]", ex);
}
}
@SuppressWarnings("unchecked")
@Override
protected void renderMergedTemplateModel(Map model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
model.put(CONTEXT_PATH, request.getContextPath());
getConfiguration().getTemplate(getUrl()).process(model,
response.getWriter());
}
}