今天我正试图从Freemarker迁移到Tiles2 + Freemarker。
我的freemarker模板使用来自spring.ftl的宏。
如果我在web.xml中提供了fremarker servlet,我的模型对于freemarker是可见的,但是特定的spring变量(自然地)没有填充到模型中,因为FreemarkerView对它负责。
如果我为特定的url配置一个单独的DispatcherServlet(比如“/ tpl / *”)并将freemarker resolver配置为该servlet的默认视图解析器并提供UrlFilenameViewController作为默认控制器,那么特殊的spring变量会填充到模型中,但是我的自己的模型不可见:它被绑定为请求属性。我可以通过$ {Request.mymodel.myvar}访问我的模型,但这样我就必须更改所有我的freemarker模板,我发现这个想法有点臭。
现在我的解决方案是扩展UrlFilenameViewController并将我的模型从请求添加到ModelAndView:
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = super.handleRequestInternal(request, response);
HashMap<String, Object> map = new HashMap<String, Object>();
Enumeration<String> attributes = request.getAttributeNames();
while(attributes.hasMoreElements()) {
String attribute = attributes.nextElement();
if("model".equals(attribute)) {
logger.debug("FreemarkerViewController.handleRequestInternal: putting attribute to model: " + attribute + "=" + request.getAttribute(attribute));
map.put(attribute, request.getAttribute(attribute));
}
}
logger.debug("FreemarkerViewController.handleRequestInternal: VIEW: " + mav.getViewName());
return new ModelAndView(mav.getViewName(), map);
}
但是这个解决方案有点臭 - 如果我在我的业务控制器中向模型中添加一些东西,我必须在这里添加它。
我的问题有优雅的解决方案吗?
答案 0 :(得分:1)
我记得我在两个项目中解决了同样的问题。
你的第二种方法几乎是正确的(FreeMarkerViewResolver
),但如果我没记错的话,我还必须从FreeMarkerView
和TilesView
扩展到明确地将两个模型连接在一起。
自定义平铺视图:
public class CustomTilesView extends TilesView {
@Override
protected void exposeModelAsRequestAttributes(Map model, HttpServletRequest request) {
request.setAttribute(CustomFreeMarkerView.MODEL_KEY, model);
}
}
自定义FreeMarker视图:
public class CustomFreeMarkerView extends FreeMarkerView {
public static final String MODEL_KEY = FreeMarkerView.class.getName() + ".MODEL";
@Override
protected void exposeHelpers(Map model, HttpServletRequest request) throws Exception {
super.exposeHelpers(model, request);
final Map savedModel = (Map) request.getAttribute(MODEL_KEY);
if (savedModel != null) {
mergeModels(model, savedModel);
}
}
private void mergeModels(Map<String, Object> targetModel, Map<String, Object> recipientModel) throws ServletException {
for (Map.Entry<String, Object> entry : recipientModel.entrySet()) {
String key = entry.getKey();
if (targetModel.containsKey(key)) {
throw new ServletException("Cannot merge models because of an existing model object of the same name: " + key);
}
targetModel.put(key, entry.getValue());
}
}
}
在Spring中注册:
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
p:viewClass="com.my.CustomTilesView"
p:contentType="text/html;charset=UTF-8"/>
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"
p:suffix=".ftl"
p:exposeSpringMacroHelpers="true"
p:viewClass="com.my.CustomFreeMarkerView"
p:contentType="text/html;charset=UTF-8"/>
应该工作。