开发者社区> 问答> 正文

spring mvc用freemarker进行页面静态化?报错

这是spring-mvc.xml里对freemarker的相关配置

<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="suffix" value=".ftl" /> <property name="contentType" value="text/html; charset=UTF-8" /> <!-- 将Spring的FreeMarkerView改成我们扩展的View --> <property name="viewClass" value="xidian.hy.wendu.test.freemarker.ExFreeMarkerView" /> <property name="exposeSpringMacroHelpers" value="true" /> <property name="exposeRequestAttributes" value="true" /> <property name="exposeSessionAttributes" value="true" /> <property name="exposePathVariables" value="true" /> <property name="allowSessionOverride" value="true" /> </bean>

<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />

<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <!-- 指定FreeMarker模板文件目录 --> <property name="templateLoaderPath" value="/WEB-INF/test/" /> <property name="freemarkerVariables"> <map> <entry key="xml_escape" value-ref="fmXmlEscape" /> </map> </property> <property name="freemarkerSettings"> <props> <prop key="defaultEncoding">UTF-8</prop> <prop key="locale">zh_CN</prop> </props> </property> </bean>

这是VIEW类

public class ExFreeMarkerView extends FreeMarkerView {

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

		SimpleHash fmModel = buildTemplateModel(model, request, response);

		if (logger.isDebugEnabled()) {
			logger.debug("Rendering FreeMarker template [" + getUrl() + "] in FreeMarkerView '" + getBeanName() + "'");
		}

		Locale locale = RequestContextUtils.getLocale(request);

		/*
		 * 在这里我们默认生成<strong>静态</strong>文件,当ModelAndView有指定STATIC_HTML = false时,就不会输出HTML文件 例如:ModelAndView modelAndView = new ModelAndView("htmlTest"); modelAndView.addObject("STATICHTML", false);
		 */
		if (Boolean.FALSE.equals(model.get("STATIC_HTML"))) {
			processTemplate(getTemplate(locale), fmModel, response);
		} else {
			createHTML(getTemplate(locale), fmModel, request, response);
		}
	}

	public void createHTML(Template template, SimpleHash model, HttpServletRequest request, HttpServletResponse response) throws IOException,
			TemplateException, ServletException {
		//站点根目录的绝对路径  
		String basePath = request.getSession().getServletContext().getRealPath("/");
		String requestHTML = this.getRequestHTML(request);
		//<strong>静态</strong><strong>页面</strong>绝对路径  
		String htmlPath = basePath + requestHTML;
		File htmlFile = new File(htmlPath);

		if (!htmlFile.getParentFile().exists()) {
			htmlFile.getParentFile().mkdirs();
		}

		/**
		 * 如果<strong>静态</strong><strong>页面</strong>已经存在,就不再创建<strong>静态</strong><strong>页面</strong>.
		 */
		if (!htmlFile.exists()) {
			htmlFile.createNewFile();
			Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(htmlFile), "UTF-8"));
			//处理模版    
			template.process(model, out);
			out.flush();
			out.close();
		}
		/* 将请求转发到生成的htm文件 */
		request.getRequestDispatcher(requestHTML).forward(request, response);
	}

	/**
	 * 计算要生成的<strong>静态</strong>文件相对路径.
	 */
	private String getRequestHTML(HttpServletRequest request) {

		//web应用名称,部署在ROOT目录时为空  
		String contextPath = request.getContextPath();

		//web应用/目录/文件.do  
		String requestURI = request.getRequestURI();

		//basePath里面已经有了web应用名称,所以直接把它replace掉,以免重复  
		requestURI = requestURI.replaceFirst(contextPath, "");
		//将请求改为.htm,稍后将请求转发到此htm文件  
		requestURI += ".htm";
		return requestURI;
	}

}


结果在继承了FreeMarkerView的类里生成好了静态页面进行重跳转

request.getRequestDispatcher("statictest.htm").forward(request, response);

的时候报错

javax.servlet.ServletException: Cannot expose bind macro helper 'springMacroRequestContext' because of an existing model object of the same name
	at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:156)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:262)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1180)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:950)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:749)
	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:487)
	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:412)
	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339)
	at xidian.hy.wendu.test.freemarker.ExFreeMarkerView.createHTML(ExFreeMarkerView.java:76)
	at xidian.hy.wendu.test.freemarker.ExFreeMarkerView.doRender(ExFreeMarkerView.java:43)
	at org.springframework.web.servlet.view.freemarker.FreeMarkerView.renderMergedTemplateModel(FreeMarkerView.java:233)
	at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:167)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:262)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1180)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:950)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:119)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1852)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:722)

展开
收起
爱吃鱼的程序员 2020-06-22 14:31:16 948 0
1 条回答
写回答
取消 提交回答
  • https://developer.aliyun.com/profile/5yerqm5bn5yqg?spm=a2c6h.12873639.0.0.6eae304abcjaIB

    我又来自己解决问题了...

    起初我就怀疑是因为我springmvc拦截了所有/请求的关系,所以我新建了一个项目,controller是以.do为结尾的拦截,果然这次没有出现任何问题,成功静态化.

    这个和以前我使用AOP的时候出现的一个小问题有点像,就是当时把满足get*的方法都拦截了,结果出现了tomcat启动报错,把外延缩小以后,成功启动.说明在以所以get开头的方法里包含到了spring启动的方法.所以在/拦截里可能也发生了这样的错误

    需要看一下你的View是怎么写的,AbstractTemplateView的renderMergedOutputModel()要求model中的springMacroRequestContext应该由他自己添加,确认下是否有占用或有重复调用,实在不行debug一下,看看哪些地方往Model添加了这个的属性
    断点下来发现在被拦截进入这个类的时候就已经存在了,按照配置来看exposeSpringMacroHelpers这个属性应该就是对应这个问题的,因为allowSessionOverride解决了Cannotexposesessionattribute'xxx'becauseofanexistingmodelobjectofthesamename这个异常,

    freemarker这玩意太恐怖了,崩一堆错误出来,然后页面布局就撑爆了。

    错误的第一句很明显。。。不好意思anexistingmodelobjectofthesamenameatorg.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel,我以为他有用呢,不过这个问题没遇到过。第一个只截取了部分..很不错的功能哦,帮忙一块加入 springrain吧

    下面 request.getRequestDispatcher(requestHTML).forward(request,response);还是会再次进入这个viewer。当第二次执行

    exposeModelAsRequestAttributes(model,request);

    的时候spring觉得这是不安全的,就报错了

    我也发现这个问题了。那要怎么解决呢~
    2020-06-23 11:58:02
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud 微服务核心组件集 mica 的设计思路 立即下载
workshop专场-微服务专场-开发者动手实践营-微服务-Spring Cloud Alibaba 微服务全家桶体验 立即下载
云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧 立即下载

相关实验场景

更多