Cereals college finally released the course list alicloud video on demand service section to upload videos

Posted by raidon on Sun, 27 Feb 2022 09:44:11 +0100

1, Course final release information display - back end

1. Entity class - used to encapsulate the data displayed on the page

@ApiModel(value = "Course final release")
@Data
public class CoursePublishVo implements Serializable {
    private static final long serialVersionUID = 1L;

    //Course title
    private String title;
    //Course cover
    private String cover;
    //Class hours
    private Integer lessonNum;
    //Primary classification
    private String subjectLevelOne;
    //Secondary classification
    private String subjectLevelTwo;
    //Lecturer name
    private String teacherName;
    //Course price
    private String price;//For display only
}

2. Write Controller class

//Course release
//Query the publishing information of the course according to the course id
@ApiOperation("Query course publishing information")
@GetMapping("getPublishCourseInfo/{id}")
public R getPublishCourseInfo(@PathVariable String id){
    CoursePublishVo courseInfo =  courseService.getPublishCourseInfo(id);
    return R.ok().data("courseInfo",courseInfo);
}

3. Write Service class

//Query course publishing information according to id
@Override
public CoursePublishVo getPublishCourseInfo(String id) {
    CoursePublishVo coursePublishVo = this.baseMapper.getPublishCourseInfo(id);
    return coursePublishVo;
}

Since the data displayed on our final release page comes from four tables (course schedule, course description table, lecturer table and classification table), we need to write SQL statements manually.

4. Write mapper interface

public interface EduCourseMapper extends BaseMapper<EduCourse> {
    public CoursePublishVo getPublishCourseInfo(String id);
}

