课程预览就是把课程的相关信息进行整合,在课程预览界面进行展示,课程预览界面与课程发布的课程详情界面一致
客户可以通过课程预览页面查看信息是否存在问题
如下课程预览的数据来源
下图显示了整个课程预览的流程图
也就是说现在怎么给前端返回一个页面呢?
最最最原始的JSP可以,一些模板引擎技术也可以
前端请求内容管理服务后,后台服务系统要返回一个页面
最终要返回的页面如下图所示(预览页面,如果客户成功确认发布后,发布后的页面和预览时的页面相同)
说明如下:
1、点击课程预览,通过Nginx、后台服务网关请求内容管理服务进行课程预览。
2、内容管理服务查询课程相关信息进行整合,并通过模板引擎技术在服务端渲染生成页面,返回给浏览器。
3、通过课程预览页面点击”马上学习“打开视频播放页面。
4、视频播放页面通过Nginx请求后台服务网关,查询课程信息展示课程计划目录,请求媒资服务查询课程计划绑定的视频文件地址,在线浏览播放视频。
在这里我们用到了两个技术,一个Nginx,一个freemarker
freemarker可以在服务端生成网页然后返回给浏览器
Nginx是一个代理服务器,所有的请求都请求到Nginx上,由Nginx进行代理,然后再由Nginx发送到后台服务上
freemarker提供很多指令用于解析各种类型的数据模型
参考地址:http://freemarker.foofun.cn/ref_directives.html
什么是模板引擎?
早期采用的jsp技术就是一种模板引擎技术
1、浏览器请求web服务器
2、服务器渲染页面,渲染的过程就是向jsp页面(模板)内填充数据(模型)。
3、服务器将渲染生成的页面返回给浏览器。
所以模板引擎就是:模板+数据=输出,Jsp页面就是模板,页面中嵌入的jsp标签就是数据,两者相结合输出html网页
模板引擎:服务端生成页面的一项技术
常用的java模板引擎还有哪些?
Jsp、Freemarker、Thymeleaf 、Velocity 等。
Freemarker官方地址:http://freemarker.foofun.cn/
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。FreeMarker 是免费的, 基于Apache许可证2.0版本发布。
在content-api工程中添加如下所示的坐标
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-freemarkerartifactId>
dependency>
freemaker 相关配置信息,我们配置在了nacos的freemarker-config-dev.yaml配置文件中
spring:
freemarker:
enabled: true
cache: false #关闭模板缓存,方便测试
settings:
template_update_delay: 0
suffix: .ftl #页面模板后缀名
charset: UTF-8
template-loader-path: classpath:/templates/ #页面模板位置(默认为 classpath:/templates/)
resources:
add-mappings: false #关闭项目中的静态资源映射(static、resources文件夹下的资源)
在content-api工程的bootstrap配置文件引入freemarker-config-dev.yaml配置文件
#微服务配置
spring:
application:
name: content-api # 项目名
cloud:
nacos:
server-addr: 192.168.101.65:8848 #Nacos地址
discovery: #服务发现(服务注册)
namespace: dev #命名空间
group: xuecheng-plus-project #组别
config: # 配置中心
...............中间省略了好多配置
shared-configs: #公用配置
- data-id: freemarker-config-dev.yaml
group: xuecheng-plus-common
refresh: true
模板其实就是一个HTML页面+数据模型
${name} 就是数据模型,也就是后台的模型数据
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World!title>
head>
<body>
Hello ${name}!
body>
html>
后台准备模型数据
// 不要使用RestController,因为返回的是JSON数据,这里我们一定不要返回JSON数据
@Controller
public class FreemarkerController {
/**
*ModelAndView 模型和数据
*/
@GetMapping("/testfreemarker")
public ModelAndView test(){
ModelAndView modelAndView = new ModelAndView();
//指定模型数据
modelAndView.addObject("name","小明");
// 指定模型视图
// 返回的是哪个视图,且不用加后缀.ftl(文件名test.ftl)
// 因为我们已经在配置文件中告诉框架我们文件的后缀名称是什么了spring.freemarker.suffix=.ftl
modelAndView.setViewName("test");
return modelAndView;
}
}
测试效果
还是能展示出来的
准备Nginx和门户
在本机部署Nginx
server {
listen 80;
server_name www.51xuecheng.cn localhost;
#rewrite ^(.*) https://$server_name$1 permanent;
#charset koi8-r;
ssi on;
ssi_silent_errors on;
#access_log logs/host.access.log main;
location / {
alias D:/zhangjingqi/Note/xuecheng/Code/xc-ui-pc-static-portal/xc-ui-pc-static-portal/;
index index.html index.htm;
}
#静态资源
location /static/img/ {
alias D:/zhangjingqi/Note/xuecheng/Code/xc-ui-pc-static-portal/xc-ui-pc-static-portal/img/;
}
location /static/css/ {
alias D:/zhangjingqi/Note/xuecheng/Code/xc-ui-pc-static-portal/xc-ui-pc-static-portal/css/;
}
location /static/js/ {
alias D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal/js/;
}
location /static/plugins/ {
alias D:/zhangjingqi/Note/xuecheng/Code/xc-ui-pc-static-portal/xc-ui-pc-static-portal/plugins/;
add_header Access-Control-Allow-Origin http://ucenter.51xuecheng.cn;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET;
}
location /plugins/ {
alias D:/zhangjingqi/Note/xuecheng/Code/xc-ui-pc-static-portal/xc-ui-pc-static-portal/plugins/;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
}
修改过后将Nginx服务进行重启
刚开始的时候80端口一直被占用,从任务浏览器中根本结束不掉对应的进程
然后根据下面两篇文章解决掉了
文章1:
https://blog.csdn.net/qq_34272964/article/details/105207651
如果文章1不能解决的话看一下文章2,我是文章2解决的
https://blog.csdn.net/weixin_43833851/article/details/130188302
启动Nginx访问80端口,如果出现下图所示的界面,说明端口问题已经被解决了
假如说按照1.3.1设置了Nginx配置的话,打开网页会是如下页面
主要访问一下预览界面http://www.51xuecheng.cn/course/course_template.html
C:\Windows\System32\drivers\etc目录下有一个host文件
将下面的内容粘贴到里面即可
127.0.0.1 www.51xuecheng.cn 51xuecheng.cn ucenter.51xuecheng.cn teacher.51xuecheng.cn file.51xuecheng.cn
Centos7操作系统的hosts文件在/etc目录下
当我们输入一个域名的时候,最红需要找到这个域名对应的服务器,也就是ip地址,首先会从host文件中中找
比如我们输入 www.51xuecheng.cn域名,首先会从host文件找,然后找到了,对应的ip是127.0.0.1
假如说在host文件中没有找到域名www.51xuecheng.cn对应的ip,那就会再从dns服务器找,请求到dns服务器进行解析,在dns服务器中就记录了ip和域名的对应关系
在进行课程预览时需要展示课程的图片,在线插放课程视频,课程图片、视频这些都在MinIO文件系统存储,下边统一由Nginx代理,通过文件服务域名统一访问。如下图
我们使用的分布式文件系统MinIO来存储的文件,并且MinIO有许多的结点
我们打算前端的请求都请求到Nginx,然后由Nginx代理请求到MinIO中
比如获取一个图片,我们可以先请求到Nginx,然后再由Nginx请求到MinIO中获取图片
host文件配置如下所示信息
127.0.0.1 www.51xuecheng.cn file.51xuecheng.cn
nginx.conf中配置文件服务器的代理地址
相当于nginx.conf中再来一套配置
其实请求/video的时候就会代理到 server 192.168.101.65:9000服务器去请求资源
#文件服务
upstream fileserver{
server 192.168.101.65:9000 weight=10;
}
server {
listen 80;
server_name file.51xuecheng.cn;
#charset koi8-r;
ssi on;
ssi_silent_errors on;
#access_log logs/host.access.log main;
location /video {
proxy_pass http://fileserver;
}
location /mediafiles {
proxy_pass http://fileserver;
}
}
配置完毕,重新加载nginx配置文件
通过cmd进入nginx.exe所在目录,运行如下命令
nginx.exe -s reload
访问:http://file.51xuecheng.cn/mediafiles/2022/09/13/a16da7a132559daf9e1193166b3e7f52.jpg
如下所示效果
首先在nginx.conf中配置视频播放页面的地址
location /course/preview/learning.html {
alias D:/zhangjingqi/Note/xuecheng/Code/xc-ui-pc-static-portal/xc-ui-pc-static-portal/course/learning.html;
}
location /course/search.html {
root D:/zhangjingqi/Note/xuecheng/Code/xc-ui-pc-static-portal/xc-ui-pc-static-portal;
}
location /course/learning.html {
root D:/zhangjingqi/Note/xuecheng/Code/xc-ui-pc-static-portal/xc-ui-pc-static-portal;
}
重新加载配置文件
之后
下边需要配置learning.html页面的视频播放路径来测试视频播放页面,找到learning.html页面中videoObject对象的定义处,配置视频的播放地址
换成minio系统中一个可以播放的地址
课程预览接口要将课程信息进行整合,在服务端渲染页面后返回浏览器。
下边对课程预览接口进行分析:
1、请求参数
传入课程id,表示要预览哪一门课程。
2、响应结果
输出课程详情页面到浏览器
响应页面到浏览器使用freemarker模板引擎技术实现,首先从课程资料目录下获取课程预览页面course_template.html,拷贝至内容管理的接口工程的resources/templates下,并将其在本目录复制一份命名为course_template.ftl
也就是说下图中的整个页面都是模板内容
其实就是下图所示的四部分信息
@Controller
public class CoursePublishController {
@Autowired
CoursePublishServiceImpl coursePublishService;
@GetMapping("/coursepreview/{courseId}")
public ModelAndView preview(@PathVariable("courseId") Long courseId) {
ModelAndView modelAndView = new ModelAndView();
// 从数据库查询模型的数据(课程营销信息表、课程师资表、课程基本信息表、课程计划)
CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId);
// 指定模型数据
modelAndView.addObject("model", coursePreviewInfo);
// 指定模板
modelAndView.setViewName("course_template");
return modelAndView;
}
}
其中需要的课程预览模型类
/**
* @description 课程预览数据模型
*/
@Data
@ToString
public class CoursePreviewDto {
//课程基本信息,课程营销信息
CourseBaseInfoDto courseBase;
//课程计划信息
List<TeachplanDto> teachplans;
//师资信息暂时不加...
}
课程预览接口虽然可以正常访问,但是页面没有样式,查看浏览器请求记录,发现图片、样式无法正常访问
这些静态资源全在门户下,我们需要由Nginx反向代理访问课程预览接口,通过门户的URL去访问课程预览
Nginx中如下所示配置
upstream gatewayserver{
server 127.0.0.1:63010 weight=10;
}
server {
listen 80;
server_name www.51xuecheng.cn localhost;
....
#api
location /api/ {
proxy_pass http://gatewayserver/;
}
之后重新启动Nginx
访问地址: http://www.51xuecheng.cn/api/content/coursepreview/74
出现的场景如下图所示
现在的请求其实是下面所示的流程:
/**
* 课程发布相关业务
*/
@Service
public class CoursePublishServiceImpl implements CoursePublishService {
//课程基础信息(课程营销信息表/课程基本信息表)
@Autowired
CourseBaseInfoService courseBaseInfoService;
//课程计划
@Autowired
TeachplanService teachplanService;
/**
* @param courseId 课程id
* @description 获取课程预览信息
*/
@Override
public CoursePreviewDto getCoursePreviewInfo(Long courseId) {
// 从数据库查询模型的数据(课程营销信息表、课程师资表、课程基本信息表、课程计划)
// 课程基本信息,营销信息
CourseBaseInfoDto courseBaseInfoDto = courseBaseInfoService.getCourseBaseInfo(courseId);
//课程计划信息
List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId);
// 组装返回信息
CoursePreviewDto coursePreviewDto = new CoursePreviewDto();
coursePreviewDto.setCourseBase(courseBaseInfoDto);
coursePreviewDto.setTeachplans(teachplanTree);
return coursePreviewDto;
}
}
模型数据准备好后下一步将模型数据填充到course_template.ftl上,填充时注意不要一次填充太多,一边填充一边刷新调试。
freemarker提供很多指令用于解析各种类型的数据模型
参考地址:http://freemarker.foofun.cn/ref_directives.html
DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/static/img/asset-favicon.ico">
<title>学成在线-${model.courseBase.name}title>
<link rel="stylesheet" href="/static/plugins/normalize-css/normalize.css"/>
<link rel="stylesheet" href="/static/plugins/bootstrap/dist/css/bootstrap.css"/>
<link rel="stylesheet" href="/static/css/page-learing-article.css"/>
head>
<body data-spy="scroll" data-target="#articleNavbar" data-offset="150">
<div id="learningArea">
<div class="article-banner">
<div class="banner-bg">div>
<div class="banner-info">
<div class="banner-left">
<p>${model.courseBase.mtName!''}<span>\ ${model.courseBase.stName!''}span>p>
<p class="tit">${model.courseBase.name}p>
<p class="pic">
<#if model.courseBase.charge=='201000'>
<span class="new-pic">免费span>
<#else>
<span class="new-pic">特惠价格¥${model.courseBase.price!''}span>
<span class="old-pic">原价¥${model.courseBase.originalPrice!''}span>
#if>
p>
<p class="info">
<a href="#" @click.prevent="startLearning()">马上学习a>
<span><em>难度等级em>
<#if model.courseBase.grade=='204001'>
初级
<#elseif model.courseBase.grade=='204002'>
中级
<#elseif model.courseBase.grade=='204003'>
高级
#if>
span>
<span><em>课程时长em>2小时27分span>
<span><em>评分em>4.7分span>
<span><em>授课模式em>
<#if model.courseBase.teachmode=='200002'>
录播
<#elseif model.courseBase.teachmode=='200003'>
直播
#if>
span>
p>
div>
<div class="banner-rit">
<p>
<a href="http://www.51xuecheng.cn/course/preview/learning.html?id=${model.courseBase.id}"
target="_blank">
<#if model.courseBase.pic??>
<img src="http://file.51xuecheng.cn${model.courseBase.pic}" alt="" width="270" height="156">
<#else>
<img src="/static/img/widget-video.png" alt="" width="270" height="156">
#if>
a>
p>
<p class="vid-act"><span> <i class="i-heart">i>收藏 23 span> <span>分享 <i class="i-weixin">i><i
class="i-qq">i>span>p>
div>
div>
div>
<div class="article-cont">
<div class="tit-list">
<a href="javascript:;" id="articleClass" class="active">课程介绍a>
<a href="javascript:;" id="articleItem">目录a>
<a href="javascript:;" id="artcleAsk">问答a>
<a href="javascript:;" id="artcleNot">笔记a>
<a href="javascript:;" id="artcleCod">评价a>
div>
<div class="article-box">
<div class="articleClass" style="display: block">
<div class="article-cont">
<div class="article-left-box">
<div class="content">
<div class="content-com suit">
<div class="title"><span>适用人群span>div>
<div class="cont cktop">
<div>
<p>${model.courseBase.users!""}p>
div>
div>
div>
<div class="content-com course">
<div class="title"><span>课程制作span>div>
<div class="cont">
<div class="img-box"><img src="/static/img/widget-myImg.jpg" alt="">div>
<div class="info-box">
<p class="name">教学方:<em>XX老师em>p>
<p class="info">
JavaEE开发与教学多年,精通JavaEE技术体系,对流行框架JQuery、DWR、Struts1/2,Hibernate,Spring,MyBatis、JBPM、Lucene等有深入研究。授课逻辑严谨,条理清晰,注重学生独立解决问题的能力。p>
div>
div>
div>
<div class="content-com about">
<div class="title"><span>课程介绍span>div>
<div class="cont cktop">
<div>
<p>${model.courseBase.description!""}p>
div>
div>
div>
<div class="content-com prob">
<div class="title"><span>常见问题span>div>
<div class="cont">
<ul>
<li class="item"><span class="on-off"><i class="i-chevron-bot">i> 我什么时候能够访问课程视频与作业?span>
<div class="drop-down">
<p>
课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。p>
div>
li>
<li class="item"><span class="on-off"><i class="i-chevron-bot">i> 如何需要额外的时间来完成课程会怎么样?span>
<div class="drop-down">
<p>
课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。p>
div>
li>
<li class="item"><span class="on-off"><i class="i-chevron-bot">i> 我支付次课程之后会得到什么?span>
<div class="drop-down">
<p>
课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。p>
div>
li>
<li class="item"><span class="on-off"><i class="i-chevron-bot">i> 退款条例是如何规定的?span>
<div class="drop-down">
<p>
课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。p>
div>
li>
<li class="item"><span class="on-off"><i class="i-chevron-bot">i> 有助学金?span>
<div class="drop-down">
<p>
课程安排灵活,课程费用支付提供180天全程准入和资格证书。自定进度课程建议的最后期限,但你不会受到惩罚错过期限,只要你赚你的证书在180天内。以会话为基础的课程可能要求你在截止日期前保持正轨,但如果你落后了,你可以切换到以后的会议,你完成的任何工作将与你转移。p>
div>
li>
ul>
div>
div>
div>
div>
div>
div>
<div class="articleItem" style="display: none">
<div class="article-cont-catalog">
<div class="article-left-box">
<div class="content">
<#list model.teachplans as firstNode>
<div class="item">
<div class="title act"><i class="i-chevron-top">i>${firstNode.pname}<span
class="time">x小时span>div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<#list firstNode.teachPlanTreeNodes as secondNode>
<li>
<a href="http://www.51xuecheng.cn/course/preview/learning.html?id=${model.courseBase.id}&chapter=${secondNode.teachplanMedia.teachplanId!''}"
target="_blank">${secondNode.pname}a>li>
#list>
ul>
div>
div>
#list>
<#-- class="item">
<div class="title act"><i class="i-chevron-top">i>第一阶段 HTTP协议基础详解<span class="time">8小时span>div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”span>li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”span>li>
<li>1.3 视频:软件安装介绍 <span>86’42”span>li>
<li>1.4 阅读:Emacs安装 <span>59’00”span>li>
<li>1.5 作业1:Emacs安装 <span>93’29”span>li>
<li>阶段测试li>
ul>
div>
div>-->
div>
div>
div>
div>
<#--<div class="articleItem" style="display: none">
<div class="article-cont-catalog">
<div class="article-left-box">
<div class="content">
<div class="item">
<div class="title act"><i class="i-chevron-top">i>第一阶段 HTTP协议基础详解<span class="time">8小时span>div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。div>
<div class="drop-down" style="height: 260px;">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”span>li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”span>li>
<li>1.3 视频:软件安装介绍 <span>86’42”span>li>
<li>1.4 阅读:Emacs安装 <span>59’00”span>li>
<li>1.5 作业1:Emacs安装 <span>93’29”span>li>
<li>阶段测试li>
ul>
div>
div>
<div class="item">
<div class="title"><i class="i-chevron-bot">i>第二阶段 HTTP协议基础详解<span class="time">8小时span>div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”span>li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”span>li>
<li>1.3 视频:软件安装介绍 <span>86’42”span>li>
<li>1.4 阅读:Emacs安装 <span>59’00”span>li>
<li>1.5 作业1:Emacs安装 <span>93’29”span>li>
<li>阶段测试li>
ul>
div>
div>
<div class="item">
<div class="title"><i class="i-chevron-bot">i>第三阶段 HTTP协议基础详解<span class="time">3小时span>div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”span>li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”span>li>
<li>1.3 视频:软件安装介绍 <span>86’42”span>li>
<li>1.4 阅读:Emacs安装 <span>59’00”span>li>
<li>1.5 作业1:Emacs安装 <span>93’29”span>li>
<li>阶段测试li>
ul>
div>
div>
<div class="item">
<div class="title"><i class="i-chevron-bot">i>第四阶段 HTTP协议基础详解<span class="time">3小时span>div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”span>li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”span>li>
<li>1.3 视频:软件安装介绍 <span>86’42”span>li>
<li>1.4 阅读:Emacs安装 <span>59’00”span>li>
<li>1.5 作业1:Emacs安装 <span>93’29”span>li>
<li>阶段测试li>
ul>
div>
div>
<div class="item">
<div class="title"><i class="i-chevron-bot">i>第五阶段 HTTP协议基础详解<span class="time">3小时span>div>
<div class="about">使用Java消息中间件处理异步消息成为了分布式系统中的必修课,通过本门课程可以深入浅出的学习如何在Java中使用消息中间件并且一步一步打造更优雅的最佳实践方案。div>
<div class="drop-down">
<ul class="list-box">
<li class="active">1.1 阅读:分级政策细节 <span>97’33”span>li>
<li>1.2 视频:为什么分为 A 部分、B 部分、C 部分 <span>66’15”span>li>
<li>1.3 视频:软件安装介绍 <span>86’42”span>li>
<li>1.4 阅读:Emacs安装 <span>59’00”span>li>
<li>1.5 作业1:Emacs安装 <span>93’29”span>li>
<li>阶段测试li>
ul>
div>
div>
<div class="item">
<a href="#" class="overwrite">毕业考核a>
div>
div>
div>
<div class="artcleAsk" style="display: none">
<div class="article-cont-ask">
<div class="article-left-box">
<div class="content">
<div class="content-title">
<p><a class="all">全部a><a>精选a><a>我的a>p>
<p>
<a class="all">全部a><span><a>1.1a><a>1.2a><a>1.3a><a>1.4a><a>1.5a>span><a
href="$" class="more">更多 <i class="i-chevron-bot">i>a>p>
div>
<div class="item">
<div class="item-left">
<p><img src="/static/img/widget-myImg.jpg" width="60px" alt="">p>