Freemarker模版技术

(一)网页静态化技术简介

  1. 如果直接从数据库中获取数据的弊端:<br /> 1、数据量大,造成查询效率低。页面响应慢,用户体验差。<br /> 2、造成数据库访问压力巨大。<br />解决的问题就是减轻数据库压力,为什么使用页面静态化技术,因为提前加载生成静态页面,直接访问静态页面效率远高于访问数据库将数据查出来展示到页面上.<br />这种技术用在电商网站商品详情和新闻网站比较多<br /> <br />另外我们如果将网页以纯静态化的形式展现,就可以使用Nginx这样的高性能的web服务器来部署。Nginx可以承载5万的并发,而Tomcat只有几百。关于Nginx我们在后续的课程中会详细讲解。<br /> <br />FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker Web 容器无关,即在 Web 运行时,它并不知道 Servlet HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成 XMLJSP Java 等。<br />![](https://cdn.nlark.com/yuque/0/2020/jpeg/350923/1592467330354-6ac3386a-5c4c-455b-987f-f87d11c2b627.jpeg#height=234&width=548)<br />

(二)入门demo

1.坐标依赖

  1. <dependency><br /> <groupId>org.freemarker</groupId><br /> <artifactId>freemarker</artifactId><br /> <version>2.3.23</version><br /> </dependency>

2.创建模版文件

通过word变成html,然后页面后缀名改成ftl 就是模版了.就是这么简单,什么都不需要修改,放在哪里都可以, 读取模版的时候是通过绝对路径读取的.是jar工程,不是war工程,没有webapps的概念

另存为html方式
Freemarker[笔记] - 图1

把变为html的文件修改后缀名为.ftl 就成功了

Freemarker[笔记] - 图2

3.步骤


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 cn.itcast.domain.User;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class FreemarkerDemo {

public static void main(String[] args) throws Exception {
// 第一步:创建一个 Configuration 对象,直接 new 一个对象。构造方法的参数就是 freemarker的版本号。
Configuration configuration = new Configuration(Configuration.getVersion());
// 第二步:设置模板文件所在的路径目录。
configuration.setDirectoryForTemplateLoading(new File(“E:\workspace\pinyougou51\freemarkerDemo\src\main\resources”));
// 第三步:设置模板文件使用的字符集。一般就是 utf-8.
configuration.setDefaultEncoding(“utf-8”);
// 第四步:加载一个模板,创建一个模板对象。
Template template = configuration.getTemplate(“test.ftl”);
// 第五步:创建一个模板使用的数据集,可以是 pojo 也可以是 map。一般是 Map。
Map map = new HashMap();
map.put(“name”, “world”);
map.put(“age”, 19);

List userList= new ArrayList();

for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(i);
user.setName(“zs”+i);
userList.add(user);
}

map.put(“userList”, userList);

map.put(“today”, new Date());

map.put(“xingming”, null);

map.put(“num”, 12345678);

// 第六步:创建一个 Writer 对象,一般创建一 FileWriter 对象,指定生成的文件名。
Writer writer = new FileWriter(“f:/abc.html”);
// 第七步:调用模板对象的 process 方法输出文件。
template.process(map, writer);
System.out.println(“执行成功了”);
// 第八步:关闭流
writer.close();
}

(三)Freemarker的操作

1.使用正则表达式给目标替换一下


Freemarker[笔记] - 图3

在idea搜索(注意需要勾选下Regex 开启正则支持)
Freemarker[笔记] - 图4

Find : >([a-zA-Z]{1,})<
Replace: >\${$1!‘’}<

(四)Freemarker的指令

注意:每次修改模版都需要运行main方法,否则修改的不会生效

1.插值&注释

插值 ${XXXXX}
注释 <#— xxxxxxx—> 也可以使用HTML的注释,都可以的.

2.#assign ${} 取值&赋值

赋值 <#assign username=’zhangsan’> 就是给username为zhangsan的赋值
取值 通过插值来获取 ${username} 就能获取上面的username属性的值了
作用在页面上进行赋值操作,有时候需要页面初始化就给元素设置内容.就需要使用assign来赋值

3.#include静态包含

静态包含 <#include ‘head.ftl’> 把别的页面包含进来 ,输入文件的名字
Freemarker[笔记] - 图5黑马出品,必是精品 是hear.ftl的内容就展示进来了

4.判空

如果不判空的话,,那么你没有值传给模版的话会报错
<#if yj??> XXXXXXX代码 </#if>

5.如果是空就给默认值

${txdz!‘’}

6.if判断

if判断

需要给age 赋值 ,注意这个括号,用括号把这个判断括起来


<#if (age > 18) >
您已成年,可以访问此网站
<#else>
你未成年,不可以访问此网站
</#if>
Freemarker[笔记] - 图6

7.#list循环遍历

循环遍历指令 遍历user对象, name是user对象的属性,对象里面需要提供getset方法
java代码:
List userList= new ArrayList();

for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(i);
user.setName(“zs”+i);
userList.add(user);
}

map.put(“userList”, userList);

模版代码
取值是看红色的,这两个红色要相同,取值是通过map的key取值

取出用户的名字

<#list userList as user>
${user.name}

</#list>

8.如何回显#list的值

Freemarker[笔记] - 图7

后台提供代码格式是 大Map 里面保存List集合,List集合里面加小Map 传递到页面给 大Map 传递过去

/**

  1. * 业绩表说明的PDF接口
  2. * **@param ****_kidYwlsh<br />_**<br /> * **@param ****_response<br />_**<br /> * **@return<br />**<br /> */<br /> @GetMapping(**"/exportyjb/{kidYwlsh}"**)

@ApiOperation(value = “导出”)

@ApiImplicitParam(name = “kidYwlsh”, value = “业务流水号”, dataType = “String”)

public R exportyjb(@PathVariable(“kidYwlsh”) String kidYwlsh, HttpServletResponse response) {

  1. //根据业务记录号查询人员业绩信息表,进行成果数据存储
  2. TB0206SRyyjxxbEntity tB0206SRyyjxxbEntity = **this**.**tB0206SRyyjxxbService**.selectOne(**new **EntityWrapper<TB0206SRyyjxxbEntity>().eq(**"KID_YWLSH"**,kidYwlsh));
  3. List<TB0206SRyyjxxbEntity> kid_ywlsh = **this**.**tB0206SRyyjxxbService**.selectList(**new **EntityWrapper<TB0206SRyyjxxbEntity>().eq(**"KID_YWLSH"**, kidYwlsh));<br />
  4. ArrayList<Map> objects = **new **ArrayList<>();
  5. **for **(TB0206SRyyjxxbEntity ywlsh : kid_ywlsh) {
  6. // dataMap.put("xh",);// 序号 xh ${yj.xh}
  7. Map<String, Object> dataMap = **new **HashMap<>();
  8. dataMap.put(**"xmkssj"**,
  9. **this**.DateToDateStringyyyyMMdd(ywlsh.getXmkssj()));//项目开始时间 xmkssj ${yj.xmkssj}
  10. dataMap.put(**"xmjzsj"**,
  11. **this**.DateToDateStringyyyyMMdd(ywlsh.getXmjssj()));//项目截止时间 xmjzsj ${yj.xmjzsj}
  12. dataMap.put(**"xmmi"**,ywlsh.getXmmc());//项目名称 xmmi ${yj.xmmi}
  13. dataMap.put(**"xmgm"**,ywlsh.getXmgm());//项目规模 xmgm ${yj.xmgm}
  14. dataMap.put(**"gznr"**,ywlsh.getGznr());//工作内容 gznr ${yj.gznr}
  15. dataMap.put(**"drzw"**,ywlsh.getDrzw());//担任职务drzw ${yj.drzw}<br />
  16. objects.add(dataMap);
  17. }
  18. HashMap<String, Object> stringlistHashMap = **new **HashMap<String, Object>();
  19. stringlistHashMap.put(**"yj"**,objects);<br /> <br />
  20. WordUtils wordUtils = **new **WordUtils();
  21. String currentSys = System._getProperty_(**"os.name"**);
  22. File dir;<br /> System.**_out_**.println(**"当前系统为:[" **+ currentSys + **"]"**);
  23. **if**(currentSys.toLowerCase().indexOf(**"win"**) != -1){
  24. System.**_out_**.println(**"====windows======开始导出word=========" **);
  25. dir = **new **File(**"C:/exportFile/exportyjb/"**+kidYwlsh);
  26. **if**(!dir.exists()){
  27. dir.mkdirs();<br /> }<br /> }**else**{//linux
  28. System.**_out_**.println(**"====Linux======开始导出word=========" **);
  29. dir = **new **File(**"/home/exportFile/exportyjb/"**+kidYwlsh);
  30. **if**(!dir.exists()){
  31. dir.mkdirs();<br /> }<br /> }<br /> String exportDocFile = dir + **"/b"**+kidYwlsh+**".doc"**;
  32. String exportPdfFile = dir + **"/b"**+kidYwlsh+**".pdf"**;
  33. wordUtils.createWord(exportDocFile,stringlistHashMap,**"exportyjb.ftl"**);
  34. **streamUtils**.fileStream(exportPdfFile,response);<br />
  35. **return **R._ok_();

}

模版代码
java代码传过来的最大的map集合名字就是 yj 然后在模版里面定义ayj来进行循环遍历取值, (!!!需要注意判断空,不然会报错)

<#if yj??>

<#list yj as ayj>

<tr style=’mso-yfti-irow:1;mso-yfti-lastrow:yes;height:23.25pt’>
<td width=”9%” valign=top style=’width:9.08%;border:solid windowtext 1.0pt;

border-top:none;mso-border-top-alt:solid windowtext .5pt;mso-border-alt:solid windowtext .5pt;

padding:0cm 5.4pt 0cm 5.4pt;height:23.25pt’>
<p class=MsoListParagraph style=’text-indent:0cm;mso-char-indent-count:0><b

style=’mso-bidi-font-weight:normal’><span lang=EN-US style=’mso-no-proof:

yes’>${ayj_index+1}<o:p></o:p></span></b></p>
</td>
<td width=”16%” valign=top style=’width:16.06%;border-top:none;border-left:

none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;

mso-border-top-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;

mso-border-alt:solid windowtext .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:23.25pt’>
<p class=MsoListParagraph style=’text-indent:0cm;mso-char-indent-count:0><b

style=’mso-bidi-font-weight:normal’><span lang=EN-US style=’mso-no-proof:

yes’>${ayj.xmkssj!“”}<o:p></o:p></span></b></p>
</td>
<td width=”16%” valign=top style=’width:16.8%;border-top:none;border-left:

none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;

mso-border-top-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;

mso-border-alt:solid windowtext .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:23.25pt’>
<p class=MsoListParagraph style=’text-indent:0cm;mso-char-indent-count:0><b

style=’mso-bidi-font-weight:normal’><span lang=EN-US style=’mso-no-proof:

yes’>${ayj.xmjzsj!“”}<o:p></o:p></span></b></p>
</td>
<td width=”14%” valign=top style=’width:14.24%;border-top:none;border-left:

none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;

mso-border-top-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;

mso-border-alt:solid windowtext .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:23.25pt’>
<p class=MsoListParagraph style=’text-indent:0cm;mso-char-indent-count:0><b

style=’mso-bidi-font-weight:normal’><span lang=EN-US style=’mso-no-proof:

yes’>${ayj.xmmi!“”}<o:p></o:p></span></b></p>
</td>
<td width=”14%” valign=top style=’width:14.6%;border-top:none;border-left:

none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;

mso-border-top-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;

mso-border-alt:solid windowtext .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:23.25pt’>
<p class=MsoListParagraph style=’text-indent:0cm;mso-char-indent-count:0><b

style=’mso-bidi-font-weight:normal’><span lang=EN-US style=’mso-no-proof:

yes’>${ayj.xmgm!“”}<o:p></o:p></span></b></p>
</td>
<td width=”14%” valign=top style=’width:14.6%;border-top:none;border-left:

none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;

mso-border-top-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;

mso-border-alt:solid windowtext .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:23.25pt’>
<p class=MsoListParagraph style=’text-indent:0cm;mso-char-indent-count:0><b

style=’mso-bidi-font-weight:normal’><span lang=EN-US style=’mso-no-proof:

yes’>${ayj.gznr!“”}<o:p></o:p></span></b></p>
</td>
<td width=”14%” valign=top style=’width:14.6%;border-top:none;border-left:

none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;

mso-border-top-alt:solid windowtext .5pt;mso-border-left-alt:solid windowtext .5pt;

mso-border-alt:solid windowtext .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:23.25pt’>
<p class=MsoListParagraph style=’text-indent:0cm;mso-char-indent-count:0><b

style=’mso-bidi-font-weight:normal’><span lang=EN-US style=’mso-no-proof:

yes’>${ayj.drzw!“”}<o:p></o:p></span></b></p>
</td>
</tr>
</#list>

</#if>

(五)Freemarker的函数

1.内建函数(内置函数)

获取集合的长度
通过 插值 来取值
语法: ${ xxxxxxxx?size}

userList集合长度:${userList?size}

结果:Freemarker[笔记] - 图8

2.?eval 将字符串转换成对象


指定对象user (在前端里面一对大括号就是一个对象,指定的时候就是属性名属性值指定)


注意下面的是带单引号,字符串,不是对象,用内置函数指定 xxxxxxxxx?eval 就可以将字符串转换成对象了

<#assign user=’{“id”:1,”username”:”王五”}’?eval>

取出usename
${user.username}

3.展示日期

java代码
map.put(“today”, new Date());
模版代码

${today?date}

${today?time}

${today?datetime}

${today?string(‘dd.MM.yyyy HH:mm:ss’)}

${today?string(‘yyyy-MM-dd HH:mm:ss’)}

${today?string(‘yyyy年MM月dd日 HH:mm:ss’)}

效果(从上往下依次显示)
Freemarker[笔记] - 图9

4.空值的处理,给个默认值,如果是null的就变为默认值

java代码
map.put(“xingming”, null);
报错原因,不能解析空值,需要处理一下
Freemarker[笔记] - 图10
解决办法
! 号, 下面意思是如果是null,你就给它替换成空串
Freemarker[笔记] - 图11
如果是null,你可以给他一个默认值为 赵六
${xingming!’zhaoliu’}
效果
Freemarker[笔记] - 图12

5.if判断处理null值

?? 两个问号判断变量是否为空 如果变量不为空就是true,

<#if xingming??>

${xingming}
<#else>

${xingming!’tianqi’}
</#if>

6.数值转换函数

java代码:
map.put(“num”, 12345678);

?C 函数

${num?c}
Freemarker[笔记] - 图13

${xingming!!}

(六)运算符

算数运算符
FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , %
逻辑运算符
逻辑运算符有如下几个:
逻辑与:&&
逻辑或:||
逻辑非:!
逻辑运算符只能作用于布尔值,否则将产生错误

比较运算符
表达式中支持的比较运算符有如下几个:
1 =或者==:判断两个值是否相等. 尽量不要写单等于号,用双等于号
2 !=:判断两个值是否不等.
3 >或者gt:判断左边值是否大于右边值
4 >=或者gte:判断左边值是否大于等于右边值
5 <或者lt:判断左边值是否小于右边值
6 <=或者lte:判断左边值是否小于等于右边值

注意: =和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值,否则会产生错误,而且FreeMarker是精确比较,”x”,”x “,”X”是不等的.其它的运行符可以作用于数字和日期,但不能作用于字符串,大部分的时候,使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成FTL标签的结束字符,当然,也可以使用括号来避免这种情况,如:<#if (x>y)>

