项目 谷粒学院Day07-09

Day07(07.06)

添加课程分类前端实现

添加课程分类路由

在这里插入图片描述

创建课程分类页面,修改路由对应的页面路径

在这里插入图片描述

实现添加课程分类页面

  1. 添加上传组件
    2.在这里插入图片描述
    在这里插入图片描述

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

课程分类列表显示

用树形结构显示

后端代码

  1. 创建接口,按照格式返回数据

    两个实体类,一级分类和二级分类

  2. 在两个实体类之间表示关系

    一个一级分类有多个二级分类

    @Data
    //一级分类
    public class OneSubject {
        private String id;
        private String title;
        //一个一级分类有多个二级分类
        private List<TwoSubject> children=new ArrayList<>();
    }
    
  3. 封装代码

在这里插入图片描述

  1. /课程分类列表(树形)
    @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;
    }
    
  2. 在这里插入图片描述

前端结果显示

在这里插入图片描述

课程管理模块

在这里插入图片描述

课程表关系

edu_course:课程表,存储课程基本信息

edu_course_description:课程简介表,存储课程简介信息

edu_chapter:课程章节表,存储课程章节信息

edu_video:课程小结表,存储章节里面小结信息

edu_teacher:讲师表

edu_subject:课程分类表

关系

在这里插入图片描述

添加课程基本信息

  1. 使用代码生成器生成课程相关代码

  2. 创建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;
    }
    

    在这里插入图片描述

  3. 编写 controller和service

    1. 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();
          }
      }
      
    2. 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);
      
          }
      }
      
    3. swagger测试结果

      在这里插入图片描述

添加课程基本信息前端

  1. 添加路由

    在这里插入图片描述

  2. 添加 vue 组件
    在这里插入图片描述

  3. 课程信息页面 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>
    
  4. 课程大纲页面 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>
    
  5. 课程发布页面 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>
    
  6. 效果

在这里插入图片描述

下拉列表显示所有讲师

 <!-- 课程讲师 -->
        <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>

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

存在问题

  1. 在添加课程基本信息时报错

在这里插入图片描述

原因:数据库中该字段是非空的,需要将其设置为可以为空。

ALTER TABLE edu_course MODIFY subject_parent_id CHAR(19) NULL

结果: edu_course_description表

在这里插入图片描述

edu_course表

在这里插入图片描述

Day08(07.06)

添加课程基本信息完善

整合文本编辑器

  1. 富文本编辑器组件

课程大纲管理

课程大纲列表显示

后端
  1. 创建两个实体类 章节和小节,章节使用list集合表示小节

  2. 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);
        }
    }
    
  3. 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;
        }
    }
    
  4. swagger测试在这里插入图片描述

前端
  1. 获取路由id,将章节和小节取到

在这里插入图片描述

  1. 遍历得到结果

    在这里插入图片描述

  2. 效果

    在这里插入图片描述

  3. 优化后的页面

在这里插入图片描述

章节添加 修改 删除

  1. 添加按钮

在这里插入图片描述

  1. 开发接口

    1. 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;
    }
}
效果

在这里插入图片描述

小节添加 修改 删除

修改课程基本信息

后端

  1. 根据课程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;
    }
    
  2. 修改课程信息

    //修改课程信息
    @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);
    }
    

前端

  1. 在 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
            })
        },
    
  2. 修改chapter页面,跳转路径

在这里插入图片描述

  1. 在数据回显页面info.vue实现数据回显

    1. 获取路由课程id,调用根据id查询接口,数据显示

在这里插入图片描述

  1. 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'})
        }

存在问题

  1. 在测试富文本编辑器添加课程基本信息时,不加图片可以添加成功,加了图片就失败

    发现是文件过大,经过富文本使用base64转码后,文本过长,超出了数据库字段的允许的大小,上传小一点的图片就成功了
    在这里插入图片描述

  2. 查询课程信息报错

在这里插入图片描述

项目中创建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

获取视频播放地址

  1. 引入依赖

  2. 初始化,创建 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;
    }
    
  3. 获取视频地址

    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");
    }
}

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

添加小节的上传视频功能

  1. 创建配置文件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
    
  2. 创建启动类VodApplication

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    @ComponentScan(basePackages = "com.lujin")
    public class VodApplication {
        public static void main(String[] args) {
            SpringApplication.run(VodApplication.class, args);
        }
    }
    
  3. 创建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;
            }
        }
    }
    
  4. swagger测试

在这里插入图片描述

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

存在问题

  1. 依赖报红
    在这里插入图片描述

    下载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

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

  1. 上传视频时出现上传不了的问题

    原因是在这里插入图片描述

    发现是8003端口没有配置nginx反向代理

    在nginx.conf中添加配置和上传大小限制,否则视频过大也上传失败

在这里插入图片描述

在这里插入图片描述

在任务管理器将所有启动的nginx关掉后,重启nginx,上传成功

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值