5. Write mapper class xml configuration file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rg.eduservice.mapper.EduCourseMapper">

    <select id="getPublishCourseInfo" resultType="com.rg.eduservice.entity.vo.CoursePublishVo" parameterType="string">
        SELECT ec.id,ec.`title`,ec.`price`,ec.`lesson_num` AS lessonNum,ec.`cover`,
        et.`name` teacherName,
        es1.`title` AS subjectLevelOne,
        es2.`title` AS subjectLevelTwo
        FROM edu_course ec 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`
        LEFT OUTER JOIN edu_teacher et ON ec.`teacher_id` = et.`id`
        WHERE ec.id=#{id}
    </select>
</mapper>

6. Errors in project operation and Solutions

The project creates the mapper interface, writes the sql statement of the xml file, and there is an error in the execution

This error is caused by maven's default loading mechanism. When maven is loaded, put it in the java folder java type files are compiled. If other types of files are used, they will not be loaded.

Solution:
1. Copy xml to target directory
2. Put the xml file in the resources directory
3. Recommended: through configuration file
(1)pom.xml
(2) Project application properties

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

In the application of the service module In properties

# The path to the configuration mapper xml file
mybatis-plus.mapper-locations=classpath:com/kuang/eduservice/mapper/xml/*.xml

Restart the service to run successfully!

2, Course final release information display - front end

1. Define api interface

//Query the basic information published by the course according to the course id
getPublishCourseInfo(id) {
    return request({
        url: `/eduservice/course/getPublishCourseInfo/${id}`,
        method: 'get'
    })
}

2. Front end pages and styles

<template>

  <div class="app-container">

    <h2 style="text-align: center;">Publish new courses</h2>

    <el-steps :active="3" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="Fill in the basic information of the course"/>
      <el-step title="Create syllabus"/>
      <el-step title="Publish courses"/>
    </el-steps>

    <div class="ccInfo">
      <img :src="coursePublish.cover">
      <div class="main">
        <h2>{{ coursePublish.title }}</h2>
        <p class="gray"><span>common{{ coursePublish.lessonNum }}class hour</span></p>
        <p><span>Classification:{{ coursePublish.subjectLevelOne }} — {{ coursePublish.subjectLevelTwo }}</span></p>
        <p>Course instructor:{{ coursePublish.teacherName }}</p>
        <h3 class="red">¥{{ coursePublish.price }}</h3>
      </div>
    </div>

    <div>
      <el-button @click="previous">Return to modify</el-button>
      <el-button :disabled="saveBtnDisabled" type="primary" @click="publish">Publish courses</el-button>
    </div>
  </div>
</template>

<style scoped>
.ccInfo {
    background: #f5f5f5;
    padding: 20px;
    overflow: hidden;
    border: 1px dashed #DDD;
    margin-bottom: 40px;
    position: relative;
}
.ccInfo img {
    background: #d6d6d6;
    width: 500px;
    height: 278px;
    display: block;
    float: left;
    border: none;
}
.ccInfo .main {
    margin-left: 520px;
}

.ccInfo .main h2 {
    font-size: 28px;
    margin-bottom: 30px;
    line-height: 1;
    font-weight: normal;
}
.ccInfo .main p {
    margin-bottom: 10px;
    word-wrap: break-word;
    line-height: 24px;
    max-height: 48px;
    overflow: hidden;
}

.ccInfo .main p {
    margin-bottom: 10px;
    word-wrap: break-word;
    line-height: 24px;
    max-height: 48px;
    overflow: hidden;
}
.ccInfo .main h3 {
    left: 540px;
    bottom: 20px;
    line-height: 1;
    font-size: 28px;
    color: #d32f24;
    font-weight: normal;
    position: absolute;
}
</style>

3. Introduction interface

import course from '@/api/edu/course'

4. Write front-end js

data() {
    return {
      //....
      saveBtnDisabled:false,
      courseId: '',
      coursePublish: {}
    }
  },
  created() {
    //Get the id value in the route
    if(this.$route.params && this.$route.params.id) {
        this.courseId = this.$route.params.id
        //Call the interface method to query according to the course id
        this.getPublishCourseInfo()
    }
  },
  methods: {
    //Query course information according to course id  
    getPublishCourseInfo(){
          course.getPublishCourseInfo(this.courseId).then(response=>{
            this.coursePublish = response.data.courseInfo
          })
        }
    //.....
  }

5. Page rendering

3, Course final release – front and back

1. Write Controller class

//Course release
@PutMapping("publishCourse/{id}")
public R publishCourse(@PathVariable String id){
    EduCourse course = new EduCourse();
    course.setId(id);
    course.setStatus("Normal");
    boolean update = courseService.updateById(course);
    if(update){
        return R.ok();
    }else{
        return R.error();
    }
}

2. Define api interface

//Publish course information
publishCourse(id) {
    return request({
        url: `/eduservice/course/publishCourse/${id}`,
        method: 'put'
    })
}

3. Write front-end js

publish(){
    course.publishCourse(this.courseId).then(response=>{
        this.$confirm('Are you sure to publish this course,Continue?','Tips',{
            confirmButtonText:'determine',
            cancelButtonText:'cancel',
            type:'warning'
        }).then(()=>{//Click OK
            this.$message({
                type:'success',
                message:'Course published successfully!' 
            }) 
            //Jump to the course list page
            this.$router.push({path:'/course/list'})
        }).catch(()=>{
            this.$message({
                type: 'info',
                message: 'Publish canceled!'
            })
        })
    }).catch(()=>{
        this.$message({
            type: 'error',
            message: 'Course publishing failed!'
        })
    })        
}

4, Course list – back end

1. Write query entity class

@Data
public class CourseQuery implements Serializable {

    private static final long serialVersionUID = 1L;

    //Primary classification id
    private String subjectParentId;

    //Secondary classification id
    private String subjectId;

    //Course name
    private String title;

    //Instructor id
    private String teacherId;


}

2. Controller class

//Paging query course
@PostMapping("pageQuery/{current}/{limit}")
public R pageQuery(@PathVariable Integer current,
                   @PathVariable Integer limit,
                   @RequestBody CourseQuery courseQuery)
{
    Page<EduCourse> page =  courseService.pageQuery(current,limit,courseQuery);
    return R.ok().data("total",page.getTotal()).data("list",page.getRecords());
}

//Delete course
@DeleteMapping("removeCourse/{id}")
public R removeCourse(@PathVariable String id){
    courseService.removeCourse(id);
    return R.ok();
}

3. Service class

//Pagination query of courses
@Override
public Page <EduCourse> pageQuery(Integer current, Integer limit, CourseQuery courseQuery) {
    Page <EduCourse> page = new Page <>(current,limit);
    QueryWrapper <EduCourse> wrapper = new QueryWrapper <>();
    String title = courseQuery.getTitle();
    String subjectId = courseQuery.getSubjectId();
    String subjectParentId = courseQuery.getSubjectParentId();
    String teacherId = courseQuery.getTeacherId();
    //Empty judgment and construct query conditions
    if(!StringUtils.isEmpty(title)){
        wrapper.like("title",title);
    }
    if(!StringUtils.isEmpty(subjectId)){
        wrapper.eq("subject_id",subjectId);
    }
    if(!StringUtils.isEmpty(subjectParentId)){
        wrapper.eq("subject_parent_id",subjectParentId);
    }
    if(!StringUtils.isEmpty(teacherId)){
        wrapper.eq("teacher_id",teacherId);
    }
    wrapper.orderByDesc("gmt_create");
    //Paging query
    this.baseMapper.selectPage(page, wrapper);//After paging query, it is automatically encapsulated in page
    return page;
}

//Delete course information according to id
@Override
public void removeCourse(String id) {
    //1. Delete section
    videoService.removeVideoByCourseId(id);
    //2. Delete chapter
    chapterService.removeChapterByCourseId(id);
    //3. Delete course description information
    courseDescriptionService.removeById(id);
    //4. Delete course information
    this.baseMapper.deleteById(id);
}

5, Course list – front end

1. Define api interface

//Delete course
removeCourse(id) {
    return request({
        url: `/eduservice/course/removeCourse/${id}`,
        method: 'delete'
    })
},
//Paging query course
pageQuery(current, limit, courseQuery) {
    return request({
        url: `/eduservice/course/pageQuery/${current}/${limit}`,
        method: 'post',
        data: courseQuery
    })
}

2. Front page - list vue

<template>

  <div class="app-container">
    <!--query form -->
    <el-form :inline="true" class="demo-form-inline">

      <!-- Category: cascade drop-down list -->
      <!-- Primary classification -->
      <el-form-item label="Course category">
        <el-select
          v-model="searchObj.subjectParentId"
          placeholder="Please select"
          @change="subjectLevelOneChanged">
          <el-option
            v-for="subject in subjectNestedList"
            :key="subject.id"
            :label="subject.title"
            :value="subject.id"/>
        </el-select>

        <!-- Secondary classification -->
        <el-select v-model="searchObj.subjectId" placeholder="Please select">
          <el-option
            v-for="subject in subSubjectList"
            :key="subject.id"
            :label="subject.title"
            :value="subject.id"/>
        </el-select>
      </el-form-item>

      <!-- title -->
      <el-form-item>
        <el-input v-model="searchObj.title" placeholder="Course title"/>
      </el-form-item>
      <!-- lecturer -->
      <el-form-item>
        <el-select
          v-model="searchObj.teacherId"
          placeholder="Please select a lecturer">
          <el-option
            v-for="teacher in teacherList"
            :key="teacher.id"
            :label="teacher.name"
            :value="teacher.id"/>
        </el-select>
      </el-form-item>

      <el-button type="primary" icon="el-icon-search" @click="getList()">query</el-button>
      <el-button type="default" @click="resetData()">empty</el-button>
    </el-form>
    
    <!-- form -->
    <el-table
      v-loading="listLoading"
      :data="list"
      element-loading-text="Data loading"
      border
      fit
      highlight-current-row
      row-class-name="myClassList">

      <el-table-column
        label="Serial number"
        width="70"
        align="center">
        <template slot-scope="scope">
          {{ (page - 1) * limit + scope.$index + 1 }}
        </template>
      </el-table-column>

      <el-table-column label="Course information" width="470" align="center">
        <template slot-scope="scope">
          <div class="info">
            <div class="pic">
              <img :src="scope.row.cover" alt="scope.row.title" width="150px">
            </div>
            <div class="title">
              <a href="">{{ scope.row.title }}</a>
              <p>{{ scope.row.lessonNum }}class hour</p>
            </div>
          </div>

        </template>
      </el-table-column>

      <el-table-column label="Creation time" align="center">
        <template slot-scope="scope">
          {{ scope.row.gmtCreate.substr(0, 10) }}
        </template>
      </el-table-column>
      <el-table-column label="Release time" align="center">
        <template slot-scope="scope">
          {{ scope.row.gmtModified.substr(0, 10) }}
        </template>
      </el-table-column>
      <el-table-column label="Price" width="100" align="center" >
        <template slot-scope="scope">
          {{ Number(scope.row.price) === 0 ? 'free' :
          '¥' + scope.row.price.toFixed(2) }}
        </template>
      </el-table-column>
      <el-table-column prop="buyCount" label="Paid student" width="100" align="center" >
        <template slot-scope="scope">
          {{ scope.row.buyCount }}people
        </template>
      </el-table-column>

      <el-table-column prop="viewCount" label="Playback times" width="100" align="center" >
        <template slot-scope="scope">
          {{ scope.row.viewCount }}second
        </template>
      </el-table-column>

      <el-table-column label="operation" width="150" align="center">
        <template slot-scope="scope">
          <router-link :to="'/course/info/'+scope.row.id">
            <el-button type="text" size="mini" icon="el-icon-edit" >Edit course information</el-button>
          </router-link>
          <router-link :to="'/course/chapter/'+scope.row.id">
            <el-button type="text" size="mini" icon="el-icon-edit" >Edit syllabus</el-button>
          </router-link>
          <el-button type="text" size="mini" icon="el-icon-delete" @click="removeCourse(scope.row.id)">delete</el-button>
        </template>
      </el-table-column>
    </el-table>

<!-- paging -->
<el-pagination
  :current-page="page"
  :page-size="limit"
  :total="total"
  style="padding: 30px 0; text-align: center;"
  layout="total, prev, pager, next, jumper"
  @current-change="getList"
/>

    

  </div>
</template>

3. Page style

<style scoped>
.myClassList .info {
    width: 450px;
    overflow: hidden;
}
.myClassList .info .pic {
    width: 150px;
    height: 90px;
    overflow: hidden;
    float: left;
}
.myClassList .info .pic a {
    display: block;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
}
.myClassList .info .pic img {
    display: block;
    width: 100%;
}
.myClassList td .info .title {
    width: 280px;
    float: right;
    height: 90px;
}
.myClassList td .info .title a {
    display: block;
    height: 48px;
    line-height: 24px;
    overflow: hidden;
    color: #00baf2;
    margin-bottom: 12px;
}
.myClassList td .info .title p {
    line-height: 20px;
    margin-top: 5px;
    color: #818181;
}
</style>

4. Write front-end js

<script>
import course from '@/api/edu/course'
import subject from '@/api/edu/subject'
export default {

    data() {
      return {
        listLoading: false, // Whether to display loading information
        list: null, // Data list
        total: 0, // Total records
        page: 1, // Page number
        limit: 10, // Records per page
        searchObj: {
          subjectParentId: '',
          subjectId: '',
          title: '',
          teacherId: ''
        }, // query criteria
        teacherList: [], // Instructor list
        subjectNestedList: [], // Primary classification list
        subSubjectList: [] // Secondary classification list,
      }
    },
    created() {
      this.init()
    },
    methods: {
        //Edit syllabus
        updateChapter(id){
          this.$router.push({path:'/course/chapter/'+id})
        },
        //Edit course basic information
        updateCourse(id){
          this.$router.push({path:'/course/info/'+id})
        },
        removeCourse(id){
            this.$confirm('This action will permanently delete all contents of this course,Continue?','Tips',{
            confirmButtonText:'determine',
            cancelButtonText:'cancel',
            type:'warning'
          }).then(()=>{//Click OK
              course.removeCourse(id).then((response)=>{
                this.$message({
                  type:'success',
                  message:'Deleted successfully!' 
                }) 
                //Return to the list page
                this.getList()
              }).catch(()=>{
                this.$message({
                  type:'error',
                  message:'Delete failed!' 
                }) 
              })
          }).catch(() => { // Click Cancel
              this.$message({
                  type: 'info',
                  message: 'Deletion cancelled!'
              })
           })
        },
        //Paging + conditional query
        getList(page = 1){//The default value of page is 1. When the paging component is used, a new page parameter will be passed in
          this.page = page
          course.pageQuery(this.page,this.limit,this.searchObj).then(response=>{
            this.list = response.data.list
            this.total = response.data.total
          })
        },
      //Query form reset method
        resetData(){
          this.searchObj = {},
          this.subSubjectList = []
        },
        //Method when the primary classification drop-down menu changes
        subjectLevelOneChanged(id){
          // console.log(id);
          for(var i = 0;i < this.subjectNestedList.length;i++){
            if(this.subjectNestedList[i].id == id){
              this.subSubjectList = this.subjectNestedList[i].children
            }
          }
        },
        //Initialization method
        init(){
          //1. Query primary classification
          subject.getAllSubject().then(response=>{
            this.subjectNestedList = response.data.list
          })
          //2. Query all lecturers
          course.getTeacherList().then(response=>{
            this.teacherList = response.data.items
          })
          //3. Query course list
          this.getList()
        }
    }
}
</script>

5, Page rendering

6, Alibaba cloud video on demand service

ApsaraVideo for VoD is a one-stop audio and video on demand solution integrating audio and video acquisition, editing, uploading, automatic transcoding processing, media resource management and distribution acceleration.

1. Video on demand

Enter Alibaba cloud's official website: https://www.aliyun.com/ , find video on demand

Open video on demand service (choose to charge by traffic)

2. Tariff description

https://www.aliyun.com/price/product?spm=a2c4g.11186623.2.12.7fbd59b9vmXVN6#/vod/detail

3. Overall process

The overall process of audio and video upload, storage, processing and playback using video on demand is as follows:

4. Basic use of video on demand service

Complete reference documents https://help.aliyun.com/product/29932.html?spm=a2c4g.11186623.6.540.3c356a58OEmVZJ

  • Server: back end interface

  • Client: browser, Android, ios

  • API: Alibaba cloud provides a fixed address. You only need to call the fixed address and pass parameters to the address to realize the function.

  • SDK: SDK encapsulates the api mode, which is more convenient to use. Previously, we used EayExcel to call the methods in the classes or interfaces provided by Alibaba cloud to realize video functions.

5. How to use Java code and SDK

Note: the uploaded video can be encrypted. After encryption, the encrypted address cannot be used for video playback. Therefore, the video id is stored in the database instead of the address.

(1) Create sub module service under service_vod module

POM.xml

<dependencies>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
    </dependency>
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
    </dependency>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-vod</artifactId>
    </dependency>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-sdk-vod-upload</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
    </dependency>
    <dependency>
        <groupId>org.json</groupId>
        <artifactId>json</artifactId>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
    </dependency>

    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>
</dependencies>

(2) Initialize the operation and create the DefaultAcsClient object

public class InitVodClient {
    public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws ClientException {
        String regionId = "cn-shanghai";  // VOD access region
        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        DefaultAcsClient client = new DefaultAcsClient(profile);
        return client;
    }
}

(3) Obtain the video playback address according to the video id

//Obtain the video playback address according to the id
public static void getPlayUrl()throws ClientException{

    //Create initialization object
    DefaultAcsClient client = InitVodClient.initVodClient("your keyId", "your keySecret");
    //Create and obtain video address request and response
    GetPlayInfoRequest request = new GetPlayInfoRequest();
    GetPlayInfoResponse response = new GetPlayInfoResponse();
    request.setVideoId("efc88346e5dd45fda5b161c9ddbd0d9d");
    //Call the method in the initialization object, pass the request and get the data
    response = client.getAcsResponse(request);

    List <GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();
    //Playback address
    for (GetPlayInfoResponse.PlayInfo playInfo : playInfoList) {
        System.out.print("PlayInfo.PlayURL = " + playInfo.getPlayURL() + "\n");
    }
    //Base information video name
    System.out.print("VideoBase.Title = " + response.getVideoBase().getTitle() + "\n");
}

(4) Obtain video playback certificate

//Obtain video playback certificate according to id
public static void getPlayAuth()throws ClientException{
    //Create initialization object
    DefaultAcsClient client = InitVodClient.initVodClient("your keyId", "your keySecret");

    GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
    GetVideoPlayAuthResponse response = new GetVideoPlayAuthResponse();

    request.setVideoId("003a83891a7b444d93727d83a5ba7d3a");

    response = client.getAcsResponse(request);
    System.out.println("palyAuth:"+response.getPlayAuth());
}

(5) Upload video to Alibaba cloud video on demand service

//Upload in the form of file stream
public static void testUploadFileStream(){
    String accessKeyId = "your keyId";
    String accessKeySecret = "your keySecret";
    String title = "6 - What If I Want to Move Faster123.mp4 ";
    String fileName = "F:/self-study course/Project data/02 Grain Academy(Distributed project)/Project data/1-Alibaba cloud upload test video/6 - What If I Want to Move Faster.mp4";
    UploadFileStreamRequest request = new UploadFileStreamRequest(accessKeyId, accessKeySecret, title, fileName);

    UploadVideoImpl uploader = new UploadVideoImpl();
    UploadFileStreamResponse response = uploader.uploadFileStream(request);
    System.out.print("RequestId=" + response.getRequestId() + "\n"); //Request ID for requesting video on demand service
    if (response.isSuccess()) {
        System.out.print("VideoId=" + response.getVideoId() + "\n");
    } else {
        /* If the setting callback URL is invalid, it will not affect the video upload. You can return VideoId and error code. When the upload fails in other cases, the VideoId is empty. At this time, the specific error reason needs to be analyzed according to the returned error code */
        System.out.print("VideoId=" + response.getVideoId() + "\n");
        System.out.print("ErrorCode=" + response.getCode() + "\n");
        System.out.print("ErrorMessage=" + response.getMessage() + "\n");
    }
}

7, Add a section to upload and delete Videos - back end

1. Introduce dependency

2. Create application profile

#Service port
server:
  port: 8003

#service name
spring:
  application:
    name: service-vod

  #Environment settings: dev,test,prod
  profiles:
    active: dev


  servlet:
    multipart:
      max-file-size: 1024MB # Maximum upload single file size: 1M by default
      max-request-size: 1024MB # Maximum total uploaded data size: 10M by default

#Alibaba cloud VOD address
aliyun:
  vod:
    file:
      keyid: your keyId
      keysecret: your keySecret

3. Constant tool class

@Component //Leave the property settings to Spring
public class ConstantPropertiesUtil implements InitializingBean {// InitializingBean: this class is executed during initialization

    //Read values from the configuration file and assign values to these attributes
    //Note that @ value cannot inject values into static attributes
    @Value("${aliyun.vod.file.keyid}")
    private String keyId;

    @Value("${aliyun.vod.file.keysecret}")
    private String keySecret;

    //Define public static methods
    public static String ACCESS_KEY_ID;
    public static String ACCESS_KEY_SECRET;

    //This method is executed after the attribute value is set
    @Override
    public void afterPropertiesSet() throws Exception {
        ACCESS_KEY_ID = keyId;
        ACCESS_KEY_SECRET = keySecret;
    }
}

4. Main startup class

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan("com.rg")//To scan the external swagger
public class VodApplication {
    public static void main(String[] args) {
        SpringApplication.run(VodApplication.class, args);
    }
}

5. Write Controller class

@RestController
@RequestMapping("/vodService/video")
@CrossOrigin
public class VodController {

    @Autowired
    private VodService vodService;

    //Upload video to Alibaba cloud VOD
    @PostMapping("uploadVideoAly")
    public R uploadVideoAly(@RequestBody MultipartFile file){
        String videoId = vodService.uploadVideoAly(file);
        return R.ok().data("videoId",videoId);
    }

    //Delete video from alicloud according to video id
    @DeleteMapping("removeAlyVideo/{id}")
    public R removeAlyVideo(@PathVariable String id){
        vodService.removeAlyVideo(id);
        return R.ok();
    }
}

6. Write Service class

@Service
public class VodServiceImpl implements VodService {
    //Upload video to Alibaba cloud VOD
    @Override
    public String uploadVideoAly(MultipartFile file) {

        String accessKeyId = ConstantPropertiesUtil.ACCESS_KEY_ID;
        String accessKeySecret = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
        String title = file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf("."));//Display name after uploading
        String fileName = file.getOriginalFilename();//Original name of uploaded file
        try {
            InputStream inputStream = file.getInputStream();//Upload file stream
            UploadStreamRequest request = new UploadStreamRequest(accessKeyId, accessKeySecret, title, fileName, inputStream);

            UploadVideoImpl uploader = new UploadVideoImpl();
            UploadStreamResponse response = uploader.uploadStream(request);
            String videoId = response.getVideoId();
            return videoId;
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuLiException(20001, "File upload failed!");
        }
    }

    //Delete videos on Alibaba cloud based on id
    @Override
    public void removeAlyVideo(String id) {
        try {
            DefaultAcsClient client = InitVodClient.initVodClient(ConstantPropertiesUtil.ACCESS_KEY_ID, ConstantPropertiesUtil.ACCESS_KEY_SECRET);
            //
            DeleteVideoRequest request = new DeleteVideoRequest();
            DeleteVideoResponse response = new DeleteVideoResponse();
            //Want to set the video id in the request
            request.setVideoIds(id);
            response = client.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            throw new GuLiException(20001, "Video deletion failed!");
        }
    }
}

8, Add a section to upload and delete Videos - front end

1. Define api

//Delete video by id
removeAlyVideo(id) {
    return request({
        url: `/vodService/video/removeAlyVideo/${id}`,
        method: 'delete'
    })
}

2. Integrated upload component

<el-form-item label="Upload video">
    <el-upload
        :on-success="handleVodUploadSuccess"
        :on-remove="handleVodRemove"
        :before-remove="beforeVodRemove"
        :on-exceed="handleUploadExceed"
        :file-list="fileList"
        :action="BASE_API+'/vodService/video/uploadVideoAly'"
        :limit="1"
        class="upload-demo">
    <el-button size="small" type="primary">Upload video</el-button>
    <el-tooltip placement="right-end">
        <div slot="content">Maximum support1 G,<br>
            Support 3 GP,ASF,AVI,DAT,DV,FLV,F4V,<br>
            GIF,M2T,M4V,MJ2,MJPEG,MKV,MOV,MP4,<br>
            MPE,MPG,MPEG,MTS,OGG,QT,RM,RMVB,<br>
            SWF,TS,VOB,WMV,WEBM Upload in other video formats</div>
        <i class="el-icon-question"/>
    </el-tooltip>
    </el-upload>
</el-form-item>

3. Data definition

fileList: [],//Upload file list
BASE_API: process.env.BASE_API // Interface API address
video: {// Class object
    title: '',
    sort: 0,
    isFree: 0,
    videoSourceId: '',
    videoOriginalName:''
}

4. Page js method

//How to upload more than the maximum number of videos
handleUploadExceed(file,fileList){
    this.$message.warning('Want to upload the video again,Please delete the uploaded video first')
},
//Click OK to call the method
handleVodRemove(){
    video.removeAlyVideo(this.video.videoSourceId).then(response=>{
        this.$message({
            type:'success',
            message:'Video deleted successfully!' 
        }) 
        //Empty the file list
        this.fileList = []
        //The deleted video information is no longer stored in the database
        this.video.videoSourceId = ''
        this.video.videoOriginalName = ''
    })
            
},
//click × Method called
beforeVodRemove(file,fileList){
    return this.$confirm(`OK to remove ${file.name}?`)
},
//Upload successful method
handleVodUploadSuccess(response,file,fileList){
    this.video.videoSourceId = response.data.videoId
    this.video.videoOriginalName = file.name
}

5. Video echo when editing a section

6. Page effect display

If there is harvest!!! I hope the old fellow will come to three links, praise, collect and forward.
It's not easy to create. Don't forget to point a praise, which can let more people see this article and encourage me to write a better blog

Topics: Java Vue Alibaba Cloud