XueChProject04(页面静态化)

一、页面静态化------>页面预览

为什么要对页面进行管理?

目的是为了能够进快的上线更新的网页。

为什要使用页面静态化?

为了实现以上功能,会用到freeMark,所以接下来学习freeMark

1、FreeMarker 介绍

是一个模板引擎 , 可以用来生成任何文本文件 (js, css, java , txt , html) ; 常用于生成html , 实现页面静态化 ;

在这里插入图片描述
freeMarker的小Demo参考另外一篇文章《FreeMark入门与小测试》请点击此链接

2、页面静态化流程

页面静态化流程如下图:
1、静态化程序(核心程序)首先读取页面获取DataUrl。 (DataUrl是集合cms_page中的一个字段)
2、静态化程序远程请求DataUrl 得到数据模型。
3、获取页面模板
4、执行页面静态化

在这里插入图片描述

2.1获取页面DataUrl-----2.2根据DataUrl获取数据模型

在这里插入图片描述

有一个没有做的功能---->数据配置(图片的添加)
在点击【配置】的时候,添加的图片的地址,存储在集合(表)cms_config中。
在这里插入图片描述

3、开发轮播图 DataUrl 接口(通过cms_page中的DataUrl来获取数据模型)

3.1、定义DataUrl接口
package com.xuecheng.api.cms;

import com.xuecheng.framework.domain.cms.CmsConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@Api(value="cms配置管理接口",description = "cms配置管理接口,提供数据模型的管理、查询接口")
public interface CmsConfigControllerApi {

    @ApiOperation("根据id查询CMS配置信息")
    public CmsConfig getCmsConfig(String id);
}
3.2、DataUrl接口的实现-----controller
package com.xuecheng.manage_cms.controller;

import com.xuecheng.api.cms.CmsConfigControllerApi;
import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.manage_cms.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;

@RestController
@RequestMapping("/cms/config")
public class CmsConfigController implements CmsConfigControllerApi {
    @Autowired
    CmsConfigService cmsConfigService;


    @Override
    @GetMapping("/getmodel/{id}")
    public CmsConfig getCmsConfig(@PathVariable("id") String id) {
        CmsConfig cmsConfig = cmsConfigService.getCmsConfig(id);
        return cmsConfig;
    }
}

3.3、DataUrl接口的实现-----service
package com.xuecheng.manage_cms.service;

import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.manage_cms.dao.CmsConfigRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;
@Service
public class CmsConfigService {

    @Autowired
    CmsConfigRepository cmsConfigRepository;


    public CmsConfig getCmsConfig(String id) {

        Optional<CmsConfig> optional = cmsConfigRepository.findById(id);
        if(optional.isPresent()){
            CmsConfig cmsConfig = optional.get();
            return cmsConfig;
        }

        return null;
    }
}

3.4、DataUrl接口的实现-----dao
package com.xuecheng.manage_cms.dao;

import com.xuecheng.framework.domain.cms.CmsConfig;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface CmsConfigRepository extends MongoRepository<CmsConfig,String> {
    
}
3.5、用java代码发送http请求,访问restful服务(访问DataUrl地址)
RestTemplate

SpringMVC 中提供的一个可用于发送 HTTP 请求的一个模板对象, 底层是对第三方的HTTP库的封装 , 如 : HttpClient, OkHttp ;

|— —添加依赖
<dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
 </dependency>
|— —在启动类里设置
.....
    //将以下的返回值,作为spring容器的Bean。
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
    }
.......
|— —在测试类里测试
	@Autowired
    RestTemplate restTemplate;

    @Test
    public void testRestTemplate() {
    //getForEntity 其中的get是指get请求,Map是指响应回来的类型。
        ResponseEntity<Map> forEntity = restTemplate.getForEntity("http://localhost:31001/cms/config/getmodel/5a791725dd573c3574ee333f", Map.class);
        System.out.println(forEntity);
    }
|— —在测试结果---->可以访问restful风格的http请求,获得正确的结果。

4、模板管理(静态化页面的模块是怎么来的?)

4.1、模板管理流程

在这里插入图片描述
在这里插入图片描述

4.2、制作模板

模板四要素:注释,插值,指令,文本。
根据html文件,来编写模板文件(.ftl)

