学成在线第六天

今天咱们做课程的预览功能
在这里插入图片描述
背景:
我们经常浏览电商网站,电商网站浏览量最大的页面是什么?商品检索列表、商品详情。对于在线教育网站,课程就是商品。因此,课程详情页的访问流量是巨大的。因此,除了上面的功能性需求,本章我们还需要满足一个非功能性需求高性能课程详情页访问。

在这里插入图片描述
需要的表
在这里插入图片描述
为什么要形成课程发布信息呢?

课程发布信息代表着一次课程输出的最终确定。后续的业务,如课程购买、学习将围绕着该课程发布信息,从业务角度该信息不可轻易修改,只读(若修改,需要重新走审核流程)。

课程业务表与发布内容相分离,课程业务信息是经常发生变动的,而课程发布信息不会轻易修改,因此形成业务级别的读写分离,两者互不影响。

Freemarker

背景:
这里我想让大家想一件事情,做课程预览这功能大家最初的想法是什么?最简单的想法:查询数据库然后将数据显示到页面,每次访问都会先查询数据库,但是这种方法在一个页面有大量的数据时(微服务大部分压力在数据库)查询多个表,数据显示会很慢,影响用户的体验
然后呢?我们怎么优化,使用redis?可以,但是还是不够快,对于一个几乎所有数据都不怎么修改的页面,其实我们可以使用freemark模板语言,生成静态html页面,然后将页面存储到阿里云或者minio中,用户点击预览实际上是访问的静态页面,而无需查询庞大的数据库,访问速度才是最快。

freeMark官网
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

​ 模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

  • freemarker并不关心数据的来源,只是根据模板的内容,将数据模型在模板中显示并输出文件(通常为html,也可以生成其它格式的文本文件)

流程:
freemarker作为springmvc一种视图格式,默认情况下SpringMVC支持freemarker视图格式。

需要创建Spring Boot+Freemarker工程用于测试模板。

在线预览:freemarker作为springmvc一种页面。在浏览器展示

浏览器发起请求---->SpringMVC---->执行Controller----->定义返回值(模板地址)---->模板中绑定数据---->浏览器展示

freeMark快速入门

这里我就简单介绍一下,要想详细了解大家可以进我发官网去看看

以下内容直接粘贴看看效果就行了,不做强制要求

导入依赖

    <!-- 添加springboot 父类依赖 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <dependencies>
        <!--添加 spring boot web 依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!-- lombok使用 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>
        <!-- apache 对 java io 的封装工具库 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>

配置application.yml配置

spring:
  freemarker:
    #开启 freemarker 功能
    enabled: true
    #关闭模板缓存,方便测试
    cache: false
    settings:
      template_update_delay: 0
    #页面模板后缀名
    suffix: .ftl
    charset: UTF-8
    #页面模板位置(默认为 classpath:/templates/)
    template-loader-path: classpath:/templates/
  resources:
    #关闭项目中的静态资源映射(static、resources文件夹下的资源)
    add-mappings: false

创建模型类;

package com.xuecheng.freemarker.entity;

import lombok.Data;
import lombok.ToString;
import java.util.Date;
import java.util.List;

@Data
@ToString
public class Student {
    private String name;//姓名
    private int age;//年龄
    private Date birthday;//生日
    private Float money;//钱包
}

模拟controller层:

package com.xuecheng.test.freemarker.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

@Controller
public class HelloController {

    @GetMapping("basic")
    public String test(Model model) {
        //1.纯文本形式的参数
        model.addAttribute("name", "freemarker");
        //2.实体类相关的参数
        Student student = new Student();
        student.setName("小明");
        student.setAge(18);
        model.addAttribute("stu", student);
        return "01-basic";
    }
}

创建模板

在resources下创建templates,此目录为freemarker的默认模板存放目录
在templates下创建模板文件 01-basic.ftl ,模板中的插值表达式最终会被freemarker替换成具体的数据。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<b>普通文本 String 展示: Hello ${name}</b><br><br>
 <br>
<hr>
<b>对象Student中的数据展示:${stu}</b><br/>
姓名:${stu.name}<br/>
年龄:${stu.age}
<hr>
</body>
</html>

支持EL表达式

在这里插入图片描述


freemarker基础
页面上的指令,语法规则。

基础语法种类:

1.注释,即<#--  -->,介于其之间的内容会被freemarker忽略
<#--我是一个freemarker注释-->

在这里插入图片描述

2、插值(Interpolation):即 ${..} 部分,freemarker会用真实的值代替${..}
  Hello ${name}

