Freemarker生成商品详情静态页面
程序员文章站
2022-05-31 14:16:03
...
Freemarker 模板引擎技术,是一种基于模板和数据生成可用的文本的工具。例如,我们可以通过定义 JavaBean 对象的格式,从数据库提取字段名称、类型,生成 JavaBean 对象。我们还可以用它生成静态的 html 页面,提供访问效率,例如电商网站商品详情页面,布局格式相同,只是内容不一样。
下面我会介绍 Freemarker 在电商网站生成商品详情页面的具体使用方法。
1.引入 jar 包
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
2.创建 service 接口和实现
package com.p7.framework.service;
import java.util.Map;
public interface StaticPageService {
void createGoodsStaticHtml(Map<String, Object> root, String id);
}
package com.p7.framework.service.impl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Map;
import javax.servlet.ServletContext;
import org.apache.log4j.Logger;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import com.p7.framework.service.StaticPageService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class StaticPageServiceImpl implements StaticPageService, ServletContextAware {
private static final Logger logger = Logger.getLogger(StaticPageServiceImpl.class);
private ServletContext servletContext;
private Configuration conf;
/**
* 注入 SpringMVC 的 FreeMarkerConfigurer 启动配置类
*/
public void setFreeMarkerConfigurer(FreeMarkerConfigurer freeMarkerConfigurer) {
this.conf = freeMarkerConfigurer.getConfiguration();
}
/**
* 注入 ServletContext ,获取路径
*/
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
/**
*
* @param root
* 商品信息
* @param id
* 商品 id
*/
public void createGoodsStaticHtml(Map<String, Object> root, String id) {
// 获取到路径
String path = servletContext.getRealPath("/html/goods/detail/" + id + ".html");
// 创建文件
File f = new File(path);
// 判断父文件夹存在不存在
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
// 输出流
Writer out = null;
// 创建输出流并指定编码UTF-8,此处的编码与
try {
out = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
// 指定模板 返回模板对象 读UTF-8
Template template = conf.getTemplate("freemarker.html");
template.process(root, out);
} catch (UnsupportedEncodingException e) {
logger.error("UnsupportedEncodingException: " + e.getMessage());
} catch (FileNotFoundException e) {
logger.error("FileNotFoundException: " + e.getMessage());
} catch (IOException e) {
logger.error("IOException: " + e.getMessage());
} catch (TemplateException e) {
logger.error("TemplateException: " + e.getMessage());
}
}
}
3.在 SpringMVC 配置文件中配置 FreeMarkerConfigurer
// 在 Freemarker 入门程序中创建的 Configuration ,用来设置模板的加载目录,这个路径必须写成绝对路径。
// Configuration conf = new Configuration();
// conf.setDirectoryForTemplateLoading(new File("E:/ws/framework/demo/ftl/"));
// 但是在实际的项目开发中,我们不可能使用这样一个路径,
// 因此,我们需要借助其他方法,例如 SpringMVC 中有 FreeMarkerConfigurer 这样的一个类
<!-- Freemarker 配置 -->
<bean id="staticPageService" class="com.p7.framework.service.impl.StaticPageServiceImpl">
<!-- 注入FreeMarkerConfigurer -->
<property name="freeMarkerConfigurer">
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- 采用相对路径来设置模板目录 -->
<property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
</bean>
</property>
</bean>
<!-- 配置静态资源访问 -->
<mvc:resources mapping="/resources/**" location="/" />
4.controller 层
由于是测试,直接访问该接口,弄一些测试数据。
package com.p7.framework.controller;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.p7.framework.service.StaticPageService;
@Controller
@RequestMapping("/freemarker")
public class FreemarkerController {
@Autowired
private StaticPageService staticPageService;
@GetMapping()
public void createGoodsStaticHtml() {
String id = "7758521";
Map<String, Object> root = new HashMap<String, Object>();
List<String> sizes = new ArrayList<String>();
sizes.add("s");
sizes.add("xl");
sizes.add("xxl");
root.put("goodsName", "苍**同款ww");
root.put("goodsPrice", new BigDecimal("100.00"));
root.put("crowd", "you just can't keep it in your pants!");
root.put("imgSrc", "xxoo");
root.put("sizes", sizes);
staticPageService.createGoodsStaticHtml(root, id);
}
}
5.项目结构
6.模板内容
因为只是测试,所以模板内容只是简单的一些文本输出。实际的应用中,模板内容是包含了引入的 js、css 等等的文件。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
商品名称:${goodsName}
商品价格:${goodsPrice}
适合人群:${crowd}
商品尺码:
<#list sizes as size>
${size}
</#list>
商品图片:<img src="${imgSrc}">
</body>
</html>
7.测试
测试通过模板和数据生成静态页面。
# resources 是映射的静态路径的相对跟路径,也就是在配置文件中配置的
# <mvc:resources mapping="/resources/**" location="/" />
http://localhost:8080/项目名/freemarker
http://localhost:8080/项目名/resources/html/goods/detail/7758521.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
商品名称:苍**同款ww
商品价格:100
适合人群:you just can't keep it in your pants!
商品尺码:
s
xl
xxl
商品图片:<img src="xxoo">
</body>
</html>
8.说明
在实际的电商应用中,一般情况下,静态的商品详情页在点击商品上架时,生成静态页面,也就是说,在上架的接口中获取到商品的信息,调用 StaticPageService 的方法生成静态页面。
在访问电商主页或者查询商品时,我们也需要对静态页面的 url 作一些处理
<a href="javascript:void(0)" onclick="window.open('http://localhost:8080/resources/html/goods/detail/${goods.id}.html')"