freemarker

2023-10-12 14:16:57 浏览数 (2)

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}&nbsp;&nbsp;&nbsp;&nbsp;
	姓名:${student.name}&nbsp;&nbsp;&nbsp;&nbsp;
	年龄:${student.age}&nbsp;&nbsp;&nbsp;&nbsp;
	家庭住址:${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/

0 人点赞