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 中可以使用下面的方法来方便建立三种模板加载

void setDirectoryForTemplateLoading(File dir);
void setClassForTemplateLoading(Class cl, String prefix);

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、从多个位置加载模板

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 目录下加载,如果还是没有发现请求的模板,那么它就会使用类加载器来加载模板。

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

package com.dxy.util;

import java.io.Writer;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletContext;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

public class FreeMarkerUtil {
	private static Configuration config = new Configuration();
	
	
	public static void processTemplate(String templateName,Map<?,?> root,Writer out){
		try{
			Template template = config.getTemplate(templateName, "utf8");
			template.process(root, out);
			out.flush();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			try {
				out.close();
				out = null;
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void initConfig(ServletContext servletContext,String templateDir){
		config.setLocale(Locale.CHINA);
		config.setDefaultEncoding("utf-8");
		config.setEncoding(Locale.CHINA, "utf-8");
		config.setServletContextForTemplateLoading(servletContext, templateDir);
		config.setObjectWrapper(new DefaultObjectWrapper());
	}
}

5.4、例子介绍

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

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

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

header.ftl

companyName==>${h.companyName}<br/>  
address==>${h.address}<br/> 


footer.ftl

des==>${f.des}<br/>  
  
<a href="http://localhost/htmlpage/UpdateFooter.do"> 更新Footer </a>


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

<!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/htmlpage/DelUser.do?id=${user.id}">删除</a></td>  
        </tr>  
    </#list>  
      
  </table>  
<hr/>  
  <#include "footer.ftl" parse=true encoding="utf-8">  
  </body>  
</html>  


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

Footer.java

package com.dxy.model;

public class Footer {
	private String des;

	public String getDes() {
		return des;
	}

	public void setDes(String des) {
		this.des = des;
	}
	
	
}


Header.java

package com.dxy.model;

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;
	}
	
	
}


User.java

package com.dxy.model;

import java.util.Date;

public class User {
	private Integer id;
	
	private String name;
	
	private int age;
	
	private Date birthday;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	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 User(Integer id, String name, int age, Date birthday) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.birthday = birthday;
	}
	
}


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

package com.dxy.service;

import com.dxy.model.Footer;

public class FooterService {
	private static Footer f = new Footer();
	
	static {
		f.setDes("sdfsdfsfdsdfsdfds");
	}
	
	public static void update(String des) {
		f.setDes(des);
	}
	
	public static Footer getFooter(){
		return f;
	}
}


 

package com.dxy.service;

import com.dxy.model.Header;

public class HeaderService {
	private static Header h = new Header();
	
	static {
		h.setAddress("aaaaaaaaaaaaa");
		h.setCompanyName("bbbbbbbbbbbb");
	}
	
	public static void update(String address,String companyName) {
		h.setAddress(address);
		h.setCompanyName(companyName);
	}
	
	public static Header getHeader() {
		return h;
	}
}


 

package com.dxy.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.dxy.model.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,"dxy"+i,i+10,new Date());
			users.add(u);
		}
	}
	
	public static List<User> getUsers(){
		return users;
	}	
	
}


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

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

package com.dxy.client;

import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.dxy.model.Footer;
import com.dxy.model.Header;
import com.dxy.model.User;
import com.dxy.service.FooterService;
import com.dxy.service.HeaderService;
import com.dxy.service.UserService;
import com.dxy.util.FreeMarkerUtil;

public class ProcessClient {
	
	private static Map<String,Object> root = new HashMap<String,Object>();
	
	public static void processBody(Writer out) {
		Header  h = HeaderService.getHeader();
		
		root.put("h",h);
		Footer f = FooterService.getFooter();
		root.put("f", f);
		List<User> users = UserService.getUsers();
		root.put("users", users);
		FreeMarkerUtil.processTemplate("body.ftl",root,out);
	}
}


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

package com.dxy.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dxy.client.ProcessClient;
import com.dxy.util.FreeMarkerUtil;

public class Index extends HttpServlet {
	
	

	public Index() {
		super();
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String dirPath = req.getSession().getServletContext().getRealPath("/templates/html");
		File path = new File(dirPath);
		String indexFileName = "index.html";
		//String[] indexfileList = path.list(new DirectoryFilter(indexFileName));
		Writer out = new OutputStreamWriter(new FileOutputStream(dirPath+"/"+indexFileName),"utf-8");
		ProcessClient.processBody(out);
		req.getRequestDispatcher("/templates/html/index.html").forward(req, resp);
	}
	
	/** 
	     * 初始化模板配置,供以后获得模板,在init里加载也主要是为保证Configuration实例唯一 
	     */  
	@Override
    public void init(ServletConfig config) throws ServletException {  
	//templateDir是所在文件夹的位置
        String templateDir = config.getInitParameter("templateDir");  
        FreeMarkerUtil.initConfig(config.getServletContext(), templateDir);  
    }  

	
}

web.xml配置

<?xml version="1.0" encoding="US-ASCII"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>	
  <servlet>
  <servlet-name>Index</servlet-name>  
   <servlet-class>com.dxy.servlet.Index</servlet-class>  
   <init-param>  
    <param-name>templateDir</param-name>
    <param-value>/templates</param-value>模板所在的位置  
   </init-param>  
   <load-on-startup>3</load-on-startup> 
 </servlet>  
  
 <servlet-mapping>  
   <servlet-name>Index</servlet-name>  
   <url-pattern>/Index.do</url-pattern>  
 </servlet-mapping>  
  
  
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

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

页面效果:



ok了。

项目目录结构图:

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

 

本文摘自http://blog.csdn.net/ajun_studio/article/details/6932185,转载时请注明原文出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值