案例

(一)根据数据库的数据生成统计图插入到word文档里面









(二)基于Freemarker生成商品详情页

1.构建项目

构建interface服务(Maven Model)
通过parent 创建MavenModel 先创建interface 的jar工程, 依赖pojo工程,(因为形参可能是pojo的)
interface工程没有配置文件,也没有web.xml (因为是jar工程)


构建service服务(Maven Model)
1. 构建是war工程,导入jar包,一堆jar包,直接复制别的工程jar包
需要引入 interface 和dao工程
配置tomcat插件,端口号也需要修改一下
2. 导入一些相关的配置文件web.xml,以及Spring的配置文件
Spring配置文件修改dubbo服务协议的端口号什么的,service层还需要事务的支持
web.xml只需要配置ContextLoaderListener 加载配置文件即可


构建controller层服务(Maven Model)
war工程,需要导入依赖, 还需要依赖interface工程和common工程,修改端口号

配置SpringMVC的配置文件:
主要就是注解驱动,
dubbo的配置
还需要静态模板的配置

修改web.xml配置文件, POST请求乱码问题,前端控制器

此致项目搭建完了

2.将数据库数据查询出来放到模板上面

需要写一个接口
思考数据问题:页面数据来源于三张表: 这 tbgoods tb_goods_desc tb_item 三张表
到底是list集合还是map集合? 思考一下,弄个组合实体类,把三张表的实体类都放在组合实体类里面.
写接口
/
基于goodsId查询页面静态化所需要的商品数据
ItemPageService.class 接口
*
@param goodsId
*
@return
*/
public Goods findOne(Long goodsId);
思考:
什么时候生成商品详情页?是在商品上架时同步生成商品详情页,下架时候删除商品详情页.
商品上下架时候传递的是主键(goodsid) 基于商品id查询商品数据,这样通过这个id查询的到三个表的数据.
组装数据
就是把数据都通过goodsId查出来保存到组合实体类里面

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.grouppojo.Goods;
import com.pinyougou.item.service.ItemPageService;
import com.pinyougou.mapper.TbGoodsDescMapper;
import com.pinyougou.mapper.TbGoodsMapper;
import com.pinyougou.mapper.TbItemCatMapper;
import com.pinyougou.mapper.TbItemMapper;
import com.pinyougou.pojo.TbGoods;
import com.pinyougou.pojo.TbGoodsDesc;
import com.pinyougou.pojo.TbItem;
import com.pinyougou.pojo.TbItemExample;
import com.pinyougou.pojo.TbItemExample.Criteria;
@Service
public class ItemPageServiceImpl implements ItemPageService {

@Autowired
private TbGoodsMapper goodsMapper;

@Autowired
private TbGoodsDescMapper goodsDescMapper;
@Autowired
private TbItemMapper itemMapper;
@Autowired
private TbItemCatMapper itemCatMapper;

/

基于goodsId查询页面静态化所需要的商品数据
ItemPageServiceImpl.class
*@param goodsId
*@return
/
@Override
public Goods findOne(Long goodsId) {
/**
组装组合实体类
/
Goods goods = new Goods();

TbGoods tbGoods = goodsMapper.selectByPrimaryKey(goodsId);
goods.setGoods(tbGoods);

TbGoodsDesc goodsDesc = goodsDescMapper.selectByPrimaryKey(goodsId);
goods.setGoodsDesc(goodsDesc);
//封装页面需要显示的分类名称
String category1Name = itemCatMapper.selectByPrimaryKey(tbGoods.getCategory1Id()).getName();
String category2Name = itemCatMapper.selectByPrimaryKey(tbGoods.getCategory2Id()).getName();
String category3Name = itemCatMapper.selectByPrimaryKey(tbGoods.getCategory3Id()).getName();

Map categoryMap = new HashMap<>();
categoryMap.put(“category1Name”, category1Name);
categoryMap.put(“category2Name”, category2Name);
categoryMap.put(“category3Name”, category3Name);
goods.setCategoryMap(categoryMap);;
//itemList 需要条件查询,因为goodsId只是一个字段,不是item表的主键 TbItemExample example = new TbItemExample();
Criteria criteria = example.createCriteria();
criteria.andGoodsIdEqualTo(goodsId);
List itemList = itemMapper.selectByExample(example);
goods.setItemList(itemList);

*return
goods;
}
}

结合组装的数据生成模版
访问一个请求生成静态页,请求访问到controller层
如果就生成一个静态页,就不需要@RequestMapping 在方法去加@RequestMapping就行了
使用模版需要导入相关的jar包

导入依赖
导入org.freemarker的依赖,还需要加spring的配置文件
在SpringMVC.xml配置,是固定的,粘过去用就行


<bean id=
“freemarkerConfig”
class=
“org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer”>
<property name=
“templateLoaderPath” value=“/WEB-INF/ftl/“ />
<property name=
“defaultEncoding” value=“UTF-8”_ />


关于Freemarker路径问题
Freemarker[笔记] - 图14
写java代码

package com.pinyougou.item.controller;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig;
import com.alibaba.dubbo.config.annotation.Reference;
import com.pinyougou.grouppojo.Goods;
import com.pinyougou.item.service.ItemPageService;
import com.pinyougou.pojo.TbItem;
import freemarker.template.Configuration;
import freemarker.template.Template;
/
静态页controller层
@author Administrator
*/
@RestController
public class ItemPageController {

@Reference
private ItemPageService itemPageService;

@Autowired
private FreeMarkerConfig freemarkerConfig;
/

生成静态页
1.使用模版,需要导入相关的jar包
2.配置文件配置
3.注入FreeMarkerConfig(是spring的FreeMarkerConfig接口,别注入错了)
ItemPageController.class
**
@param goodsId
*
@return
*/
@RequestMapping(“/genItemHtml”)
public String genItemHtml(Long goodsId) {
try {
//把数据取出来
Goods goods = itemPageService.findOne(goodsId);

// 第一步:创建一个 Configuration
Configuration configuration = freemarkerConfig.getConfiguration();
// 第二步:加载一个模板,创建一个模板对象。这个填写的路径是根据配置文件配置的,
//你的模版文件也需要放入在那个指定的配置文件里面
Template template = configuration.getTemplate(“item.ftl”);
// 第三步 :取出数据准备放入模版里面
List itemList = goods.getItemList();
/

可能很多人有疑问,tbItem里面不是有goods么,为什么还取出来,
因为我们是输出模版,所以需要取出来当前的tbItem出来,如果你不循环遍历这个,
光itemList你不知道取出哪个来
/
for (TbItem tbItem : itemList) {
//组装数据把页面需要的数据放入map中
Map map = new HashMap<>();
map.put(“goods”, goods);
//当前商品的信息
map.put(“tbItem”, tbItem);
// 第四步:创建一个 Writer 对象,一般创建一 FileWriter 对象,指定生成的文件名。
Writer writer = new FileWriter(“F:\item51\“+tbItem.getId()+”.html”);
// 第五步:调用模板对象的 process 方法输出文件。
template.process(map, writer);
// 第六步:关闭流
writer.close();
}
//这个是提供程序员自己查看的,查看是否成功失败
return “success”;
} catch (Exception e) {
e.printStackTrace();
//这个是提供程序员自己查看的,查看是否成功失败
return e.getMessage();
}
}
}

3.HTML页面改模版处理

多个页面都有一段重复的代码,比如头部,和底部声明,将这些页面重复的代码抽取出来放到别的模版里面用#include标签
<#include ‘xxxxxx.ftl’>
抽取出来的代码不需要表头,直接创建一个file文件修改成 .ftl结尾就可以了

图片的回显(字符串转对象再获取第一个值)



//字符串转对象
<#assign imageList=goods.goodsDesc.itemImages?eval>



<#if (imageList?size>0)>
Freemarker[笔记] - 图15
</#if>


展示商品数据,数组套数据,取值就是遍历套遍历


<#assign specList=goods.goodsDesc.specificationItems?eval>

<#list specList as spec>



${spec.attributeName}





<#list spec.attributeValue as value>

${value} 

</#list>

</#list>

(三)商品上下架操作时同步和删除静态页

用ActiveMQ技术来写,就需要有两个消息,一个是新增静态页的消息,一个是删除静态页的消息,
步骤:
1. 配置两个消息
发布者的配置文件










写发布消息代码(在服务层写的多)

@Override
public void updateIsMarketable(Long[] ids, String isMarketable) {
for (final Long id : ids) {
TbGoods tbGoods = goodsMapper.selectByPrimaryKey(id);
if(“1”.equals(tbGoods.getAuditStatus())) {
//上架
if(“1”.equals(isMarketable)) {
//同步索引库商品数据
jmsTemplate.send(addItemSolrDestination, new MessageCreator() {

@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(id+””);
}
});

//同步生成商品静态页
jmsTemplate.send(itemAddDestination, new MessageCreator() {

@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(id+””);
}
});
}
//下架
if(“0”.equals(isMarketable)) {
//同步删除索引库商品数据
jmsTemplate.send(deleItemSolrDestination, new MessageCreator() {

@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(id+””);
}
});

//同步删除商品静态页
jmsTemplate.send(itemDeleDestination, new MessageCreator() {

@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(id+””);
}
});
}
//审核通过商品,可以上下架
tbGoods.setIsMarketable(isMarketable);
}else {
throw new RuntimeException(“只有审核通过的商品才能上下架操作!”);
}
goodsMapper.updateByPrimaryKey(tbGoods);
}
}

