|
|
@@ -0,0 +1,271 @@
|
|
|
+package com.doc.biz.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.io.IoUtil;
|
|
|
+import com.doc.biz.domain.DocumentFile;
|
|
|
+import com.doc.biz.mapper.MongoFileRepository;
|
|
|
+import com.doc.biz.service.IMongoService;
|
|
|
+import com.doc.biz.vo.DocumentVO;
|
|
|
+import com.doc.common.constant.Constants;
|
|
|
+import com.doc.common.utils.sign.Md5Utils;
|
|
|
+import com.mongodb.client.gridfs.GridFSBucket;
|
|
|
+import com.mongodb.client.gridfs.GridFSDownloadStream;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.bson.types.Binary;
|
|
|
+import org.bson.types.ObjectId;
|
|
|
+import org.springframework.data.mongodb.core.MongoTemplate;
|
|
|
+import org.springframework.data.mongodb.core.query.Criteria;
|
|
|
+import org.springframework.data.mongodb.core.query.Query;
|
|
|
+import org.springframework.data.mongodb.gridfs.GridFsTemplate;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.Optional;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 文档协作Service业务层处理
|
|
|
+ *
|
|
|
+ * @author wukai
|
|
|
+ * @date 2023-08-15
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class MongoServiceImpl implements IMongoService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MongoFileRepository mongoFileRepository;
|
|
|
+ @Resource
|
|
|
+ private MongoTemplate mongoTemplate;
|
|
|
+ @Resource
|
|
|
+ private GridFsTemplate gridFsTemplate;
|
|
|
+ @Resource
|
|
|
+ private GridFSBucket gridFSBucket;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 多文件上传
|
|
|
+ *
|
|
|
+ * @param files
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<DocumentVO> uploadFiles(List<MultipartFile> files) {
|
|
|
+
|
|
|
+ return files.stream().map(file -> {
|
|
|
+ try {
|
|
|
+ return this.uploadFile(file);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("文件上传失败", e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }).filter(Objects::nonNull).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 文件上传
|
|
|
+ *
|
|
|
+ * @param file
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public DocumentVO uploadFile(MultipartFile file) throws Exception {
|
|
|
+ if (file.getSize() > Constants.MONGO_FILE_SIZE) {
|
|
|
+ return this.saveGridFsFile(file);
|
|
|
+ } else {
|
|
|
+ return this.saveBinaryFile(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 文件下载
|
|
|
+ *
|
|
|
+ * @param fileId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public DocumentVO downloadFile(String fileId) {
|
|
|
+ Optional<DocumentFile> option = this.getBinaryFileById(fileId);
|
|
|
+
|
|
|
+ if (option.isPresent()) {
|
|
|
+ DocumentFile documentFile = option.get();
|
|
|
+ if (Objects.isNull(documentFile.getContent())) {
|
|
|
+ option = this.getGridFsFileById(fileId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return option.map(DocumentVO::new).orElse(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 文件删除
|
|
|
+ *
|
|
|
+ * @param fileId
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void removeFile(String fileId) {
|
|
|
+ Optional<DocumentFile> option = this.getBinaryFileById(fileId);
|
|
|
+
|
|
|
+ if (option.isPresent()) {
|
|
|
+ if (Objects.nonNull(option.get().getGridFsId())) {
|
|
|
+ this.removeGridFsFile(fileId);
|
|
|
+ } else {
|
|
|
+ this.removeBinaryFile(fileId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除Binary文件
|
|
|
+ *
|
|
|
+ * @param fileId
|
|
|
+ */
|
|
|
+ public void removeBinaryFile(String fileId) {
|
|
|
+ mongoFileRepository.deleteById(fileId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除GridFs文件
|
|
|
+ *
|
|
|
+ * @param fileId
|
|
|
+ */
|
|
|
+ public void removeGridFsFile(String fileId) {
|
|
|
+ // 根据id查询文件
|
|
|
+ DocumentFile documentFile = mongoTemplate.findById(fileId, DocumentFile.class);
|
|
|
+ if (Objects.nonNull(documentFile)) {
|
|
|
+ // 根据文件ID删除fs.files和fs.chunks中的记录
|
|
|
+ Query deleteFileQuery = new Query().addCriteria(Criteria.where("_id").is(documentFile.getGridFsId()));
|
|
|
+ gridFsTemplate.delete(deleteFileQuery);
|
|
|
+ // 删除集合documentFile中的数据
|
|
|
+ Query deleteQuery = new Query(Criteria.where("id").is(fileId));
|
|
|
+ mongoTemplate.remove(deleteQuery, DocumentFile.class);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存Binary文件(小文件)
|
|
|
+ *
|
|
|
+ * @param file
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public DocumentVO saveBinaryFile(MultipartFile file) throws Exception {
|
|
|
+
|
|
|
+ String suffix = getFileSuffix(file);
|
|
|
+ DocumentFile documentFile = null;
|
|
|
+ try (InputStream in = file.getInputStream()) {
|
|
|
+ documentFile = mongoFileRepository.save(
|
|
|
+ DocumentFile.builder()
|
|
|
+ .fileName(file.getOriginalFilename())
|
|
|
+ .fileSize(file.getSize())
|
|
|
+ .content(new Binary(file.getBytes()))
|
|
|
+ .contentType(file.getContentType())
|
|
|
+ .uploadDate(new Date())
|
|
|
+ .suffix(suffix)
|
|
|
+ .md5(Md5Utils.getMd5ByInputStream(in))
|
|
|
+ .build()
|
|
|
+ );
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.getMessage());
|
|
|
+ throw e;
|
|
|
+ // 抛出异常,让调用方处理
|
|
|
+ }
|
|
|
+
|
|
|
+ return new DocumentVO(documentFile);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存GridFs文件(大文件)
|
|
|
+ *
|
|
|
+ * @param file
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public DocumentVO saveGridFsFile(MultipartFile file) throws Exception {
|
|
|
+ String suffix = getFileSuffix(file);
|
|
|
+ DocumentFile documentFile = null;
|
|
|
+ try (InputStream in = file.getInputStream()) {
|
|
|
+ String gridFsId = this.storeFileToGridFS(in, file.getOriginalFilename(), file.getContentType());
|
|
|
+ documentFile = mongoFileRepository.save(
|
|
|
+ DocumentFile.builder()
|
|
|
+ .fileName(file.getOriginalFilename())
|
|
|
+ .fileSize(file.getSize())
|
|
|
+ .contentType(file.getContentType())
|
|
|
+ .uploadDate(new Date())
|
|
|
+ .suffix(suffix)
|
|
|
+ .md5(Md5Utils.getMd5ByInputStream(in))
|
|
|
+ .gridFsId(gridFsId)
|
|
|
+ .build()
|
|
|
+ );
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.getMessage());
|
|
|
+ throw e;
|
|
|
+ // 抛出异常,让调用方处理
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return new DocumentVO(documentFile);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 上传文件到Mongodb的GridFs中
|
|
|
+ *
|
|
|
+ * @param in
|
|
|
+ * @param contentType
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String storeFileToGridFS(InputStream in, String filename, String contentType) {
|
|
|
+ // 将文件存储进GridFS中
|
|
|
+ ObjectId gridFsId = gridFsTemplate.store(in, filename, contentType);
|
|
|
+ return gridFsId.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取Binary文件
|
|
|
+ *
|
|
|
+ * @param id
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Optional<DocumentFile> getBinaryFileById(String id) {
|
|
|
+ return mongoFileRepository.findById(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取Grid文件
|
|
|
+ *
|
|
|
+ * @param id
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Optional<DocumentFile> getGridFsFileById(String id) {
|
|
|
+ DocumentFile documentFile = mongoTemplate.findById(id, DocumentFile.class);
|
|
|
+ if (Objects.nonNull(documentFile)) {
|
|
|
+ try (GridFSDownloadStream in = gridFSBucket.openDownloadStream(new ObjectId(documentFile.getGridFsId()))) {
|
|
|
+ documentFile.setContent(new Binary(IoUtil.readBytes(in)));
|
|
|
+ return Optional.of(documentFile);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("获取MongoDB大文件失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return Optional.empty();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取文件后缀
|
|
|
+ *
|
|
|
+ * @param file
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getFileSuffix(MultipartFile file) {
|
|
|
+ String suffix = "";
|
|
|
+ if (Objects.requireNonNull(file.getOriginalFilename()).contains(".")) {
|
|
|
+ suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
|
|
|
+ }
|
|
|
+ return suffix;
|
|
|
+ }
|
|
|
+}
|