package com.gkhy.exam.system.service.impl;
|
|
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.io.FileUtil;
|
import com.alibaba.excel.EasyExcel;
|
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.config.MinioConfig;
|
import com.gkhy.exam.common.domain.entity.SysUser;
|
import com.gkhy.exam.common.enums.ResourceTypeEnum;
|
import com.gkhy.exam.common.enums.UserTypeEnum;
|
import com.gkhy.exam.common.excel.StudentExcelData;
|
import com.gkhy.exam.common.excel.StudentExcelDataListener;
|
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.ExStudent;
|
import com.gkhy.exam.system.domain.SysCompany;
|
import com.gkhy.exam.system.domain.vo.UploadObjectVO;
|
import com.gkhy.exam.system.mapper.ExResourceMapper;
|
import com.gkhy.exam.system.service.ExStudentService;
|
import com.gkhy.exam.system.service.SysCommonService;
|
import com.gkhy.exam.system.service.SysCompanyService;
|
import com.gkhy.exam.system.service.SysUserService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.io.FileUtils;
|
import org.springframework.beans.BeanUtils;
|
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.transaction.annotation.Transactional;
|
import org.springframework.util.CollectionUtils;
|
import org.springframework.web.multipart.MultipartFile;
|
import sun.misc.BASE64Decoder;
|
|
import javax.annotation.Resource;
|
import java.io.*;
|
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 {
|
|
@Autowired
|
private MinioConfig minioConfig;
|
|
@Value("${image.upload_image}")
|
private String uploadPath;
|
@Autowired
|
private M3u8Utils m3u8Utils;
|
@Autowired
|
private MinioUtils minioUtils;
|
@Autowired
|
private ExResourceMapper resourceMapper;
|
@Resource
|
private FilePathConfig filePathConfig;
|
@Autowired
|
private SysCompanyService companyService;
|
@Autowired
|
private ExStudentService studentService;
|
@Autowired
|
private SysUserService userService;
|
|
// 使用HashSet存储允许的文件格式,提高查找效率
|
private final HashSet<String> FORMATSET = new HashSet<>(Arrays.asList(".mp4",".doc", ".docx", ".ppt", ".pptx", ".pdf"));
|
|
|
@Resource(name = "threadPoolTaskExecutor")
|
private ThreadPoolTaskExecutor poolTaskExecutor;
|
|
@Override
|
public UploadObjectVO uploadFile(MultipartFile file) {
|
if(file==null){
|
throw new ApiException("上传文件不能为空");
|
}
|
UploadObjectVO uploadObjectVO=doUpload(file);
|
return uploadObjectVO;
|
}
|
|
@Override
|
public boolean removeFile(String path) {
|
String systemDir=System.getProperty("user.dir");
|
String filePath=systemDir+File.separator+path;
|
File dirFile=new File(filePath);
|
if(!dirFile.exists()){
|
throw new ApiException("文件不存在");
|
}
|
if(!dirFile.isFile()){
|
throw new ApiException("非文件,不能删除");
|
}
|
dirFile.delete();
|
return true;
|
}
|
|
@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);
|
uploadObjectVO.setUrl(minioConfig.getEndpoint()+minioConfig.getBucketName()+"/"+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);
|
}
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = RuntimeException.class)
|
public void importStudent() {
|
String path="/home/java/multi_system/back/安全教育学员模板.xlsx";
|
// String path="F:/kzy/乱七八糟/安全教育学员模板.xlsx";
|
List<StudentExcelData> studentExcelDataList=EasyExcel.read(path, StudentExcelData.class,new StudentExcelDataListener()).sheet().doReadSync();
|
List<ExStudent> students=new ArrayList<>();
|
List<StudentExcelData> errorStudents=new ArrayList<>();
|
SysCompany company=companyService.getOne(Wrappers.<SysCompany>lambdaQuery().eq(SysCompany::getName,studentExcelDataList.get(0).getCompanyName())
|
.eq(SysCompany::getDelFlag,0));
|
if(company==null){
|
throw new ApiException("公司不存在");
|
}
|
for(StudentExcelData studentExcelData:studentExcelDataList){
|
String errorMessage=validateData(studentExcelData);
|
if(StringUtils.isNotBlank(errorMessage)){
|
studentExcelData.setRemark(errorMessage);
|
errorStudents.add(studentExcelData);
|
continue;
|
}
|
ExStudent dbStudent=studentService.getOne(Wrappers.<ExStudent>lambdaQuery().eq(ExStudent::getPhone,studentExcelData.getPhone()));
|
if(dbStudent!=null){
|
if(!dbStudent.getName().equals(studentExcelData.getName())){
|
studentExcelData.setRemark("序号"+studentExcelData.getIndex()+"学员用户已存在");
|
errorStudents.add(studentExcelData);
|
}
|
continue;
|
}
|
ExStudent student=new ExStudent();
|
BeanUtils.copyProperties(studentExcelData,student,new String[]{"sex"});
|
if("男".equals(studentExcelData.getSex())){
|
student.setSex(0);
|
}else{
|
student.setSex(1);
|
}
|
String departName=studentExcelData.getDeptName();
|
|
List<SysUser> users=userService.list(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getName,departName).eq(SysUser::getUserType, UserTypeEnum.DEPART_USER.getCode()).eq(SysUser::getDelFlag,0).last(" limit 1"));
|
if(users.isEmpty()){
|
studentExcelData.setRemark("序号"+studentExcelData.getIndex()+"未找到相应的部门账号");
|
errorStudents.add(studentExcelData);
|
continue;
|
}
|
|
student.setPassword(SecurityUtils.encryptPassword("123456@a"));
|
student.setCompanyId(company.getId());
|
student.setCreateId(users.get(0).getId());
|
students.add(student);
|
}
|
if(!errorStudents.isEmpty()){
|
EasyExcel.write("error.xlsx").head(StudentExcelData.class)
|
.sheet("异常用户列表")
|
.doWrite(errorStudents);
|
}
|
studentService.saveBatch(students);
|
}
|
|
|
|
|
|
public String validateData(StudentExcelData studentExcelData){
|
if(StringUtils.isBlank(studentExcelData.getName())){
|
return "序号"+studentExcelData.getIndex()+"姓名为空";
|
}
|
if(StringUtils.isBlank(studentExcelData.getSex())){
|
return "序号"+studentExcelData.getIndex()+"性别为空";
|
}
|
if(StringUtils.isBlank(studentExcelData.getIdNo())||studentExcelData.getIdNo().length()!=18){
|
return "序号"+studentExcelData.getIndex()+"身份证为空或者长度不正确";
|
}
|
if(StringUtils.isBlank(studentExcelData.getPhone())||studentExcelData.getPhone().length()!=11){
|
return "序号"+studentExcelData.getIndex()+"手机号为空或者长度不正确";
|
}
|
|
if(StringUtils.isBlank(studentExcelData.getDeptName())){
|
return "序号"+studentExcelData.getIndex()+"部门为空";
|
}
|
return "";
|
}
|
|
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;
|
String subfix=filename.substring(filename.lastIndexOf("."));
|
Long size=file.getSize();
|
filename= UUID.randomUUID().toString().replace("-","")+subfix;
|
String systemDir=System.getProperty("user.dir");
|
String dateStr= DateUtil.format(new Date(),"yyyyMMdd");
|
String filePath=uploadPath+File.separator+dateStr;
|
File dirFile=new File(filePath);
|
if(!dirFile.exists()){
|
dirFile.mkdirs();
|
}
|
filePath=filePath+File.separator+filename;
|
try {
|
file.transferTo(new File(systemDir+File.separator+filePath));
|
} catch (FileNotFoundException e) {
|
throw new ApiException("找不到文件");
|
} catch (IOException e) {
|
throw new ApiException("发生错误,请联系管理员");
|
}
|
filePath=filePath.replace("\\","/");
|
UploadObjectVO uploadObjectVO=new UploadObjectVO().setFilename(filename)
|
.setPath(filePath).setOriginName(originName).setSize(size);
|
return uploadObjectVO;
|
}
|
|
@Override
|
public UploadObjectVO doUpload(String imageBase64) {
|
String originName="";
|
String filename=originName;
|
String subfix=".png";
|
filename= UUID.randomUUID().toString().replace("-","")+subfix;
|
String systemDir=System.getProperty("user.dir");
|
String dateStr= DateUtil.format(new Date(),"yyyyMMdd");
|
String filePath=uploadPath+File.separator+dateStr;
|
File dirFile=new File(filePath);
|
if(!dirFile.exists()){
|
dirFile.mkdirs();
|
}
|
filePath=filePath+File.separator+filename;
|
BASE64Decoder decoder = new BASE64Decoder();
|
try {
|
// Base64解码
|
byte[] bytes = decoder.decodeBuffer(imageBase64);
|
for (int i = 0; i < bytes.length; ++i) {
|
if (bytes[i] < 0) {// 调整异常数据
|
bytes[i] += 256;
|
}
|
}
|
// 生成jpeg图片
|
OutputStream out = new FileOutputStream(systemDir+File.separator+filePath);
|
out.write(bytes);
|
out.flush();
|
out.close();
|
} catch (FileNotFoundException e) {
|
throw new ApiException("找不到文件");
|
} catch (IOException e) {
|
throw new ApiException("发生错误,请联系管理员");
|
}
|
filePath=filePath.replace("\\","/");
|
UploadObjectVO uploadObjectVO=new UploadObjectVO().setFilename(filename)
|
.setPath(filePath).setOriginName(originName);
|
return uploadObjectVO;
|
}
|
|
}
|