前言
这个方案是基于这篇博客写的 https://www.cnblogs.com/xxt19970908/p/5553045.html
我在根据这个方案完成项目后在
发现报错,问题和这篇博客是一样的
https://www.oschina.net/question/1000732_132645?sort=time
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)
经过分析,是因为生成的spring 我配置的是截获所有的请求,而不是诸如.do .action类的后缀请求,所以生成的静态文件地址在转发时,又被截获。
问题的本质是这个原因,所以我们只要保证静态文件的转发地址不被截获就可以了
两个方案,
- 请求类的统一是.do .action之类
- 生成的静态文件路径不要被spring截获,所以我添加了一个前缀 lzStaticPages绕过spring的截获
/**
* 计算要生成的静态文件相对路径 因为大家在调试的时候一般在Tomcat的webapps下面新建站点目录的,
* 但在实际应用时直接布署到ROOT目录里面,这里要保证路径的一致性。
*
* @param request HttpServletRequest
* @return /目录/*.htm
*/
public static String getRequestHTML(HttpServletRequest request) {
// web应用名称,部署在ROOT目录时为空
String contextPath = request.getContextPath();
// web应用/目录/文件.do
String requestURI = request.getRequestURI();
// basePath里面已经有了web应用名称,所以直接把它replace掉,以免重复
requestURI = requestURI.replaceFirst(contextPath, "");
// 将.do改为.html,稍后将请求转发到此html文件
// requestURI = requestURI.substring(0, requestURI.indexOf(".")) + ".html";
requestURI = requestURI + ".html";
return "/lzStaticPages" + requestURI;
}
到此崩溃的问题处理了;
上面解决的是生成静态文件的问题,接下来我们要处理以什么样的策略显示静态文件的问题;
我的思路是:在构建静态文件时,配合缓存 redis memcache都可以了,添加一条文件创建信息 并设置过期时间;当用户请求时根据上述两个条件判断 是否存在可用的静态文件路径;如果存在则直接转发到静态文件地址,若不存在继续走freemarker的渲染;
Controller直接走下面的调用
@Autowired
MemCachedClient memCachedClient;
@RequestMapping("/toFreemarker")
public ModelAndView toFreemarker(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) {
FreeMarkerMvMaker mvMaker = new FreeMarkerMvMaker("/freemarker", memCachedClient);
mvMaker.put("username", "this is a test");
mvMaker.setLoad_mode(FreeMarkerMvMaker.LOAD_MODE.UPDATE_THEN_CATHE);
// mvMaker.setExpiredDate(new Date(System.currentTimeMillis() + 1000 * 60 * *60*24));//十分钟后到期
return mvMaker.create(request, response);
}
package com.oilsites.common.freemarkerView;
import com.danga.MemCached.MemCachedClient;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
public class LzFreeMarkerViewHelper {
/**
* 判断静态页面是否有效 是否需要生成
*
* @param request
* @param memCachedClient
* @return
*/
public static boolean isPageEffective(HttpServletRequest request, MemCachedClient memCachedClient) {
File file = new File(LzFreeMarkerView.getRequestHtmlAbsolutPath(request));
Object ResultObj = memCachedClient.get(LzFreeMarkerView.getRequestHTML(request));
return file.exists() && ResultObj != null;
}
}
package com.oilsites.common.freemarkerView;
import com.danga.MemCached.MemCachedClient;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
public class FreeMarkerMvMaker {
ModelAndView modelAndView;
MemCachedClient cachedClient;
Date expiredDate;
LOAD_MODE load_mode;
public FreeMarkerMvMaker(String viewName, MemCachedClient cachedClient) {
modelAndView = new ModelAndView(viewName);
this.cachedClient = cachedClient;
load_mode = LOAD_MODE.NO_CACHE;
}
public FreeMarkerMvMaker(ModelAndView modelAndView, MemCachedClient cachedClient) {
this.modelAndView = modelAndView;
this.cachedClient = cachedClient;
load_mode = LOAD_MODE.NO_CACHE;
}
public ModelAndView create(HttpServletRequest request, HttpServletResponse response) {
switch (load_mode) {
case NO_CACHE:
return modelAndView;
case CACHE_FIRST:
boolean pageEffective = LzFreeMarkerViewHelper.isPageEffective(request, cachedClient);
if (!pageEffective) {
if (expiredDate == null) {
expiredDate = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24);
}
cachedClient.add(LzFreeMarkerView.getRequestHTML(request), "isStatic", expiredDate);
modelAndView.addObject("CREATE_HTML", true);
return modelAndView;
} else {
try {
request.getRequestDispatcher(LzFreeMarkerView.getRequestHTML(request)).forward(request, response);
return null;
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
case UPDATE_THEN_CATHE:
if (expiredDate == null) {
expiredDate = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24);
}
cachedClient.add(LzFreeMarkerView.getRequestHTML(request), "isStatic", expiredDate);
modelAndView.addObject("CREATE_HTML", true);
return modelAndView;
}
return null;
}
public LOAD_MODE getLoad_mode() {
return load_mode;
}
public FreeMarkerMvMaker setLoad_mode(LOAD_MODE load_mode) {
this.load_mode = load_mode;
return this;
}
public FreeMarkerMvMaker put(String key, Object value) {
modelAndView.addObject(key, value);
return this;
}
public FreeMarkerMvMaker setExpiredDate(Date expiredDate) {
this.expiredDate = expiredDate;
return this;
}
public enum LOAD_MODE {
CACHE_FIRST, NO_CACHE, UPDATE_THEN_CATHE
}
}
网友评论