在这里插入图片描述

3、FTL指令:和HTML标记类似,名字前加#予以区分,Freemarker会解析标签中的表达式或逻辑。
  <#>FTL指令</#> 
 @GetMapping("/list")
    public String list(Model model) {
        //响应数据
        //2.1 小强对象模型数据
        Student stu1 = new Student();
        stu1.setName("小强");
        stu1.setAge(18);
        stu1.setMoney(1000.86f);

        //2.2 小红对象模型数据
        Student stu2 = new Student();
        stu2.setName("小红");
        stu2.setMoney(200.1f);
        stu2.setAge(19);

        //2.3 将两个对象模型数据存放到List集合中
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);
        model.addAttribute("stus",stus);

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>

<b>展示list中的stu数据:</b>
<br>
<br>
<#--list 数据的展示-->
<b>展示list中的stu数据:</b>
<#list stus as s>
    name:${s.name},
    age:${s.age},
    money:${s.money},
</#list>

<hr>
</body>
</html>

在这里插入图片描述

  4、文本,仅文本信息,这些不是freemarker的注释、插值、FTL指令的内容会被freemarker忽略解析,直接输出内容.
  
     <#--freemarker中的普通文本-->
     我是一个普通的文本

在这里插入图片描述


集合指令(List和Map)

 @GetMapping("/list")
    public String list(Model model) {
        //响应数据
        //2.1 小强对象模型数据
        Student stu1 = new Student();
        stu1.setName("小强");
        stu1.setAge(18);
        stu1.setMoney(1000.86f);

        //2.2 小红对象模型数据
        Student stu2 = new Student();
        stu2.setName("小红");
        stu2.setMoney(200.1f);
        stu2.setAge(19);

        //2.3 将两个对象模型数据存放到List集合中
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);
        model.addAttribute("stus",stus);


        //3. 创建Map数据
        Map<String,Student> stuMap = new HashMap<>();
        stuMap.put("stu1",stu1);
        stuMap.put("stu2",stu2);
        model.addAttribute("stuMap", stuMap);

        //返回模板地址
        return "02-collection";
    }
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>

<b>展示list中的stu数据:</b>
<br>
<br>
<#--list 数据的展示-->
<b>展示list中的stu数据:</b>
<#list stus as s>
    name:${s.name},
    age:${s.age},
    money:${s.money},
</#list>
<hr>
<b>展示map中的数据:</b>
<#--获取map中某个key下的数据:map.key.属性-->
stu1的name:${stuMap.stu1.name}<br>
stu2的name:${stuMap.stu2.name}<br>
<#--遍历map集合,获取map中的所有数据
    语法:[map]?keys as key  -- 循环map集合获取获取每个key
-->
<hr>
遍历map集合 <br>
<#--<#list stuMap?keys as key>-->
<#--    ${stuMap[key].name} --  ${stuMap[key].age} <br>-->
<#--</#list>-->

<#list stuMap? keys as key>
    ${stuMap[key].name} ---- ${stuMap[key].age}-----${stuMap[key].money}<br>
</#list>
</body>
</html>

在这里插入图片描述

${k_index}:
	index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始

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


if指令
if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否则跳过内容不再输出。

<#--格式-->
<#if condition>
      ...
    <#elseif condition2>
      ...
    <#elseif condition3>
      ...
    ...
    <#else>
      ...
</#if>
package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

import java.util.*;

@Controller
public class HelloController {

    @GetMapping("basic")
    public String test(Model model) {
        //1.纯文本形式的参数
        model.addAttribute("name", "freemarker");
        //2.实体类相关的参数
        Student student = new Student();
        student.setName("小明");
        student.setAge(18);
        model.addAttribute("stu", student);
        return "01-basic";
    }


    @GetMapping("/list")
    public String list(Model model) {
        //响应数据
        //2.1 小强对象模型数据
        Student stu1 = new Student();
        stu1.setName("小强");
        stu1.setAge(18);
        stu1.setMoney(1000.86f);

        //2.2 小红对象模型数据
        Student stu2 = new Student();
        stu2.setName("小红");
        stu2.setMoney(200.1f);
        stu2.setAge(19);

        //2.3 将两个对象模型数据存放到List集合中
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);
        model.addAttribute("stus",stus);


        //3. 创建Map数据
        Map<String,Student> stuMap = new HashMap<>();
        stuMap.put("stu1",stu1);
        stuMap.put("stu2",stu2);
        model.addAttribute("stuMap", stuMap);

