Day07(07.06)
添加课程分类前端实现
添加课程分类路由
创建课程分类页面,修改路由对应的页面路径
实现添加课程分类页面
- 添加上传组件
2.
课程分类列表显示
用树形结构显示
后端代码
-
创建接口,按照格式返回数据
两个实体类,一级分类和二级分类
-
在两个实体类之间表示关系
一个一级分类有多个二级分类
@Data //一级分类 public class OneSubject { private String id; private String title; //一个一级分类有多个二级分类 private List<TwoSubject> children=new ArrayList<>(); }
-
封装代码
-
/课程分类列表(树形) @Override public List<OneSubject> getAllOneTwoSubject() { //1 查询所有一级分类 QueryWrapper<EduSubject> wrapperOne=new QueryWrapper<>(); wrapperOne.eq("parent_id","0"); List<EduSubject> oneSubjectList = baseMapper.selectList(wrapperOne); //2 查询所有二级分类,parent_id!=0 QueryWrapper<EduSubject> wrapperTwo=new QueryWrapper<>(); wrapperTwo.ne("parent_id","0"); List<EduSubject> twoSubjectList = baseMapper.selectList(wrapperTwo); //创建list集合,用于存储最终封装数据 List<OneSubject> finalSubjectList=new ArrayList<>(); //3 封装一级分类 //查询出的所有的一级分类list集合,得到每一个一级分类对象,获取每个一级分类对象值,封装到要求的list集合里面List<OneSubject> finalSubjectList for (int i = 0; i < oneSubjectList.size(); i++) { //得到oneSubject每个eduSubject对象 EduSubject eduSubject=oneSubjectList.get(i); //把eduSubject的值放到OneSubject对象里面 //多个OneSubject放到finalSubjectList里面 OneSubject oneSubject=new OneSubject(); //eduSubject值复制到对应OneSubject对象里面 BeanUtils.copyProperties(eduSubject,oneSubject); finalSubjectList.add(oneSubject); //在一级分类循环遍历查询所有的二级分类 //创建list集合,封装每个一级分类的二级分离 List<TwoSubject> twoFinalSubjectList=new ArrayList<>(); //遍历二级分类list集合 for (int m = 0; m < twoSubjectList.size(); m++) { EduSubject tSubject=twoSubjectList.get(m); //判断二级分类parent_id和一级分类id是否一样 if (tSubject.getParentId().equals(eduSubject.getId())){ //把TSubject值复制到TwoSubject里面,放到twoFinalSubjectList里面 TwoSubject twoSubject=new TwoSubject(); BeanUtils.copyProperties(tSubject,twoSubject); twoFinalSubjectList.add(twoSubject); } } //把一级下面所有二级分类放到一级分类里面 oneSubject.setChildren(twoFinalSubjectList); } return finalSubjectList; }
-
前端结果显示
课程管理模块
课程表关系
表
edu_course:课程表,存储课程基本信息
edu_course_description:课程简介表,存储课程简介信息
edu_chapter:课程章节表,存储课程章节信息
edu_video:课程小结表,存储章节里面小结信息
edu_teacher:讲师表
edu_subject:课程分类表
关系
添加课程基本信息
-
使用代码生成器生成课程相关代码
-
创建vo 实体类用于表单数据封装
@Data public class CourseInfoVo { @ApiModelProperty(value = "课程ID") private String id; @ApiModelProperty(value = "课程讲师ID") private String teacherId; @ApiModelProperty(value = "课程专业ID") private String subjectId; @ApiModelProperty(value = "课程标题") private String title; @ApiModelProperty(value = "课程销售价格,设置为0则可免费观看") //价格0.01的情况,元角分 private BigDecimal price; @ApiModelProperty(value = "总课时") private Integer lessonNum; @ApiModelProperty(value = "课程封面图片路径") private String cover; @ApiModelProperty(value = "课程简介") private String description; }
-
编写 controller和service
-
controller
@RestController @RequestMapping("/eduservice/course") @CrossOrigin public class EduCourseController { @Autowired private EduCourseService courseService; //添加课程基本信息方法 @PostMapping("addCourseInfo") public R addCourseInfo(@RequestBody CourseInfoVo courseInfoVo){ courseService.saveCourseInfo(courseInfoVo); return R.ok(); } }
-
service
@Service public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService { @Autowired private EduCourseDescriptionService courseDescriptionService; //添加课程基本信息方法 @Override public void saveCourseInfo(CourseInfoVo courseInfoVo) { //1 向课程表添加课程基本信息 //CourseInfoVo对象转换eduCourse对象 EduCourse eduCourse=new EduCourse(); BeanUtils.copyProperties(courseInfoVo,eduCourse); int insert = baseMapper.insert(eduCourse); if (insert<=0){ //添加失败 throw new GuliException(20001,"添加课程信息失败"); } //获取添加成功的课程id String cid=eduCourse.getId(); //2 向课程简介表添加课程简介 //edu_course_description EduCourseDescription courseDescription=new EduCourseDescription(); courseDescription.setDescription(courseInfoVo.getDescription()); //设置描述id就是课程id courseDescription.setId(cid); courseDescriptionService.save(courseDescription); } }
-
swagger测试结果
-
添加课程基本信息前端
-
添加路由
-
添加 vue 组件
-
课程信息页面 info.vue
<template> <div class="app-container"> <h2 style="text-align: center;">发布新课程</h2> <el-steps :active="1" process-status="wait" align-center style="margin-bottom: 40px;"> <el-step title="填写课程基本信息"/> <el-step title="创建课程大纲"/> <el-step title="最终发布"/> </el-steps> <el-form label-width="120px"> <el-form-item label="课程标题"> <el-input v-model="courseInfo.title" placeholder=" 示例:机器学习项目课:从基础到搭建项目视频课程。专业名称注意大小写"/> </el-form-item> <!-- 所属分类 TODO --> <!-- 课程讲师 TODO --> <el-form-item label="总课时"> <el-input-number :min="0" v-model="courseInfo.lessonNum" controls-position="right" placeholder="请填写课程的总课时数"/> </el-form-item> <!-- 课程简介 TODO --> <el-form-item label="课程简介"> <el-input v-model="courseInfo.description" placeholder=" "/> </el-form-item> <!-- 课程封面 TODO --> <el-form-item label="课程价格"> <el-input-number :min="0" v-model="courseInfo.price" controls-position="right" placeholder="免费课程请设置为0元"/> 元 </el-form-item> <el-form-item> <el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存并下一步</el-button> </el-form-item> </el-form> </div> </template> <script> import course from '@/api/edu/course' export default { data() { return{ saveBtnDisabled:false, courseInfo:{ title: '', subjectId: '', teacherId: '', lessonNum: 0, description: '', cover: '', price: 0 } } }, created(){ }, methods:{ saveOrUpdate(){ course.addCourseInfo(this.courseInfo) .then(response =>{ //提示 this.$message({ type: 'success', message: '添加课程信息成功!' }); //进度条跳转到第二步 this.$router.push({path:'/course/chapter/'+response.data.courseId}) }) } } } </script><template> <div class="app-container"> <h2 style="text-align: center;">发布新课程</h2> <el-steps :active="1" process-status="wait" align-center style="margin-bottom: 40px;"> <el-step title="填写课程基本信息"/> <el-step title="创建课程大纲"/> <el-step title="最终发布"/> </el-steps> <el-form label-width="120px"> <el-form-item> <el-button :disabled="saveBtnDisabled" type="primary" @click="next">保存并下一步</el-button> </el-form-item> </el-form> </div> </template> <script> export default { data() { return{ saveBtnDisabled:false } }, created(){ }, methods:{ next(){ //进度条跳转到第二步 this.$router.push({path:'/course/chapter/1'}) } } } </script>
-
课程大纲页面 chapter.vue
<template> <div class="app-container"> <h2 style="text-align: center;">发布新课程</h2> <el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;"> <el-step title="填写课程基本信息"/> <el-step title="创建课程大纲"/> <el-step title="最终发布"/> </el-steps> <el-form label-width="120px"> <el-form-item> <el-button @click="previous">上一步</el-button> <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button> </el-form-item> </el-form> </div> </template> <script> export default { data() { return{ saveBtnDisabled:false } }, created(){ }, methods:{ //上一步方法,跳转到第一步 previous(){ this.$router.push({path:'/course/info/1'}) }, next(){ //进度条跳转到第三步 this.$router.push({path:'/course/publish/1'}) } } } </script>
-
课程发布页面 publish.vue
<template> <div class="app-container"> <h2 style="text-align: center;">发布新课程</h2> <el-steps :active="3" process-status="wait" align-center style="margin-bottom: 40px;"> <el-step title="填写课程基本信息"/> <el-step title="创建课程大纲"/> <el-step title="最终发布"/> </el-steps> <el-form label-width="120px"> <el-form-item> <el-button @click="previous">返回修改</el-button> <el-button :disabled="saveBtnDisabled" type="primary" @click="publish">发布课程</el-button> </el-form-item> </el-form> </div> </template> <script> export default { data() { return{ saveBtnDisabled:false } }, created(){ }, methods:{ //上一步方法,跳转到第二步 previous(){ this.$router.push({path:'/course/chapter/1'}) }, publish(){ this.$router.push({path:'/course/list'}) } } } </script>
-
效果
下拉列表显示所有讲师
<!-- 课程讲师 -->
<el-form-item label="课程讲师">
<el-select
v-model="courseInfo.teacherId"
placeholder="请选择">
<el-option
v-for="teacher in teacherList"
:key="teacher.id"
:label="teacher.name"
:value="teacher.id"/>
</el-select>
</el-form-item>
存在问题
- 在添加课程基本信息时报错
原因:数据库中该字段是非空的,需要将其设置为可以为空。
ALTER TABLE edu_course MODIFY subject_parent_id CHAR(19) NULL
结果: edu_course_description表
edu_course表
Day08(07.06)
添加课程基本信息完善
整合文本编辑器
- 富文本编辑器组件
课程大纲管理
课程大纲列表显示
后端
-
创建两个实体类 章节和小节,章节使用list集合表示小节
-
controller
@RestController @RequestMapping("/eduservice/edu-chapter") @CrossOrigin public class EduChapterController { @Autowired private EduChapterService chapterService; //课程大纲列表,根据课程id查询 @GetMapping("getChapterVideo/{courseId}") public R getChapterVideo(@PathVariable String courseId){ List<ChapterVo> list=chapterService.getChapterVideoByCourseId(courseId); return R.ok().data("allChapterVideo",list); } }
-
service
@Service public class EduChapterServiceImpl extends ServiceImpl<EduChapterMapper, EduChapter> implements EduChapterService { @Autowired private EduVideoService videoService;//注入小节service用于查询 //课程大纲列表,根据课程id查询 @Override public List<ChapterVo> getChapterVideoByCourseId(String courseId) { //1 根据课程id查询课程里所有的章节 QueryWrapper<EduChapter> wrapperChapter=new QueryWrapper<>(); wrapperChapter.eq("course_id",courseId); List<EduChapter> eduChapterList=baseMapper.selectList(wrapperChapter); //2 查询小节 QueryWrapper<EduVideo> wrapperVideo=new QueryWrapper<>(); wrapperVideo.eq("course_id",courseId); List<EduVideo> eduVideoList=videoService.list(wrapperVideo); //创建list集合,用于封装最终数据 List<ChapterVo> finalList=new ArrayList<>(); //3 遍历查询章节list集合进行封装 //遍历查询章节list集合 for (int i = 0; i < eduChapterList.size(); i++) { EduChapter eduChapter=eduChapterList.get(i); //eduChapter对象复制到ChapterVo中 ChapterVo chapterVo=new ChapterVo(); BeanUtils.copyProperties(eduChapter,chapterVo); //把chapterVo放到最终list集合 finalList.add(chapterVo); //创建集合,用于封装章节的小节 List<VideoVo> videoList=new ArrayList<>(); //4 遍历查询小节list集合进行封装 for (int m = 0; m < eduVideoList.size(); m++) { //得到每个小节 EduVideo eduVideo=eduVideoList.get(m); //判断:小节的chapterID是否等于章节的id if (eduVideo.getChapterId().equals(eduChapter.getId())){ //进行封装 VideoVo videoVo=new VideoVo(); BeanUtils.copyProperties(eduVideo,videoVo); //放到小节封装集合 videoList.add(videoVo); } } //把封装之后小节list集合,放到章节对象里 chapterVo.setChildren(videoList); } return finalList; } }
-
swagger测试
前端
- 获取路由id,将章节和小节取到
-
遍历得到结果
-
效果
-
优化后的页面
章节添加 修改 删除
- 添加按钮
-
开发接口
-
controller
//添加章节 @PostMapping("addChapter") public R addChapter(@RequestBody EduChapter eduChapter){ chapterService.save(eduChapter); return R.ok(); } //根据id查询章节 @GetMapping("getChapterInfo/{chapterId}") public R getChapterInfo(@PathVariable String chapterId){ EduChapter eduChapter = chapterService.getById(chapterId); return R.ok().data("chapter",eduChapter); } //修改章节 @PostMapping("updateChapter") public R updateChapter(@RequestBody EduChapter eduChapter){ chapterService.updateById(eduChapter); return R.ok(); } //删除章节 @DeleteMapping("{chapterId}") public R deleteChapter(@PathVariable String chapterId){ boolean flag=chapterService.deleteChapter(chapterId); if (flag){ return R.ok(); }else { return R.error(); } }
-
删除
若章节中有小节如何删除?
1.删除章节时,把章节里所有小节都删除
2.若章节下面有小节,不让进行删除操作,只有没有小节的章节可以删除
//删除章节的方法
@Override
public boolean deleteChapter(String chapterId) {
//根据chapterId章节id查询小节video表,若查询的到数据,不删除
QueryWrapper<EduVideo> wrapper=new QueryWrapper<>();
wrapper.eq("chapter_id",chapterId);
int count = videoService.count(wrapper);
//判断
if (count>0){//查询出小节,不进行删除
throw new GuliException(20001,"不能删除");
}else {//删除
int result = baseMapper.deleteById(chapterId);
return result>0;
}
}
效果
小节添加 修改 删除
修改课程基本信息
后端
-
根据课程id查询课程基本信息接口
@Override public CourseInfoVo getCourseInfo(String courseId) { //1 查询课程表 EduCourse eduCourse = baseMapper.selectById(courseId); CourseInfoVo courseInfoVo=new CourseInfoVo(); BeanUtils.copyProperties(eduCourse,courseInfoVo); //2 查询描述表 EduCourseDescription courseDescription = courseDescriptionService.getById(courseId); courseInfoVo.setDescription(courseDescription.getDescription()); return courseInfoVo; }
-
修改课程信息
//修改课程信息 @Override public void updateCourseInfo(CourseInfoVo courseInfoVo) { //1 修改课程表 EduCourse eduCourse=new EduCourse(); BeanUtils.copyProperties(courseInfoVo,eduCourse); int update = baseMapper.updateById(eduCourse); if (update==0){ throw new GuliException(20001,"修改课程信息失败"); } //2 修改描述表 EduCourseDescription description=new EduCourseDescription(); description.setId(courseInfoVo.getId()); description.setDescription(courseInfoVo.getDescription()); courseDescriptionService.updateById(description); }
前端
-
在 api 里面course.js定义接口两个方法
//根据课程id查询课程基本信息 getCourseInfoId(id){ return request({ url: `/eduservice/course/getCourseInfo/`+id,//接口地址 method: 'get' }) }, //修改课程信息 updateCourseInfo(courseInfo){ return request({ url: `/eduservice/course/updateCourseInfo/`,//接口地址 method: 'post', data:courseInfo }) },
-
修改chapter页面,跳转路径
-
在数据回显页面info.vue实现数据回显
- 获取路由课程id,调用根据id查询接口,数据显示
-
403错误:一般是跨域或路径写错了
回显
created(){
//获取路由id值
if(this.$route.params && this.$route.params.id){
//有id值就做修改操作
this.courseId = this.$route.params.id
//调用根据id查询课程的方法
this.getInfo()
}else{
//没有id值就做添加操作
//初始化所有讲师
this.getListTeacher()
//初始化一级分类
this.getOneSubject()
}
},
methods:{
//根据课程id查询
getInfo(){
course.getCourseInfoId(this.courseId)
.then(response =>{
//在courseInfo中会有课程基本信息,包含一级分类id和二级分类id
this.courseInfo=response.data.courseInfoVo
//1 查询出所有分类,包含一级和二级
subject.getSubjectList()
.then(response =>{
//2 获取所有一级分类
this.subjectOneList=response.data.list
//3 遍历所有一级分类数据,比较当前courseInfo中的一级分类id是否和所有一级分类id有相同的,有将其二级分类存储到二级分类数组中
for(var i=0;i<this.subjectOneList.length;i++){
//获取每个一级分类
var oneSubject=this.subjectOneList[i]
//比较当前courseInfo中的一级分类是否和所有一级分类id有相同的
if(this.courseInfo.subjectParentId === oneSubject.id){
this.subjectTwoList=oneSubject.children
}
}
})
//初始化所有讲师
this.getListTeacher()
})
},
修改课程信息
info.vue代码
//添加课程
addCourse(){
course.addCourseInfo(this.courseInfo)
.then(response =>{
//提示
this.$message({
type: 'success',
message: '添加课程信息成功!'
});
//进度条跳转到第二步
this.$router.push({path:'/course/chapter/'+response.data.courseId})
})
},
//修改课程
updateCourse(){
course.updateCourseInfo(this.courseInfo)
.then( response =>{
//提示
this.$message({
type: 'success',
message: '修改课程信息成功!'
});
//进度条跳转到第二步
this.$router.push({path:'/course/chapter/'+this.courseId})
})
},
saveOrUpdate(){
//判断添加还是修改
if(!this.courseInfo.id){
//,没有id值,为添加
this.addCourse()
}else{
this.updateCourse()
}
}
课程信息确认
编写SQL语句实现
需要显示多个数据,在多个表中,所以一般用SQL语句实现
内连接
左外连接
右外连接
用左外连接
SELECT ec.id,ec.title,ec.price,ec.lesson_num,ecd.description,et.name,es1.title AS oneSubject,es2.title AS twoSubject
FROM edu_course ec
LEFT OUTER JOIN edu_course_description ecd ON ec.id=ecd.id
LEFT OUTER JOIN edu_teacher et ON ec.teacher_id=et.id
LEFT OUTER JOIN edu_subject es1 ON ec.subject_parent_id=es1.id
LEFT OUTER JOIN edu_subject es2 ON ec.subject_id=es2.id
WHERE ec.id='1412674103233568770'
通过controller调service,通过service调自己写的mapper中的SQL语句来查询数据库
课程最终发布
修改课程的status状态是Normal 已发布
controller
//课程最终发布
//修改课程状态
@PostMapping("publishCourse/{id}")
public R publishCourse(@PathVariable String id){
EduCourse eduCourse=new EduCourse();
eduCourse.setId(id);
eduCourse.setStatus("Normal");//设置课程发布zt
courseService.updateById(eduCourse);
return R.ok();
}
前端
publish(){
course.publishCourse(this.courseId)
.then( response =>{
//提示信息
this.$message({
type: 'success',
message: '课程发布成功!'
});
})
//跳转到课程列表页面
this.$router.push({path:'/course/list'})
}
存在问题
-
在测试富文本编辑器添加课程基本信息时,不加图片可以添加成功,加了图片就失败
发现是文件过大,经过富文本使用base64转码后,文本过长,超出了数据库字段的允许的大小,上传小一点的图片就成功了
-
查询课程信息报错
项目中创建mapper接口,编写xml文件SQL语句,执行出现错误
原因是maven默认加载机制出问题
因为maven加载时,会把src-main-java文件夹里的java类型文件进行编译加载,但是其他类型如xml文件不会加载,所 以运行时会找不到文件
解决方式
1.赋值xml到target目录中
2.把xml文件放到resource是目录中
3.通过配置实现:
(1)pom.xml中
<!-- 项目打包时会将java目录中的*.xml文件也进行打包 --> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
(2)项目的application.properties中
mybatis-plus.mapper-locations=classpath:com/lujin/eduservice/mapper/xml/*.xml
Day09(07.08)
课程列表模块
课程列表显示
课程删除
删除课程,需将视频,小节,章节,描述,课程本身删除
阿里云视频点播服务
API:阿里云提供固定的地址,只需要调用这个固定的地址,向地址传参数,实现功能
http://vod.cn-shanghai.aliyuncs.com/
httpclient技术可以调用API地址,不需要浏览器
SDK:对API进行封装,可以更方便使用,调用阿里云提供的类或接口里面的方法实现视频功能
因为上传视频可以加密,加密以后,使用加密之后的地址不能进行视频播放,所以在数据库不存地址,存 视频id
获取视频播放地址
-
引入依赖
-
初始化,创建 Default AcsClient对象
public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws ClientException { String regionId = "cn-shanghai"; // 点播服务接入区域 DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret); DefaultAcsClient client = new DefaultAcsClient(profile); return client; }
-
获取视频地址
public class TestVod { public static void main(String[] args) throws Exception { //1 根据视频id获取视频播放地址 //创建初始化对象 DefaultAcsClient client=InitObject.initVodClient("LTAI5t8mpHbQi5QDdST6ZUvB","bViQGRmtaaQfCxCmw14VlXseRi01yx"); //创建获取视频地址request和response GetPlayInfoRequest request=new GetPlayInfoRequest(); GetPlayInfoResponse response=new GetPlayInfoResponse(); //向request对象里面设置视频id request.setVideoId("1491fa1ea19c4ee5921c4c1b31253d9a"); //调用初始化对象里面的方法,传递request,获取数据 response=client.getAcsResponse(request); List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList(); //播放地址 for (GetPlayInfoResponse.PlayInfo playInfo : playInfoList) { System.out.print("PlayInfo.PlayURL = " + playInfo.getPlayURL() + "\n"); } //Base信息 System.out.print("VideoBase.Title = " + response.getVideoBase().getTitle() + "\n"); } }
获取视频播放凭证
public static void main(String[] args) throws Exception {
//根据视频id获取视频凭证
DefaultAcsClient client=InitObject.initVodClient("LTAI5t8mpHbQi5QDdST6ZUvB","bViQGRmtaaQfCxCmw14VlXseRi01yx");
//创建获取视频凭证的request和response
GetVideoPlayAuthRequest request= new GetVideoPlayAuthRequest();
GetVideoPlayAuthResponse response= new GetVideoPlayAuthResponse();
//向request中设置id值
request.setVideoId("1491fa1ea19c4ee5921c4c1b31253d9a");
response=client.getAcsResponse(request);
System.out.println("playauth:"+response.getPlayAuth());
}
上传视频到阿里云视频点播服务
public static void main(String[] args) throws Exception {
String accessKeyId="LTAI5t8mpHbQi5QDdST6ZUvB";
String accessKeySecret="bViQGRmtaaQfCxCmw14VlXseRi01yx";
String title="test";//上传之后文件的名称
String fileName="F:/6 - What If I Want to Move Faster.mp4";//本地文件路径和名称
//上传实现代码
UploadVideoRequest request = new UploadVideoRequest(accessKeyId, accessKeySecret, title, fileName);
/* 可指定分片上传时每个分片的大小,默认为2M字节 */
request.setPartSize(2 * 1024 * 1024L);
/* 可指定分片上传时的并发线程数,默认为1,(注:该配置会占用服务器CPU资源,需根据服务器情况指定)*/
request.setTaskNum(1);
UploadVideoImpl uploader = new UploadVideoImpl();
UploadVideoResponse response = uploader.uploadVideo(request);
if (response.isSuccess()) {
System.out.print("VideoId=" + response.getVideoId() + "\n");
} else {
/* 如果设置回调URL无效,不影响视频上传,可以返回VideoId同时会返回错误码。其他情况上传失败时,VideoId为空,此时需要根据返回错误码分析具体错误原因 */
System.out.print("VideoId=" + response.getVideoId() + "\n");
System.out.print("ErrorCode=" + response.getCode() + "\n");
System.out.print("ErrorMessage=" + response.getMessage() + "\n");
}
}
添加小节的上传视频功能
-
创建配置文件application.properties
# 服务端口 server.port=8003 # 服务名 spring.application.name=service-vod # 环境设置:dev、test、prod spring.profiles.active=dev #阿里云 vod #不同的服务器,地址不同 aliyun.vod.file.keyid=LTAI5t8mpHbQi5QDdST6ZUvB aliyun.vod.file.keysecret=bViQGRmtaaQfCxCmw14VlXseRi01yx # 最大上传单个文件大小:默认1M,改成了1G spring.servlet.multipart.max-file-size=1024MB # 最大置总上传的数据大小 :默认10M spring.servlet.multipart.max-request-size=1024MB
-
创建启动类VodApplication
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @ComponentScan(basePackages = "com.lujin") public class VodApplication { public static void main(String[] args) { SpringApplication.run(VodApplication.class, args); } }
-
创建controller、service
@RestController @RequestMapping("/eduvod/video") @CrossOrigin public class VodController { @Autowired private VodService vodService; //上传视频到阿里云的方法 @PostMapping("uploadAlyVideo") public R uploadAlyVideo(MultipartFile file){ //返回上传视频id String videoId=vodService.uploadVideoAly(file); return R.ok().data("videoId",videoId); } } @Service public class VodServiceImpl implements VodService { @Override public String uploadVideoAly(MultipartFile file) { try{ //accessKeyId, accessKeySecret 为id和密钥 //fileName:上传文件原始名称 String fileName=file.getOriginalFilename(); //title:上传之后显示名称 String title=fileName.substring(0, fileName.lastIndexOf(".")); //inputStream:上传文件输入流 InputStream inputStream=file.getInputStream(); UploadStreamRequest request = new UploadStreamRequest(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET, title, fileName, inputStream); UploadVideoImpl uploader = new UploadVideoImpl(); UploadStreamResponse response = uploader.uploadStream(request); String videoId=null; if (response.isSuccess()) { videoId=response.getVideoId(); } else { //如果设置回调URL无效,不影响视频上传,可以返回VideoId同时会返回错误码。其他情况上传失败时,VideoId为空,此时需要根据返回错误码分析具体错误原因 videoId=response.getVideoId(); } return videoId; }catch (Exception e){ e.printStackTrace(); return null; } } }
-
swagger测试
存在问题
-
依赖报红
下载jar包,解压文件进入lib文件夹执行cmd命令
mvn install:install-file -DgroupId=com.aliyun -DartifactId=aliyun-sdk-vod-upload -Dversion=1.4.11 -Dpackaging=jar -Dfile=aliyun-java-vod-upload-1.4.11.jar
-
上传视频时出现上传不了的问题
原因是
发现是8003端口没有配置nginx反向代理
在nginx.conf中添加配置和上传大小限制,否则视频过大也上传失败
在任务管理器将所有启动的nginx关掉后,重启nginx,上传成功