FreeMarker(3)轻量的静态化方案

前言

这个方案是基于这篇博客写的 https://www.cnblogs.com/xxt19970908/p/5553045.html
我在根据这个方案完成项目后在

image.png

发现报错,问题和这篇博客是一样的
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类的后缀请求,所以生成的静态文件地址在转发时,又被截获。
问题的本质是这个原因,所以我们只要保证静态文件的转发地址不被截获就可以了
两个方案,

  1. 请求类的统一是.do .action之类
  2. 生成的静态文件路径不要被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
    }
}

你可能感兴趣的:(FreeMarker(3)轻量的静态化方案)