多表连接查询
方式如下
内连接
左外连接
右外连接
课程全部信息查询(后端) 创建值封装对象类 1 2 3 4 5 6 7 8 9 10 11 @Data public class CoursePublishVo { private String id; private String title; private String cover; private Integer lessonNum; private String subjectLevelOne; private String subjectLevelTwo; private String teacherName; private String price; }
编写对应mapper接口 1 2 3 public interface EduCourseMapper extends BaseMapper <EduCourse > { CoursePublishVo getCoursePublishInfo (String courseId) ; }
编写对应mapper中sql语句
先查询完了之后再贴上来,出错率很高
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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.atguigu.eduservice.mapper.EduCourseMapper" > <select id ="getCoursePublishInfo" resultType ="com.atguigu.eduservice.entity.vo.CoursePublishVo" > select ec.id, ec.title, ec.price, ec.lesson_num AS lessonNum, ec.cover, et.name AS teacherName, es1.title AS subjectLevelOne, es2.title AS subjectLevelTwo from edu_course ec left join edu_course_description ecd on ec.id = ecd.id left join edu_teacher et on ec.teacher_id = et.id left join edu_subject es1 on ec.subject_parent_id = es1.id left join edu_subject es2 on ec.subject_id = es2.id where ec.id = #{courseId} </select > </mapper >
编写controller 1 2 3 4 5 6 @PostMapping("getCoursePublishInfo/{courseId}") public R getCoursePublishInfo (@PathVariable String courseId) { CoursePublishVo coursePublishInfo = courseService.getCoursePublishInfo(courseId); return R.ok().data("coursePublishInfo" , coursePublishInfo); }
编写service
同理,直接快捷键就行
1 2 3 4 5 @Override public CoursePublishVo getCoursePublishInfo (String courseId) { return baseMapper.getCoursePublishInfo(courseId); }
调试
Invalid bound statement (not found): com.atguigu.eduservice.mapper.EduCourseMapper.getCoursePublishInfo
报错如上,解决如下(详见p130)
mapper有没有写错
在target文件夹中xml配置文件有没有被引入
可以把mapper.xml放在resource下
配置pom.xml和application.properties(子模块的pom.xml)
1 mybatis-plus.mapper-locations =classpath:com/atguigu/eduservice/mapper/xml/*.xml
1 2 3 4 5 6 7 8 9 10 11 12 <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > </includes > <filtering > false</filtering > </resource > </resources > </build >
课程全部信息查询(前端) api 1 2 3 4 5 6 7 getCoursePublishInfo (courseId ) { return request({ url : `/eduservice/course/getCoursePublishInfo/` + courseId, method : 'get' , }) }
vue模板和方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 <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> <div class="ccInfo"> <img :src="coursePublishInfo.cover" /> <div class="main"> <h2>{{ coursePublishInfo.title }}</h2> <p class="gray"> <span>共{{ coursePublishInfo.lessonNum }}课时</span> </p> <p> <span >所属分类:{{ coursePublishInfo.subjectLevelOne }} — {{ coursePublishInfo.subjectLevelTwo }}</span > </p> <p>课程讲师:{{ coursePublishInfo.teacherName }}</p> <h3 class="red">¥{{ coursePublishInfo.price }}</h3> </div> </div> <div> <el-button @click="previous">返回修改</el-button> <el-button :disabled="saveBtnDisabled" type="primary" @click="publish" >发布课程</el-button > </div> </div> </template> <script> import courseApi from '@/api/edu/course.js' export default { data() { return { saveBtnDisabled: false, // 保存按钮是否禁用 courseId: '', // 课程id coursePublishInfo: {} } }, created() { // 获取到路由中的id值 if (this.$route.params && this.$route.params.id) { this.courseId = this.$route.params.id this.getCoursePublishInfo(this.courseId) } console.log(this.coursePublishInfo) }, methods: { getCoursePublishInfo(id) { // 调用api courseApi.getCoursePublishInfo(id).then(result => { console.log this.coursePublishInfo = result.data.coursePublishInfo }) }, previous() { console.log('previous') this.$router.push({ path: '/course/chapter/' + this.courseId }) }, publish() { console.log('publish') this.$router.push({ path: '/course/list' }) } } } </script>
课程发布(后端+前端) 后端
发布就是修改表中一个字段值就行
1 2 3 4 5 6 7 8 @PostMapping("publishCourse/{courseId}") public R publishCourse (@PathVariable String courseId) { EduCourse eduCourse = courseService.getById(courseId); eduCourse.setStatus("Normal" ); courseService.updateById(eduCourse); return R.ok(); }
前端
api
1 2 3 4 5 6 7 publishCourse (courseId ) { return request({ url : `/eduservice/course/publishCourse/` + courseId, method : 'post' , }) }
method
1 2 3 4 5 publish ( ) { courseApi.publishCourse(this .courseId).then(result => { this .$router.push({ path : '/course/list' }) }) }
课程列表(后端+前端) 后端(待完善) 1 2 3 4 5 6 @GetMapping("getCourseList") public R getCourseList () { List<EduCourse> list = courseService.list(null ); return R.ok().data("courseList" , list); }
前端 api 1 2 3 4 5 6 7 getCourseList ( ) { return request({ url : `/eduservice/course/getCourseList` , method : 'get' , }) }
vue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 <template> <div class="app-container"> 课程列表 <!--查询表单--> <el-form :inline="true" class="demo-form-inline"> <el-form-item> <el-input v-model="courseQuery.title" placeholder="课程名称" /> </el-form-item> <el-form-item> <el-select v-model="courseQuery.status" clearable placeholder="课程状态" > <el-option value="Normal" label="已发布" /> <el-option value="Draft" label="未发布" /> </el-select> </el-form-item> <el-button type="primary" icon="el-icon-search" @click="getList()" >查询</el-button > <el-button type="default" @click="resetData()">清空</el-button> </el-form> <!-- 表格 --> <el-table :data="list" border fit highlight-current-row> <el-table-column label="序号" width="70" align="center"> <template slot-scope="scope"> {{ (page - 1) * limit + scope.$index + 1 }} </template> </el-table-column> <el-table-column prop="title" label="课程名称" width="80" /> <el-table-column label="课程状态" width="80"> <template slot-scope="scope"> {{ scope.row.status === "Normal" ? "已发布" : "未发布" }} </template> </el-table-column> <el-table-column prop="lessonNum" label="课时数" /> <el-table-column prop="gmtCreate" label="添加时间" width="160" /> <el-table-column prop="viewCount" label="浏览数量" width="60" /> <el-table-column label="操作" width="200" align="center"> <template slot-scope="scope"> <router-link :to="'/teacher/edit/' + scope.row.id"> <el-button type="primary" size="mini" icon="el-icon-edit" >编辑课程基本信息</el-button > </router-link> <router-link :to="'/teacher/edit/' + scope.row.id"> <el-button type="primary" size="mini" icon="el-icon-edit" >编辑课程大纲息</el-button > </router-link> <el-button type="danger" size="mini" icon="el-icon-delete" @click="removeDataById(scope.row.id)" >删除课程信息</el-button > </template> </el-table-column> </el-table> <!-- 分页 --> <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> <script> // 引入调用teacher.js文件 import courseApi from '@/api/edu/course' export default { data() { return { list: null, // 查询之后接口返回集合(注意这里是数组用null) page: 1, // 当前页 limit: 10, // 每页记录数 total: 0, // 总记录数 courseQuery: {} // 条件封装对象 } }, created() { // 页面渲染之前执行,一般调用methods定义的方法 // 调用 this.getList() }, methods: { getList() { courseApi.getCourseList().then(response => { // 请求成功 // response接口返回的数据 this.list = response.data.courseList }) }, resetData() { // 表单输入项数据清空 this.courseQuery = {} this.getList() } } } </script>
课程删除(后端+前端)
删除课程:所有章节也会被删除
后端 controller 1 2 3 4 5 6 @DeleteMapping("{courseId}") public R deleteCourse (@PathVariable String courseId) { courseService.deleteCourse(courseId); return R.ok(); }
service 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public void deleteCourse (String courseId) { videoService.removeByCourseId(courseId); chapterService.removeByCourseId(courseId); descriptionService.removeById(courseId); int row = baseMapper.deleteById(courseId); if (row == 0 ) { throw new GuliException(20001 , "删除课程失败" ); } }
1 2 3 4 5 6 7 @Override public void removeByCourseId (String courseId) { QueryWrapper<EduChapter> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("course_id" , courseId); baseMapper.delete(queryWrapper); }
前端 api 1 2 3 4 5 6 7 deleteCourse (courseId ) { return request({ url : `/eduservice/course/` + courseId, method : 'delete' , }) },
vue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 deleteCourse (courseId ) { courseApi .deleteCourse(courseId) .then(result => { this .$message({ type : 'success' , message : '删除成功!' }) this .getList() }) .catch(err => { this .$message({ type : 'error' , message : '删除失败!' }) }) }
阿里云视频点播
视频点播_音视频点播解决方案_视频转码_媒体资源管理系统-阿里云 (aliyun.com)
视频点播 (aliyun.com)
环境搭建
依赖见官网(项目环境搭建的时候已经引入了)
创建模块
子子模块service_vod
引入依赖
注意这个aliyun-java-vod-upload.version依赖未开源,需要手动下载jar包,然后使用命令行安装
mvn install:install-file -DgroupId=com.aliyun -DartifactId=aliyun-java-vod-upload -Dversion=1.4.11 -Dpackaging=jar -Dfile=aliyun-java-vod-upload-1.4.14.jar
注意这里的版本要和下载的jar包对应,还有包名aliyun-java-vod-upload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <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-java-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 >
测试 根据视频id获取视频播放地址 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class TestVod { public static void main (String[] args) throws ClientException { DefaultAcsClient client = InitObject.initVodClient("" , "" ); GetPlayInfoRequest request = new GetPlayInfoRequest(); request.setVideoId("" ); GetPlayInfoResponse acsResponse = client.getAcsResponse(request); List<GetPlayInfoResponse.PlayInfo> playInfoList = acsResponse.getPlayInfoList(); for (GetPlayInfoResponse.PlayInfo playInfo : playInfoList) { System.out.print("PlayInfo.PlayURL = " + playInfo.getPlayURL() + "\n" ); } System.out.print("VideoBase.Title = " + acsResponse.getVideoBase().getTitle() + "\n" ); System.out.println(acsResponse); } }
根据视频id获取视频播放凭证 1 2 3 4 5 6 7 8 9 10 11 12 public static void main (String[] args) throws ClientException { DefaultAcsClient client = InitObject.initVodClient("" , "" ); GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest(); request.setVideoId("" ); GetVideoPlayAuthResponse acsResponse = client.getAcsResponse(request); System.out.println("视频凭证: " + acsResponse.getPlayAuth()); }
上传视频
这里注意,如果使用upload的版本为1.4.14,那么根据官方文档说明,oss-sdk的版本必须为3.9及以上,否则会显示一直上传中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public static void main (String[] args) throws ClientException { String accessKeyId = "" ; String accessKeySecret = "" ; String title = "6 - What If I Want to Move Faster - upload by sdk" ; String fileName = "D:/MyProject/6 - What If I Want to Move Faster.mp4" ; UploadVideoRequest request = new UploadVideoRequest(accessKeyId, accessKeySecret, title, fileName); request.setPartSize(2 * 1024 * 1024L ); request.setTaskNum(1 ); UploadVideoImpl uploader = new UploadVideoImpl(); UploadVideoResponse response = uploader.uploadVideo(request); if (response.isSuccess()) { System.out.print("VideoId=" + response.getVideoId() + "\n" ); } else { System.out.print("VideoId=" + response.getVideoId() + "\n" ); System.out.print("ErrorCode=" + response.getCode() + "\n" ); System.out.print("ErrorMessage=" + response.getMessage() + "\n" ); } }
课程增加、删除小节(视频)功能(完善) 后端 配置文件application.properties 1 2 3 4 5 6 7 8 9 10 11 12 13 14 server.port =8003 spring.application.name =service-vod spring.profiles.active =dev aliyun.vod.file.keyid =aliyun.vod.file.keysecret =spring.servlet.multipart.max-file-size =1024MB spring.servlet.multipart.max-request-size =1024MB
编写常量类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Component public class ConstantVodUtils implements InitializingBean { @Value("${aliyun.vod.file.keyid}") private String keyid; @Value("${aliyun.vod.file.keysecret}") private String keysecret; public static String ACCESS_KEY_SECRET; public static String ACCESS_KEY_ID; @Override public void afterPropertiesSet () throws Exception { ACCESS_KEY_ID = keyid; ACCESS_KEY_SECRET = keysecret; } }
编写初始化VodClient 1 2 3 4 5 6 7 8 9 10 11 @Component public class InitVodClient { 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; } }
创建启动类 1 2 3 4 5 6 7 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @ComponentScan(basePackages = {"com.atguigu"}) public class VodApplication { public static void main (String[] args) { SpringApplication.run(VodApplication.class, args); } }
编写controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @RestController @RequestMapping("/eduvod/video") @CrossOrigin public class VodController { @Autowired private VodService vodService; @PostMapping("uploadVideo") public R uploadVideo (MultipartFile file) { String videoId = vodService.uploadVideo(file); return R.ok(); } @DeleteMapping("removeVideo/{videoId}") public R removeVideo (@PathVariable String videoId) { vodService.removeVideo(videoId); return R.ok(); } }
编写service 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 @Service public class VodServiceImpl implements VodService { @Override public String uploadVideo (MultipartFile file) { try { String fileName = file.getOriginalFilename(); String title = fileName.substring(0 , fileName.lastIndexOf("." )); 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 { System.out.print("VideoId=" + response.getVideoId() + "\n" ); System.out.print("ErrorCode=" + response.getCode() + "\n" ); System.out.print("ErrorMessage=" + response.getMessage() + "\n" ); } return videoId; } catch (Exception e) { e.printStackTrace(); return null ; } } @Override public void removeVideo (String videoId) { try { DefaultAcsClient client = InitVodClient.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET); DeleteVideoRequest request = new DeleteVideoRequest(); request.setVideoIds(videoId); DeleteVideoResponse acsResponse = client.getAcsResponse(request); } catch (Exception e) { e.printStackTrace(); throw new GuliException(20001 , "删除视频失败" ); } } }
前端 api 1 2 3 4 5 6 7 deleteVideoAli(videoId) { return request({ url: `/eduvod/video/removeVideo/` + videoId, method: 'delete' , }) }
vue模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <el-upload :on-success ="handleVodUploadSuccess" :on-remove ="handleVodRemove" :before-remove ="beforeVodRemove" :on-exceed ="handleUploadExceed" :file-list ="fileList" :action ="BASE_API+'/eduvod/video/uploadVideo'" :limit ="1" class ="upload-demo" > <el-button size ="small" type ="primary" > 上传视频</el-button > <el-tooltip placement ="right-end" > <div slot ="content" > 最大支持1G,<br > 支持3GP、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 等视频格式上传</div > <i class ="el-icon-question" /> </el-tooltip > </el-upload >
调用方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 beforeVodRemove (file, fileList ) { return this .$confirm(`确定移除${file.name} ?` ) }, handleVodRemove ( ) { videoApi.deleteVideoAli(this .video.videoSourceId).then(result => { this .$message({ type : 'success' , message : '删除成功!' }) this .fileList = [] this .video.videoSourceId = '' }) }, handleVodUploadSuccess (response, file, fileList ) { this .video.videoSourceId = response.data.videoId }, handleUploadExceed ( ) { this .$message.warning('想要重新上传视频,请先删除已上传的视频' ) },
测试
注意这里,要修改nginx的上传文件大小
1 2 3 4 5 http { include mime.types; default_type application/octet-stream; client_max_body_size 1024m; }
由于controller中返回data只有videoId,所以从后端拿不到原始文件吗,所以从前端赋值即可
删除视频后要清空sourceId,要不然不上传视频也有id存留
springcloud微服务(删除小节功能完善) springcloud
服务集合,TODO
springcloud调用接口过程
Nacos服务注册
注册中心
home (nacos.io)
启动
下载并解压,然后启动startup.cmd即可,可能会启动失败,需要修改MODE为standalone
Nacos 启动失败_RookieMZL 的博客-CSDN博客_nacos启动失败
依赖
先引入依赖
1 2 3 4 5 <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-nacos-discovery</artifactId > </dependency >
配置
在要注册的服务的配置文件application.properties中配置
1 2 spring.cloud.nacos.discovery.server-addr =127.0.0.1:8848
注解
在启动类上添加注解
1 2 3 4 5 6 @EnableDiscoveryClient public class EduApplication { public static void main (String[] args) { SpringApplication.run(EduApplication.class, args); } }
测试
致命bug,springboot的版本要2.2.x才行,要不然application启动不起来
http://localhost:8848/nacos
Feign服务调用
前提条件:将互相调用的服务在nacos注册完毕
依赖 1 2 3 4 5 <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-openfeign</artifactId > </dependency >
添加注解
在需要调用服务的启动类上添加注解如下
1 2 3 4 5 6 7 8 9 @SpringBootApplication @ComponentScan(basePackages = {"com.atguigu"}) @EnableDiscoveryClient @EnableFeignClients public class EduApplication { public static void main (String[] args) { SpringApplication.run(EduApplication.class, args); } }
创建接口
在调用端创建接口,使用注解指定需要调用哪一个服务,并定义调用的方法和路径
注意结构(service_edu要调用service_vod的功能)
@ Feignclient注解用于指定从哪个服务中调用功能,名称与被调用的服务名保持致。 @ GetMapping注解用于对被调用的微服务进行地址映射 @ PathVariable注解定要指定参数名称,否则出错 @ Component注解防止,在其他位置注入 Codclient时idea报错
1 2 3 4 5 6 7 8 @FeignClient("service-vod") @Component public interface VodClient { @DeleteMapping("/eduvod/video/removeVideo/{videoId}") public R removeVideo (@PathVariable("videoId") String videoId) ; }
注意这里的@FeignClient(“service-vod”),服务名不能使用下划线
实现调用(删除小节)
注入接口,调用接口方法即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @RestController @RequestMapping("/eduservice/video") @CrossOrigin public class EduVideoController { @Autowired private VodClient vodClient; @DeleteMapping("{videoId}") public R deleteVideo (@PathVariable("videoId") String videoId) { EduVideo eduVideo = videoService.getById(videoId); String videoSourceId = eduVideo.getVideoSourceId(); vodClient.removeVideo(videoSourceId); videoService.removeById(videoId); return R.ok(); } }
如果不成功rerun一下就行了
Hystrix熔断器
提供延迟与容错功能
添加依赖 1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-netflix-ribbon</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-netflix-hystrix</artifactId > </dependency >
调用端配置
注意是在调用端,开启熔断器配置,也可使设置超时时间
1 2 feign.hystrix.enabled =true
创建接口对应实现类
编写出错时的输出信息,实现FeignClient接口
1 2 3 4 5 6 7 8 9 10 11 12 @Component public class VodFileDegradeFeignClient implements VodClient { @Override public R removeVideo (String videoId) { return R.error().message("出错了" ); } @Override public R deleteVideoBatch (List<String> videoIdList) { return R.error().message("出错了" ); } }
接口添加属性
feignClient添加注解和属性
1 2 3 4 5 6 @FeignClient(name = "service-vod", fallback = VodFileDegradeFeignClient.class) @Component public interface VodClient {}
删除课程(功能完善)
删除视频,删除视频下的章节和小节
后端
video中的删除小节功能需要调用vod中的删除
VodController 1 2 3 4 5 6 @DeleteMapping("deleteVideoBatch") public R deleteVideoBatch (@RequestParam("videoIdList") List<String> videoIdList) { vodService.removeBatch(videoIdList); return R.ok(); }
VodService 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Override public void removeVideoBatch (List<String> videoIdList) { try { DefaultAcsClient client = InitVodClient.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET); DeleteVideoRequest request = new DeleteVideoRequest(); String list = StringUtils.join(videoIdList.toArray(), "," ); request.setVideoIds(list); DeleteVideoResponse acsResponse = client.getAcsResponse(request); } catch (Exception e) { e.printStackTrace(); throw new GuliException(20001 , "删除视频失败" ); } }
Feign调用接口
这是service_edu中的
1 2 3 4 5 6 7 8 9 10 11 12 @FeignClient("service-vod") @Component public interface VodClient { @DeleteMapping("/eduvod/video/removeVideo/{videoId}") public R removeVideo (@PathVariable("videoId") String videoId) ; @DeleteMapping("/eduvod/video/deleteVideoBatch") public R deleteVideoBatch (@RequestParam("videoIdList") List<String> videoIdList) ; }
videoMapper 1 2 3 4 5 6 7 8 9 10 11 12 <?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.atguigu.eduservice.mapper.EduVideoMapper" > <select id ="getVideoIdListByCourse" resultType ="java.lang.String" > SELECT video_source_id FROM `edu_video` WHERE course_id = #{courseId} AND video_source_id IS NOT NULL AND video_source_id != ''; </select > </mapper >
videoService 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Service public class EduVideoServiceImpl extends ServiceImpl <EduVideoMapper , EduVideo > implements EduVideoService { @Autowired private VodClient vodClient; @Override public void removeByCourseId (String courseId) { List<String> idList = baseMapper.getVideoIdListByCourse(courseId); vodClient.deleteVideoBatch(idList); QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("course_id" , courseId); baseMapper.delete(wrapper); } }
测试
OK
前端
TODO
注意这里有个问题,由于我确定按钮没有绑定是否能够按下的boolean值,所有在文件上传完成之前按下会没有sourceId,之后再改
待续
后台还有好多TODO和完善,竟然就直接进入前台了,好吧还得靠自己