        //返回模板地址
        return "03-if";
    }
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<#list stus as s>
    <#if s.name='小红'>
        <b style="color: red">
            ${s.name}<br>
        </b>
        <#elseif s.name='小绿'>
          <b style="color: green">
              ${s.name}<br>
          </b>
          <#--类似于swich中的default-->
            <#else>
        ${s.name}<br>
    </#if>
</#list>
</body>
</html>

在这里插入图片描述


空值处理:
Freemarker 在显示数据时,如果遇到了null或空,Freemarker就会在显示页面中报出错误信息:null or missing,

Freemarker中需要对空值间判断,判断后的数据就不会显示错误信息。

判断某变量是否存在使用 “??”
如:为防止stus为空报错可以加上判断如下:
    <#if stus??>
    <#list stus as stu>
    	......
    </#list>
    </#if>
缺失变量默认值使用 “!**
使用!要以指定一个默认值,当变量为空时显示默认值
如:${name!''}表示如果name为空显示空字符串。

实际例子:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<#list stus as s>
    <#if s??>
        <#if s.name='小红'>
            <b style="color: red">
                ${s.name}<br>
                ${s.birthday!'2022-8-11'}<br>
            </b>
        <#elseif s.name='小绿'>
            <b style="color: green">
                ${s.name}<br>
                ${s.birthday!'2022-8-11'}<br>
            </b>
        <#else>
            ${s.name}<br>
            ${s.birthday!'2022-8-11'}<br>
        </#if>
    </#if>
</#list>
</body>
</html>

在这里插入图片描述


内建函数
内建函数语法格式: 变量+?+函数名称

  • 某个集合的大小
<hr>
 集合大小:${stus?size}<br>

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

  • 日期格式化

    显示年月日: ${today?date}
    显示时分秒:${today?time}
    显示日期+时间:${today?datetime}
    自定义格式化: ${today?string("yyyy年MM月")}

 Date date = new Date();
        model.addAttribute("today",date);
<hr>
日期格式
<br>
显示年月日:${today?date}<br>
显示时分秒:${today?time}<br>
显示日期+时间:${today?datetime}<br>
自定义格式化:${today?string("yyyy/MM月dd日")}

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

  • 内函数c
model.addAttribute("point", 102920122);

point是数字型,使用${point}会显示这个数字的值,每三位使用逗号分隔。

如果不想显示为每三位分隔的数字,可以使用c函数将数字型转成字符串输出

在这里插入图片描述

 model.addAttribute("point", 102920122);
<hr>
内函数:<br>
有c:${point?c}<br>
无c:${point}

在这里插入图片描述


静态化测试(练习)

之前的测试都是SpringMVC将Freemarker作为视图解析器(ViewReporter)来集成到项目中,工作中,有的时候需要使用Freemarker原生Api来生成静态内容并使用文件来存储静态化后的内容,下面一起来学习下原生Api生成文本文件。

使用freemarker原生Api将页面生成html文件,本节测试html文件生成的方法:

1、根据模板文件生成html文件的字符串

​	模板文件 + 数据模型 = 静态文件 

2、根据模板字符串生成静态文件

​    模板字符串 + 数据模型 = 静态文件 

GeneratorHtml.class

package com.example;

import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;


@SpringBootTest
public class GeneratorHtml {

    @Test
    public void testHtml() throws Exception {
        //1、创建配置类,指定版本信息
        Configuration configuration = new Configuration(Configuration.getVersion());
        //2、指定模板,字符编码
        String path = this.getClass().getResource("/templates").getPath();
        configuration.setDirectoryForTemplateLoading(new File(path)); //指定模板文件的文件夹路径
        configuration.setDefaultEncoding("utf-8");
        //3、获取模板文件
        Template template = configuration.getTemplate("01-basic.ftl");
        //4、构造数据,必须是一个Map集合
        Map data = getData();
        //5、根据数据 + 模板文件进行数据填充,得到字符串
        String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
        //6、将静态化字符串写入到指定文件下
        InputStream inputStream = IOUtils.toInputStream(content); //字符串转化为输入流
        FileOutputStream outputStream = new FileOutputStream(new File("e:/index.html")); //创建文件
        IOUtils.copy(inputStream, outputStream); //输入流写入文件
    }

    private Map getData() {
        Map map = new HashMap();
        map.put("name","zjf");
        Student student  = new Student();
        student.setName("王者荣耀");
        student.setAge(12);
        map.put("student",student);
        return map;
    }
}

