美文网首页
FreeMarker(3)轻量的静态化方案

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

作者: NoChangeNoValue | 来源:发表于2018-04-27 16:29 被阅读100次

    前言

    这个方案是基于这篇博客写的 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)轻量的静态化方案

          本文链接:https://www.haomeiwen.com/subject/srqilftx.html