• 利用freemarker 静态化网页


    1、介绍-FreeMarker是什么

         模板引擎:一种基于模板的、用来生成输出文本的通用工具

         基于Java的开发包和类库

        

    2、介绍-FreeMarker能做什么

         MVC框架中的View层组件

         Html页面静态化

        代码生成工具

        CMS模板引擎

      页面栏目动态定制

    3、介绍-为什么要用FreeMarker

          程序逻辑(Java 程序)和页面设计(FreeMarker模板)分离

          分层清晰,利于分工合作

          主流Web框架良好的集成(struts2,springmvc)

          简单易学、功能强大

          免费开源

    4、FreeMarker优点

         FreeMarker不依赖于Servlet,网络或Web 环境

         FreeMarker一开始就是为MVC设计的,它仅仅专注于展示

         你可以从任意位置加载模板;从类路径下,从数据库中等

         易于定义特设的宏和函数

    5、上面简单介绍一下Freemarker,下面主要是利用Freemarker实习网页静态化的功能。

    通过上面的介绍知道Freemarker是一种基于模板的、用来生成输出文本的通用工具,所以我们必须要定制符合自己业务的模板出来,然后生成的我们得html页面

    Freemarker是通过freemarker.template.Configuration这个对象对模板进行加载的(它也处理创建和缓存预解析模板的工作),然后我们通过getTemplate方法获得你想要的模板,有一点要记住freemarker.template.Configuration在你整个应用必须保证唯一实例。

    5.1、在Configuration 中可以使用下面的方法来方便建立三种模板加载

    1. void setDirectoryForTemplateLoading(File dir);  
    1. void setClassForTemplateLoading(Class cl, String prefix);  
    1. void setServletContextForTemplateLoading(Object servletContext, String path);  

    上述的第一种方法在磁盘的文件系统上设置了一个明确的目录,它确定了从哪里加载模板。不要说可能,File 参数肯定是一个存在的目录。否则,将会抛出异常。
    第二种调用方法使用了一个Class 类型的参数和一个前缀。这是让你来指定什么时候通过相同的机制来加载模板,不过是用Java 的ClassLoader 来加载类。这就意味着传
    入的Class 参数会被用来调用Class.getResource()方法来找到模板。参数prefix是给模板的名称来加前缀的。在实际运行的环境中,类加载机制是首选用来加载模板的方法,因为通常情况下,从类路径下加载文件的这种机制,要比从文件系统的特定目录位置加载安全而且简单。在最终的应用程序中,所有代码都使用.jar 文件打包也是不错的,这样用户就可以直接执行包含所有资源的.jar 文件了。
    第三种调用方式需要Web 应用的上下文和一个基路径作为参数,这个基路径是Web 应用根路径(WEB-INF 目录的上级目录)的相对路径。那么加载器将会从Web 应用目录开
    始加载模板。尽管加载方法对没有打包的.war 文件起作用, 因为它使用了ServletContext.getResource()方法来访问模板,注意这里我们指的是“目录”。如果忽略了第二个参数(或使用了””),那么就可以混合存储静态文件(.html,.jpg 等)和.ftl 文件,只是.ftl 文件可以被送到客户端执行。当然必须在WEB-INF/web.xml中配置一个Servlet 来处理URI 格式为*.ftl 的用户请求,否则客户端无法获取到模板,因此你将会看到Web 服务器给出的秘密提示内容。在站点中不能使用空路径,这将成为一个问题,你应该在WEB-INF 目录下的某个位置存储模板文件,这样模板源文件就不会偶然
    void setDirectoryForTemplateLoading(File dir);
    void setClassForTemplateLoading(Class cl, String prefix);
    void setServletContextForTemplateLoading(Object
    servletContext, String path);
    地被执行到,这种机制对servlet 应用程序来加载模板来说,是非常好用的方式,而且模板可以自动更新而不需重启Web 应用程序,但是对于类加载机制,这样就行不通了。

    5.2、从多个位置加载模板

    1. import freemarker.cache.*; // 模板加载器在这个包下  
    2. ...  
    3. FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates"));  
    4. FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates"));  
    5. ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(),"");  
    6. TemplateLoader[] loaders = new TemplateLoader[] { ftl1, ftl2,ctl };  
    7. MultiTemplateLoader mtl = new MultiTemplateLoader(loaders);  
    8. cfg.setTemplateLoader(mtl);  

    现在,FreeMarker 将会尝试从/tmp/templates 目录加载模板,如果在这个目录下没有发现请求的模板,它就会继续尝试从/usr/data/templates 目录下加载,如果还是没有发现请求的模板,那么它就会使用类加载器来加载模板。

    5.3、封装freemarker用于创建模板和加载模板

    1. package com.ajun.template.utils;  
    2.   
    3. import java.io.IOException;  
    4. import java.io.Writer;  
    5. import java.util.Locale;  
    6. import java.util.Map;  
    7.   
    8. import javax.servlet.ServletContext;  
    9.   
    10. import freemarker.template.Configuration;  
    11. import freemarker.template.DefaultObjectWrapper;  
    12. import freemarker.template.Template;  
    13. import freemarker.template.TemplateException;  
    14.   
    15. /** 
    16.  * @author ajun 
    17.  * @http://blog.csdn.net/ajun_studio   
    18.  **/  
    19. public class FreeMarkertUtil {  
    20.   
    21.     private static  Configuration config = new Configuration();   
    22.       
    23.     /** 
    24.      * @param templateName 模板名字 
    25.      * @param root 模板根 用于在模板内输出结果集 
    26.      * @param out 输出对象 具体输出到哪里 
    27.      */  
    28.     public static void processTemplate(String templateName, Map<?,?> root, Writer out){  
    29.         try{  
    30.             //获得模板  
    31.             Template template=config.getTemplate(templateName,"utf-8");  
    32.             //生成文件(这里是我们是生成html)  
    33.             template.process(root, out);     
    34.             out.flush();     
    35.         } catch (IOException e) {  
    36.             e.printStackTrace();  
    37.         } catch (TemplateException e) {  
    38.             e.printStackTrace();  
    39.         }finally{  
    40.              try {  
    41.                 out.close();  
    42.                 out=null;  
    43.             } catch (IOException e) {  
    44.                 e.printStackTrace();  
    45.             }  
    46.         }  
    47.     }  
    48.     /** 
    49.      * 初始化模板配置 
    50.      * @param servletContext javax.servlet.ServletContext 
    51.      * @param templateDir 模板位置 
    52.      */  
    53.     public static void initConfig(ServletContext servletContext,String templateDir){  
    54.             config.setLocale(Locale.CHINA);  
    55.             config.setDefaultEncoding("utf-8");  
    56.             config.setEncoding(Locale.CHINA, "utf-8");  
    57.             config.setServletContextForTemplateLoading(servletContext, templateDir);  
    58.             config.setObjectWrapper(new DefaultObjectWrapper());  
    59.     }  
    60. }  

    5.4、例子介绍

    会用freemarker.jar自己google下载吧。

    这个例子中我们会Freemarker生成一个html文件 包括html的头部和尾部,已经body,这三个部分会分别对应三个模板文件,如下:

    在模板内要想输出结果集 可以用类似于EL表达式输出${}

    header.ftl

    [plain] view plain copy
     print?
    1. companyName==>${h.companyName}<br/>  
    2. address==>${h.address}<br/>  

    footer.ftl

    [plain] view plain copy
     print?
    1. des==>${f.des}<br/>  
    2.   
    3. <a href="http://localhost/htmlpage/UpdateFooter.do"> 更新Footer </a>  


    body.ftl,这个模板include以上两个模板文件

    [plain] view plain copy
     print?
    1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
    2. <html>  
    3.   <head>  
    4.     <title>用户列表</title>  
    5.       
    6.     <meta http-equiv="pragma" content="no-cache">  
    7.     <meta http-equiv="cache-control" content="no-cache">  
    8.     <meta http-equiv="expires" content="0">      
    9.     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
    10.     <meta http-equiv="description" content="This is my page">  
    11.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
    12.     <!--  
    13.     <link rel="stylesheet" type="text/css" href="styles.css">  
    14.     -->  
    15.    
    16.   </head>  
    17.     
    18.   <body>  
    19.   <#include "header.ftl" parse=true encoding="utf-8">  
    20.   <hr/>  
    21.   <a href="#">用户列表</a><br/>  
    22.   <table border="1">  
    23.     <tr>  
    24.         <td>用户名</td>  
    25.         <td>年龄</td>  
    26.         <td>生日</td>  
    27.         <td>id</td>  
    28.         <td>操作</td>  
    29.     </tr>  
    30.     <#list users as user>  
    31.         <tr>  
    32.             <td>${user.name}</td>  
    33.             <td>${user.age}</td>  
    34.             <td>  
    35.             ${user.birthday?string("yyyy-MM-dd HH:mm:ss")}  
    36.             </td>  
    37.             <td>${user.id}</td>  
    38.             <td><a href="http://localhost/htmlpage/DelUser.do?id=${user.id}">删除</a></td>  
    39.         </tr>  
    40.     </#list>  
    41.       
    42.   </table>  
    43. <hr/>  
    44.   <#include "footer.ftl" parse=true encoding="utf-8">  
    45.   </body>  
    46. </html>  


    这三个模板对应的三个实体类

    Footer.java

    1. package com.ajun.template.bean;  
    2.   
    3. /** 
    4.  * @author ajun 
    5.  * @http://blog.csdn.net/ajun_studio   
    6.  **/  
    7. public class Footer {  
    8.   
    9.     private String des;  
    10.   
    11.     public String getDes() {  
    12.         return des;  
    13.     }  
    14.   
    15.     public void setDes(String des) {  
    16.         this.des = des;  
    17.     }  
    18.       
    19.       
    20. }  


    Header.java

    1. package com.ajun.template.bean;  
    2. /** 
    3.  * @author ajun 
    4.  * @http://blog.csdn.net/ajun_studio   
    5.  **/  
    6. public class Header {  
    7.   
    8.     private String companyName;  
    9.       
    10.     private String address;  
    11.   
    12.     public String getCompanyName() {  
    13.         return companyName;  
    14.     }  
    15.   
    16.     public void setCompanyName(String companyName) {  
    17.         this.companyName = companyName;  
    18.     }  
    19.   
    20.     public String getAddress() {  
    21.         return address;  
    22.     }  
    23.   
    24.     public void setAddress(String address) {  
    25.         this.address = address;  
    26.     }  
    27.       
    28.       
    29.       
    30. }  


    User.java

    1. package com.ajun.template.bean;  
    2.   
    3. import java.util.Date;  
    4.   
    5. public class User {  
    6.       
    7.     private Integer id;  
    8.   
    9.     private String name ;  
    10.       
    11.     private int age;  
    12.       
    13.     private Date birthday;  
    14.   
    15.     public String getName() {  
    16.         return name;  
    17.     }  
    18.   
    19.     public void setName(String name) {  
    20.         this.name = name;  
    21.     }  
    22.   
    23.     public int getAge() {  
    24.         return age;  
    25.     }  
    26.   
    27.     public void setAge(int age) {  
    28.         this.age = age;  
    29.     }  
    30.   
    31.     public Date getBirthday() {  
    32.         return birthday;  
    33.     }  
    34.   
    35.     public void setBirthday(Date birthday) {  
    36.         this.birthday = birthday;  
    37.     }  
    38.   
    39.       
    40.     public Integer getId() {  
    41.         return id;  
    42.     }  
    43.   
    44.     public void setId(Integer id) {  
    45.         this.id = id;  
    46.     }  
    47.   
    48.     public User(Integer id,String name, int age, Date birthday) {  
    49.         super();  
    50.         this.name = name;  
    51.         this.age = age;  
    52.         this.birthday = birthday;  
    53.         this.id = id;  
    54.     }  
    55.   
    56.     public User() {  
    57.         super();  
    58.     }  
    59.       
    60.       
    61. }  


    下面模板一些业务逻辑操作,对这三个实体类

    1. package com.ajun.template.service;  
    2.   
    3. import com.ajun.template.bean.Footer;  
    4. /** 
    5.  * @author ajun 
    6.  * @http://blog.csdn.net/ajun_studio   
    7.  **/  
    8. public class FooterService {  
    9.   
    10.     private static Footer f = new Footer();  
    11.     static{  
    12.         f.setDes("北京-廊坊-好公司呢!!!!哇哈哈!!!");  
    13.     }  
    14.       
    15.     public static void update(String des){  
    16.         f.setDes(des);  
    17.     }  
    18.       
    19.     public static Footer gerFooter(){  
    20.         return f;  
    21.     }  
    22. }  
    1. package com.ajun.template.service;  
    2.   
    3. import com.ajun.template.bean.Header;  
    4. /** 
    5.  * @author ajun 
    6.  * @http://blog.csdn.net/ajun_studio   
    7.  **/  
    8. public class HeaderService {  
    9.   
    10.     private static Header h = new Header();  
    11.       
    12.     static{  
    13.         h.setAddress("北京朝阳CBD");  
    14.         h.setCompanyName("上海唐秀!!!");  
    15.     }  
    16.       
    17.     public static void update(String address,String companyName){  
    18.         h.setAddress(address);  
    19.         h.setCompanyName(companyName);  
    20.     }  
    21.       
    22.     public static Header getHeader(){  
    23.         return h;  
    24.     }  
    25. }  
    1. package com.ajun.template.service;  
    2.   
    3. import java.util.ArrayList;  
    4. import java.util.Date;  
    5. import java.util.List;  
    6.   
    7. import com.ajun.template.bean.User;  
    8. /** 
    9.  * @author ajun 
    10.  * @http://blog.csdn.net/ajun_studio   
    11.  **/  
    12. public class UserService {  
    13.   
    14.     private static List<User> users = new ArrayList<User>();  
    15.       
    16.     static{  
    17.         for(int i=0;i<10;i++){  
    18.             User u = new User(i,"ajun"+i,i+10,new Date());  
    19.             users.add(u);  
    20.         }  
    21.     }  
    22.       
    23.     public static List<User> getUsers(){  
    24.         return users;  
    25.     }  
    26.       
    27.     public static void delete(int index){  
    28.         for(int i=0 ;i<users.size();i++){  
    29.             User u = users.get(i);  
    30.             if(u.getId()==index){  
    31.                 users.remove(u);  
    32.                 //users.remove(index);  
    33.             }  
    34.         }  
    35.     }  
    36. }  


    上面主要是模板你的一些业务和dao层得操作,因此没有涉及数据库的操作,主要是为实验。

    生成html对外调用的方法,会用到FreeMarkertUtil这个类 这个类得代码上面已经给出。

    1. package com.ajun.template.client;  
    2.   
    3. import java.io.Writer;  
    4. import java.util.HashMap;  
    5. import java.util.List;  
    6. import java.util.Map;  
    7.   
    8. import com.ajun.template.bean.Footer;  
    9. import com.ajun.template.bean.Header;  
    10. import com.ajun.template.bean.User;  
    11. import com.ajun.template.service.FooterService;  
    12. import com.ajun.template.service.HeaderService;  
    13. import com.ajun.template.service.UserService;  
    14. import com.ajun.template.utils.FreeMarkertUtil;  
    15.   
    16. /** 
    17.  * @author ajun 
    18.  * @http://blog.csdn.net/ajun_studio   
    19.  **/  
    20. public class ProcessClient {  
    21.   
    22.     private static Map<String,Object> root = new HashMap<String,Object>();  
    23.   
    24.     /** 
    25.      * 调用FreeMarkertUtil.java 
    26.      * FreeMarkertUtil.processTemplate("body.ftl", root, out); 
    27.      * 来生成html文件 
    28.      * @param out 
    29.      */  
    30.     public static void processBody(Writer out){  
    31.         Header h = HeaderService.getHeader();  
    32.         root.put("h", h);  
    33.         Footer f = FooterService.gerFooter();  
    34.         root.put("f", f);  
    35.         List<User> users = UserService.getUsers();  
    36.         root.put("users", users);  
    37.         FreeMarkertUtil.processTemplate("body.ftl", root, out);  
    38.     }  
    39.       
    40. }  

    此时我会提供一个servlet在客户端进行第一次请求的时候 我会调用这个ProcessClient来生成html页面,之后每次访问就可以直接访问html,来做到真正的静态化了

    1. package com.ajun.template.servlet;  
    2.   
    3. import java.io.File;  
    4. import java.io.FileOutputStream;  
    5. import java.io.IOException;  
    6. import java.io.OutputStreamWriter;  
    7. import java.io.Writer;  
    8.   
    9. import javax.servlet.ServletConfig;  
    10. import javax.servlet.ServletException;  
    11. import javax.servlet.http.HttpServlet;  
    12. import javax.servlet.http.HttpServletRequest;  
    13. import javax.servlet.http.HttpServletResponse;  
    14.   
    15. import com.ajun.template.client.ProcessClient;  
    16. import com.ajun.template.utils.DirectoryFilter;  
    17. import com.ajun.template.utils.FreeMarkertUtil;  
    18.   
    19. /** 
    20.  * @author ajun 
    21.  * @http://blog.csdn.net/ajun_studio   
    22.  **/  
    23. public class Index extends HttpServlet {  
    24.   
    25.     private static final long serialVersionUID = 7474850489594438527L;  
    26.   
    27.     public Index() {  
    28.         super();  
    29.     }  
    30.   
    31.       
    32.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
    33.             throws ServletException, IOException {  
    34.   
    35.         this.doPost(request, response);  
    36.     }  
    37.   
    38.       
    39.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
    40.             throws ServletException, IOException {  
    41.         //html生成之后存放的路径  
    42.         String dirPath = request.getSession().getServletContext().getRealPath("/templates/html");  
    43.         File path = new File(dirPath);  
    44.         //生成的文件的名字  
    45.         String indexFileName = "index.html";  
    46.         /** 
    47.          * 判断是否已经存在该html文件,存在了就直接访问html ,不存在生成html文件 
    48.          */  
    49.         String[] indexfileList = path.list(new DirectoryFilter(indexFileName));  
    50.         if(indexfileList.length<=0){  
    51.             Writer out = new OutputStreamWriter(new FileOutputStream(dirPath+"/"+indexFileName),"UTF-8");  
    52.             //生成html文件  
    53.             ProcessClient.processBody(out);  
    54.             request.getRequestDispatcher("/templates/html/index.html").forward(request, response);   
    55.         }else{  
    56.             request.getRequestDispatcher("/templates/html/"+indexfileList[0]).forward(request, response);   
    57.         }  
    58.           
    59.       
    60.     }  
    61.   
    62.       
    63.   
    64.     /** 
    65.      * 初始化模板配置,供以后获得模板,在init里加载也主要是为保证Configuration实例唯一 
    66.      */  
    67.     public void init(ServletConfig config) throws ServletException {  
    68.         String templateDir = config.getInitParameter("templateDir");  
    69.         FreeMarkertUtil.initConfig(config.getServletContext(), templateDir);  
    70.     }  
    71.   
    72.       
    73. }  

    web.xml配置

    1. <servlet>  
    2.    <description>This is the description of my J2EE component</description>  
    3.    <display-name>This is the display name of my J2EE component</display-name>  
    4.    <servlet-name>Index</servlet-name>  
    5.    <servlet-class>com.ajun.template.servlet.Index</servlet-class>  
    6.    <init-param>  
    7.     <param-name>templateDir</param-name>模板存放位置,是基于app的根目录的  
    8.     <param-value>/templates</param-value>  
    9.    </init-param>  
    10.    <load-on-startup>3</load-on-startup>为了启动的时候初始化模板配置  
    11.  </servlet>  
    12.   
    13.  <servlet-mapping>  
    14.    <servlet-name>Index</servlet-name>  
    15.    <url-pattern>/Index.do</url-pattern>  
    16.  </servlet-mapping>  


    部署到tomcat上,输入:http://localhost/htmlpage/Index.do

    页面效果:

    页面是做好了,但是内容变化了 ,更新怎么办呢,我这里是当列表内容变化之后 ,我是删除原来的html ,利用模板然后重新生成的符合新结果的html页面

    当我删除一条的时候,我会重新生成html页面,但是由于浏览器缓存的原因,即是你删除了,重新生成了新html页面,可是浏览器还是保存原来的页面,不刷新两次是不行的,

    这里我采用的没更新的时候,都会给这个html改个名字,让浏览器去加载最新的,就可以了

    具体的删除操作如下:

    1. package com.ajun.template.servlet;  
    2.   
    3. import java.io.File;  
    4. import java.io.FileOutputStream;  
    5. import java.io.IOException;  
    6. import java.io.OutputStreamWriter;  
    7. import java.io.Writer;  
    8. import java.util.UUID;  
    9.   
    10. import javax.servlet.ServletException;  
    11. import javax.servlet.http.HttpServlet;  
    12. import javax.servlet.http.HttpServletRequest;  
    13. import javax.servlet.http.HttpServletResponse;  
    14.   
    15. import com.ajun.template.client.ProcessClient;  
    16. import com.ajun.template.service.UserService;  
    17. import com.ajun.template.utils.DirectoryFilter;  
    18. /** 
    19.  * @author ajun 
    20.  * @http://blog.csdn.net/ajun_studio   
    21.  **/  
    22. public class DelUser extends HttpServlet {  
    23.   
    24.       
    25.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
    26.             throws ServletException, IOException {  
    27.             this.doPost(request, response);  
    28.     }  
    29.   
    30.     //删除用户  
    31.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
    32.             throws ServletException, IOException {  
    33.           
    34.         String id = request.getParameter("id");  
    35.         UserService.delete(Integer.valueOf(id));  
    36.           
    37.         //生成html的位置  
    38.         String dirPath = request.getSession().getServletContext().getRealPath("/templates/html");  
    39.         //文件名字  
    40.         String indexFileName = "index.html";  
    41.           
    42.         //删除原来的文件  
    43.         delOldHtml(dirPath,indexFileName);  
    44.           
    45.         //防止浏览器缓存,用于重新生成新的html  
    46.         UUID uuid = UUID.randomUUID();  
    47.         Writer out = new OutputStreamWriter(new FileOutputStream(dirPath+"/"+uuid+indexFileName),"UTF-8");  
    48.         ProcessClient.processBody(out);  
    49.         response.sendRedirect("templates/html/"+uuid+"index.html");  
    50.     }  
    51.       
    52.     /** 
    53.      * 删除原来的html文件 
    54.      * @param htmlDir 
    55.      * @param htmlName 
    56.      */  
    57.     private void delOldHtml(String htmlDir,String htmlName){  
    58.         File path = new File(htmlDir);  
    59.         String[] indexfileList = path.list(new DirectoryFilter(htmlName));  
    60.         if(indexfileList.length>=0){  
    61.             for(String f:indexfileList){  
    62.                 File delf = new File(htmlDir+"/"+f);  
    63.                 delf.delete();  
    64.             }  
    65.         }  
    66.     }  
    67.   
    68. }  


    通过以上操作,每次更新html,就可以不解决浏览器缓存的问题了。

    还有一个工具类需要介绍,就是判断是否已经生成了特定的html文件的java类

    1. package com.ajun.template.utils;  
    2.   
    3. import java.io.File;  
    4. import java.io.FilenameFilter;  
    5. /** 
    6.  * @author ajun 
    7.  * @http://blog.csdn.net/ajun_studio   
    8.  **/  
    9. public class DirectoryFilter implements FilenameFilter {  
    10.   
    11.     String myString;  
    12.     public DirectoryFilter(String myString)  
    13.     {  
    14.         this.myString = myString;  
    15.     }  
    16.       
    17.     public boolean accept(File dir,String name)  
    18.     {   //FilenameFilter.accept(File dir, String name)   
    19.        // 测试指定文件是否应该包含在某一文件列表中。  
    20.         String f= new File(name).getName();  
    21.         if(f.contains(myString) || f.equals(myString)){  
    22.             return true;  
    23.         }  
    24.         return false;  
    25.     }  
    26.   
    27. }  

    到这里整个静态化就完成了,静态化更新机制,是根据你自己项目的业务进行定制的,可以定时生成html文件,也可以需要手动生成。

    项目结构图如下:

    记住:网站不是所有的页面都是需要静态化的,主要是一些实时性不是很高的数据页面进行静态化(来提高访问速度),其他都是通过伪静态来实现的,就是重写utl。

    页面静态化不是提高网站性能的唯一途径,还可以利用一些缓存产品来实现。

    常用FreeMarker资源

    官网主页:http://www.freemarker.org/

    Eclipse插件JbossTool:http://www.jboss.org/tools/download/

    中文文档:https://sourceforge.net/projects/freemarker/files/chinese-manual/FreeMarker_Manual_zh_CN.pdf/download

  • 相关阅读:
    log4net 发布到生产环境不写日志的解决方法--使用 NLog日志
    centos 下Supervisor 守护进程基本配置
    centos 7 下安装Nginx
    Haproxy+asp.net +RedisSessionStateProvider 完美实现负载均衡,并且session保持
    centos之Haproxy 负载均衡学习笔记
    改进初学者的PID-介绍
    实现Modbus TCP多网段客户端应用
    有一种亲切是手机
    实现Modbus ASCII多主站应用
    爱好
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/6206302.html
Copyright © 2020-2023  润新知