*不在使用jsp去动态的生成页面,而是先使用FreeMarker生成真正的静态页面,这样下次访问该静态资源也没必要使用tomcat了。只要是支持http访问的都能访问该静态资源。
*为什么要使用纯静态页面呢?
tomcat一般用来处理动态页面(jsp),但是当访问量增大时还使用jsp来动态的返回页面给客户端会让tomcat压力很大。所以要使用真正的静态页面。
*而且网页静态化后也不需要去访问tomcat获取静态资源。使用Nginx即可。
*场景:访问商品的详情页面。
二.分析*每个商品都要生成对应的一个html文件(商品详情页面),保存到磁盘,下次访问该商品详情页面就不需要使用tomcat(因为tomcat本身处理静态资源就不是很效率)返回动态页面,可以使用Nginx直接请求静态页面(html)。
*如何生成静态页面?
*使用freemarker生成静态页面
三.FreeMarker
1.什么是freemarker?
FreeMarker是一个用java语言编写的模版引擎,它基于模版来生成文本输出。FreeMarker与web容器无关,即在web运行时,它并不知道Servlet或http。它不仅可以用做表现层的实现技术,还可以用于生成XML,JSP或java等。就像是模具,输入数据然后生成html页面。
使用FreeMarker的时候就不需要使用jsp了,当然非要混用也没事。
需要的 jar包:freemarker-2.3.23.jar
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
2.FreeMarker的使用方法(模版是自己写的)
1.添加jar包
2.测试FreeMarker的使用方法
*FreeMarker的使用并不依赖web容器,可以在java工程中运行。
3.创建一个Configuration对象
4.告诉Configuration对象模版文件存放路径。
5.设置Configuration的默认字符集,一般是utf-8
6.从Configuration对象中获得模版对象,需要指定一个模版文件的名字。
7.创建模版需要的数据集(可以是map对象也可以是pojo),把模版需要的数据放入数据集。
8.创建一个Writer对象。指定生成的文件保存的路径以及文件名。
9.调用模版对象的process方法生成静态文件。需要两个参数:数据集和writer对象。
10.关闭writer(文件保存到磁盘上)。
eg:
package com.taotao.freemarker;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.taotao.pojo.Student;
import freemarker.template.Configuration;
import freemarker.template.Template;
/**
* 使用FreeMarker步骤: 1.添加jar包 2.测试FreeMarker的使用方法
* *FreeMarker的使用并不依赖web容器,可以在java工程中运行。 * 3.创建一个Configuration对象
* 4.告诉Config对象模版文件存放路径。 5.设置config的默认字符集,一般是utf-8
* 6.从config对象中获得模版对象,需要指定一个模版文件的名字。
* 7.创建模版需要的数据集(可以是map对象也可以是pojo),把模版需要的数据放入数据集。
* 8.创建一个Writer对象。指定生成的文件保存的路径以及文件名。
* 9.调用模版对象的process方法生成静态文件。需要两个参数:数据集和writer对象。 10.关闭writer(文件保存到磁盘上)。
*
* @author tb
*
*/
public class FreeMarkerTest {
@Test
public void testFreeMarker() throws Exception {
// 3.创建Configuration对象,这里注意:没有参数的构造函数过期了,这里写的构造函数要传入版本号的。直接获取版本号即可。
Configuration configuration = new Configuration(
Configuration.getVersion());
// 4.设置模版文件存放路径,一般FreeMarker文件的扩展名是ftl所以我们可以在WEB-INF中新建一个ftl文件夹。
configuration.setDirectoryForTemplateLoading(new File(
"D:/MyEclipse/taotao-portal/src/main/webapp/WEB-INF/ftl"));// 写如该文件夹的全路径。注意折线的书写方式。
// 5.设置字符集
configuration.setDefaultEncoding("utf-8");
// 6.在ftl文件夹中创建一个文件:first.ftl
// 6.从configuration对象中获取模版对象(Template)需要指定一个模版文件的名字,就是刚才创建的first.stl
Template template = configuration.getTemplate("second.ftl");
// 7.创建模版需要的数据集,可以是一个map对象也可以是一个pojo,把模版需要的数据放入数据集。
Map root = new HashMap<>();
root.put("title", "hello freemarker");
List<Student> stuList = new ArrayList<>();
Student stu1 = new Student();
stu1.setId(1);
stu1.setName("占三1");
stu1.setAdds("地址1");
Student stu2 = new Student();
stu2.setId(2);
stu2.setName("占三2");
stu2.setAdds("地址2");
stuList.add(stu1);
stuList.add(stu2);
root.put("students",stuList);
root.put("curdate", new Date());
// 8.创建一个Writer对象。指定生成的文件保存的路径(这个存放路径不一定要在工程里面,我这里放在:E:\html)以及文件名。
Writer out = new FileWriter(new File("E:/html/seconds.html"));
// 9.调用模版对象的process方法生成静态文件。需要两个参数:数据集和writer对象。
template.process(root, out);
// 10.关闭Writer对象。
out.flush();
out.close();
}
}
*这里的模版文件ftl中就是使用EL表达式来获取数据集中的值。
*freemarker的使用过程很简单,关键就是模版的编写。
*如果使用的FreeMarker就不要在想jsp了,这时不需要jsp了。直接使用生成的静态Html页面。
*模版和jsp其实很像,但还是不同的比如:jsp可以使用的一些标签模版中就不能使用,毕竟它不是jsp。
3.FreeMarker模版的写法
1.取简单数据类型的数据
*使用EL表达式
*如:${hello}
2.取包装类的数据(简单数据类型多层结构)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${title}</title>
</head>
<body>
<label>学号:</label>${student.id}
<label>姓名:</label>${student.name}
<label>住址:</label>${student.adds}
</body>
</html>
3.遍历集合数组
<!--取list集合students中数据-->
<#list students as s>
<tr>
<td>${s.id}</td>
<td>${s.name}</td>
<td>${s.adds}</td>
</tr>
</#list>
4.if条件判断
*格式
<#if 判断条件>
<#else>
</#if>
*逻辑运算符:(== != || &&)
*eg:
<!--if条件判断(隔一行变色:判断条件是偶数行为红色)-->
<#list students as s>
<#if s_index % 2 ==0>
<tr style="color:red">
<#else>
<tr>
</#if>
<td>${s.id}</td>
<td>${s.name}</td>
<td>${s.adds}</td>
</tr>
</#list>
5.日期类型格式化(显示日期)
*三种默认的显示格式:time,date,datetime
*获取时间
root.put("curdate", new Date());//在数据集中保存当前时间
*在模版中获取数据集中保存的当前时间
${curdate}
//这种写法会报错,要指定date的显示格式
${curdate?time}
或 ${curdate?date} 或 ${curdate?datetime}
*如果上面三中都不是你需要的格式,可以自定义格式
${curdate?string("yyyy/MM/dd HH:mm:ss")}
6.null处理
*如果在数据集中存入:root.put("val",null);
*如果存入的是null模版取不到数据会报错。
*解决办法:
1.将null变为空字符串
*在模版中获取数据时在key后面加“!”即:${val!}这样如果val是空值那么将会变成空字符串""而不会报错。
2.设置默认值
*${val!"写默认值"}
*拓展:如何防止日期为空
*${curdate?!"默认值"time} 这种写法错误!没有这种写法!
*正确的方式是加个判断条件
<#if curdate ??> //这个判断条件不是“curdate != null”这样写的,??表示有值
当前日期:${curdate?time}
<#else>
curdate属性值为null
</#if>
7.include
*将另外一个页面引入本页面时可使用以下命令
<#include "first.ftl"/> //这里要注意的是:你的当前数据集中必须有first.ftl中需要的数据才行。
*其实FreeMarker模版和jsp差不多,jsp也是一种模版。
*注意:如果在生成Html页面时,模版中取的数据,数据集中没有,那么会报错,还有ftl文件中<!---->并不是注释,只有在生成对应的html文件后,
*在html文件中它才是有效的。所以即便你是在<!---->中写的取数据,如果取不到一样会报错。
*模版文件的扩展名为ftl但是这个不是规定的,你可以取任意扩展名,即便你写为jsp也行但是容易误导你自己,所以一般都使用ftl
<html>
<head>
<meta charset="UTF-8">
<title>${title}</title>
</head>
<body>
<!--取包装类中的数据-->
<label>学号:</label>${student.id}
<label>姓名:</label>${student.name}
<label>住址:</label>${student.adds}
<!--取list列表students中数据-->
<#list students as s>
<tr>
<td>${s.id}</td>
<td>${s.name}</td>
<td>${s.adds}</td>
</tr>
</#list>
<!--if条件判断(隔一行变色:判断条件是偶数行为红色)-->
<#list students as s>
<#if s_index % 2 ==0>
<tr style="color:red">
<#else>
<tr>
</#if>
<td>${s.id}</td>
<td>${s.name}</td>
<td>${s.adds}</td>
</tr>
</#list>
当前日期:${curdate?string("yyyy/MM/dd HH:mm:ss")}
当前日期:${curdate?date}
当前日期:${curdate?time}
当前日期:${curdate?datetime}
引入另外一个页面
<#include "first.ftl"/>
</body>
</html>
--------------项目中使用FreeMarker----------------
*在项目中使用FreeMarker要把FreeMarker和spring整合下
*把Configuration对象交给spring去管理。交给spring管理后创建Configuration对象的类就不一样了
*在ApplicationContext.xml配置文件中添加
<!-- 配置FreeMarker的Configuration对象 -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- 模版路径 -->
<property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
<!-- 默认字符集 -->
<property name="defaultEncoding" value="utf-8"/>
</bean>
*添加jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
*静态文件生成的时机
1.当用户第一次访问时生成静态文件(不推荐!)
*缺点:如果并发高,多个用户同时访问,可能会导致静态页面在没有生成完全的时候被访问。不推荐!
2.提前生成(推荐)
*比如商品详情页面,当我们在后台添加某个商品的时,就该生成该商品详情的静态页面。在后台编辑该商品详情时,重新生成静态页面。
*如果要实现这样的功能,后台需要和taotao-portal联动。需要portal发布服务,供后台系统调用。当后台添加或编辑商品的时候就调用该服务(生成静态页面)。
*此时portal所需要做的就是发布服务供后台调用生成静态页面。用户访问这些静态页面时,不需要在访问tortal所在的tomcat服务,直接访问Nginx请求静态资源(html页面)
*portal发布生成静态页面的服务
1.获得数据的方式还是通过rest发布的服务获得数据。
2.生成静态页面
3.响应:生成成功。
*Service
*获得参数:商品id,根据id调用rest发布的服务获得商品数据,生成静态页面。返回:成功。
*参数:商品id
*返回值:TaotaoResult
*写模版
*将item.jsp拷贝过来改为item.ftl,然后在此基础上做些修改。
*需要修改的地方就是一些jsp标签使用的地方,其他的比如js和el表达式都不需要改变。(Js中有关延迟加载的部分代码可以删掉了)
*Controller
*接收商品id,调用Service生成静态页面,返回json数据。
*参数:商品ID
*返回值:TaotaoResult。
*静态页面会输出到指定的文件夹。生成的静态页面css样式如果是用不了,使用Nginx访问本地静态资源即可。