学成在线--day04 页面静态化

学成在线 第4天 讲义-页面静态化 页面预

 

1 页面静态化需求 
1、为什么要进行页面管理?
  本项目cms系统的功能就是根据运营需要,对门户等子系统的部分页面进行管理,从而实现快速根据用户需求修改 页面内容并上线的需求。
2、如何修改页面的内容?
 
 在开发中修改页面内容是需要人工编写html及JS文件,CMS系统是通过程序自动化的对页面内容进行修改,通过 页面静态化技术生成html页面。

3、如何对页面进行静态化?
一个页面等于模板加数据,在添加页面的时候我们选择了页面的模板。
页面静态化就是将页面模板和数据通过技术手段将二者合二为一,生成一个html网页文件。

4、页面静态化及页面发布流程图如下

2 FreeMarker 研究

3 页面静态化

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、执行页面静态化。

新建一个test-framarker模块进行测试

 

引入Pom依赖

 

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>
    </dependencies>

引入配置文件

server:
  port: 8088 #服务端口

spring:
  application:
    name: test-freemarker #指定服务名
  freemarker:
    cache: false  #关闭模板缓存,方便测试
    settings:
      template_update_delay: 0 #检查模板更新延迟时间,设置为0表示立即检查,如果时间大于0会有缓存不方便进行模板测试

创建启动类

@SpringBootApplication
public class FreemarkerTestApplication {
    public static void main(String[] args) {
        SpringApplication.run(FreemarkerTestApplication.class,args);
    }
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
    }
}

编写Controller:

@RequestMapping("/freemarker")
@Controller
public class FreemarkerController {

    @RequestMapping("/test1")
    public String test1(Map<String,Object> map){
        map.put("name","这个是freemarker得测试内容");
        return "test2";
    }
}

进行模板内容得测试:

Freemarker得list命令得测试

获取Map中的对应得属性得值得内容
${stuMap['stu1'].name}</br>
${stuMap['stu1'].age}</br>
${stuMap.stu2.age}</br>
通过遍历map里面得key来实现更简便得方法
<#list stuMap?keys as k>
    ${stuMap[k].name}
    ${stuMap[k].age}
    ${stuMap[k].mondy}
</#list>

进行测试: 

freemarker中if指令得使用,当学生得金额大于300时候,显示背景色为红色

完成测试:

freemarker中得空值得处理判断

采用双??得形式进行list得非空得判断对属性得非空判断,采用!''缺省值赋值为空得默认判断

关于freemarker得内建函数得实现

定义模板类型,新建模板测试类,利用工具类生成模板文件,来创建一个html得静态化文件

   @Test
    public void generatorHtml() throws IOException, TemplateException {
        //设置配置类
        Configuration configuration=new Configuration(Configuration.getVersion());
        //设置模板文件获取文件路径
        String classpath = this.getClass().getResource("/").getPath();
        configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/"));
        //获取模板路径
        Template template = configuration.getTemplate("test2.ftl");
        //获取的模板的数据
        Map map = getMap();
        //开始生成模板
        String string = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
        //获取文件输入出流,写入到磁盘当中
        InputStream inputStream = IOUtils.toInputStream(string);
        FileOutputStream outputStream=new FileOutputStream(new File("d:/test1.html"));
        IOUtils.copy(inputStream,outputStream);
        inputStream.close();
        outputStream.close();
    }

开始渲染出来模板文件的位置

根据字符串生成模板文件

 @Test
    public void stringToTemplate() throws IOException, TemplateException {
        Configuration configuration=new Configuration(Configuration.getVersion());
        //定义模板串
        String templateString="" +
                "<html>\n" +
                "    <head></head>\n" +
                "    <body>\n" +
                "    名称:${name}\n" +
                "    </body>\n" +
                "</html>";
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template",templateString);
        configuration.setTemplateLoader(stringTemplateLoader);
        Template template = configuration.getTemplate("template", "utf-8");
        Map map = getMap();
        //开始生成模板
        String string = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
        //获取文件输入出流,写入到磁盘当中
        InputStream inputStream = IOUtils.toInputStream(string);
        FileOutputStream outputStream=new FileOutputStream(new File("d:/tes232t1.html"));
        IOUtils.copy(inputStream,outputStream);
        inputStream.close();
        outputStream.close();

    }

3.2 数据模型 
3.2.1 轮播图DataUrl接口 3.2.1.1 需求分析 
CMS中有轮播图管理、精品课程推荐的功能,以轮播图管理为例说明:轮播图管理是通过可视化的操作界面由管理 员指定轮播图图片地址,最后将轮播图图片地址保存在cms_config集合中,下边是轮播图数据模型:

关于静态页面的静态化,调用CMSConfig接口的步骤

Controller:

@RestController
@RequestMapping("/cms/config")
public class CmsConfigController implements CmsConfigControllerApi {
    @Autowired
    private PageService pageService;

    @Override
    @GetMapping("/getmodel/{id}")
    public CmsConfig getmodel(@PathVariable("id") String id) {
        return pageService.CmsConfigfindById(id);
    }
}

Service:

 public CmsConfig CmsConfigfindById(String id){
        Optional<CmsConfig> cmsConfig = cmsConfigRepository.findById(id);
        if (cmsConfig.isPresent()){
            CmsConfig cmsConfig1 = cmsConfig.get();
            return cmsConfig1;
        }
        return null;
    }

关于轮播图模板的制作,整个模板的制作过程还是比较简单,只要把原网页复制一下。之后把要替换的数据换成framaker的标签就可以了

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