<#if model??>
    <#list model as item>
    	<div class="item" style="background-image: url(${item.value});"></div>
    </#list>
</#if>

GridFS 概述

介绍 : 是MongoDB中提供的存储文件的系统, 在存储大文件时, 会对文件进行分块存储(256k) ;

在本项目中的关于GridFS说明

两个集合 :
fs.files ----> 存放文件的基本信息(文件名, 文件别名, 文件大小 , md5)
fs.chunks —> 存放文件的内容信息 ;

GridFS 存取文件测试

GridFS 存文件

在GridFS存储文件后,要更新cms_template中的字段 templateFileId

package com.xuecheng.manage_cms.dao.gridfs;


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;

/**
 * 测试用GridFS-----存储文件
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestGridFS {
    //注入 GridFsTemplate 类
    @Autowired
    GridFsTemplate gridFsTemplate;

    /**
     * 用GridFS------存储文件
     *
     * 存储原理说明:
     * 文件存储成功得到一个文件id 此文件id是fs.files集合中的主键。
     * 可以通过文件id查询fs.chunks表中的记录,得到文件的内容。
     */
    @Test
    public void testGridFs() throws FileNotFoundException {
        //要存储的文件
        File file = new File("d:/index_banner.ftl");
        //定义输入流
        FileInputStream inputStram = new FileInputStream(file);
        //向GridFS存储文件
        ObjectId objectId = gridFsTemplate.store(inputStram, "轮播图测试文件01", "");
        //得到文件ID
        String fileId = objectId.toString();
        System.out.println(fileId);
    }
}
index_banner.ftl
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="http://caojiawan.ltd/plugins/normalize-css/normalize.css" />
    <link rel="stylesheet" href="http://caojiawan.ltd/plugins/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="http://caojiawan.ltd/css/page-learing-index.css" />
    <link rel="stylesheet" href="http://caojiawan.ltd/css/page-header.css" />
</head>
<body>
<div class="banner-roll">
    <div class="banner-item">
        <#if model??>
            <#list model as item>
                <div class="item" style="background-image: url(${item.value});"></div>
            </#list>
        </#if>
	 <#--<div class="item" style="background-image: url(http://caojiawan.ltd/img/widget-bannerA.jpg);"></div>-->
        <#--<div class="item" style="background-image: url(http://caojiawan.ltd/img/widget-banner3.png);"></div>-->
        <#--<div class="item" style="background-image: url(http://caojiawan.ltd/img/widget-bannerB.jpg);"></div>-->
        <#--<div class="item" style="background-image: url(http://caojiawan.ltd/img/widget-bannerA.jpg);"></div>-->
        <#--<div class="item" style="background-image: url(http://caojiawan.ltd/img/widget-banner3.png);"></div>-->
    <#--</div>-->
    <div class="indicators"></div>
</div>
<script type="text/javascript" src="http://caojiawan.ltd/plugins/jquery/dist/jquery.js"></script>
<script type="text/javascript" src="http://caojiawan.ltd/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>

GridFS 取文件

在config包中定义Mongodb的配置类,如下: GridFSBucket用于打开下载流对象
package com.xuecheng.manage_cms.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;

@Configuration
public class MongoConfig {

    //此格式是将yml格式的配置文件内容,注入 String db 中。
    @Value("${spring.data.mongodb.database}")
    String db;

    @Bean
    public GridFSBucket getGridFSBucket(MongoClient mongoClient){
        MongoDatabase database = mongoClient.getDatabase(db);
        GridFSBucket bucket = GridFSBuckets.create(database);
        return bucket;
    }
}
application.yml
server:
  port: 31001
spring:
  application:
    name: xc‐service‐manage‐cms
  data:
    mongodb:
      uri: mongodb://root:root@localhost:27017
      database: xc_cms
取文件测试代码
package com.xuecheng.manage_cms.dao.gridfs;


import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import org.apache.commons.io.IOUtils;
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.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
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;
import java.io.IOException;