写监听消息代码. 在服务层
1. 添加依赖
Freemarker[笔记] - 图16
2.编写配置文件
配置监听类已经监听消息
配置事务和dubbo等等
3.准备模版,因为需要上架的时候生成静态页需要模版

applicationContext-activemq-consumer.xml

<?xml version=“1.0” encoding=“UTF-8”?>
xmlns:jms=http://www.springframework.org/schema/jms
xsi:schemaLocation=http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd”>













































编写两个监听类(生成静态页的监听类,删除静态页的监听类)


ItemAddMessageListener

package com.pinyougou.search.listener;

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

import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.pinyougou.grouppojo.Goods;
import com.pinyougou.item.service.ItemPageService;
import com.pinyougou.pojo.TbItem;

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

public class ItemAddMessageListener implements MessageListener{

@Autowired
private ItemPageService itemPageService;

@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;

@Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage)message;
String goodsId = textMessage.getText();
Goods goods = itemPageService.findOne(Long.parseLong(goodsId));
//获取模板
Configuration configuration = freeMarkerConfigurer.getConfiguration();
Template template = configuration.getTemplate(“item.ftl”);

//组装静态页数据
List itemList = goods.getItemList();
for (TbItem tbItem : itemList) {
Map map = new HashMap<>();
map.put(“goods”, goods);
map.put(“tbItem”, tbItem);

FileWriter writer = new FileWriter(“F:\item51\“+tbItem.getId()+”.html”);
template.process(map, writer);
writer.close();
}

System.out.println(“生成了商品详情页”+goodsId);
} catch (Exception e) {
e.printStackTrace();
}
}

}

删除模版
ItemDeleMessageListener
package com.pinyougou.search.listener;

import java.io.File;
import java.util.List;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.springframework.beans.factory.annotation.Autowired;

import com.pinyougou.grouppojo.Goods;
import com.pinyougou.item.service.ItemPageService;
import com.pinyougou.pojo.TbItem;

public class ItemDeleMessageListener implements MessageListener{

@Autowired
private ItemPageService itemPageService;

@Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage)message;
String goodsId = textMessage.getText();
Goods goods = itemPageService.findOne(Long.parseLong(goodsId));
List itemList = goods.getItemList();
for (TbItem tbItem : itemList) {
//删除静态页
new File(“F:\item51\“+tbItem.getId()+”.html”).delete();
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}