1.课程管理页面美化
demo-course.jpg
复制search.html中的部分代码
course.vue
看效果
测试一下新增修改删除效果
1.课程管理页面美化2
scoped:style下的样式只应用于当前组件,防止互相污染
1.课程管理与大章管理互相跳转
完成功能:在课程列表中增加“大章”按钮,点击会跳转到大章页面,并且筛选出当前课程下所有的大章。大章页面增加显示课程名称,并有可以返回课程管理页面
local-storage.js
sessionStorage是会话缓存,浏览器窗口关闭,缓存就没了。localStorage是本地缓存,浏览器关闭后,下次再打开还能读到
session-storage.js
setItem自带的必须要求是string
localStorage和sessionStorage只能操作字符串,但是我们经常要放对象数据,所以封装一下
index.html
course.vue
组件(页面)间传输数据可以用h5原生的localStorage,sessionStorage;也可以用js全局变量;也可以用vuex stofe,但是后两者在页面刷新时会丢失数据,所以推荐使用h5原生的。
测试一下,点击大章,会跳转到大章页面
chapter.vue
null.name会报错,{}.name不会报错
简单的跳转可以用router-link(类似a标签),如果是有其它的操作,可以写个click方法。比如前面完成的,从课程跳到大章,需要先缓存课程信息,所以写click方法。
继续更改大章页面
1.大章管理保存和查询功能关联courseId
chapter.vue
ChapterPageDto.java
经验分享:service层到查询条件写得松一点,灵活一点。service 层可能被多个controller 调用,也可能被其它service 调用,每个调用的查询条件可能不一样。
ChapterService.java
controller 需要严格一点,根据前端的业务,校验参数
ChapterController.java
测试(我是后面重启了一下,又更新出来的)
1.大章管理与小节管理互相跳转
2.小节管理保存和查询功能关联courseId,chapterId
chapter.vue
section.vue
SectionPageDto.java
SectionController.java
?service 同样写的灵活一些,查询条件根据参数是否为空来判断
SectionService.java
criteria 类似于写where 条件
测试
1.保存节时,更新课程总时长
2.增加自定义mapper
时长不应该是手输的,后续在介绍视频文件上传时,会介绍到怎么自动获取视频时长
自定义的mapper和自动生成的mapper分开存放
MyCourseMapper.xml
MyCourseMapper.java
代码规范小提示:SectionService 不要直接调用course 的mapper,而是调用平级的CourseService.
CourseService.java
SectionService.java
保存小节时,不管是新增还是修改,都更新课程总时长
application.properties
1.增加事务配置
一次操作会更新或修改多张表,一般为了保证数据一致,需要增加事务处理。
TransactionManagementConfig.java
SectionService.java?
SectionController.java?
数据保存进数据库了,说明事务没有回滚,事务不起作用。
自定义异常一般可以选择继承RuntimeException??
同一个类的内部方法互相调用,methodA调用methodB,methodB事务不起作用。Spring的事务处理是利用AOP生成动态代理类,内部方法调用时不经过代理类,所以事务不生效。
把代码调整好,然后进行提交
1.增加时长格式化filter formatSecond
?filter.js
?course.vue
section.vue
1.分类表设计和基本代码生成
all.sql
generatorConfig.xml
然后生成持久层mybatis-generator、ServerGenerator、VueGenerator
admin.vue
router.js
? service.ftl
要执行生成器,不能有编译报错
再次运行
1.分类列表查询与显示,左右两个表格
做成左右两个表格,左边是一级分类,右边是二级分类。点击一级分类时,显示对应的二级分类
分类总数不多,不需要分页,一次查询全部数据,由前端来处理显示
CategoryService.java
CategoryController.java
?vue.ftl
category.vue
list->all,并且没有参数
?点击一行的任何位置,显示二级分类
问题1:点击刷新时,level1数据出现重复。
问题2:level2的刷新不需要了。
问题3:从页面上看不出来当前显示的二级分类是属于哪个一级分类
动态class:使用v-bind:class=json表达式,key就是样式,value是boolean,为true时,表示key的样式生效。可以和原生的class 并存
1.两级分类的新增修改删除
category.vue
CategoryService.java
问题:新增、编辑、删除二级分类时,没有马上刷新出来,会用到另外一个小知识点,待会介绍。
1.对当前一级分类中选中的表格触发一次点击事件,以刷新二级分类
处理:对一级或二级分类的增删改查,都会调用all()刷新数据,所以all()的后面触发一次表格行点击事件。
category.vue
小技巧:当界面又用了vue,又用了jquery(特别是第三方插件),当觉得代码没问题,但是效果又没出来时,可以加个小延时看看。
1.集成树型展示插件zTree
zTree是jquery插件,用于展示树型结构数据。分类数据有两层结构,可用树形结构展示。
Home [zTree -- jQuery tree plug-ins.]
功能设计:新增课程的时候,同时选择这门课程属于哪些分类,并且一门课程可以属于多个分类在。
将下载解压后的文件夹整个拷贝进项目,放在下面路径上course>admin>public>zTree_v3,重命名
没用的注释代码就大胆删除,保持代码干净,以后如果要用,可以通过git提交记录再找回来。
1.zTree 数据改为分类所有记录
course.vue
分类表相关字段:id,parent,name
category.vue中列表查询方法all()复制到course.vue,进行修改
course.vue
方法名和注释同样重要,要容易理解。all(),容易被误解为是查找所有的课程,所以改名allCategory()
pId 是zTree 默认的父ID名称,而分类表是用parent,需要配置转换
1.保存课程时,同时保存课程分类
2.增加课程分类关联表,一门课程可以属于多个分类
all.sql
generatorConfig.xml
再执行ServerGenerator
course.vue
我们只需要保存分类的ID,所以数据传输可以选择id数组,也可以选择category数组。
CourseDto.java
属性名和前端传递的参数名一致,这样spring会自动映射参数
CourseCategoryService.java
也可以通过自定义mapper写动态sql,将list传入mybatis,批量插入一批数据,只要一条insert语句。项目开发需要在开发效率和运行效率间找平衡。
?问题:保存课程时,调用saveBatch,那么课程新增的时候,会批量插入数据,课程更新的时候,会再次批量插入数据,每次调用保存都会批量插入数据。
CourseService.java
1.编辑课程时,加载课程分类树,并设置勾选
CourseService.java
CourseCategoryService.java
外层save 增加了事务,saveBatch 按理可以不加事务。但是由于本身也是多个sql操作,且以后可能被多个地方调用,为了防止外层save 忘记加事务,所以在saveBatch加事务,以防万一。
CourseController.java
course.vue
1.课程内容表设计与基本代码生成
all.sql
课程表和课程内容表是1:1关系,两张表都用同样的id字段。
课程详情一般会有文字,图片,视频等,虽然不会把整张图片或整个视频放到数据库,但是存的信息还是很多,所以用大字段。
mediumtext比text类型长度更长。
分表分为:垂直(纵向)分表;水平(横向)分表。
垂直分表的场景:1.大字段;2.经常更新的字段
generatorConfig.xml
执行ServerGenerator
CourseContentService.java
删除掉CourseContentController.java和CourseContentService.java
因为之后我们会统一在CourseController.java中写,所以不需要单独每一个都写controller,另一个同样
1.完成课程内容管理功能
Summernote - Super Simple WYSIWYG editor
富文本编辑器,一个很重要的特征:所见即所得。
CourseService.java
正常的思路,先去select,看看有没有数据,再判断是insert还是update,这样会执行两个sql。其实可以直接更新,没有更新到再插入,只有第一次会更新不到,执行两个sql,后面都只需要一个sql
CourseController.java
index.html
course.vue
课程内容,只有读和写,没有列表查询,也没有删除
1.利用setInterval完成自动保存功能
2.增加js日期格式化方法
course.vue
tool.js
1.课程管理增加自定义排序
course.vue
这里也可以初始化更多的字段,比如三个枚举字段,初始数据,收费、初稿、草稿
SortDto.java?
统一日志AOP打印的日志比较泛,可以在 controller中打印更详细的日志
CourseController.java
CourseService.java
MyCourseMapper.java
MyCourseMapper.xml
1.菜单隐藏掉大章和小节
修改1:菜单栏不出现大章管理和小章管理(我之前忘加大章管理了,抱歉)
修改2:页面进到大章管理和小节管理时,侧边栏的课程管理应该显示激活样式
admin.vue
chapter.vue
section.vue
1.sessionStorage的key改为常量
key值不要直接写字符串,后面缓存用得越来越多,key名有可能冲突,这时要改key名的话,所有set和get都要改。且不要用单一的单词,最好加一些前后缀。
session- storage.js
course.vue
chapter.vue
section.vue
1.增加全局自定义样式style.css,表格内文字上下居中
index.html
style.css
1.增加讲师管理功能
all.sql
generatorConfig.xml
再执行ServerGenerator、VueGenerator
admin.vue
router.js
1.讲师管理页面布局优化
teacher.vue
鼠标放在图像上时,会出现介绍
1.课程与讲师关联
一个分类可以有多门课程,一门课程也可以属于多个分类,所以他们是多对多的关系。多对多的关系,一般会设计个中间表来维护关系。
一个讲师可以讲多门课程,一门课程只能有一个讲师,所以他们是一对多的关系。一对多的关系,可以把关系维护在“一”那张表中。
旧表加字段,使用单独的sql:alter table,这样,上生产的时候也是执行这个sql。
all.sql
generatorConfig.xml
CourseDto.java
course.vue
页面打开始,加载所有的讲师
在后端增加all方法,加载所有的讲师信息。
TeacherController.java
TeacherService.java
表单里要增加讲师选择框
course.vue
1.课程列表中显示讲师信息
2.课程名称字体自适应
v-for中,对循环的数组,可通过filter进行数据过滤
字体大小自适应,根据屏幕的分辨率显示不同大小的字体