使用Freemarker 实现JSP页面的静态化

DFRJasper 6年前

一、原理

Freemarker 生成静态页面,首先需要使用自己定义的模板页面,这个模板页面可以是最最普通的 html ,也可以是嵌套 freemarker 中的 取值表达式, 标签或者自定义标签等等,然后后台读取这个模板页面,解析其中的标签完成相对应的操作, 然后采用键值对的方式传递参数替换模板中的的取值表达式,做完之后 根据配置的路径生成一个新的 html 页面, 以达到静态化访问的目的。

二、Freemaker 提供的标签

Freemarker 提供了很多有用 常用的标签, 具体可以分为三个部分:Freemarker 标签都是 类似 Html 标签 , 不同的是它是为了与 HTML 标记区分,用 # 开始。例如 <# 标签名称 > ;${value}  表示输出变量名的内容   ;注释:包含在 <#-- 和 --> (而不是 <!-- 和 --> )之间;

三、Freemaker 实现网页静态化 DEMO

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

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

Body.ftl    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">      <html>        <head>          <title>用户列表</title>                    <meta http-equiv="pragma" content="no-cache">          <meta http-equiv="cache-control" content="no-cache">          <meta http-equiv="expires" content="0">              <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">          <meta http-equiv="description" content="This is my page">          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />          <!--          <link rel="stylesheet" type="text/css" href="styles.css">          -->               </head>                <body>        <#include "header.ftl" parse=true encoding="utf-8">        <hr/>        <a href="#">用户列表</a><br/>        <table border="1">          <tr>              <td>用户名</td>              <td>年龄</td>              <td>生日</td>              <td>id</td>              <td>操作</td>          </tr>          <#list users as user>              <tr>                  <td>${user.name}</td>                  <td>${user.age}</td>                  <td>                  ${user.birthday?string("yyyy-MM-dd HH:mm:ss")}                  </td>                  <td>${user.id}</td>                  <td><a href="http://localhost:8082/JspToHtml/DelUser.do?id=${user.id}">删除</a></td>              </tr>          </#list>                  </table>      <hr/>        <#include "footer.ftl" parse=true encoding="utf-8">        </body>      </html>      Footer.ftl    ${f.des}<br/>     Header.ftl    company:${h.companyName}<br/>      address:${h.address}<br/>      它们对于的实体类分别是:    User.java    package com.cys.jsptohtml.schema;         import java.util.Date;           public class User {                    private Integer id;                private String name ;                    private int age;                    private Date birthday;                public String getName() {              return name;          }                public void setName(String name) {              this.name = name;          }                public int getAge() {              return age;          }                public void setAge(int age) {              this.age = age;          }                public Date getBirthday() {              return birthday;          }                public void setBirthday(Date birthday) {              this.birthday = birthday;          }                          public Integer getId() {              return id;          }                public void setId(Integer id) {              this.id = id;          }                public User(Integer id,String name, int age, Date birthday) {              super();              this.name = name;              this.age = age;              this.birthday = birthday;              this.id = id;          }                public User() {              super();          }                          }      Header.java    package com.cys.jsptohtml.schema;              public class Header {                private String companyName;                    private String address;                public String getCompanyName() {              return companyName;          }                public void setCompanyName(String companyName) {              this.companyName = companyName;          }                public String getAddress() {              return address;          }                public void setAddress(String address) {              this.address = address;          }            }      Footer.java    package com.cys.jsptohtml.schema;              public class Header {                private String companyName;                    private String address;                public String getCompanyName() {              return companyName;          }                public void setCompanyName(String companyName) {              this.companyName = companyName;          }                public String getAddress() {              return address;          }                public void setAddress(String address) {              this.address = address;          }       }      对应的Service有(在Service中模仿了数据库操作):    UserService.java:    package com.cys.jsptohtml.service;         import java.util.ArrayList;    import java.util.Date;    import java.util.List;         import com.cys.jsptohtml.schema.User;         public class UserService {                private static List<User> users = new ArrayList<User>();                    static{              for(int i=0;i<10;i++){                  User u = new User(i,"cys"+i,i+10,new Date());                  users.add(u);              }          }                    public static List<User> getUsers(){              return users;          }                    public static void delete(int index){              for(int i=0 ;i<users.size();i++){                  User u = users.get(i);                  if(u.getId()==index){                      users.remove(u);                      //users.remove(index);                  }              }          }      }       HeaderService.java    package com.cys.jsptohtml.service;         import com.cys.jsptohtml.schema.Header;         public class HeaderService {                private static Header h = new Header();                    static{              h.setAddress("中关村东路");              h.setCompanyName("中科软");          }                    public static void update(String address,String companyName){              h.setAddress(address);              h.setCompanyName(companyName);          }                    public static Header getHeader(){              return h;          }      }      FooterService.java    package com.cys.jsptohtml.service;         import com.cys.jsptohtml.schema.Footer;                   public class FooterService {                private static Footer f = new Footer();          static{              f.setDes("这是底部");          }                    public static void update(String des){              f.setDes(des);          }                    public static Footer gerFooter(){              return f;          }      }      Servlet操作:    DelUser.java    package com.cys.jsptohtml.servlet;         import java.io.File;    import java.io.FileOutputStream;    import java.io.FilenameFilter;    import java.io.IOException;    import java.io.OutputStreamWriter;    import java.io.Writer;    import java.util.UUID;         import javax.servlet.ServletException;    import javax.servlet.http.HttpServlet;    import javax.servlet.http.HttpServletRequest;    import javax.servlet.http.HttpServletResponse;         import com.cys.jsptohtml.service.UserService;    import com.cys.jsptohtml.util.ProcessClient;          /**      * @author cys      **/      @SuppressWarnings("serial")    public class DelUser extends HttpServlet {                          public void doGet(HttpServletRequest request, HttpServletResponse response)                  throws ServletException, IOException {                  this.doPost(request, response);          }                //删除用户          public void doPost(HttpServletRequest request, HttpServletResponse response)                  throws ServletException, IOException {               System.out.println("Del dopost");            String id = request.getParameter("id");              UserService.delete(Integer.valueOf(id));                            //生成html的位置              String dirPath = request.getSession().getServletContext().getRealPath("/templateDir/html");              //文件名字              String indexFileName = "index.html";                            //删除原来的文件              delOldHtml(dirPath,indexFileName);                            //防止浏览器缓存,用于重新生成新的html              UUID uuid = UUID.randomUUID();              Writer out = new OutputStreamWriter(new FileOutputStream(dirPath+"/"+uuid+indexFileName),"UTF-8");              ProcessClient.processBody(out, "body.ftl");            response.sendRedirect("templateDir/html/"+uuid+"index.html");          }                    /**          * 删除原来的html文件          * @param htmlDir          * @param htmlName          */          private void delOldHtml(String htmlDir,String htmlName){              File path = new File(htmlDir);              String[] indexfileList = path.list(new FilenameFilter(){         public boolean accept(File dir, String name) {    return name.endsWith(".html");    }                        });              if(indexfileList.length>0){                  for(String f:indexfileList){                      File delf = new File(htmlDir+"/"+f);                      delf.delete();                  }              }          }            }    JspToHtmlServlet.java    package com.cys.jsptohtml.servlet;         import java.io.File;    import java.io.FileOutputStream;    import java.io.FilenameFilter;    import java.io.IOException;    import java.io.OutputStreamWriter;    import java.io.Writer;         import javax.servlet.ServletException;    import javax.servlet.http.HttpServlet;    import javax.servlet.http.HttpServletRequest;    import javax.servlet.http.HttpServletResponse;         import com.cys.jsptohtml.util.ProcessClient;         public class JspToHtmlServlet extends HttpServlet{         private static final long serialVersionUID = 1L;         public JspToHtmlServlet() {              super();          }               public void doGet(HttpServletRequest request,HttpServletResponse response)                  throws ServletException, IOException {           System.out.println("doget");            this.doPost(request, response);          }                      public void doPost(HttpServletRequest request,     HttpServletResponse response)                  throws ServletException, IOException {           System.out.println("doPost");            // html生成之后存放的路径            String dirPath = request.getSession().getServletContext().getRealPath("/templateDir/html");              File path = new File(dirPath);              // 生成的文件的名字            String indexFileName = "index.html";              /**     * 判断是否已经存在该html文件,存在了就直接访问html ,不存在生成html文件     */              String[] indexfileList = path.list(new FilenameFilter(){         public boolean accept(File dir, String name) {    return name.endsWith(".html");    }            });            System.out.println(indexfileList);            if(indexfileList.length<=0){                  Writer out = new OutputStreamWriter(new FileOutputStream(dirPath+"/"+indexFileName),"UTF-8");                 // 生成html文件                ProcessClient.processBody(out,"body.ftl");                  request.getRequestDispatcher("/templateDir/html/index.html").forward(request, response);               }else{                  request.getRequestDispatcher("/templateDir/html/"+indexfileList[0]).forward(request, response);               }                }    }    Login.java(该类用于测试环境,与静态化无关)    package com.cys.jsptohtml.servlet;         import java.io.IOException;         import javax.servlet.ServletException;    import javax.servlet.http.HttpServlet;    import javax.servlet.http.HttpServletRequest;    import javax.servlet.http.HttpServletResponse;         public class Login extends HttpServlet{        private static final long serialVersionUID = 7474850489594438527L;      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {            doPost(request, response);        }             protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {            request.setCharacterEncoding("UTF-8");              response.setContentType("text/html;charset=utf-8");                        String action = request.getParameter("action");              if("login_input".equals(action)) {                  request.getRequestDispatcher("login.jsp").forward(request , response);              } else if("login".equals(action)) {                  String name = request.getParameter("name");                  String password = request.getParameter("password");                                    System.out.println("name->" + name + ",password->" + password);            }        }         }    Jsp页面:    Index.jsp    <%@ page language="java" contentType="text/html; charset=UTF-8"        pageEncoding="UTF-8"%>    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    <html>    <head>    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">    <title>Insert title here</title>    </head>    <body>        <p>用Maven创建web项目,测试Servlet</p>        <a href="demo?action=login_input">登录(demo?action=login_input)</a>        <a href="index?action=login_input">静态化</a>    </body>    </html>    Login.jsp    <%@ page language="java" contentType="text/html; charset=UTF-8"        pageEncoding="UTF-8"%>    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    <html>    <head>    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">    <title>Insert title here</title>    </head>    <body>        <form action="demo?action=login" method="post">              Name:<input type="text" name="name" />              Password:<input type="password" name="password" />                                <input type="submit" value="登录" />          </form>      </body>    </html>    Web.xml    <?xml version="1.0" encoding="UTF-8"?>    <web-app xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">      <javaee:display-name>Archetype Created Web Application</javaee:display-name>      <servlet>        <javaee:description></javaee:description>        <javaee:display-name>ServletDemo</javaee:display-name>        <servlet-name>ServletDemo</servlet-name>        <servlet-class>com.cys.jsptohtml.servlet.Login</servlet-class>      </servlet>      <servlet-mapping>        <servlet-name>ServletDemo</servlet-name>        <url-pattern>/demo</url-pattern>      </servlet-mapping>            <servlet>         <servlet-name>Index</servlet-name>         <servlet-class>com.cys.jsptohtml.servlet.JspToHtmlServlet</servlet-class>         <load-on-startup>3</load-on-startup>     </servlet>             <servlet-mapping>         <servlet-name>Index</servlet-name>         <url-pattern>/index</url-pattern>       </servlet-mapping>            <servlet>         <servlet-name>DelUser</servlet-name>         <servlet-class>com.cys.jsptohtml.servlet.DelUser</servlet-class>         <load-on-startup>3</load-on-startup>     </servlet>             <servlet-mapping>         <servlet-name>DelUser</servlet-name>         <url-pattern>/DelUser.do</url-pattern>       </servlet-mapping>     </web-app>    Util类:    FreeMarkertUtil .java    package com.cys.jsptohtml.util;    import java.io.IOException;    import java.io.Writer;    import java.util.Map;         import freemarker.template.Configuration;    import freemarker.template.Template;    import freemarker.template.TemplateException;         public class FreeMarkertUtil {         public Template getTemplate(String name) {            try {                // 通过Freemaker的Configuration读取相应的ftl                Configuration cfg = new Configuration();                // 设定去哪里读取相应的ftl模板文件                cfg.setClassForTemplateLoading(this.getClass(), "ftl");                // 在模板文件目录中找到名称为name的文件                Template temp = cfg.getTemplate(name);                System.out.println(temp.getName());                return temp;            } catch (IOException e) {                e.printStackTrace();            }            return null;        }        /**          * @param templateName 模板名字          * @param root 模板根 用于在模板内输出结果集          * @param out 输出对象 具体输出到哪里          */          public  void processTemplate(Template template,Map<?,?> root, Writer out){              try{               System.out.println("processTemplate");                template.process(root, out);                   out.flush();                 } catch (IOException e) {                  e.printStackTrace();              } catch (TemplateException e) {                  e.printStackTrace();              }finally{                   try {                      out.close();                      out=null;                  } catch (IOException e) {                      e.printStackTrace();                  }              }          }      }    在该类中加载模板的方式有多种:    void setDirectoryForTemplateLoading(File dir);// 根据全路径加载  void setClassForTemplateLoading(Class cl, String prefix);//根据类的路径加载,prefix为模板前缀    void setServletContextForTemplateLoading(Object servletContext, String path); //根据web上下文    从多地址加载模板    import freemarker.cache.*; // 模板加载器在这个包下      ...      FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates"));      FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates"));      ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(),"");      TemplateLoader[] loaders = new TemplateLoader[] { ftl1, ftl2,ctl };      MultiTemplateLoader mtl = new MultiTemplateLoader(loaders);      cfg.setTemplateLoader(mtl);      现在,FreeMarker 将会尝试从/tmp/templates 目录加载模板,如果在这个目录下没有发现请求的模板,它就会继续尝试从/usr/data/templates 目录下加载,如果还是没有发现请求的模板,那么它就会使用类加载器来加载模板。         ProcessClient .java         package com.cys.jsptohtml.util;         import java.io.Writer;    import java.util.HashMap;    import java.util.List;    import java.util.Map;         import com.cys.jsptohtml.schema.Footer;    import com.cys.jsptohtml.schema.Header;    import com.cys.jsptohtml.schema.User;    import com.cys.jsptohtml.service.FooterService;    import com.cys.jsptohtml.service.HeaderService;    import com.cys.jsptohtml.service.UserService;         import freemarker.template.Template;                     /**      * @author cys       **/      public class ProcessClient {               private static Map<String,Object> root = new HashMap<String,Object>();                /**          * 调用FreeMarkertUtil.java          * FreeMarkertUtil.processTemplate("body.ftl", root, out);          * 来生成html文件          * @param out          */          public static void processBody(Writer out,String filename){              Header h = HeaderService.getHeader();              root.put("h", h);              Footer f = FooterService.gerFooter();              root.put("f", f);              List<User> users = UserService.getUsers();              root.put("users", users);            FreeMarkertUtil freeMarkertUtil = new FreeMarkertUtil();            Template template = freeMarkertUtil.getTemplate(filename);            freeMarkertUtil.processTemplate(template, root, out);        }      }         Pom.xml(对应的jar包,以及插件):         <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">      <modelVersion>4.0.0</modelVersion>      <groupId>com.cys</groupId>      <artifactId>JspToHtml</artifactId>      <packaging>war</packaging>      <version>0.0.1-SNAPSHOT</version>      <name>JspToHtml Maven Webapp</name>      <url>http://maven.apache.org</url>      <dependencies>        <dependency>          <groupId>junit</groupId>          <artifactId>junit</artifactId>          <version>3.8.1</version>          <scope>test</scope>        </dependency>       <dependency>             <groupId>javax.servlet</groupId>             <artifactId>servlet-api</artifactId>             <version>2.5</version>             <scope>provided</scope>            </dependency>        <dependency>        <groupId>javax.servlet.jsp</groupId>        <artifactId>jsp-api</artifactId>        <version>2.1</version>        <scope>provided</scope>    </dependency>    <dependency>      <groupId>org.freemarker</groupId>      <artifactId>freemarker</artifactId>      <version>2.3.23</version>    </dependency>      </dependencies>       <build>        <finalName>codingdream</finalName>        <plugins>          <plugin>    <groupId>org.codehaus.mojo</groupId>    <artifactId>tomcat-maven-plugin</artifactId>    <version>1.1</version>    <configuration>        <path></path>        <port>8082</port>        <uriEncoding>UTF-8</uriEncoding>        <url>http://localhost:8087/codingdream</url>        <server>tomcat6</server>    </configuration>    </plugin>        </plugins>      </build>    </project>

四、运行结果

参考:http://freemarker.incubator.apache.org/

http://blog.csdn.net/ajun_studio/article/details/6932185/

来自: http://www.cnblogs.com/caoyusongnet/p/5150850.html