Freemarker
网页静态化解决方案在实际开发中运用比较多,例如新闻网站,门户网站中的新闻频道或者是文章类的频道。
网页静态化技术和缓存技术的共同点都是为了减轻数据库的访问压力,但是具体的应用场景不同,缓存比较适合小规模的数据,而网页静态化比较适合大规模且相对变化不太频繁的数据。另外网页静态化还有利于SEO。
如果将网页以纯静态化的形式展现,就可以使用Nginx这样的高性能的web服务器来部署。Nginx可以承载5万的并发,而Tomcat只有几百。
Freemarker简介:
FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker与 Web 容器无关,即在 Web 运行时,它并不知道 Servlet 或 HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成 XML,JSP 或 Java 等。
Freemarker使用:
1. 引入依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
2.spring添加配置
<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>
3.properties/page.properties(文件的生成地址)
pagedir=f:\\item\\
4.生成静态文件
@Value("${pagedir}")
private String pagedir;
@Autowired
private FreeMarkerConfig freeMarkerConfig;
@Autowired
private TbGoodsMapper goodsMapper;
@Override
publicboolean genItemHtml(Long goodsId){
try {
Template template = configuration.getTemplate("item.ftl");
//创建数据模型
Map dataModel=new HashMap<>();
//1.商品主表数据
TbGoods goods = goodsMapper.selectByPrimaryKey(goodsId);
dataModel.put("goods", goods);
//2.商品扩展表数据
TbGoodsDesc goodsDesc = goodsDescMapper.selectByPrimaryKey(goodsId);
dataModel.put("goodsDesc", goodsDesc);
//3.读取商品分类
String itemCat1 = itemCatMapper.selectByPrimaryKey(goods.getCategory1Id()).getName();
String itemCat2 = itemCatMapper.selectByPrimaryKey(goods.getCategory2Id()).getName();
String itemCat3 = itemCatMapper.selectByPrimaryKey(goods.getCategory3Id()).getName();
dataModel.put("itemCat1", itemCat1);
dataModel.put("itemCat2", itemCat2);
dataModel.put("itemCat3", itemCat3);
//4.读取SKU 列表
TbItemExample example =new TbItemExample();
Criteria criteria = example.createCriteria();
criteria.andGoodsIdEqualTo(goodsId);
criteria.andStatusEqualTo("1");
example.setOrderByClause("is_default desc");//按是否默认字段降序排序
List<TbItem> itemList = itemMapper.selectByExample(example);
dataModel.put("itemList", itemList);
Writer out =new FileWriter(pagedir+goodsId+".html");
template.process(dataModel, out);
out.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
5.创建模板xxx.ftl
例子:
<html>
<head>
<meta charset="utf-8">
<title>Freemarker入门小DEMO </title>
</head>
<meta charset="utf-8">
<title></title>
<body>
<#include "head.ftl">
<#--我是一个注释,不会输出。生成代码没有-->
<!--html注释,生成代码中有 -->
${name},你还.${message}
<#assign linkman="周先生">
联系人:${linkman}
<#if success=true>
你已经通过认证
<#else>
你未通过人认证
</#if>
</br>
<#list goodsList as goods>
${goods_index+1} 商品名称: ${goods.name} 价格:${goods.price}<br>
</#list>
共 ${goodsList?size} 条记录
</br>
<#assign text="{'bank':'工商银行','account':'10101920201920212'}" />
<#assign data=text?eval />
开户行:${data.bank} 账号:${data.account}
</br>
当前日期:${today?date} <br>
当前时间:${today?time} <br>
当前日期+时间:${today?datetime} <br>
日期格式化: ${today?string("yyyy年MM月")}
</br>
累计积分:${point}
累计积分:${point?c}
</br>
<#if aaa??>
aaa变量存在
<#else>
aaa变量不存在
</#if>
${bbbb!'-'}
<#if (point>100)>
黄金会员
</#if>
</body>
</hrtml>
FTL指令
1 assign指令
此指令用于在页面上定义一个变量
(1)定义简单类型:
<#assign linkman="周先生"> 联系人:${linkman} |
(2)定义对象类型:
<#assign info={"mobile":"13301231212",'address':'北京市昌平区王府街'} > 电话:${info.mobile} 地址:${info.address} |
2 include指令
此指令用于模板文件的嵌套
<#include "head.ftl"> |
3 if指令
在模板文件上添加
<#if success=true> 你已通过实名认证 <#else> 你未通过实名认证 </#if> |
在代码中对str变量赋值
map.put("success", true); |
在freemarker的判断中,可以使用= 也可以使用==
4 list指令
需求,实现商品价格表,如下图:
(1)代码中对变量goodsList赋值
List goodsList=new ArrayList(); Map goods1=new HashMap(); goods1.put("name", "苹果"); goods1.put("price", 5.8); Map goods2=new HashMap(); goods2.put("name", "香蕉"); goods2.put("price", 2.5); Mapgoods3=newHashMap(); goods3.put("name", "橘子"); goods3.put("price", 3.2); goodsList.add(goods1); goodsList.add(goods2); goodsList.add(goods3); map.put("goodsList", goodsList); |
(2)在模板文件上添加
----商品价格表----<br> <#list goodsList as goods> ${goods_index+1} 商品名称: ${goods.name} 价格:${goods.price}<br> </#list> |
如果想在循环中得到索引,使用循环变量+_index就可以得到。
5 内建函数
语法格式: 变量+?+函数名称
5.1获取集合大小
我们通常要得到某个集合的大小,如下图:
我们使用size函数来实现,代码如下:
共 ${goodsList?size} 条记录 |
5.2转换JSON字符串为对象
我们通常需要将json字符串转换为对象,那如何处理呢?看代码
<#assign text="{'bank':'工商银行','account':'10101920201920212'}" /> <#assign data=text?eval /> 开户行:${data.bank} 账号:${data.account} |
5.3日期格式化
代码中对变量赋值:
dataModel.put("today", new Date()); |
在模板文件中加入
当前日期:${today?date} <br> 当前时间:${today?time} <br> 当前日期+时间:${today?datetime} <br> 日期格式化: ${today?string("yyyy年MM月")} |
5.4数字转换为字符串
代码中对变量赋值:
map.put("point", 102920122); |
修改模板:
累计积分:${point} |
页面显示:
我们会发现数字会以每三位一个分隔符显示,有些时候我们不需要这个分隔符,就需要将数字转换为字符串,使用内建函数c
累计积分:${point?c} |
页面显示效果如下:
6空值处理运算符
如果你在模板中使用了变量但是在代码中没有对变量赋值,那么运行生成时会抛出异常。但是有些时候,有的变量确实是null,怎么解决这个问题呢?
6.1判断某变量是否存在:“??”
用法为:variable??,如果该变量存在,返回true,否则返回false
<#if aaa??> aaa变量存在 <#else> aaa变量不存在 </#if> |
6.2缺失变量默认值:“!”
我们除了可以判断是否为空值,也可以使用!对null值做转换处理
在模板文件中加入
${aaa!'-'} |
在代码中不对aaa赋值,也不会报错了 ,当aaa为null则返回!后边的内容-
7运算符
7.1算数运算符
FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , %
7.2逻辑运算符
逻辑运算符有如下几个:
逻辑与:&&
逻辑或:||
逻辑非:!
逻辑运算符只能作用于布尔值,否则将产生错误
7.3比较运算符
表达式中支持的比较运算符有如下几个:
1=或者==:判断两个值是否相等.
2!=:判断两个值是否不等.
3>或者gt:判断左边值是否大于右边值
4>=或者gte:判断左边值是否大于等于右边值
5<或者lt:判断左边值是否小于右边值
6<=或者lte:判断左边值是否小于等于右边值
注意:=和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值,否则会产生错误,而且FreeMarker是精确比较,"x","x ","X"是不等的.其它的运行符可以作用于数字和日期,但不能作用于字符串,大部分的时候,使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成FTL标签的结束字符,当然,也可以使用括号来避免这种情况,如:<#if (x>y)>
例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<title>产品详情页</title>
<link rel="icon" href="assets/img/favicon.ico">
<link rel="stylesheet" type="text/css" href="css/webbase.css" />
<link rel="stylesheet" type="text/css" href="css/pages-item.css" />
<link rel="stylesheet" type="text/css" href="css/pages-zoom.css" />
<link rel="stylesheet" type="text/css" href="css/widget-cartPanelView.css" />
<script type="text/javascript" src="plugins/angularjs/angular.min.js"></script>
<script type="text/javascript" src="js/base.js"></script>
<script type="text/javascript" src="js/controller/itemController.js"></script>
<script>
var skuList=[
<#list itemList as item>
{
id:${item.id?c},
title:'${item.title}',
price:${item.price?c},
spec:${item.spec}
},
</#list>
];
</script>
</head>
<body ng-app="pinyougou" ng-controller="itemController" ng-init="num=1;loadSku()">
<!--页面顶部 开始-->
<#include "head.ftl">
<#--图片列表 -->
<#assign imageList=goodsDesc.itemImages?eval>
<#--扩展属性 -->
<#assign customAttributeList=goodsDesc.customAttributeItems?eval>
<#--规格列表 -->
<#assign specificationList=goodsDesc.specificationItems?eval>
<!--页面顶部 结束-->
<div class="py-container">
<div id="item">
<div class="crumb-wrap">
<ul class="sui-breadcrumb">
<li>
<a href="#">${itemCat1}</a>
</li>
<li>
<a href="#">${itemCat2}</a>
</li>
<li>
<a href="#">${itemCat3}</a>
</li>
</ul>
</div>
<!--product-info-->
<div class="product-info">
<div class="fl preview-wrap">
<!--放大镜效果-->
<div class="zoom">
<!--默认第一个预览-->
<div id="preview" class="spec-preview">
<span class="jqzoom">
<#if (imageList?size>0)>
<img jqimg="${imageList[0].url}" src="${imageList[0].url}" width="400px" height="400px"/></span>
</#if >
</div>
<!--下方的缩略图-->
<div class="spec-scroll">
<a class="prev"><</a>
<!--左右按钮-->
<div class="items">
<ul>
<#list imageList as item>
<li><img src="${item.url}" bimg="${item.url}" onmousemove="preview(this)" /></li>
</#list>
</ul>
</div>
<a class="next">></a>
</div>
</div>
</div>
<div class="fr itemInfo-wrap">
<div class="sku-name">
<h4>{{sku.title}}</h4>
</div>
<div class="news"><span>${goods.caption}</span></div>
<div class="summary">
<div class="summary-wrap">
<div class="fl title">
<i>价 格</i>
</div>
<div class="fl price">
<i>¥</i>
<em>{{sku.price}}</em>
<span>降价通知</span>
</div>
<div class="fr remark">
<i>累计评价</i><em>612188</em>
</div>
</div>
<div class="summary-wrap">
<div class="fl title">
<i>促 销</i>
</div>
<div class="fl fix-width">
<i class="red-bg">加价购</i>
<em class="t-gray">满999.00另加20.00元,或满1999.00另加30.00元,或满2999.00另加40.00元,即可在购物车换
购热销商品</em>
</div>
</div>
</div>
<div class="support">
<div class="summary-wrap">
<div class="fl title">
<i>支 持</i>
</div>
<div class="fl fix-width">
<em class="t-gray">以旧换新,闲置手机回收 4G套餐超值抢 礼品购</em>
</div>
</div>
<div class="summary-wrap">
<div class="fl title">
<i>配 送 至</i>
</div>
<div class="fl fix-width">
<em class="t-gray">满999.00另加20.00元,或满1999.00另加30.00元,或满2999.00另加40.00元,即可在购物车换购热销商品</em>
</div>
</div>
</div>
<div class="clearfix choose">
<div id="specification" class="summary-wrap clearfix">
<#list specificationList as spec>
<dl >
<dt>
<div class="fl title">
<i>${spec.attributeName}</i>
</div>
</dt>
<!--<dd><a href="javascript:;" class="selected">金色<span title="点击取消选择"> </span>
</a></dd>-->
<#list spec.attributeValue as item>
<dd><a href="javascript:;" class="{{isSelected('${spec.attributeName}','${item}')?'selected':''}}" ng-click="selectSpecification('${spec.attributeName}','${item}')">${item}<span title="点击取消选择"> </span></a></dd>
</#list>
</dl>
</#list>
</div>
{{specificationItems}}
<div class="summary-wrap">
<div class="fl title">
<div class="control-group">
<div class="controls">
<input autocomplete="off" type="text" ng-model="num" value="{{num}}" minnum="1" class="itxt" ng-model="num"/>
<a href="javascript:void(0)" class="increment plus" ng-click="addNum(1)">+</a>
<a href="javascript:void(0)" class="increment mins" ng-click="addNum(-1)">-</a>
</div>
</div>
</div>
<div class="fl">
<ul class="btn-choose unstyled">
<li>
<a class="sui-btn btn-danger addshopcar" ng-click="addToCart()">加入购物车</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!--product-detail-->
<div class="clearfix product-detail">
<div class="fl aside">
<ul class="sui-nav nav-tabs tab-wraped">
<li class="active">
<a href="#index" data-toggle="tab">
<span>相关分类</span>
</a>
</li>
<li>
<a href="#profile" data-toggle="tab">
<span>推荐品牌</span>
</a>
</li>
</ul>
<div class="tab-content tab-wraped">
<div id="index" class="tab-pane active">
<ul class="part-list unstyled">
<li>手机</li>
<li>手机壳</li>
<li>内存卡</li>
<li>Iphone配件</li>
<li>贴膜</li>
<li>手机耳机</li>
<li>移动电源</li>
<li>平板电脑</li>
</ul>
<ul class="goods-list unstyled">
<li>
<div class="list-wrap">
<div class="p-img">
<img src="img/_/part01.png" />
</div>
<div class="attr">
<em>Apple苹果iPhone 6s (A1699)</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>6088.00</i>
</strong>
</div>
<div class="operate">
<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
</div>
</div>
</li>
<li>
<div class="list-wrap">
<div class="p-img">
<img src="img/_/part02.png" />
</div>
<div class="attr">
<em>Apple苹果iPhone 6s (A1699)</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>6088.00</i>
</strong>
</div>
<div class="operate">
<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
</div>
</div>
</li>
<li>
<div class="list-wrap">
<div class="p-img">
<img src="img/_/part03.png" />
</div>
<div class="attr">
<em>Apple苹果iPhone 6s (A1699)</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>6088.00</i>
</strong>
</div>
<div class="operate">
<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
</div>
</div>
<div class="list-wrap">
<div class="p-img">
<img src="img/_/part02.png" />
</div>
<div class="attr">
<em>Apple苹果iPhone 6s (A1699)</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>6088.00</i>
</strong>
</div>
<div class="operate">
<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
</div>
</div>
<div class="list-wrap">
<div class="p-img">
<img src="img/_/part03.png" />
</div>
<div class="attr">
<em>Apple苹果iPhone 6s (A1699)</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>6088.00</i>
</strong>
</div>
<div class="operate">
<a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
</div>
</div>
</li>
</ul>
</div>
<div id="profile" class="tab-pane">
<p>推荐品牌</p>
</div>
</div>
</div>
<div class="fr detail">
<div class="clearfix fitting">
<h4 class="kt">选择搭配</h4>
<div class="good-suits">
<div class="fl master">
<div class="list-wrap">
<div class="p-img">
<img src="img/_/l-m01.png" />
</div>
<em>¥5299</em>
<i>+</i>
</div>
</div>
<div class="fl suits">
<ul class="suit-list">
<li class="">
<div id="">
<img src="img/_/dp01.png" />
</div>
<i>Feless费勒斯VR</i>
<label data-toggle="checkbox" class="checkbox-pretty">
<input type="checkbox"><span>39</span>
</label>
</li>
<li class="">
<div id=""><img src="img/_/dp02.png" /> </div>
<i>Feless费勒斯VR</i>
<label data-toggle="checkbox" class="checkbox-pretty">
<input type="checkbox"><span>50</span>
</label>
</li>
<li class="">
<div id=""><img src="img/_/dp03.png" /></div>
<i>Feless费勒斯VR</i>
<label data-toggle="checkbox" class="checkbox-pretty">
<input type="checkbox"><span>59</span>
</label>
</li>
<li class="">
<div id=""><img src="img/_/dp04.png" /></div>
<i>Feless费勒斯VR</i>
<label data-toggle="checkbox" class="checkbox-pretty">
<input type="checkbox"><span>99</span>
</label>
</li>
</ul>
</div>
<div class="fr result">
<div class="num">已选购0件商品</div>
<div class="price-tit"><strong>套餐价</strong></div>
<div class="price">¥5299</div>
<button class="sui-btn btn-danger addshopcar">加入购物车</button>
</div>
</div>
</div>
<div class="tab-main intro">
<ul class="sui-nav nav-tabs tab-wraped">
<li class="active">
<a href="#one" data-toggle="tab">
<span>商品介绍</span>
</a>
</li>
<li>
<a href="#two" data-toggle="tab">
<span>规格与包装</span>
</a>
</li>
<li>
<a href="#three" data-toggle="tab">
<span>售后保障</span>
</a>
</li>
<li>
<a href="#four" data-toggle="tab">
<span>商品评价</span>
</a>
</li>
<li>
<a href="#five" data-toggle="tab">
<span>手机社区</span>
</a>
</li>
</ul>
<div class="clearfix"></div>
<div class="tab-content tab-wraped">
<div id="one" class="tab-pane active">
<ul class="goods-intro unstyled">
<#list customAttributeList as item>
<#if item.value??>
<li>${item.text}:${item.value}</li>
</#if>
</#list>
</ul>
<div class="intro-detail">
${goodsDesc.introduction}
</div>
</div>
<div id="two" class="tab-pane">
<p>${goodsDesc.packageList}</p>
</div>
<div id="three" class="tab-pane">
<p>${goodsDesc.saleService}</p>
</div>
<div id="four" class="tab-pane">
<p>商品评价</p>
</div>
<div id="five" class="tab-pane">
<p>手机社区</p>
</div>
</div>
</div>
</div>
</div>
<!--like-->
<div class="clearfix"></div>
<div class="like">
<h4 class="kt">猜你喜欢</h4>
<div class="like-list">
<ul class="yui3-g">
<li class="yui3-u-1-6">
<div class="list-wrap">
<div class="p-img">
<img src="img/_/itemlike01.png" />
</div>
<div class="attr">
<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>3699.00</i>
</strong>
</div>
<div class="commit">
<i class="command">已有6人评价</i>
</div>
</div>
</li>
<li class="yui3-u-1-6">
<div class="list-wrap">
<div class="p-img">
<img src="img/_/itemlike02.png" />
</div>
<div class="attr">
<em>Apple苹果iPhone 6s/6s Plus 16G 64G 128G</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>4388.00</i>
</strong>
</div>
<div class="commit">
<i class="command">已有700人评价</i>
</div>
</div>
</li>
<li class="yui3-u-1-6">
<div class="list-wrap">
<div class="p-img">
<img src="img/_/itemlike03.png" />
</div>
<div class="attr">
<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>4088.00</i>
</strong>
</div>
<div class="commit">
<i class="command">已有700人评价</i>
</div>
</div>
</li>
<li class="yui3-u-1-6">
<div class="list-wrap">
<div class="p-img">
<img src="img/_/itemlike04.png" />
</div>
<div class="attr">
<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>4088.00</i>
</strong>
</div>
<div class="commit">
<i class="command">已有700人评价</i>
</div>
</div>
</li>
<li class="yui3-u-1-6">
<div class="list-wrap">
<div class="p-img">
<img src="img/_/itemlike05.png" />
</div>
<div class="attr">
<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>4088.00</i>
</strong>
</div>
<div class="commit">
<i class="command">已有700人评价</i>
</div>
</div>
</li>
<li class="yui3-u-1-6">
<div class="list-wrap">
<div class="p-img">
<img src="img/_/itemlike06.png" />
</div>
<div class="attr">
<em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>4088.00</i>
</strong>
</div>
<div class="commit">
<i class="command">已有700人评价</i>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 底部栏位 -->
<!--页面底部 开始 -->
<#include "foot.ftl">
<!--页面底部 结束 -->
</body>
</html>