From 14821e28286d773ad5ff2c13510e39c5eb117daf Mon Sep 17 00:00:00 2001
From: kongzy <kongzy>
Date: Fri, 05 Jul 2024 13:46:32 +0800
Subject: [PATCH] update
---
exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 232 insertions(+), 2 deletions(-)
diff --git a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java
index c09d109..2ee2b25 100644
--- a/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java
+++ b/exam-system/src/main/java/com/gkhy/exam/system/service/impl/SysCommonServiceImpl.java
@@ -1,23 +1,55 @@
package com.gkhy.exam.system.service.impl;
import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.gkhy.exam.common.config.FilePathConfig;
+import com.gkhy.exam.common.enums.ResourceTypeEnum;
import com.gkhy.exam.common.exception.ApiException;
+import com.gkhy.exam.common.utils.*;
+import com.gkhy.exam.system.domain.ExResource;
import com.gkhy.exam.system.domain.vo.UploadObjectVO;
+import com.gkhy.exam.system.mapper.ExResourceMapper;
import com.gkhy.exam.system.service.SysCommonService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
+import javax.annotation.Resource;
import java.io.*;
-import java.util.Date;
-import java.util.UUID;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
@Service
+@Slf4j
public class SysCommonServiceImpl implements SysCommonService {
@Value("${image.upload_image}")
private String uploadPath;
+ @Autowired
+ private M3u8Utils m3u8Utils;
+ @Autowired
+ private MinioUtils minioUtils;
+ @Autowired
+ private ExResourceMapper resourceMapper;
+ @Resource
+ private FilePathConfig filePathConfig;
+
+ // 使用HashSet存储允许的文件格式,提高查找效率
+ private final HashSet<String> FORMATSET = new HashSet<>(Arrays.asList(".mp4", ".mp3", ".xls", ".xlsx", ".doc", ".docx", ".ppt", ".pptx", ".pdf"));
+
+
+ @Resource(name = "threadPoolTaskExecutor")
+ private ThreadPoolTaskExecutor poolTaskExecutor;
@Override
public UploadObjectVO uploadFile(MultipartFile file) {
@@ -44,6 +76,204 @@
}
@Override
+ public String uploadVideo2M3u8(MultipartFile file) throws Exception {
+ String path=m3u8Utils.mediaFileToM3u8(file);
+ String name= upload2M3u8(path,null);
+ if(StringUtils.isBlank(name)){
+ throw new ApiException("文件上传失败");
+ }
+ return name;
+ }
+
+ public String localVideo2M3u8(String path,String mainName) throws Exception {
+ String paths=m3u8Utils.localFileToM3u8(path,mainName);
+ return upload2M3u8(paths,mainName);
+ }
+
+
+ /**
+ * 上传转码后得视频至OSS或minIOn
+ * @param path
+ * @return 路径
+ * @throws Exception
+ */
+ public synchronized String upload2M3u8(String path,String filePrex) throws Exception {
+ //存储转码后文件
+ String realPath = path.substring(0, path.lastIndexOf("/"));
+ log.info("视频解析后的 realPath {}", realPath);
+ String name = path.substring(path.lastIndexOf("/") + 1);
+ log.info("解析后视频 name {}", name);
+ File allFile = new File(realPath);
+ File[] files = allFile.listFiles();
+ if (null == files || files.length == 0) {
+ return null;
+ }
+ List<File> errorFile = new ArrayList<>();
+ long start = System.currentTimeMillis();
+ //替换m3u8文件中的路径
+
+// FileUtil.replaceTextContent(path, name.substring(0, name.lastIndexOf(".")),
+// aliOssProperties.getMyHostUrl() + filePath.getProxy() + patch +
+// name.substring(0, name.lastIndexOf(".")));
+ //开始上传
+ CountDownLatch countDownLatch = new CountDownLatch(files.length);
+ Arrays.stream(files).forEach(li -> poolTaskExecutor.execute(() -> {
+ try (FileInputStream fileInputStream = new FileInputStream(li)) {
+ String objectKey=li.getName();
+ if(StringUtils.isNotBlank(filePrex)){
+ objectKey=filePrex+"/"+li.getName();
+ }
+ minioUtils.fileUploader(objectKey, fileInputStream);
+ log.info("文件:{} 正在上传", li.getName());
+ } catch (Exception e) {
+ errorFile.add(li);
+ log.error("文件:{}上传失败",li.getName());
+ e.printStackTrace();
+ } finally {
+ countDownLatch.countDown();
+ }
+ }));
+ countDownLatch.await();
+ long end = System.currentTimeMillis();
+ log.info("解析文件上传成功,共计:{} 个文件,失败:{},共耗时: {}ms", files.length, errorFile.size(), end - start);
+ //异步移除所有文件
+ poolTaskExecutor.execute(() -> {
+ FileUtil.del(realPath);
+ log.warn("临时目录 {}已删除", realPath);
+ });
+ if (CollectionUtils.isEmpty(errorFile)) {
+ return StringUtils.isNotBlank(filePrex)? filePrex+"/"+name:name;
+ }
+ return "";
+ }
+
+
+ @Override
+ public boolean uploadSlice( String fileMd5, String chunkName, MultipartFile file) {
+ String systemDir=System.getProperty("user.dir");
+ String filePath=systemDir+filePathConfig.getTempPath()+"chunk/"+fileMd5;
+ File dirFile=new File(filePath);
+ if(!dirFile.exists()){
+ dirFile.mkdirs();
+ }
+ filePath=filePath+File.separator+chunkName;
+ try {
+ file.transferTo(new File(filePath));
+ } catch (FileNotFoundException e) {
+ throw new ApiException("找不到文件");
+ } catch (IOException e) {
+ throw new ApiException("发生错误,请联系管理员");
+ }
+ return false;
+ }
+
+
+ @Override
+ public UploadObjectVO uploadMerge(String fileMd5, String fileName) throws Exception {
+ String subfix=fileName.substring(fileName.lastIndexOf("."),fileName.length());
+ checkFileFormat(subfix);
+ UploadObjectVO uploadObjectVO=mergeFile(fileMd5,fileName);
+ String localPath=uploadObjectVO.getPath();
+ String minioPath="";
+ if(".mp4".equalsIgnoreCase(subfix)){
+ String m3u8Path=m3u8Utils.localFileToM3u8(localPath, fileMd5);
+ //计算mp4时长
+ uploadObjectVO.setResourceLength(VideoUtils.getMp4Duration(m3u8Path));
+ uploadObjectVO.setResourceType(ResourceTypeEnum.VIDEO.getCode());
+ minioPath= upload2M3u8(m3u8Path,fileMd5);
+ }else{
+ if(".mp3".equalsIgnoreCase(subfix)){
+ uploadObjectVO.setResourceType(ResourceTypeEnum.AUDIO.getCode());
+ //计算mp3时长
+ uploadObjectVO.setResourceLength(VideoUtils.getMp3Duration(localPath));
+ }else{
+ uploadObjectVO.setResourceType(ResourceTypeEnum.DOC.getCode());
+ //计算文件页数
+ uploadObjectVO.setDocPage(DocUtils.getDocPageCount(fileName,Files.newInputStream(Paths.get(localPath))));
+ }
+ minioPath=minioUtils.fileUploader(uploadObjectVO.getFilename(), Files.newInputStream(Paths.get(localPath)));
+ }
+ if(StringUtils.isBlank(minioPath)){
+ throw new ApiException("上传文件失败");
+ }
+ //移除文件
+ poolTaskExecutor.execute(() -> {
+ FileUtil.del(new File(localPath).getParent());
+ log.warn("临时目录 {}已删除", new File(localPath).getParent());
+ });
+ uploadObjectVO.setPath(minioPath);
+ return uploadObjectVO;
+ }
+
+ private void checkFileFormat(String subfix){
+ if(!FORMATSET.contains(subfix)){
+ throw new ApiException(String.format("文件格式<%s>暂时不支持",subfix));
+ }
+ }
+
+ @Override
+ public void removeMinioFile(Long resourceId,String path) {
+ String md5="";
+ if(path.indexOf("/")!=-1){
+ md5=path.substring(0,path.indexOf("/"));
+ }else{
+ md5=path.substring(0,path.lastIndexOf("."));
+ }
+ LambdaQueryWrapper<ExResource> lambdaQueryWrapper = Wrappers.<ExResource>lambdaQuery().
+ eq(true, ExResource::getMd5, md5);
+ if(resourceId!=null){
+ lambdaQueryWrapper.ne(ExResource::getId,resourceId);
+ }
+ lambdaQueryWrapper.last(" limit 1");
+ ExResource resource=resourceMapper.selectOne(lambdaQueryWrapper);
+ if(resource==null){//不存在共用md5文件
+ //删除minio文件
+ if(path.endsWith(".m3u8")){
+ minioUtils.removeFolder(md5);
+ }else{
+ minioUtils.removeFile(path);
+ }
+ }
+ }
+
+ public UploadObjectVO mergeFile(String fileMd5,String fileName){
+ String subfix = fileName.substring(fileName.lastIndexOf("."));
+ String systemDir=System.getProperty("user.dir");
+ String filePath=systemDir+filePathConfig.getTempPath()+"chunk/"+fileMd5;
+
+ File parentFileDir=new File(filePath);
+ if(!parentFileDir.exists()||!parentFileDir.isDirectory()){
+ throw new ApiException("切片文件合并失败,文件不存在");
+ }
+ String destPath=systemDir+filePathConfig.getTempPath()+fileMd5;
+ File destTempFile=new File(destPath,fileMd5+subfix);
+ if(!destTempFile.exists()){
+ destTempFile.getParentFile().mkdirs();
+ }
+ try{
+ //destTempFile.createNewFile();
+ for(int i=0;i<Objects.requireNonNull(parentFileDir.listFiles()).length;i++){
+ File partFile=new File(parentFileDir,fileMd5+"-"+i);
+ FileOutputStream destTempfos = new FileOutputStream(destTempFile, true);
+ //遍历"所有分片文件"到"最终文件"中
+ FileUtils.copyFile(partFile, destTempfos);
+ destTempfos.close();
+ }
+ FileUtil.del(parentFileDir);
+ }catch (Exception e){
+ log.error("切片文件合并,失败原因e:{}", e.getMessage());
+ throw new ApiException("切片文件合并失败:"+e.getMessage());
+ }
+ UploadObjectVO uploadObjectVO=new UploadObjectVO();
+ uploadObjectVO.setSize(destTempFile.length());
+ uploadObjectVO.setPath(destTempFile.getPath());
+ uploadObjectVO.setOriginName(fileName);
+ uploadObjectVO.setFilename(fileMd5+subfix);
+ uploadObjectVO.setMd5(fileMd5);
+ return uploadObjectVO;
+ }
+
+ @Override
public UploadObjectVO doUpload(MultipartFile file){
String originName=file.getOriginalFilename();
String filename=originName;
--
Gitblit v1.9.2