Controller:

 @RequestMapping("/banner")
    public String test1(Map<String,Object> map){
        //向数据模型放数据
        ResponseEntity<Map> entity = restTemplate.getForEntity("http://localhost:31001/cms/config/getmodel/5a791725dd573c3574ee333f", Map.class);
        Map body = entity.getBody();
        map.putAll(body);
        return "index_banner";
    }

完成测试:

使用GridFsTemplate进行文件的存入

   //存文件
    @Test
    public void testStore() throws FileNotFoundException {
        //定义file
        File file =new File("d:/index_banner.ftl");
        //定义fileInputStream
        FileInputStream fileInputStream = new FileInputStream(file);
        ObjectId objectId = gridFsTemplate.store(fileInputStream, "index_banner.ftl");
        System.out.println(objectId);
    }

完成测试:

 读取文件

//取文件
    @Test
    public void queryFile() throws IOException {
        //根据文件id查询文件
        GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is("5e68b1f810b34108bc9f94b3")));

        //打开一个下载流对象
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
        //创建GridFsResource对象,获取流
        GridFsResource gridFsResource = new GridFsResource(gridFSFile,gridFSDownloadStream);
        //从流中取数据
        String content = IOUtils.toString(gridFsResource.getInputStream(), "utf-8");
        System.out.println(content);

    }

配置类报错,这个BUG就是无法读取到GridFsBucket,因为是在测试类做的,且测试类里面的配置文件无法读取到,在复制一个到test文件加下就可以了

成功读取到内容

 

这个地方有些绕,确实比较繁琐,因为没有模板的管理的操作只有页面管理的操作,所以有时候,往数据库里面的操作,操作的ID对不上回出现空指针异常,先说明一下,主要分为cms_page这个表里面存着的就是整个页面的配置信息,主要又三个关键的地方一个是,template_id这个字段的意思就是说明,这个页面的模板大致是那个模板,类似数据轮播图模板,或者是课程详情模板,接下来就是主键的ID这个就是这条记录的唯一标识,这个不须多解释,接下来的就是dataUrl,这个就比较不好理解了,因为模板ID 又了,主键ID也又了,需要找个dataURL的作用就是用httplClient通过远程调用接口的方法,来动态生成一个模板的页面,因为我这个dataURL后面跟的ID是从cms_config这个表里面的ID,换而言之,就是这个dataURL的作用决定了要生成什么类型的模板,轮播图类型的模板还是课程详情的模板。这三个字段搞明白了之后,就是开始静态化了,因为需求是轮播图需要更换,更换的前提是不能重复的编写代码,这个需要用程序自动来控制,用Freemarker来实现的时候,需要又两个必备条件,一个是模型数据,一个是模板数据,模型数据可以根据cms_page的主键id查询到,然后查询到这个cms_page对象之后,我们可以获取到对应的dataURL,拿到dataURL就可以生成指定的模板了,这个模板就是cms_config这个里面的不是cms_template这个表里,他生成的配置信息是参照的cms_config,接着就会生成对应的模板,对应的模板这个记录就回存在cms_template这个表中,这个cms_template这个表里面也又几个字段需要注意一下templateFiled这个字段注意是fs_files这个表里的主键,拿这个字段是怎么来的呢,这个字段就是要执行要给Freemaker的测试程序,将模板的信息存入到硬盘,然后会将存取的信息写入的Mongdb中,接着就会生成一个GradFs的主键,这个主键就是template模板的外键,然后这个Tempalte的主键就作为了cms_page的外键,这个过程必须的理清楚,如果理不清楚,这个页面就一直生成不成功,还有一点就是cms_confg他着几个页面的IP地址都是192.168.0.104也就是他提前已经配置了FastFds的文件存储系统,如果没有配置这个,图片是显示不出来了,

接下来就是用程序来控制,显示获取数据模型的代码,接着就是获取模板的代码,最好是执行自动绘的页面静态化

   //执行静态化程序
    public String generateHtml(String templateConten,Map model){
        Configuration configuration=new Configuration(Configuration.getVersion());
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template",templateConten);
        configuration.setTemplateLoader(stringTemplateLoader);
        try {
            Template template = configuration.getTemplate("template");
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
            return content;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    //执行根据pageId获取模板数据
    public String getTemplateByPageId(String pageId){
        CmsPage cmsPage = this.findById(pageId);
        if (cmsPage==null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String templateId = cmsPage.getTemplateId();
        if (StringUtils.isEmpty(templateId)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        //开始执行根据Tmeplate查询对应得模板信息
        Optional<CmsTemplate> optional = cmsTemplatesRepository.findById(templateId);
        if (optional.isPresent()){
            CmsTemplate cmsTemplate = optional.get();
            String fileId = cmsTemplate.getTemplateFileId();
            //从GridFS中取模板文件内容
            //根据文件id查询文件
            GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));

            //打开一个下载流对象
            GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
            //创建GridFsResource对象,获取流
            GridFsResource gridFsResource = new GridFsResource(gridFSFile,gridFSDownloadStream);
            //从流中取数据
            try {
                String content = IOUtils.toString(gridFsResource.getInputStream(), "utf-8");
                return content;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    //执行根据PaGeId获取模型数据
    public Map getModelByPageId(String pageId){
        CmsPage cmsPage = this.findById(pageId);
        if (cmsPage==null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String dataUrl = cmsPage.getDataUrl();
        if (StringUtils.isEmpty(dataUrl)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
        }
        //开始发送dataUrl的请求
        ResponseEntity<Map> entity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = entity.getBody();
        return body;
    }

 最好就是添加页面预览功能及其Nginx进行访问代理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值