package com.moral.api.service.impl;
|
|
import com.moral.api.config.Interceptor.UserHelper;
|
import com.moral.api.entity.FileTable;
|
import com.moral.api.exception.BusinessException;
|
import com.moral.api.mapper.FileTableMapper;
|
import com.moral.api.pojo.enums.FileType;
|
import com.moral.api.pojo.enums.YesOrNo;
|
import com.moral.api.pojo.vo.file.FileVo;
|
import com.moral.api.pojo.vo.user.QxUser;
|
import com.moral.api.service.FileTableService;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.moral.api.utils.FileTypeUtils;
|
import com.moral.api.utils.StringUtils;
|
import com.moral.util.DateUtils;
|
import lombok.extern.slf4j.Slf4j;
|
import net.coobird.thumbnailator.Thumbnails;
|
import org.apache.commons.collections4.CollectionUtils;
|
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.*;
|
import java.net.URLEncoder;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 附件表 服务实现类
|
* </p>
|
*
|
* @author moral
|
* @since 2023-09-21
|
*/
|
@Service
|
@Slf4j
|
public class FileTableServiceImpl extends ServiceImpl<FileTableMapper, FileTable> implements FileTableService {
|
@Value("${file.path}")
|
private String basePath;
|
@Override
|
public FileVo upload(MultipartFile file, Integer sysCode) {
|
String originalFilename = file.getOriginalFilename().replaceAll(StringUtils.SPACE, StringUtils.EMPTY).toLowerCase();
|
String suffix = originalFilename.substring(originalFilename.lastIndexOf(StringUtils.DOT));
|
FileType fileType = FileTypeUtils.getFileType(suffix.toLowerCase());
|
// 处理文件相对路径 系统代码 + 业务代码 + 日期
|
String filePath = getFilePath(sysCode.toString());
|
// 保存文件
|
String targetFolder = basePath.replaceAll(StringUtils.BACKSLASH.concat(StringUtils.BACKSLASH), StringUtils.SLASH).concat(StringUtils.SLASH).concat(filePath);
|
//使用uuid 替换上传文件名,避免重复
|
String storageFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf(StringUtils.DOT));
|
storageFile(file, storageFileName, targetFolder);
|
|
// 封装文件信息
|
QxUser user = UserHelper.getCurrentUser();
|
FileTable sysFile = new FileTable();
|
sysFile.setFileName(originalFilename).setFileType(fileType.getValue()).setFileSize((int) file.getSize()).setFileAddress(filePath.concat(storageFileName))
|
.setFileModule(sysCode).setCreateTime(new Date());
|
if (Objects.nonNull(user)) {
|
sysFile.setCreateId(user.getUserId()).setCreateName(user.getUserName());
|
}
|
save(sysFile);
|
return new FileVo().setFileId(sysFile.getFileId()).setFileName(originalFilename);
|
}
|
|
@Override
|
public List<FileVo> upload(List<MultipartFile> files, Integer sysCode) {
|
List<FileVo> fileList = new LinkedList<>();
|
for (MultipartFile file : files) {
|
fileList.add(upload(file, sysCode));
|
}
|
return fileList;
|
}
|
|
@Override
|
public void preview(Integer id, HttpServletRequest request, HttpServletResponse response) {
|
FileTable sysFile = getById(id);
|
File file = new File(handleFileRealPath(sysFile.getFileAddress()));
|
String suffix = file.getName().substring(file.getName().lastIndexOf(StringUtils.DOT));
|
if (FileTypeUtils.SUFFIX_MP4.equals(suffix)) {
|
videoPreview(file, request, response);
|
} else {
|
try (OutputStream out = response.getOutputStream(); InputStream in = new FileInputStream(file)) {
|
response.setContentType(FileTypeUtils.convertHeaderType(suffix));
|
response.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(sysFile.getFileName(), "UTF-8"));
|
int len;
|
// 创建数据缓冲区
|
byte[] buffer = new byte[1024];
|
while ((len = in.read(buffer)) > 0) {
|
out.write(buffer, 0, len);
|
}
|
} catch (Exception e) {
|
log.error("读取文件异常!!! e={}", e.getMessage());
|
}
|
}
|
}
|
|
private String getFilePath(String sysCode) {
|
return sysCode.concat(StringUtils.SLASH).concat(StringUtils.SLASH).concat(DateUtils.dateToDateString(new Date(),DateUtils.yyyyMMdd_EN)).concat(StringUtils.SLASH);
|
}
|
|
public void storageFile(MultipartFile file, String originalFilename, String targetFolder) {
|
File f = new File(targetFolder, originalFilename);
|
try {
|
// 保存文件
|
if (!f.getParentFile().exists()) {
|
if (!f.getParentFile().mkdirs()) {
|
log.error("error:创建文件失败! dir={}", f.getAbsolutePath());
|
}
|
}
|
file.transferTo(f);
|
} catch (IOException e) {
|
log.error("error:文件上传失败!!!e={}", e.getMessage());
|
throw new BusinessException("文件上传失败,请重试!");
|
}
|
}
|
private String handleFileRealPath(String path) {
|
return basePath.replaceAll(StringUtils.BACKSLASH.concat(StringUtils.BACKSLASH), StringUtils.SLASH).concat(StringUtils.SLASH).concat(path);
|
}
|
private void videoPreview(File file, HttpServletRequest request, HttpServletResponse response) {
|
String suffix = file.getName().substring(file.getName().lastIndexOf(StringUtils.DOT));
|
//设置属性
|
response.setContentType(FileTypeUtils.convertHeaderType(suffix));
|
response.setHeader("Accept-Ranges", "bytes");
|
response.setHeader("ETag", file.getName());
|
response.setHeader("Last-Modified", new Date().toString());
|
long contentLength = file.length();
|
|
//每次传递实际长度(初始第一次读取少选数据)
|
long length = Math.min(contentLength, 1024);
|
long start = 0, end = 0;
|
String range = request.getHeader("Range");
|
//第一次请求只返回content length来让客户端请求多次实际数据
|
if (range == null) {
|
response.setHeader("Content-length", contentLength + "");
|
} else {
|
//以后的多次以断点续传的方式来返回视频数据
|
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
|
|
if (range.startsWith("bytes=")) {
|
String[] values = range.split("=")[1].split("-");
|
start = Integer.parseInt(values[0]);
|
if (values.length > 1) {
|
end = Integer.parseInt(values[1]);
|
}
|
}
|
//无end,每次允许的最大长度
|
long maxSize = 1024 * 1024; //1MB
|
if (end > 0) {
|
length = end - start + 1;
|
response.setHeader("Content-length", "" + length);
|
response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + contentLength);
|
} else {
|
length = Math.min((contentLength - start), maxSize);
|
response.setHeader("Content-length", "" + length);
|
response.setHeader("Content-Range", "bytes " + start + "-" + (start + length - 1) + "/" + contentLength);
|
}
|
}
|
try {
|
FileInputStream fileInputStream = new FileInputStream(file);
|
OutputStream out = response.getOutputStream();
|
//将数据截取并存入byte[]数组中
|
byte[] data = new byte[(int) length];
|
fileInputStream.skip(start);
|
fileInputStream.read(data);
|
//取出要传给前端的有效数据
|
out.write(data);
|
out.close();
|
fileInputStream.close();
|
} catch (Exception e) {
|
log.error("读取文件异常!!! e={}", e.getMessage());
|
}
|
}
|
@Override
|
public void coverPreview(Integer id, HttpServletRequest request, HttpServletResponse response) {
|
FileTable sysFile = getById(id);
|
|
File file = new File(handleFileRealPath(sysFile.getFileAddress()));
|
String suffix = file.getName().substring(file.getName().lastIndexOf(StringUtils.DOT));
|
|
try (OutputStream out = response.getOutputStream()) {
|
response.setContentType(FileTypeUtils.convertHeaderType(suffix));
|
response.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(sysFile.getFileName(), "UTF-8"));
|
Thumbnails.of(file).size(420, 200).toOutputStream(out);
|
} catch (Exception e) {
|
log.error("读取文件异常!!! e={}", e.getMessage());
|
}
|
}
|
|
@Override
|
@Transactional
|
public void upDateResult(List<FileVo> list,int relationId,int fileModule) {
|
List<FileTable> existsList = this.lambdaQuery().eq(FileTable::getRelationId, relationId)
|
.eq(FileTable::getFileModule, fileModule)
|
.eq(FileTable::getIsDel, YesOrNo.NO.value).list();
|
|
// 新增附件
|
if (!CollectionUtils.isEmpty(list)) {
|
List<FileTable> addList = new ArrayList();
|
// 2.2.筛选出需要保存的文件
|
list.forEach(it -> {
|
existsList.removeIf(file -> file.getFileId().equals(it.getFileId()));
|
FileTable file = new FileTable();
|
BeanUtils.copyProperties(it,file);
|
file.setRelationId(relationId);
|
addList.add(file);
|
});
|
if (!CollectionUtils.isEmpty(addList)) {
|
// 保存
|
this.updateBatchById(addList);
|
}
|
}
|
// 删除附件
|
if (!CollectionUtils.isEmpty(existsList)) {
|
removeByIds(existsList.stream().map(FileTable::getFileId).collect(Collectors.toList()));
|
}
|
}
|
|
@Override
|
public List<FileVo> list(int relationId, int fileModule) {
|
List<FileVo> list = new ArrayList<>();
|
List<FileTable> existsList = this.lambdaQuery().eq(FileTable::getRelationId, relationId)
|
.eq(FileTable::getFileModule, fileModule)
|
.eq(FileTable::getIsDel, YesOrNo.NO.value).orderByAsc(FileTable::getCreateTime).list();
|
existsList.forEach(it->{
|
FileVo fileVo = new FileVo();
|
fileVo.setFileId(it.getFileId());
|
fileVo.setFileName(it.getFileName());
|
list.add(fileVo);
|
});
|
return list;
|
}
|
}
|