feature: [课程] 修改和删除课程
This commit is contained in:
parent
520207c8d2
commit
16eb04344b
9
pom.xml
9
pom.xml
|
@ -142,8 +142,6 @@
|
|||
<version>2.15.3</version> <!-- 请使用最新的版本 -->
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
|
@ -228,7 +226,6 @@
|
|||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.arcsoft.face</groupId>
|
||||
<artifactId>arcsoft-sdk-face</artifactId>
|
||||
|
@ -525,6 +522,12 @@
|
|||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ws.schild</groupId>
|
||||
<artifactId>jave-all-deps</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ public class SecurityConstants {
|
|||
|
||||
"/bs/courses/queryByPage",
|
||||
|
||||
"/captcha/verify", //验证码认证接口
|
||||
|
||||
"/challenge",
|
||||
"/ws/**",
|
||||
"/faceTest", "/compareFaces",
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package com.guwan.backend.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/captcha")
|
||||
public class CaptchaController {
|
||||
|
||||
private static final Map<String, String> keyMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
keyMap.put("99c6323b7b65100d4f9ff07b036e57fa", "12e9e88d5cb19d63d44f8d95a21b69b6");
|
||||
}
|
||||
|
||||
@GetMapping("/verify")
|
||||
public ResponseEntity<?> login(@RequestParam Map<String, String> params) {
|
||||
String captchaId = params.get("captcha_id");
|
||||
String lotNumber = params.get("lot_number");
|
||||
|
||||
String prikey = keyMap.get(captchaId);
|
||||
|
||||
if (prikey == null) {
|
||||
return ResponseEntity.ok(Map.of("result", "fail", "reason", "id is not in id pools"));
|
||||
}
|
||||
|
||||
String signToken = generateSignToken(lotNumber, prikey);
|
||||
|
||||
// 构建新的查询参数
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.setAll(params);
|
||||
queryParams.add("sign_token", signToken);
|
||||
|
||||
// 调用 Geetest 接口
|
||||
try {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
URI uri = UriComponentsBuilder.fromHttpUrl("http://gcaptcha4.geetest.com/validate")
|
||||
.queryParams(queryParams)
|
||||
.build()
|
||||
.toUri();
|
||||
//这个url的响应是text/javascript;charset=UTF-8
|
||||
// 不是application/json,RestTemplate 默认的 JSON 转换器(Jackson)不会处理它,就会抛出异常。
|
||||
|
||||
//Map response = restTemplate.getForObject(uri, Map.class);
|
||||
|
||||
String responseStr = restTemplate.getForObject(uri, String.class);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String, Object> responseMap = mapper.readValue(responseStr, new TypeReference<>() {});
|
||||
return ResponseEntity.ok(responseMap);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.ok(Map.of("result", "success", "reason", "request geetest api fail"));
|
||||
}
|
||||
}
|
||||
|
||||
private String generateSignToken(String lotNumber, String privateKey) {
|
||||
try {
|
||||
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec secretKey = new SecretKeySpec(privateKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
|
||||
sha256Hmac.init(secretKey);
|
||||
byte[] hashBytes = sha256Hmac.doFinal(lotNumber.getBytes(StandardCharsets.UTF_8));
|
||||
return HexFormat.of().formatHex(hashBytes); // Java 17+,或者使用 Apache Commons Codec
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to generate sign token", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ package com.guwan.backend.controller;
|
|||
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.guwan.backend.common.Result;
|
||||
import com.guwan.backend.common.SearchResult;
|
||||
|
@ -18,6 +20,7 @@ import com.guwan.backend.service.*;
|
|||
import com.guwan.backend.util.MinioUtil;
|
||||
import com.guwan.backend.util.PPTUtil;
|
||||
import com.guwan.backend.util.UUIDUtil;
|
||||
import com.guwan.backend.util.VideoDurationUtils;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
|
@ -211,6 +214,104 @@ public class CourseController {
|
|||
section.setType(sectionVO.getType());
|
||||
section.setUrl(sectionVO.getUrl());
|
||||
section.setOrderNumber(j + 1);
|
||||
|
||||
if (Objects.equals(sectionVO.getType(), "video")){
|
||||
long videoDuration = VideoDurationUtils.getVideoDuration(sectionVO.getUrl());
|
||||
section.setDuration((int) videoDuration);
|
||||
}
|
||||
|
||||
sectionService.save(section);
|
||||
|
||||
if (Objects.equals(sectionVO.getType(), "ppt")){
|
||||
try {
|
||||
List<String> urlList = pptUtil.PPTToImageConverter(sectionVO.getUrl());
|
||||
|
||||
for (int k = 0; k < urlList.size(); k++) {
|
||||
Slide slide = new Slide();
|
||||
slide.setId(UUIDUtil.uuid());
|
||||
slide.setSectionId(sectionId);
|
||||
slide.setUrl(minioUtil.getUrl(minioUtil.getFileUrl("photo", urlList.get(k))));
|
||||
slide.setOrderNumber(k + 1);
|
||||
slideService.save(slide);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@PostMapping("/updateCourse")
|
||||
public Result updateCourse(@RequestBody InsertCourseDTO insertCourseDTO) {
|
||||
System.out.println("insertCourseDTO = " + insertCourseDTO);
|
||||
|
||||
String courseDTOId = insertCourseDTO.getId();
|
||||
|
||||
Course course = courseService.getById(courseDTOId);
|
||||
|
||||
BeanUtils.copyProperties(insertCourseDTO, course);
|
||||
course.setId(courseDTOId);
|
||||
courseService.update(course, new LambdaUpdateWrapper<Course>().eq(Course::getId, courseDTOId));
|
||||
|
||||
List<ChapterVO> chapterVOS = insertCourseDTO.getChapterVOS();
|
||||
//全删 TODO 优化
|
||||
List<String> chapterIds = null;
|
||||
if (!chapterVOS.isEmpty()) {
|
||||
chapterIds = chapterVOS.stream().map(ChapterVO::getId).toList();
|
||||
}
|
||||
|
||||
chapterService.remove(new LambdaQueryWrapper<Chapter>().eq(Chapter::getCourseId, courseDTOId));
|
||||
|
||||
if (chapterIds != null && !chapterIds.isEmpty()) {
|
||||
List<Section> sectionList = sectionService.list(new LambdaQueryWrapper<Section>().in(Section::getChapterId, chapterIds));
|
||||
|
||||
List<String> sectionIds = null;
|
||||
if (!sectionList.isEmpty()) {
|
||||
sectionIds = sectionList.stream().map(Section::getId).toList();
|
||||
}
|
||||
|
||||
sectionService.remove(new LambdaQueryWrapper<Section>().in(Section::getChapterId, chapterIds));
|
||||
|
||||
if (sectionIds != null && !sectionIds.isEmpty()) {
|
||||
slideService.remove(new LambdaQueryWrapper<Slide>().in(Slide::getSectionId, sectionIds));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < chapterVOS.size(); i++) {
|
||||
ChapterVO chapterVO = chapterVOS.get(i);
|
||||
Chapter chapter = new Chapter();
|
||||
String chapterId = UUIDUtil.uuid();
|
||||
chapter.setId(chapterId);
|
||||
chapter.setCourseId(courseDTOId);
|
||||
chapter.setTitle(chapterVO.getTitle());
|
||||
chapter.setOrderNumber(i);
|
||||
chapterService.save(chapter);
|
||||
|
||||
List<BaseSectionVO> sectionVOS = chapterVO.getSectionVOS();
|
||||
|
||||
for (int j = 0; j < sectionVOS.size(); j++) {
|
||||
BaseSectionVO sectionVO = sectionVOS.get(j);
|
||||
String sectionId = UUIDUtil.uuid();
|
||||
Section section = new Section();
|
||||
section.setId(sectionId);
|
||||
section.setChapterId(chapterId);
|
||||
section.setTitle(sectionVO.getTitle());
|
||||
section.setType(sectionVO.getType());
|
||||
section.setUrl(sectionVO.getUrl());
|
||||
section.setOrderNumber(j + 1);
|
||||
//根据url 得到视频时长
|
||||
if (Objects.equals(sectionVO.getType(), "video")){
|
||||
long videoDuration = VideoDurationUtils.getVideoDuration(sectionVO.getUrl());
|
||||
section.setDuration((int) videoDuration);
|
||||
}
|
||||
|
||||
sectionService.save(section);
|
||||
|
||||
if (Objects.equals(sectionVO.getType(), "ppt")) {
|
||||
|
@ -239,5 +340,15 @@ public class CourseController {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@Transactional
|
||||
@PostMapping("/deleteCourse")
|
||||
public Result deleteCourse(@RequestParam String courseId) {
|
||||
|
||||
courseService.remove(new LambdaQueryWrapper<Course>().eq(Course::getId, courseId));
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -4,16 +4,19 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
import com.guwan.backend.pojo.response.courseDetail.ChapterVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class InsertCourseDTO {
|
||||
private String id;
|
||||
private String title;
|
||||
private String description;
|
||||
private String categoryId;
|
||||
private String levelId;
|
||||
private String typeId;
|
||||
private String teacherId;
|
||||
private BigDecimal price;
|
||||
private String coverImg;
|
||||
@JsonProperty("chapters")
|
||||
private List<ChapterVO> chapterVOS;
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class CourseDetailVO {
|
||||
private String id;
|
||||
/**
|
||||
* 课程标题
|
||||
*/
|
||||
|
|
|
@ -72,6 +72,7 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
|||
System.out.println("course = " + course);
|
||||
|
||||
CourseDetailVO courseDetailVO = new CourseDetailVO();
|
||||
courseDetailVO.setId(course.getId());
|
||||
courseDetailVO.setTitle(course.getTitle());
|
||||
courseDetailVO.setDescription(course.getDescription());
|
||||
courseDetailVO.setCategoryName(bsCategoryMapper.selectById(course.getCategoryId()).getChineseName());
|
||||
|
@ -118,9 +119,10 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
|||
List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>().eq(Chapter::getCourseId, courseId));
|
||||
|
||||
List<String> chapterIds = chapters.stream().map(Chapter::getId).toList();
|
||||
//TODO
|
||||
List<Section> sections = sectionMapper.selectList(new LambdaQueryWrapper<Section>().in(Section::getChapterId, chapterIds));
|
||||
// 注意!当集合为 空或null 时, sql会拼接为:WHERE (字段名 IN ()), 执行时报错
|
||||
|
||||
if (!chapterIds.isEmpty()) {
|
||||
List<Section> sections = sectionMapper.selectList(new LambdaQueryWrapper<Section>().in(Section::getChapterId, chapterIds));
|
||||
int videoCount = 0;
|
||||
|
||||
int docCount = 0;
|
||||
|
@ -142,6 +144,7 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
|||
courseDetailVO.setDocCount(docCount);
|
||||
|
||||
courseDetailVO.setTotalDuration(totalTimeOfMinute / 60);
|
||||
}
|
||||
|
||||
|
||||
UserCourseRegistration userCourseRegistration = userCourseRegistrationMapper.selectOne(new LambdaQueryWrapper<UserCourseRegistration>()
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package com.guwan.backend.util;
|
||||
|
||||
import com.guwan.backend.core.exception.ServiceException;
|
||||
import ws.schild.jave.EncoderException;
|
||||
import ws.schild.jave.MultimediaObject;
|
||||
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class VideoDurationUtils {
|
||||
|
||||
/**
|
||||
* 获取视频时长
|
||||
*/
|
||||
public static long getVideoDuration(String videoFilePath) {
|
||||
try {
|
||||
URL url = new URL(videoFilePath);
|
||||
MultimediaObject multimediaObject = new MultimediaObject(url);
|
||||
long duration = (multimediaObject.getInfo().getDuration()) / 1000 / 60;
|
||||
System.out.println(duration + "分钟");
|
||||
return duration;
|
||||
} catch (EncoderException | MalformedURLException e) {
|
||||
throw new ServiceException("" + e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
getVideoDuration("http://localhost:9000/file/courseSource/4b0445fb-7d47-45ea-a8f8-fa9f2fa108bd.mp4");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue