文章目錄
一、頁面靜態化需求
1.1 爲什麼要進行頁面管理
本項目cms系統的功能就是根據運營需要,對門戶等子系統的部分頁面進行管理,從而實現快速根據用戶需求修改頁面內容並上線的需求。
1.2 如何修改頁面的內容
在開發中修改頁面內容是需要人工編寫html及JS文件,CMS系統是通過程序自動化的對頁面內容進行修改,通過頁面靜態化技術生成html頁面。
1.3 如何對頁面進行靜態化
一個頁面等於模板加數據,在添加頁面的時候我們選擇了頁面的模板。
頁面靜態化就是將頁面模板和數據通過技術手段將二者合二爲一,生成一個html網頁文件
1.4 頁面靜態化及頁面發佈流程如下圖
業務流程如下:
- 獲取模板數據
- 製作模板
- 對頁面進行靜態化
- 將靜態化生成的html頁面存放在文件系統中
- 將存在在文件系統的html文件發佈到服務器上
二、FreeMaker入門
三、頁面靜態化
3.1 頁面靜態化流程
通過上邊對FreeMarker的研究我們得出:模板+數據模型=輸出,頁面靜態化需要準備數據模型和模板,先知道數據模型的結構纔可以編寫模板,因爲在模板中要引用數據模型中的數據,本節將系統講解CMS頁面數據模型獲取、模板管理及靜態化的過程。
如何獲取頁面的數據模型?
CMS管理了各種頁面,CMS對頁面進行靜態化時需要數據模型,但是CMS並不知道每個頁面的數據模型的具體內容,它只管執行靜態化程序便可對頁面進行靜態化,所以CMS靜態化程序需要通過一種通用的方法來獲取數據模型。
在編輯頁面信息時指定一個DataUrl,此DataUrl便是獲取數據模型的Url,它基於Http方式,CMS對頁面進行靜態化時會從頁面信息中讀取DataUrl,通過Http遠程調用的方法請求DataUrl獲取數據模型。
管理員怎麼知道DataUrl的內容呢?
舉例說明:
此頁面是輪播圖頁面,它的DataUrl由開發輪播圖管理的程序員提供。
此頁面是精品課程推薦頁面,它的DataUrl由精品課程推薦的程序員提供。
此頁面是課程詳情頁面,它的DataUrl由課程管理的程序員提供。
頁面靜態化流程如下圖:
1、靜態化程序首先讀取頁面獲取DataUrl。
2、靜態化程序遠程請求DataUrl得到數據模型。
3、獲取頁面模板。
4、執行頁面靜態化。
3.2 數據模型
3.2.1 輪播圖DataUrl接口
3.2.1.1 需求分析
CMS中有輪播圖管理、精品課程推薦的功能,以輪播圖管理爲例說明:輪播圖管理是通過可視化的操作界面由管理員指定輪播圖圖片地址,最後將輪播圖圖片地址保存在cms_config集合中,下邊是輪播圖數據模型:
針對首頁的輪播圖信息、精品推薦等信息的獲取統一提供一個Url供靜態化程序調用,這樣我們就知道了輪播圖頁面、精品課程推薦頁面的DataUrl,管理在頁面配置中將此Url配置在頁面信息中。
本小節開發一個查詢輪播圖、精品推薦信息的接口,此接口供靜態化程序調用獲取數據模型。
3.2.1.2 接口定義
輪播圖信息、精品推薦等信息存儲在MongoDB的cms_config集合中
cms_config有固定的數據結構,如下:
package com.xuecheng.framework.domain.cms;
import lombok.Data;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
/**
* @author 98050
*/
@Data
@ToString
@Document(collection = "cms_config")
public class CmsConfig {
@Id
private String id;
private String name;
private List<CmsConfigModel> model;
}
數據模型內容如下:
package com.xuecheng.framework.domain.cms;
import lombok.Data;
import lombok.ToString;
import java.util.Map;
/**
* @author 98050
*/
@Data
@ToString
public class CmsConfigModel {
/**
* 主鍵
*/
private String key;
/**
* 項目名稱
*/
private String name;
/**
* 項目url
*/
private String url;
/**
* 項目複雜值
*/
private Map mapValue;
/**
* 項目簡單值
*/
private String value;
}
上邊的模型結構可以對照cms_config中的數據進行分析。
其中,在mapValue 中可以存儲一些複雜的數據模型內容。
根據配置信息Id查詢配置信息,定義接口如下:
package com.xuecheng.api.cms;
import com.xuecheng.framework.domain.cms.CmsConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: 98050
* @Time: 2019-03-28 16:44
* @Feature: cms配置管理接口
*/
@RequestMapping("/cms/config")
@Api(value = "cms配置信息管理接口",description = "cms配置信息管理接口,提供對配置信息的CRUD")
public interface CmsConfigControllerApi {
/**
* 根據id查詢CMS配置信息
* @param id
* @return
*/
@ApiOperation("根據id查詢CMS配置信息")
@GetMapping("/getModel/{id}")
CmsConfig getModel(@PathVariable("id") String id);
}
3.2.1.3 DAO
package com.xuecheng.managecms.dao;
import com.xuecheng.framework.domain.cms.CmsConfig;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* @Author: 98050
* @Time: 2019-03-28 16:46
* @Feature:
*/
public interface CmsConfigRepository extends MongoRepository<CmsConfig,String> {
}
3.2.1.4 Service
接口:
package com.xuecheng.managecms.service;
import com.xuecheng.framework.domain.cms.CmsConfig;
/**
* @Author: 98050
* @Time: 2019-03-28 16:48
* @Feature:
*/
public interface CmsConfigService {
/**
* 根據id查詢配置管理信息
* @param id
* @return
*/
CmsConfig getConfigById(String id);
}
實現:
package com.xuecheng.managecms.service.impl;
import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.managecms.dao.CmsConfigRepository;
import com.xuecheng.managecms.service.CmsConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
/**
* @Author: 98050
* @Time: 2019-03-28 16:49
* @Feature:
*/
@Service
public class CmsConfigServiceImpl implements CmsConfigService {
@Autowired
private CmsConfigRepository cmsConfigRepository;
/**
* 根據id查詢配置管理信息
* @param id
* @return
*/
@Override
public CmsConfig getConfigById(String id) {
Optional<CmsConfig> optional = cmsConfigRepository.findById(id);
return optional.orElse(null);
}
}
3.2.1.5 Controller
package com.xuecheng.managecms.controller;
import com.xuecheng.api.cms.CmsConfigControllerApi;
import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.managecms.service.CmsConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: 98050
* @Time: 2019-03-28 16:52
* @Feature:
*/
@RestController
@RequestMapping("/cms/config")
public class CmsConfigController implements CmsConfigControllerApi {
@Autowired
private CmsConfigService cmsConfigService;
@Override
@GetMapping("/getModel/{id}")
public CmsConfig getModel(@PathVariable("id") String id) {
return cmsConfigService.getConfigById(id);
}
}
3.2.1.6 測試
接口文檔測試:
結果:
3.2.2 遠程請求接口
SpringMVC提供 RestTemplate請求http接口,RestTemplate的底層可以使用第三方的http客戶端工具實現http 的請求,常用的http客戶端工具有Apache HttpClient、OkHttpClient等,本項目使用OkHttpClient完成http請求,原因也是因爲它的性能比較出衆。
1、添加依賴
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
2、配置RestTemplate
在SpringBoot啓動類中配置 RestTemplate
@Bean
public RestTemplate restTemplate(){
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
3、測試RestTemplate
根據url獲取數據,並且轉爲map格式。
package com.xuecheng.managecms;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
/**
* @Author: 98050
* @Time: 2019-03-28 17:28
* @Feature:
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class CmsPageConfigTest {
@Autowired
private RestTemplate restTemplate;
@Test
public void testRestTemplate(){
ResponseEntity<Map> entity = this.restTemplate.getForEntity("http://localhost:31001/cms/config/getModel/5a791725dd573c3574ee333f", Map.class);
System.out.println(entity.getBody());
}
}
結果:
3.3 模板管理
3.3.1 模板管理業務流程
CMS提供模板管理功能,業務流程如下:
1、要增加新模板首先需要製作模板,模板的內容就是Freemarker ftl模板內容。
2、通過模板管理模塊功能新增模板、修改模板、刪除模板。
3、模板信息存儲在MongoDB數據庫,其中模板信息存儲在cms_template集合中,模板文件存儲在GridFS文件系統中。
cms_template集合:
上邊模板信息中templateFileId是模板文件的ID,此ID對應GridFS文件系統中文件ID。
3.3.2 模板製作
3.3.2.1 編寫模板文件
1、輪播圖頁面原型
在門戶的靜態工程目錄有輪播圖的靜態頁面,路徑是:/include/index_banner.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/plugins/normalize-css/normalize.css" />
<link rel="stylesheet" href="/plugins/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="/css/page-learing-index.css" />
<link rel="stylesheet" href="/css/page-header.css" />
</head>
<body>
<div class="banner-roll">
<div class="banner-item">
<div class="item" style="background-image: url(../img/widget-bannerB.jpg);"></div>
<div class="item" style="background-image: url(../img/widget-bannerA.jpg);"></div>
<div class="item" style="background-image: url(../img/widget-banner3.png);"></div>
<div class="item" style="background-image: url(../img/widget-bannerB.jpg);"></div>
<div class="item" style="background-image: url(../img/widget-bannerA.jpg);"></div>
<div class="item" style="background-image: url(../img/widget-banner3.png);"></div>
</div>
<div class="indicators"></div>
</div>
<script type="text/javascript" src="/plugins/jquery/dist/jquery.js"></script>
<script type="text/javascript" src="/plugins/bootstrap/dist/js/bootstrap.js"></script>
<script type="text/javascript">
var tg = $('.banner-item .item');
var num = 0;
for (i = 0; i < tg.length; i++) {
$('.indicators').append('<span></span>');
$('.indicators').find('span').eq(num).addClass('active');
}
function roll() {
tg.eq(num).animate({
'opacity': '1',
'z-index': num
}, 1000).siblings().animate({
'opacity': '0',
'z-index': 0
}, 1000);
$('.indicators').find('span').eq(num).addClass('active').siblings().removeClass('active');
if (num >= tg.length - 1) {
num = 0;
} else {
num++;
}
}
$('.indicators').find('span').click(function() {
num = $(this).index();
roll();
});
var timer = setInterval(roll, 3000);
$('.banner-item').mouseover(function() {
clearInterval(timer)
});
$('.banner-item').mouseout(function() {
timer = setInterval(roll, 3000)
});
</script>
</body>
</html>
2、數據模型
通過http獲取到的數據模型如下:
下圖數據模型的圖片路徑改成可以瀏覽的正確路徑
{
"id": "5a791725dd573c3574ee333f",
"name": "輪播圖",
"model": [
{
"key": "banner1",
"name": "輪播圖1地址",
"url": null,
"mapValue": null,
"value": "http://192.168.101.64/group1/M00/00/01/wKhlQFp5wnCAG-kAAATMXxpSaMg864.png"
},
{
"key": "banner2",
"name": "輪播圖2地址",
"url": null,
"mapValue": null,
"value": "http://192.168.101.64/group1/M00/00/01/wKhlQVp5wqyALcrGAAGUeHA3nvU867.jpg"
},
{
"key": "banner3",
"name": "輪播圖3地址",
"url": null,
"mapValue": null,
"value": "http://192.168.101.64/group1/M00/00/01/wKhlQFp5wtWAWNY2AAIkOHlpWcs395.jpg"
}
]
}
3、編寫模板
在freemarker測試工程中新建模板index_banner.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="http://www.xuecheng.com/plugins/normalize-css/normalize.css" />
<link rel="stylesheet" href="http://www.xuecheng.com/plugins/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="http://www.xuecheng.com/css/page-learing-index.css" />
<link rel="stylesheet" href="http://www.xuecheng.com/css/page-header.css" />
</head>
<body>
<div class="banner-roll">
<div class="banner-item">
<#--<div class="item" style="background-image: url(http://www.xuecheng.com/img/widget-bannerB.jpg);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com/img/widget-bannerA.jpg);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com/img/widget-banner3.png);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com/img/widget-bannerB.jpg);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com/img/widget-bannerA.jpg);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com/img/widget-banner3.png);"></div>-->
<#if model??>
<#list model as item>
<div class="item" style="background-image: url(${item.value});"></div>
</#list>
</#if>
</div>
<div class="indicators"></div>
</div>
<script type="text/javascript" src="http://www.xuecheng.com/plugins/jquery/dist/jquery.js"></script>
<script type="text/javascript" src="http://www.xuecheng.com/plugins/bootstrap/dist/js/bootstrap.js"></script>
<script type="text/javascript">
var tg = $('.banner-item .item');
var num = 0;
for (i = 0; i < tg.length; i++) {
$('.indicators').append('<span></span>');
$('.indicators').find('span').eq(num).addClass('active');
}
function roll() {
tg.eq(num).animate({
'opacity': '1',
'z-index': num
}, 1000).siblings().animate({
'opacity': '0',
'z-index': 0
}, 1000);
$('.indicators').find('span').eq(num).addClass('active').siblings().removeClass('active');
if (num >= tg.length - 1) {
num = 0;
} else {
num++;
}
}
$('.indicators').find('span').click(function() {
num = $(this).index();
roll();
});
var timer = setInterval(roll, 3000);
$('.banner-item').mouseover(function() {
clearInterval(timer)
});
$('.banner-item').mouseout(function() {
timer = setInterval(roll, 3000)
});
</script>
</body>
</html>
3.3.2.2 模板測試
在freemarker測試工程編寫一個方法測試輪播圖模板,代碼如下:
@Autowired
RestTemplate restTemplate;
@RequestMapping("/banner")
public String index_banner(Map<String,Object> map){
String dataUrl = "http://localhost:31001/cms/config/getModel/5a791725dd573c3574ee333f";
ResponseEntity<Map> entity = restTemplate.getForEntity(dataUrl, Map.class);
Map body = entity.getBody();
System.out.println(body);
if (body != null) {
map.putAll(body);
}
return "index_banner";
}
問題:圖片服務器沒有搭建,修改一下模型數據
{
"_id" : ObjectId("5a791725dd573c3574ee333f"),
"_class" : "com.xuecheng.framework.domain.cms.CmsConfig",
"name" : "輪播圖",
"model" : [
{
"key" : "banner1",
"name" : "輪播圖1地址",
"value" : "http://mycsdnblog.work/201919291432-F.png"
},
{
"key" : "banner2",
"name" : "輪播圖2地址",
"value" : "http://mycsdnblog.work/201919291433-e.png"
},
{
"key" : "banner3",
"name" : "輪播圖3地址",
"value" : "http://mycsdnblog.work/201919291433-0.png"
}
]
}
請求:http://localhost:8088/freemarker/banner
結果:
3.3.3 GridFS研究
3.3.3.1 GridFS介紹
GridFS是MongoDB提供的用於持久化存儲文件的模塊,CMS使用MongoDB存儲數據,使用GridFS可以快速集成開發。
它的工作原理是:在GridFS存儲文件是將文件分塊存儲,文件會按照256KB的大小分割成多個塊進行存儲,GridFS使用兩個集合(collection)存儲文件,一個集合是chunks, 用於存儲文件的二進制數據;一個集合是files,用於存儲文件的元數據信息(文件名稱、塊大小、上傳時間等信息)。
從GridFS中讀取文件要對文件的各各塊進行組裝、合併。
3.3.3.2 GridFS存取文件測試
存文件
使用GridFsTemplate存儲文件測試代碼:
package com.xuecheng.managecms;
import org.bson.types.ObjectId;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/**
* @Author: 98050
* @Time: 2019-03-29 15:57
* @Feature:
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class GridFsTest {
@Autowired
private GridFsTemplate gridFsTemplate;
@Test
public void testGridFs() throws FileNotFoundException {
//1.要存儲的文件
File file = new File("D:\\test1.html");
//2.定義輸入流
FileInputStream inputStream = new FileInputStream(file);
//3.向GridFS存儲文件
ObjectId objectId = gridFsTemplate.store(inputStream, "測試文件", "");
//4.得到文件ID
String fileId = objectId.toString();
System.out.println(fileId);
}
}
存儲原理:
文件存儲成功得到一個文件Id
此文件Id是fs.files集合中的主鍵
可以通過文件id查詢fs.chunks表中的記錄,得到文件的內容。
讀取文件
1)在config包中定義Mongodb的配置類,如下:
GridFSBucket用於打開下載流對象
package com.xuecheng.managecms.config;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: 98050
* @Time: 2019-03-29 16:12
* @Feature: mongodb配置類
*/
@Configuration
public class MongoConfig {
@Value("${spring.data.mongodb.database}")
private String db;
@Bean
public GridFSBucket getGridFSBucket(MongoClient mongoClient){
MongoDatabase database = mongoClient.getDatabase(db);
GridFSBucket bucket = GridFSBuckets.create(database);
return bucket;
}
}
2)測試代碼
@Autowired
private GridFSBucket gridFSBucket;
/**
* 讀取文件
* @throws IOException
*/
@Test
public void queryFile() throws IOException {
String fileId = "";
//1.根據id查詢文件
GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
assert gridFSFile != null;
//2.打開下載流對象
GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
//3.創建gridResource用於獲取流對象
GridFsResource gridFsResource = new GridFsResource(gridFSFile,gridFSDownloadStream);
//4.獲取流中的數據
String s = IOUtils.toString(gridFsResource.getInputStream(),"UTF-8");
System.out.println(s);
}
刪除文件
@Test
public void testDelFile(){
String id = "";
//根據文件id刪除fs.files和fs.chunks中的記錄
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(id)));
}
3.3.4 模板存儲
根據模板管理的流程,最終將模板信息存儲到MongoDB的cms_template,將模板文件存儲到GridFS中。
模板管理功能在
3.4 靜態化測試
上邊章節完成了數據模型和模板管理的測試,下邊測試整個頁面靜態化的流程,流程如下:
1、填寫頁面DataUrl
在編輯cms頁面信息界面填寫DataUrl,將此字段保存到cms_page集合中。
2、靜態化程序獲取頁面的DataUrl
3、靜態化程序遠程請求DataUrl獲取數據模型。
4、靜態化程序獲取頁面的模板信息
5、執行頁面靜態化
在CmsService中定義頁面靜態化方法,如下:
/**
* 頁面靜態化
* @param pageId
* @return
*/
@Override
public String getPageHtml(String pageId) {
//1.獲取頁面模型數據
Map model = getModelByPageId(pageId);
if (model == null){
//2.獲取頁面模型爲空的時候拋出異常
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
}
//3.獲取頁面模板
String templateContent = getTemplateByPageId(pageId);
if (StringUtils.isEmpty(templateContent)){
//4.頁面模板爲空的話就拋出異常
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
}
//5.執行靜態化
String html = generateHtml(templateContent,model);
if (StringUtils.isEmpty(html)){
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
}
return html;
}
整體代碼框架如上所示,接下來就完成getModelByPageId
,getTemplateByPageId
,generateHtml
三個方法。
3.4.1 getModelByPageId
根據pageId查詢靜態化頁面時所需的模型數據
/**
* 根據頁面Id查詢模型數據
* @param pageId
* @return
*/
private Map getModelByPageId(String pageId) {
//1.查詢頁面信息
CmsPage cmsPage = this.findById(pageId);
if (cmsPage == null){
//2.頁面不存在
ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
}
//3.取出dataUrl
String dataUrl = cmsPage.getDataUrl();
if (StringUtils.isEmpty(dataUrl)){
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
}
ResponseEntity<Map> entity = this.restTemplate.getForEntity(dataUrl, Map.class);
return entity.getBody();
}
3.4.2 getTemplateByPageId
根據頁面Id查詢模板信息,獲取到模板文件的id後,把模板文件轉換成字符串返回。
/**
* 根據頁面Id查詢模板
* @param pageId
* @return
*/
private String getTemplateByPageId(String pageId) {
//1.查詢頁面信息
CmsPage cmsPage = this.findById(pageId);
if (cmsPage == null){
//2.頁面不存在
ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
}
//3.取出getTemplateId
String templateId = cmsPage.getTemplateId();
if (StringUtils.isEmpty(templateId)){
ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
}
//4.查詢頁面模板
Optional<CmsTemplate> optional = this.cmsTemplateRepository.findById(templateId);
if (optional.isPresent()){
CmsTemplate cmsTemplate = optional.get();
//5.模板文件Id
String templateFileId = cmsTemplate.getTemplateFileId();
//6.根據id查詢文件
GridFSFile gridFSFile = this.gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
assert gridFSFile != null;
//7.打開下載流對象
GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
//8.創建gridResource用於獲取流對象
GridFsResource gridFsResource = new GridFsResource(gridFSFile,gridFSDownloadStream);
//9.獲取流中的數據
try {
return IOUtils.toString(gridFsResource.getInputStream(),"UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
3.4.3 generateHtml
拿到模板和數據後,就可以進行頁面的靜態化了。
/**
* 頁面靜態化
* @param templateContent
* @param model
* @return
*/
private String generateHtml(String templateContent, Map model){
try {
//1.創建配置類
Configuration configuration = new Configuration(Configuration.getVersion());
//2.模板加載器
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("template", templateContent);
configuration.setTemplateLoader(stringTemplateLoader);
//4.得到模板
Template template = configuration.getTemplate("template", "utf-8");
//5.靜態化
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
return html;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
3.4.4 測試
3.4.4.1 新增測試頁面
結果:
3.4.4.2 上傳輪播圖模板
GridFS上傳index_banner.ftl
文件:
結果:
3.4.4.3 修改輪播圖模板中的templateFileId
將templateFileId
字段的值修改爲剛剛上傳的文件id:5c9e0072dff2be4a682f5f47
修改後的結果:
3.4.4.4 頁面靜態化測試
編寫測試類
package com.xuecheng.managecms;
import com.xuecheng.managecms.service.CmsService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @Author: 98050
* @Time: 2019-03-29 18:59
* @Feature: 頁面靜態化測試
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class PageStaticTest {
@Autowired
private CmsService cmsService;
@Test
public void pageStatic(){
cmsService.getPageHtml("5c9df9dadff2be27386be51b");
}
}
結果:
完成
四、頁面預覽
4.1 頁面預覽開發
4.1.1 需求分析
頁面在發佈前增加預覽的步驟,方便用戶檢查頁面內容是否正確。具體流程如下所示:
1、用戶進入cms前端,點擊“頁面預覽”在瀏覽器請求cms頁面預覽鏈接
2、cms根據頁面id查詢DataUrl並遠程請求DataUrl獲取數據模型。
3、cms根據頁面id查詢頁面模板內容
4、cms執行頁面靜態化。
5、cms將靜態化內容響應給瀏覽器。
6、在瀏覽器展示頁面內容,實現頁面預覽的功能。
4.1.2 搭建環境
在cms服務中需要集成freemarker
1、在cms服務中加入freemarker的依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
2、在application.yml中配置freemarker
server:
port: 31001
spring:
application:
name: xc-service-manage-cms
data:
mongodb:
uri: mongodb://root:root@localhost:27017
database: xc_cms
freemarker:
cache: false #關閉模板緩存,方便測試
settings:
template_update_delay: 0 #檢查模板更新延遲時間,設置爲0表示立即檢查,如果時間大於0會有緩存不方便進行模板測試
4.1.3 Service方法
在靜態化測試中已經完成
4.1.4 Controller
直接調用service的靜態化方法即可,將靜態化內容通過response輸出到瀏覽器顯示
創建CmsPagePreviewController類,用於頁面預覽:
請求頁面id,查詢得到頁面的模板信息、數據模型url,根據數據模型和模板生成靜態化內容,並輸出到瀏覽器。
package com.xuecheng.managecms.controller;
import com.xuecheng.framework.web.BaseController;
import com.xuecheng.managecms.service.CmsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @Author: 98050
* @Time: 2019-03-30 19:12
* @Feature: 頁面預覽
*/
@Controller
public class CmsPagePreviewController extends BaseController {
@Autowired
private CmsService cmsService;
@RequestMapping(value = "/cms/preview/{pageId}",method = RequestMethod.GET)
public void preview(@PathVariable("pageId") String pageId){
String pageHtml = this.cmsService.getPageHtml(pageId);
if (StringUtils.isNotEmpty(pageHtml)){
try {
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(pageHtml.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
測試:http://localhost:31001/cms/preview/5c9df9dadff2be27386be51b
4.2 頁面預覽測試
4.2.1 配置Nginx代理
爲了通過nginx請求靜態資源(css、圖片等),通過nginx代理進行頁面預覽
在 www.xuecheng.com虛擬主機中進行配置:
重啓nginx,測試:
http://www.xuecheng.com/cms/preview/5c9df9dadff2be27386be51b
4.2.2 添加“頁面預覽”連接
添加preview方法:
preview (pageId) {
window.open('http://www.xuecheng.com/cms/preview/' + pageId)
},
效果:
找到剛剛添加的頁面:
點擊預覽
頁面的靜態化操作放在發佈功能開發中,即靜態頁面上傳到GridFS中,所以對前端頁面進行調整: