feat: 🎸 资源接口
This commit is contained in:
parent
a9e3e9146a
commit
e92e6ffeca
@ -32,5 +32,12 @@
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-system-biz</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/ws.schild/jave-all-deps -->
|
||||
<dependency>
|
||||
<groupId>ws.schild</groupId>
|
||||
<artifactId>jave-all-deps</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -0,0 +1,7 @@
|
||||
package org.jeecg.modules.aiol.constant;
|
||||
|
||||
public final class ResourceTypeConst {
|
||||
public static final int VIDEO = 0;
|
||||
public static final int IMAGE = 1;
|
||||
public static final int DOCUMENT = 2;
|
||||
}
|
@ -480,10 +480,10 @@ public class AiolClassController extends JeecgController<AiolClass, IAiolClassSe
|
||||
/**
|
||||
* 新建学生并添加至班级
|
||||
*
|
||||
* 前端传参:realName(姓名)、studentNumber(学号)、password(登录密码,可选)、school(所属学校)、classId(所属班级ID)
|
||||
* 前端传参:realName(姓名)、studentNumber(学号)、password(登录密码,可选)、school(所属学校)、classId(所属班级ID,支持多个,用逗号分割)
|
||||
*/
|
||||
@AutoLog(value = "班级学生-新建学生并添加至班级")
|
||||
@Operation(summary = "新建学生并添加至班级", description = "创建sysUser,保存aiol_user_info的学校信息,并写入aiol_class_student")
|
||||
@Operation(summary = "新建学生并添加至班级", description = "创建sysUser,保存aiol_user_info的学校信息,并写入aiol_class_student。支持多个班级ID,用逗号分割")
|
||||
@PostMapping(value = "/create_and_add_student")
|
||||
public Result<Map<String, Object>> createStudentAndAddToClass(@RequestBody Map<String, Object> body,
|
||||
HttpServletRequest request) {
|
||||
@ -524,17 +524,37 @@ public class AiolClassController extends JeecgController<AiolClass, IAiolClassSe
|
||||
aiolUserInfoService.save(userInfo);
|
||||
|
||||
// 3) 写入班级关系 aiol_class_student
|
||||
// 支持多个班级ID,用逗号分割
|
||||
String[] classIds = classId.split(",");
|
||||
int successCount = 0;
|
||||
int skipCount = 0;
|
||||
|
||||
for (String singleClassId : classIds) {
|
||||
if (singleClassId == null || singleClassId.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
singleClassId = singleClassId.trim();
|
||||
|
||||
// 检查是否已存在关系,避免重复
|
||||
QueryWrapper<AiolClassStudent> checkWrapper = new QueryWrapper<>();
|
||||
checkWrapper.eq("class_id", classId).eq("student_id", created.getId());
|
||||
checkWrapper.eq("class_id", singleClassId).eq("student_id", created.getId());
|
||||
AiolClassStudent exist = aiolClassStudentService.getOne(checkWrapper);
|
||||
|
||||
if (exist == null) {
|
||||
AiolClassStudent relation = new AiolClassStudent();
|
||||
relation.setClassId(classId);
|
||||
relation.setClassId(singleClassId);
|
||||
relation.setStudentId(created.getId());
|
||||
relation.setCreateBy(sysUser.getUsername());
|
||||
relation.setCreateTime(new Date());
|
||||
aiolClassStudentService.save(relation);
|
||||
boolean saved = aiolClassStudentService.save(relation);
|
||||
if (saved) {
|
||||
successCount++;
|
||||
log.info("成功将学生 {} 添加到班级 {}", created.getUsername(), singleClassId);
|
||||
}
|
||||
} else {
|
||||
skipCount++;
|
||||
log.info("学生 {} 已在班级 {} 中,跳过", created.getUsername(), singleClassId);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> resp = new HashMap<>();
|
||||
@ -542,6 +562,9 @@ public class AiolClassController extends JeecgController<AiolClass, IAiolClassSe
|
||||
resp.put("username", created.getUsername());
|
||||
resp.put("classId", classId);
|
||||
resp.put("school", school);
|
||||
resp.put("totalClassCount", classIds.length);
|
||||
resp.put("successCount", successCount);
|
||||
resp.put("skipCount", skipCount);
|
||||
|
||||
return Result.OK(resp);
|
||||
} catch (Exception e) {
|
||||
|
@ -2,18 +2,28 @@ package org.jeecg.modules.aiol.controller;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.system.query.QueryRuleEnum;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.common.util.MinioUtil;
|
||||
import org.jeecg.common.util.oss.OssBootUtil;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.config.shiro.IgnoreAuth;
|
||||
import org.jeecg.modules.aiol.constant.EntityLinkConst;
|
||||
import org.jeecg.modules.aiol.constant.ResourceTypeConst;
|
||||
import org.jeecg.modules.aiol.entity.AiolResource;
|
||||
import org.jeecg.modules.aiol.service.IAiolEntityLinkService;
|
||||
import org.jeecg.modules.aiol.service.IAiolResourceService;
|
||||
@ -22,6 +32,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ws.schild.jave.MultimediaObject;
|
||||
import ws.schild.jave.info.MultimediaInfo;
|
||||
|
||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
||||
@ -222,11 +234,235 @@ public class AiolResourceController extends JeecgController<AiolResource, IAiolR
|
||||
return Result.OK(list);
|
||||
}
|
||||
|
||||
@PostMapping("/upload")
|
||||
@Operation(summary = "课程视频文件上传", description = "课程视频文件上传,返回各清晰度的m3u8文件地址")
|
||||
public Result<Map<String, String>> upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {
|
||||
if (file == null || file.isEmpty()) return Result.error("没有找到上传的文件");
|
||||
@PostMapping("/video_upload")
|
||||
@Operation(summary = "课程视频文件上传", description = "课程视频文件上传,创建资源记录并关联到课程")
|
||||
public Result<Map<String, Object>> upload(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("courseId") String courseId,
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam(value = "description", required = false) String description,
|
||||
HttpServletRequest request) throws Exception {
|
||||
|
||||
if (file == null || file.isEmpty()) {
|
||||
return Result.error("没有找到上传的文件");
|
||||
}
|
||||
|
||||
if (courseId == null || courseId.trim().isEmpty()) {
|
||||
return Result.error("课程ID不能为空");
|
||||
}
|
||||
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
return Result.error("视频名称不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 上传视频文件,获取各清晰度的m3u8地址
|
||||
Map<String, String> qualityUrls = aiolResourceService.uploadHls(file, request);
|
||||
return Result.OK(qualityUrls);
|
||||
|
||||
// 2. 将m3u8地址用逗号拼接成字符串
|
||||
String fileUrl = String.join(",", qualityUrls.values());
|
||||
|
||||
// 3. TODO 获取视频时长和文件大小
|
||||
Integer duration = (int) 0;
|
||||
Integer fileSize = (int) file.getSize();
|
||||
|
||||
// 4. 创建资源记录
|
||||
AiolResource resource = new AiolResource();
|
||||
resource.setName(name.trim());
|
||||
resource.setDescription(description != null ? description.trim() : "");
|
||||
resource.setType(ResourceTypeConst.VIDEO);
|
||||
resource.setFileUrl(fileUrl);
|
||||
resource.setDuration(duration);
|
||||
resource.setFileSize(fileSize);
|
||||
|
||||
// 5. 保存资源记录
|
||||
boolean saved = aiolResourceService.save(resource);
|
||||
if (!saved) {
|
||||
return Result.error("保存资源记录失败");
|
||||
}
|
||||
|
||||
// 6. 创建课程与资源的关联关系
|
||||
entityLinkBizService.save(
|
||||
EntityLinkConst.SourceType.COURSE,
|
||||
courseId,
|
||||
EntityLinkConst.TargetType.RESOURCE,
|
||||
resource.getId()
|
||||
);
|
||||
|
||||
log.info("视频上传成功: resourceId={}, courseId={}, name={}",
|
||||
resource.getId(), courseId, name);
|
||||
|
||||
return Result.OK(resource.getId());
|
||||
} catch (Exception e) {
|
||||
log.error("视频上传失败: courseId={}, name={}, error={}",
|
||||
courseId, name, e.getMessage(), e);
|
||||
return Result.error("视频上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/document_upload")
|
||||
@Operation(summary = "课程文档文件上传", description = "上传文档文件并关联到课程,支持word、ppt、excel、pdf、txt、markdown等格式")
|
||||
public Result<String> uploadDocument(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("courseId") String courseId,
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam(value = "description", required = false) String description,
|
||||
HttpServletRequest request) throws Exception {
|
||||
|
||||
if (file == null || file.isEmpty()) {
|
||||
return Result.error("没有找到上传的文件");
|
||||
}
|
||||
|
||||
if (courseId == null || courseId.trim().isEmpty()) {
|
||||
return Result.error("课程ID不能为空");
|
||||
}
|
||||
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
return Result.error("文档名称不能为空");
|
||||
}
|
||||
|
||||
// 检查文件类型
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
if (originalFilename == null || !isValidDocumentType(originalFilename)) {
|
||||
return Result.error("不支持的文件类型,仅支持word、ppt、excel、pdf、txt、markdown等格式");
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 上传文档文件
|
||||
String fileUrl = uploadDocumentFile(file, request);
|
||||
|
||||
// 2. 获取文件大小
|
||||
Integer fileSize = (int) file.getSize();
|
||||
|
||||
// 3. 创建资源记录
|
||||
AiolResource resource = new AiolResource();
|
||||
resource.setName(name.trim());
|
||||
resource.setDescription(description != null ? description.trim() : "");
|
||||
resource.setType(ResourceTypeConst.DOCUMENT); // 2:文档
|
||||
resource.setFileUrl(fileUrl);
|
||||
resource.setFileSize(fileSize);
|
||||
|
||||
// 4. 保存资源记录
|
||||
boolean saved = aiolResourceService.save(resource);
|
||||
if (!saved) {
|
||||
return Result.error("保存资源记录失败");
|
||||
}
|
||||
|
||||
// 5. 创建课程与资源的关联关系
|
||||
entityLinkBizService.save(
|
||||
EntityLinkConst.SourceType.COURSE,
|
||||
courseId,
|
||||
EntityLinkConst.TargetType.RESOURCE,
|
||||
resource.getId()
|
||||
);
|
||||
|
||||
log.info("文档上传成功: resourceId={}, courseId={}, name={}",
|
||||
resource.getId(), courseId, name);
|
||||
|
||||
return Result.OK(resource.getId());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("文档上传失败: courseId={}, name={}, error={}",
|
||||
courseId, name, e.getMessage(), e);
|
||||
return Result.error("文档上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/course_materials")
|
||||
@Operation(summary = "查询课程课件", description = "根据课程ID、资源分类和资源名关键词查询课程相关资源")
|
||||
@IgnoreAuth
|
||||
public Result<List<AiolResource>> queryCourseMaterials(
|
||||
@RequestParam("courseId") String courseId,
|
||||
@RequestParam(value = "resourceType", required = false) Integer resourceType,
|
||||
@RequestParam(value = "name", required = false) String name) {
|
||||
try {
|
||||
// 1. 根据课程ID查询关联的资源ID列表
|
||||
List<String> resourceIds = entityLinkBizService.listTargetIds(
|
||||
EntityLinkConst.SourceType.COURSE,
|
||||
courseId,
|
||||
EntityLinkConst.TargetType.RESOURCE
|
||||
);
|
||||
|
||||
if (resourceIds.isEmpty()) {
|
||||
return Result.OK(new ArrayList<>());
|
||||
}
|
||||
|
||||
// 2. 根据资源ID列表查询资源详情
|
||||
QueryWrapper<AiolResource> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in("id", resourceIds);
|
||||
|
||||
// 3. 根据资源分类过滤
|
||||
if (resourceType != null) {
|
||||
queryWrapper.eq("type", resourceType);
|
||||
}
|
||||
|
||||
// 4. 根据资源名关键词过滤
|
||||
if (name != null && !name.trim().isEmpty()) {
|
||||
queryWrapper.like("name", name.trim());
|
||||
}
|
||||
|
||||
List<AiolResource> resourceList = aiolResourceService.list(queryWrapper);
|
||||
|
||||
log.info("查询课程课件成功: courseId={}, resourceType={}, name={}, 结果数量={}",
|
||||
courseId, resourceType, name, resourceList.size());
|
||||
|
||||
return Result.OK(resourceList);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("查询课程课件失败: courseId={}, resourceType={}, name={}, error={}",
|
||||
courseId, resourceType, name, e.getMessage(), e);
|
||||
return Result.error("查询课程课件失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为有效的文档类型
|
||||
*/
|
||||
private boolean isValidDocumentType(String filename) {
|
||||
if (filename == null) return false;
|
||||
|
||||
String lowerFilename = filename.toLowerCase();
|
||||
return lowerFilename.endsWith(".doc") || lowerFilename.endsWith(".docx") || // Word
|
||||
lowerFilename.endsWith(".ppt") || lowerFilename.endsWith(".pptx") || // PowerPoint
|
||||
lowerFilename.endsWith(".xls") || lowerFilename.endsWith(".xlsx") || // Excel
|
||||
lowerFilename.endsWith(".pdf") || // PDF
|
||||
lowerFilename.endsWith(".txt") || // Text
|
||||
lowerFilename.endsWith(".md") || lowerFilename.endsWith(".markdown"); // Markdown
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文档文件
|
||||
*/
|
||||
private String uploadDocumentFile(MultipartFile file, HttpServletRequest request) throws Exception {
|
||||
// 读取上传类型
|
||||
String configUploadType = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("jeecg.uploadType", "minio");
|
||||
String uploadType = configUploadType;
|
||||
|
||||
// 生成文件路径
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||||
String fileName = uuid + fileExtension;
|
||||
String relativePath = "document/" + fileName;
|
||||
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
String fileUrl = "";
|
||||
if ("minio".equals(uploadType)) {
|
||||
fileUrl = MinioUtil.upload(inputStream, relativePath);
|
||||
} else if ("alioss".equals(uploadType)) {
|
||||
OssBootUtil.upload(inputStream, relativePath);
|
||||
fileUrl = relativePath; // 可在网关拼域名
|
||||
} else {
|
||||
// 本地存储
|
||||
String uploadpath = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("jeecg.path.upload");
|
||||
Path target = Path.of(uploadpath, relativePath);
|
||||
Files.createDirectories(target.getParent());
|
||||
Files.copy(inputStream, target, StandardCopyOption.REPLACE_EXISTING);
|
||||
fileUrl = relativePath;
|
||||
}
|
||||
|
||||
log.info("文档文件上传成功: originalFilename={}, fileUrl={}", originalFilename, fileUrl);
|
||||
return fileUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user