/**
 * 测试用GridFS-----存储文件
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestGridFS {
    //注入 GridFsTemplate 类
    @Autowired
    GridFsTemplate gridFsTemplate;

    /**
     * 用GridFS------存储文件
     *
     * 存储原理说明:
     * 文件存储成功得到一个文件id 此文件id是fs.files集合中的主键。
     * 可以通过文件id查询fs.chunks表中的记录,得到文件的内容。
     */
    @Test
    public void testGridFs() throws FileNotFoundException {
        //要存储的文件
        File file = new File("d:/index_banner.ftl");
        //定义输入流
        FileInputStream inputStram = new FileInputStream(file);
        //向GridFS存储文件
        ObjectId objectId = gridFsTemplate.store(inputStram, "轮播图测试文件01", "");
        //得到文件ID
        String fileId = objectId.toString();
        System.out.println(fileId);
    }


     @Autowired
     GridFSBucket gridFSBucket;
    @Test
    public void queryFile() throws IOException {
        String fileId = "5e9fc6c549797d1dd0b40414";
        //根据id查询文件
        //    GridFS在数据库中,默认使用fs.chunks和fs.files来存储文件。
        //        1.fs.files集合存放文件的信息;
        //        2.fs.chunks存放文件数据;
        GridFSFile gridFSFile =  gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
        //打开下载流对象
        GridFSDownloadStream gridFSDownloadStream =  gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
        //创建gridFsResource,用于获取流对象
        GridFsResource gridFsResource = new GridFsResource(gridFSFile,gridFSDownloadStream);
        //获取流中的数据
        String s = IOUtils.toString(gridFsResource.getInputStream(),"UTF-8");
        System.out.println(s);
    }
}
删除文件测试代码

.....
//删除文件
    @Test
    public void testDelFile() throws IOException {
        //根据文件id删除fs.files和fs.chunks中的记录
        gridFsTemplate.delete(Query.query(Criteria.where("_id").is("5e9fc6c549797d1dd0b40414")));
    }
.....

模板存储

根据模板管理的流程,最终将模板信息存储到MongoDB的cms_template中,将模板文件存储到GridFS中。 模板管理功能在课堂中不再讲解,教学中手动向cms_template及GridFS中存储模板,方法如下:
1、添加模板
1)使用GridFS测试代码存储模板文件到GridFS,并得到文件id.
2)向cms_template添加记录。
在这里插入图片描述
2、删除模板
1)使用GridFS测试代码根据文件id删除模板文件。
2)根据模板id删除cms_template中的记录。
3、修改模板信息
使用Studio 3T修改cms_template中的记录。
4、修改模板文件
1)通过Studio 3T修改模板文件(此方法限文件小于256K)
可以通过Studio 3T修改模板文件,先找到模板文件,再导入进去:
在这里插入图片描述

真正实现页面静态化

package com.xuecheng.manage_cms.service;

import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsTemplate;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.manage_cms.dao.CmsPageRepository;
import com.xuecheng.manage_cms.dao.CmsTemplateRepository;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;
import freemarker.template.Template;

import java.io.IOException;
import java.util.Map;
import java.util.Optional;
@Service
public class PageService {
    @Autowired
    CmsPageRepository cmsPageRepository;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    CmsTemplateRepository cmsTemplateRepository;
    @Autowired
    GridFSBucket gridFSBucket;
    //注入 GridFsTemplate 类
    @Autowired
    GridFsTemplate gridFsTemplate;

    /**
     * 根据ID找页面
     *
     * @param pageId
     * @return
     */
    public CmsPage getPageById(String pageId) {
        //判断ID是否存在
        if (pageId == null) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXTISTS);
        }
        //判断页面是否存在
        Optional<CmsPage> byId = cmsPageRepository.findById(pageId);
        if (!(byId.isPresent())) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXTISTS);
        }
        CmsPage cmsPage = byId.get();
        return cmsPage;


    }

    //页面静态化
    public String getPageHtml(String pageId) throws IOException, TemplateException {
        CmsPage cmsPage = this.getPageById(pageId);


        //------获取数据模型
        //根据页面ID得到CmsPage
        //在CmsPage中得到DataUrl
        //然后根据DataUrl发送客户端请求,获得数据模型。
        Map modelByPageId = this.getModel(cmsPage);
        if(modelByPageId==null){
            //数据模型获取不到
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }

        //------获取模板
        //根据页面ID得到CmsPage
        //在CmsPage中得到templateId
        //然后根据templateId得到CmsTemplate
        //在CmsTemplate中,得到templateFileId
        //然后根据templateFileId,获取模板
        //执行页面静态化
        String templateByPageId = this.getTemplate(cmsPage);
            if(templateByPageId==null){
              ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
            }
        //------执行页面静态化
        return this.generateHtml(templateByPageId,modelByPageId);
    }

    //获取数据模型
    //根据页面ID得到CmsPage
    //在CmsPage中得到DataUrl
    //然后根据DataUrl发送客户端请求,获得数据模型。
    private Map getModel(CmsPage cmsPage) {

        String dataUrl = cmsPage.getDataUrl();
        if(StringUtils.isEmpty(dataUrl)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
        }
            ResponseEntity<Map> forEntity = restTemplate.getForEntity(dataUrl, Map.class);
            return forEntity.getBody();

    }

    //获取模板
    //根据页面ID得到CmsPage
    //在CmsPage中得到templateId
    //然后根据templateId得到CmsTemplate
    //在CmsTemplate中,得到templateFileId
    //然后根据templateFileId,获取模板
    private String getTemplate(CmsPage cmsPage) throws IOException {

        String templateId = cmsPage.getTemplateId();
        if(StringUtils.isEmpty(templateId)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        Optional<CmsTemplate> byId = cmsTemplateRepository.findById(templateId);
        if (byId.isPresent()) {
            CmsTemplate cmsTemplate = byId.get();
            //获取模板文件ID
            String templateFileId = cmsTemplate.getTemplateFileId();


            //然后根据templateFileId,获取模板

            //根据id查询文件
            //  GridFS在数据库中,默认使用fs.chunks和fs.files来存储文件。
            //      1.fs.files集合存放文件的信息;
            //      2.fs.chunks存放文件数据;
            GridFSFile gridFSFile =  gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
            //打开下载流对象
            GridFSDownloadStream gridFSDownloadStream =  gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
            //创建gridFsResource,用于获取流对象
            GridFsResource gridFsResource = new GridFsResource(gridFSFile,gridFSDownloadStream);
            //获取流中的数据
            String s = IOUtils.toString(gridFsResource.getInputStream(),"UTF-8");

            return s;
        }
        return null;
    }

    //执行页面静态化(以模板字符串方式,实现网页静态化)
    private String generateHtml(String template,Map model) throws IOException, TemplateException {
        //创建配置类
        Configuration configuration = new Configuration(Configuration.getVersion());

        //模板加载器
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template", template);
        configuration.setTemplateLoader(stringTemplateLoader);
        //得到模板
        Template template1 = configuration.getTemplate("template", "utf‐8");

        //静态化
        String content = FreeMarkerTemplateUtils.processTemplateIntoString(template1, model);
        //静态化内容
        System.out.println(content);
        return content;
    }
}

单元测试

package com.xuecheng.manage_cms.dao;


import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.manage_cms.service.PageService;
import freemarker.template.TemplateException;
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.domain.*;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * 这是单元测试,在postman或者swagger测试叫接口测试
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class FreemarkerTest {
    @Autowired
    PageService pageService;


    @Test
    public void freemarkerTest() throws IOException, TemplateException {
        String pageHtml = pageService.getPageHtml("5a795ac7dd573c04508f3a56");
        System.out.println(pageHtml);
    }

}

页面预览

在以上操作后,只得到了String类型的HTML内容,如果要 实现页面预览, 就必须将String类型的数据通过流的方式输出到网页。具体操作代码如下:

package com.xuecheng.framework.web;

import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Created by mrt on 2018/5/22.
 */
public class BaseController {
    protected HttpServletRequest request;

    protected HttpServletResponse response;

    protected HttpSession session;

    @ModelAttribute
    public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {

        this.request = request;

        this.response = response;

        this.session = request.getSession();

    }
}

package com.xuecheng.manage_cms.controller;

import com.xuecheng.framework.web.BaseController;
import com.xuecheng.manage_cms.service.PageService;
import freemarker.template.TemplateException;
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;

@Controller
public class CmsPagePreviewController extends BaseController {

    @Autowired
    PageService pageService;
    //接收到页面id
    @RequestMapping(value="/cms/preview/{pageId}",method = RequestMethod.GET)
     public void preview(@PathVariable("pageId")String pageId) throws IOException, TemplateException {
        String pageHtml = pageService.getPageHtml(pageId);

        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(pageHtml.getBytes("utf-8"));
    }
}

前端部分添加预览链接

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值