zoukankan      html  css  js  c++  java
  • Spring MVC + freemarker实现半自动静态化

    这里对freemarker的代码进行了修改,效果:
    1,请求.do的URL时直接生成对应的.htm文件,并将请求转发到该htm文件
    2,自由控制某个页面是否需要静态化
    原理:对org.springframework.web.servlet.view.freemarker.FreeMarkerView类进行扩展
    第一步:在web.xml中将*.do请求交给SpringMVC

    <servlet>
          <servlet-name>demo</servlet-name>
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
          <init-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>/WEB-INF/demo-servlet.xml</param-value>
          </init-param>
          <load-on-startup>1</load-on-startup>
      </servlet>
    
      <servlet-mapping>
          <servlet-name>demo</servlet-name>
          <url-pattern>*.do</url-pattern>
      </servlet-mapping>

     

    第二步:配置/WEB-INF/demo-servlet.xml

    <!--freemarker页面解析器 -->
     <bean id="viewResolver"  class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
            <property name="suffix" value=".ftl"></property>
            <property name="contentType" value="text/html;charset=UTF-8" />
           <!-- <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" /> -->
            <!-- 将Spring的FreeMarkerView改成我们扩展的View -->
            <property name="viewClass" value="com.myview.MyFreeMarkerView" />
            <property name="exposeRequestAttributes" value="true" />
            <property name="exposeSessionAttributes" value="true" />
            <property name="exposeSpringMacroHelpers" value="true" />
     </bean>
    <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />
    
    <!--配置Freemarker -->
    <bean id="freemarkerConfigurer"  class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
            <property name="templateLoaderPath" value="/WEB-INF/freemarker/"></property>
            <property name="freemarkerVariables">
                <map>
                    <entry key="xml_escape" value-ref="fmXmlEscape" />
                </map>
            </property>
            <property name="freemarkerSettings">
                <props>
                    <prop key="template_update_delay">1</prop>
                    <prop key="defaultEncoding">UTF-8</prop>
                </props>
            </property>
      </bean>

     

    第三步:新建package,com.myview,新建一个MyFreeMarkerView,继承自org.springframework.web.servlet.view.freemarker.FreeMarkerView,在这里对原类进行扩展

    package com.myview;
    
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.io.Writer;
    import java.util.Locale;
    import java.util.Map;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.web.servlet.support.RequestContextUtils;
    import org.springframework.web.servlet.view.freemarker.FreeMarkerView;
    import freemarker.template.SimpleHash;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;
    
    public class MyFreeMarkerView extends FreeMarkerView{
        @Override
        protected void doRender(Map<String, Object> model,
                HttpServletRequest request, HttpServletResponse response)
                throws Exception {
            // Expose model to JSP tags (as request attributes).
            exposeModelAsRequestAttributes(model, request);
            // Expose all standard FreeMarker hash models.
            SimpleHash fmModel = buildTemplateModel(model, request, response);
    
            if (logger.isDebugEnabled()) {
                logger.debug("Rendering FreeMarker template [" + getUrl() + "] in FreeMarkerView '" + getBeanName() + "'");
            }
    
            // Grab the locale-specific version of the template.
            Locale locale = RequestContextUtils.getLocale(request);       
    
            /*
             * 默认生成静态文件,除非在编写ModelAndView时指定CREATE_HTML = false,
             * 这样对静态文件生成的粒度控制更细一点
             * 例如:ModelAndView mav = new ModelAndView("search");
             *       mav.addObject("CREATE_HTML", false);
             */
            if(Boolean.FALSE.equals(model.get("CREATE_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);
                //静态页面绝对路径
                String htmlPath = basePath + requestHTML;         
                File htmlFile = new File(htmlPath);
                if(!htmlFile.getParentFile().exists()){
                    htmlFile.getParentFile().mkdirs();
                }
                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);
    
        }
    
        /**
         * 计算要生成的静态文件相对路径
         * 因为大家在调试的时候一般在Tomcat的webapps下面新建站点目录的,
         * 但在实际应用时直接布署到ROOT目录里面,这里要保证路径的一致性。
         * @param request HttpServletRequest
         * @return /目录/*.htm
         */
         private String getRequestHTML(HttpServletRequest request){
            //web应用名称,部署在ROOT目录时为空
            String contextPath = request.getContextPath();
            //web应用/目录/文件.do
            String requestURI = request.getRequestURI();
            //basePath里面已经有了web应用名称,所以直接把它replace掉,以免重复
            requestURI = requestURI.replaceFirst(contextPath, "");
            //将.do改为.htm,稍后将请求转发到此htm文件
            requestURI = requestURI.substring(0, requestURI.indexOf(".")) + ".htm";
            return requestURI;
         }
    
    }

     

     到这里就基本完成了。

    一个Controller类的例子:

    Java code

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.servlet.ModelAndView;
    
    @Controller
    public class IndexController {
        @RequestMapping("/index.do")
        public ModelAndView index(){
            ModelAndView mav = new ModelAndView("index");
            mav.addObject("title", "网站标题");
            mav.addObject("origin", "freemarker");
            //在这里可以控制不生成静态htm
            mav.addObject("CREATE_HTML", false);
            return mav;
        }
    
        @RequestMapping("/abc/index.do")
        public ModelAndView abcindex(){
            ModelAndView mav = new ModelAndView("index");
            mav.addObject("origin", "html");
            //默认生成htm文件
            mav.addObject("title", "网站标题");
            return mav;
        }
    }

     

    测试结果如下:

  • 相关阅读:
    几个新角色:数据科学家、数据分析师、数据(算法)工程师
    人类投资经理再也无法击败电脑的时代终将到来了...
    Action Results in Web API 2
    Multiple actions were found that match the request in Web Api
    Routing in ASP.NET Web API
    how to create an asp.net web api project in visual studio 2017
    网站漏洞扫描工具
    How does asp.net web api work?
    asp.net web api history and how does it work?
    What is the difference between a web API and a web service?
  • 原文地址:https://www.cnblogs.com/lxl57610/p/7043619.html
Copyright © 2011-2022 走看看