01-basic.ftl

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<#--我是一个freemarker注释-->
<b>普通文本 String 展示:</b><br><br>
Hello  ${name1!""}<br>
<hr>
<b>对象Student中的数据展示:</b><br/>
姓名:${student.name}<br/>
年龄:${student.age}
<hr>


</body>
</html>

在这里插入图片描述

课程预览

课程管理中,教学机构和运营平台都是需要对课程生成的详情页进行预览操作,项目中的课程预览会使用 Freemarker 模板技术来做业务实现,之前已经将 Freemarker 的相关技术学习完后,下面将进行课程预览的相关需求开发。

需求分析
此模块主要针对教育机构平台运营对课程信息的预览,主要功能包括:

  • 教育机构提交审核前预览,教育机构课程提交审核前,往往需要看一下课程最终会被发布成什么样子,是否符合所预期,因此需要提供 教学机构课程预览功能来满足该需求,若符合预期,则进行课程提交审核操作。
  • 平台运营审核过程中预览,平台运营在课程的审核过程中,也需要预览功能来更直观的看到课程内容,因此需要提供平台运营课程预览功能来满足该需求。

教育机构用户课程管理中可对该机构内所管理的课程进行检索。

课程预览交互流程如下:

在这里插入图片描述
步骤描述:

​ 1.前端对某审核通过的课程执行课程发布操作

​ 2.查询课程基本信息、课程营销、课程计划、教师信息并保存到 课程发布中。

​ 3.远程调用系统管理查询课程分类信息

​ 4.保存课程发布信息

​ 5.获得页面的数据模型(课程发布、课程营销、课程计划、教师信息、课程分类等)

​ 6.使用Spring MVC 结果视图器 Freemarker 选择页面模板,生成静态页面

​ 7.将生成的静态页面返回给前端
内容管理开发中,需要调用系统管理服务来完成数据的获取。所以本次开发中,需 要在两个微服务中,分别进行开发,功能如下:
​ - 系统管理服务:开发根据可曾分类 ID 获得课程分类信息的接口。
- 内容管理服务:开发课程预览的接口。

项目环境搭建
学成在线的课程预览会在 xc-content-service 微服务工程中,进行开发。在开发前,我们需要将其运行环境先构建出来。

  • 数据库环境
  • Freemarker 环境集成

导入pom.xml依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

yml配置文件

spring:
  freemarker:
    #开启 freemarker 功能
    enabled: true
    #关闭模板缓存,方便测试
    cache: false
    settings:
      template_update_delay: 0
    #页面模板后缀名
    suffix: .ftl
    charset: UTF-8
    #页面模板位置(默认为 classpath:/templates/)
    template-loader-path: classpath:/templates/
  resources:
    #关闭项目中的静态资源映射(static、resources文件夹下的资源)
    add-mappings: false

导入ftl模板
在这里插入图片描述
代码太多了,这里我就不具体显示了,需要的私信我

课程分类信息业务实现
在课程预览中,内容管理微服务 远程调用 系统管理服务接口来获得课程分类名称,如下:
在这里插入图片描述
下面将在系统管理微服务xc-basic-service中开发此接口。

注意这里我们只需要查询大分类就行,为了去填补mt
在这里插入图片描述YAPI文档接口
在这里插入图片描述
在这里插入图片描述
代码展示

    //根据id 查询分类信息
    @GetMapping("/{id}")
    public ResponseResult findCategoryById(@PathVariable("id") String id){
        Category category = categoryService.getById(id);
        CategoryVo categoryVo = BeanHelper.copyProperties(category, CategoryVo.class);
        return ResponseResult.okResult(categoryVo);
    }

效果展示
在这里插入图片描述
使用idea自带的Http client测试以下,点击以下那个小地球(IDEA21版才有,以前的版本,在Tools里面)
在这里插入图片描述

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


抽取feign接口:
由于课程预览功能要调用此功能,不同微服务之间可以使用feign进行练习,所以我们需要抽取feign接口。

引入依赖:在这里插入图片描述

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-framework-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

在这里插入图片描述

package com.xuecheng.basic.api;


import com.xuecheng.commons.model.vo.CategoryVo;
import com.xuecheng.commons.model.vo.ResponseResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("xc-basic-service")
public interface BasicClient {
    //泛型必须写,不写会报错
    @GetMapping("/category/{id}")
    ResponseResult<CategoryVo> findCategoryById(@PathVariable("id") String id);
}

在ContentApplication启动类加@EnableFeignClients包扫描
在这里插入图片描述


课程预览
在这里插入图片描述

在这里插入图片描述

YAPI文档:
在这里插入图片描述
xc-content-service引入分接口

<!--        引入分类feign接口-->
  <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-basic-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

在这里插入图片描述
需要的表:
在这里插入图片描述
在这里插入图片描述
代码修复:

需要将 coursePub实体类中的price字段修改为BigDecimal
在这里插入图片描述

代码展示:

web层
在这里插入图片描述

package com.xuecheng.content.controller;

import com.xuecheng.commons.model.vo.ResponseResult;
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;
import com.xuecheng.content.service.CoursePubService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.ModelAndView;

/**
 * <p>
 * 课程发布前端控制器
 * </p>
 *
 * @author ZJF
 */
@Slf4j
@RestController
@RequestMapping("/coursePub")
public class CoursePubController {

    @Autowired
    private CoursePubService  coursePubService;
    //课程发布预览
    @GetMapping("/preview/{courseBaseId}")
    public ModelAndView previewCourser(@PathVariable("courseBaseId") Long courseBaseId){
     return coursePubService.previewCourser(courseBaseId);
    }
}

serviceImpl层

package com.xuecheng.content.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.basic.api.BasicClient;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.vo.CategoryVo;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.model.vo.TeachplanVo;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.domain.CourseBase;
import com.xuecheng.content.domain.CoursePub;
import com.xuecheng.content.domain.CourseTeacher;
import com.xuecheng.content.mappers.CourseBaseMapper;
import com.xuecheng.content.mappers.CoursePubMapper;
import com.xuecheng.content.mappers.CourseTeacherMapper;
import com.xuecheng.content.service.CoursePubService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.TeachplanService;
import com.xuecheng.web.exception.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author zjf
 * @since 2022-07-27
 */
@Service
public class CoursePubServiceImpl extends ServiceImpl<CoursePubMapper, CoursePub> implements CoursePubService {
    @Autowired
    private BasicClient basicClient;
    @Autowired
    private TeachplanService teachplanService;
    @Autowired
    private CourseBaseMapper courseBaseMapper;
    @Autowired
    private CourseTeacherMapper courseTeacherMapper;

    /**
     * 获取预览的课程发布数据
     *  1、课程信息
     *  2、课程老师
     *  3、课程计划信息
     * 将3部分数据,转化成页面所需要的map集合
     *  coursePub:课程发布对象数据
     *  teachplanNode:课程计划数据
     */
    @Override
    public ModelAndView previewCourser(Long courseBaseId) {

        //根据id查询课程基本信息
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseBase::getId, courseBaseId);
        CourseBase courseBase = courseBaseMapper.selectOne(wrapper);
        if (courseBase == null) {
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        CoursePub coursePub = BeanHelper.copyProperties(courseBase, CoursePub.class);
        //补全信息
        coursePub.setCreateDate(new Date());
        coursePub.setCourseId(courseBaseId);
        String mt = courseBase.getMt();
        String mtName = getMtNameOrStName(mt);
        String st = courseBase.getSt();
        String stName = getMtNameOrStName(st);

        //根据id查询教师信息
        LambdaQueryWrapper<CourseTeacher> qw = new LambdaQueryWrapper<>();
        qw.eq(CourseTeacher::getCourseId,courseBaseId);
        List<CourseTeacher> teacherList = courseTeacherMapper.selectList(qw);
        //补全信息
        coursePub.setTeachers(JSON.toJSONString(teacherList));
        coursePub.setMtName(mtName);
        coursePub.setStName(stName);
        //查询课程结构
        ResponseResult<TeachplanVo> rr = teachplanService.treeNodes(courseBaseId);
        TeachplanVo teachplanVo = rr.getData();
        coursePub.setTeachplan(JSON.toJSONString(teachplanVo));
        //使用modelAndView直接转到页面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("coursePub",coursePub);
        modelAndView.addObject("teachplanNode",teachplanVo);
        modelAndView.setViewName("learing_article");
       return modelAndView;
    }
    //根据id,调用feign接口查询分类名称
    public String getMtNameOrStName(String m){
        ResponseResult<CategoryVo> result = basicClient.findCategoryById(m);
        CategoryVo categoryVo = result.getData();
        if (categoryVo == null) {
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        String name = categoryVo.getName();
        return name;
    }
}

效果展示:

点击预览
在这里插入图片描述
在这里插入图片描述
今天的任务完成,明天做freemarker静态页面的保存

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皇家小黄

创作不易!!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值