freemarker
为什么用freemarker
商品详情信息频繁访问 jsp页面被频繁解析 加载起来太慢, 因此我们要把网页静态化。
什么是freemarker
FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成XML,JSP或Java 等。
目前企业中:主要用Freemarker做静态页面或是页面展示
Freemarker的语法和使用方法
把freemarker的jar包添加到工程中。
Maven工程添加依赖
代码语言:javascript复制<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
原理就是用java文件和模板通过freemarker来生成html静态文件。
ftl文件和jsp文件差不多 就是有点语法稍微不同 ftl文件在jsp文件中改造。
student.ftl
代码语言:javascript复制<html>
<head>
<title>student</title>
</head>
<body>
学生信息:<br>
学号:${student.id}
姓名:${student.name}
年龄:${student.age}
家庭住址:${student.address}<br>
学生列表:
<table border="1">
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
<th>家庭住址</th>
</tr>
<#list students as stu>
<#if stu_index % 2 ==0>
<tr bgcolor="red">
<#else>
<tr bgcolor="green">
</#if>
<td>${stu_index}</td>
<td>${stu.id}</td>
<td>${stu.name}</td>
<td>${stu.age}</td>
<td>${stu.address}</td>
</tr>
</#list>
</table>
<!-- 可以使用?date ?time ?datetime ?string(partten)-->
当前日期:${date?string("yyyy/MM/dd HH:mm:ss")}<br>
null值的处理: ${val!"val的值为null"}<br>
判断val的值是否为null:<br>
<#if val??>
val中有内容
<#else>
val的值为null
</#if>
引用模板测试:<br>
<#include "hello.ftl">
</body>
</html>
hello.ftl
代码语言:javascript复制${hello}
java文件
student实体类
代码语言:javascript复制package cn.e3mall.freemarker;
public class Student {
private int id;
private String name;
private int age;
private String address;
public Student() {}
public Student(int id, String name, int age, String address) {
super();
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int 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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
测试类:
代码语言:javascript复制package cn.e3mall.freemarker;
import java.io.File;
import java.io.FileWriter;
import java.io.FilterWriter;
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 freemarker.template.Configuration;
import freemarker.template.Template;
public class FreeMarkerTest {
@Test
public void testFreeMarker() throws Exception {
//创建Configuration对象
Configuration configuration = new Configuration(Configuration.getVersion());
//设置模板文件
configuration.setDirectoryForTemplateLoading(new File("D:/workspace/e3-item-web/src/main/webapp/WEB-INF/ftl"));
//模板文件编码格式
configuration.setDefaultEncoding("utf-8");
//加载模板文件 创建模板对象
// Template template = configuration.getTemplate("hello.ftl");
Template template = configuration.getTemplate("student.ftl");
//创建数据集
Map data = new HashMap<>();
data.put("hello", "hello freemarker!");
//创建pojo对象
Student student = new Student(1,"小明",18,"北京");
data.put("student", student);
List<Student> students = new ArrayList<>();
students.add(new Student(1,"小明1",18,"北京"));
students.add(new Student(2,"小明2",18,"北京"));
students.add(new Student(3,"小明3",18,"北京"));
students.add(new Student(4,"小明4",18,"北京"));
students.add(new Student(5,"小明5",18,"北京"));
students.add(new Student(6,"小明6",18,"北京"));
students.add(new Student(7,"小明7",18,"北京"));
data.put("students", students);
//添加日期类型
data.put("date", new Date());
//null值的处理
data.put("val", "123");
//创建Writer对象 指定输出文件的路径和文件名
// Writer out = new FileWriter(new File("D:/freemarkertest/hello.txt"));
Writer out = new FileWriter(new File("D:/freemarkertest/student.html"));
//生成静态页面
template.process(data, out);
//关闭流
out.close();
}
}
生成的html文件:
freemarker与spring整合:
springmvc.xml文件
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:conf/resource.properties" />
<context:component-scan base-package="cn.e3mall.item.controller" />
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<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>
<!-- 引用dubbo服务 -->
<dubbo:application name="e3-item-web"/>
<dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/>
<dubbo:reference interface="cn.e3mall.service.ItemService" id="itemService" />
</beans>
web.xml文件
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>e3-item-web</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!-- 解决post乱码 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- springmvc的前端控制器 -->
<servlet>
<servlet-name>e3-item-web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name "-servlet.xml" -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>e3-item-web</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
测试类:
代码语言:javascript复制package cn.e3mall.item.controller;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import freemarker.template.Configuration;
import freemarker.template.Template;
@Controller
public class HtmlGenController {
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@RequestMapping("genhtml")
@ResponseBody
public String genHtml() throws Exception{
Configuration configuration = freeMarkerConfigurer.getConfiguration();
//加载模板对象
Template template = configuration.getTemplate("hello.ftl");
//创建数据集
Map data = new HashMap<>();
data.put("hello", 123456);
Writer out = new FileWriter(new File("D:/freemarkertest/hello2.html"));
template.process(data, out);
out.close();
return "OK";
}
}
生产中:
在商品添加后发送消息 这边接收消息 因此我们需要配置ActiveMQ消息队列
我们需要改造商品详情页面的jsp页面,改成ftl文件 然后我们实现消息队列的MessageListener接口就可以生成指定目录下的静态文件 ,然后我们用Nginx访问html文件。
输出文件的名称:商品id “.html”
输出文件的路径:工程外部的任意目录。
网页访问:使用nginx访问网页。在此方案下tomcat只有一个作用就是生成静态页面。
工程部署:可以把e3-item-web部署到多个服务器上。
生成静态页面的时机:商品添加后,生成静态页面。可以使用Activemq,订阅topic(商品添加)
applicationContext-activemq.xml
代码语言:javascript复制<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.25.130:61616" />
</bean>
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="targetConnectionFactory" />
</bean>
<!--这个是主题目的地,一对多的 -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="itemAddTopic" />
</bean>
<!-- 监听商品添加消息 同步索引库 -->
<bean id="htmlGenListener" class="cn.e3mall.item.listener.HtmlGenListener"/>
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="topicDestination" />
<property name="messageListener" ref="htmlGenListener" />
</bean>
</beans>
MessageListener接口实现类:
代码语言:javascript复制package cn.e3mall.item.listener;
import java.io.FileWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import cn.e3mall.item.pojo.Item;
import cn.e3mall.pojo.TbItem;
import cn.e3mall.pojo.TbItemDesc;
import cn.e3mall.service.ItemService;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class HtmlGenListener implements MessageListener{
@Autowired
private ItemService itemService;
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@Value("${HTML_GEN_PATH}")
private String HTML_GEN_PATH;
@Override
public void onMessage(Message message) {
try {
//创建模板
//从消息中取商品id
TextMessage textMessage = (TextMessage)message;
String text = textMessage.getText();
Long itemId = new Long(text);
//等待事务提交
Thread.sleep(1000);
//根据商品id查询商品信息
TbItem tbItem = itemService.geTbItemById(itemId);
Item item = new Item(tbItem);
//取商品描述信息
TbItemDesc itemDesc = itemService.geTbItemDescById(itemId);
Map data = new HashMap<>();
data.put("item", item);
data.put("itemDesc", itemDesc);
//加载模板对象
Configuration configuration = freeMarkerConfigurer.getConfiguration();
Template template = configuration.getTemplate("item.ftl");
//创建输出流 指定目录和文件名
Writer out = new FileWriter(HTML_GEN_PATH itemId ".html");
//生成静态页面
template.process(data, out);
//关闭流
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
resource.properties
代码语言:javascript复制#静态页面输出目录
HTML_GEN_PATH=D:/freemarkertest/item/