diff --git a/securitycontrol-model/securitycontrol-system/pom.xml b/securitycontrol-model/securitycontrol-system/pom.xml index 215f211..12baf7c 100644 --- a/securitycontrol-model/securitycontrol-system/pom.xml +++ b/securitycontrol-model/securitycontrol-system/pom.xml @@ -115,6 +115,10 @@ commons-collections4 4.4 + + org.springframework.boot + spring-boot-starter-data-mongodb + diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/config/MongoConfig.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/config/MongoConfig.java new file mode 100644 index 0000000..6f2508d --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/config/MongoConfig.java @@ -0,0 +1,56 @@ +package com.securitycontrol.system.mongodb.config; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.gridfs.GridFSBucket; +import com.mongodb.client.gridfs.GridFSBuckets; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +/** + * @author coisini + * @version 1.0 + * @Description MongoDB配置类 + * @date Apr 17, 2022 + */ +@Configuration +public class MongoConfig { + /** + * 数据库配置信息 + */ + @Value("${spring.data.mongodb.database}") + private String db; + + @Value("${spring.data.mongodb.host}") + private String host; + + @Value("${spring.data.mongodb.port}") + private Integer port; + + private static final String UN = "zhlydb"; + + private static final String PD = "Bonus%40admin123!"; + + private MongoDatabase mongoDatabase; + + public MongoClient getMongoClient(){ + String addr = "mongodb://" + UN + ":" + PD + "@" + host + ":" + port + "/" + db; + MongoClient mongoClient = MongoClients.create(addr); + return mongoClient; + } + + public MongoDatabase getMongoConn(){ + MongoClient mongoClient = getMongoClient(); + mongoDatabase = mongoClient.getDatabase(db); + System.out.println("mongodb数据库连接成功!"); + return mongoDatabase; + } + + @Bean + public GridFSBucket getGridFsBucket(){ + MongoDatabase mongoDatabase = getMongoConn(); + return GridFSBuckets.create(mongoDatabase); + } +} diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/model/MongoFile.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/model/MongoFile.java new file mode 100644 index 0000000..8e03ffe --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/model/MongoFile.java @@ -0,0 +1,71 @@ +package com.securitycontrol.system.mongodb.model; + +import lombok.Builder; +import lombok.Data; +import org.bson.types.Binary; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +/** + * @Description MongoDB文件实体 + * @author coisini + * @date Apr 17, 2022 + * @version 1.0 + */ +@Document +@Builder +@Data +public class MongoFile { + + /** + * 主键 + */ + @Id + public String id; + + /** + * 文件名称 + */ + public String fileName; + + /** + * 文件大小 + */ + public long fileSize; + + /** + * 上传时间 + */ + public String uploadDate; + + /** + * MD5值 + */ + public String md5; + + /** + * 文件内容 + */ + private Binary content; + + /** + * 文件类型 + */ + public String contentType; + + /** + * 文件后缀名 + */ + public String suffix; + + /** + * 文件描述 + */ + public String description; + + /** + * 大文件管理GridFS的ID + */ + private String gridFsId; + +} diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/model/ResponseMessage.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/model/ResponseMessage.java new file mode 100644 index 0000000..e9e9c38 --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/model/ResponseMessage.java @@ -0,0 +1,78 @@ +package com.securitycontrol.system.mongodb.model; + +/** + * @Description 统一消息 + * @author coisini + * @date Apr 17, 2022 + * @version 1.0 + */ +public class ResponseMessage { + + private String status; + private String message; + private T data; + + public static ResponseMessage ok() { + return create("0", (String)null, (Object)null); + } + + public static ResponseMessage ok(String message) { + return create("0", message, (Object)null); + } + + public static ResponseMessage ok(String message, T data) { + return create("0", message, data); + } + + public static ResponseMessage ok(T data) { + return create("0", (String)null, data); + } + + public static ResponseMessage error() { + return create("1", (String)null, (Object)null); + } + + public static ResponseMessage error(String message) { + return create("1", message, (Object)null); + } + + public static ResponseMessage error(String message, T data) { + return create("1", message, data); + } + + private static ResponseMessage create(String status, String message, T data) { + ResponseMessage t = new ResponseMessage(); + t.setStatus(status); + t.setMessage(message); + t.setData(data); + return t; + } + + public ResponseMessage() { + } + + public String getStatus() { + return this.status; + } + + public String getMessage() { + return this.message; + } + + public T getData() { + return this.data; + } + + public void setStatus(final String status) { + this.status = status; + } + + public void setMessage(final String message) { + this.message = message; + } + + public void setData(final T data) { + this.data = data; + } + +} diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/repository/MongoFileRepository.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/repository/MongoFileRepository.java new file mode 100644 index 0000000..0b7e27c --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/repository/MongoFileRepository.java @@ -0,0 +1,15 @@ +package com.securitycontrol.system.mongodb.repository; + + +import com.securitycontrol.system.mongodb.model.MongoFile; +import org.springframework.data.mongodb.repository.MongoRepository; + +/** + * @Description MongoDB文件仓储 + * @author coisini + * @date Apr 17, 2022 + * @version 1.0 + */ +public interface MongoFileRepository extends MongoRepository { + +} diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/service/FileUploadService.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/service/FileUploadService.java new file mode 100644 index 0000000..d503834 --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/service/FileUploadService.java @@ -0,0 +1,50 @@ +package com.securitycontrol.system.mongodb.service; + +import com.securitycontrol.system.mongodb.vo.FileExportVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * @author coisini + * @version 1.0 + * @Description 文件上传接口 + * @date Apr 17, 2022 + */ +public interface FileUploadService { + + /** + * 文件上传 + * @param file + * @return FileExportVo + * @description + * @author cwchen + * @date 2024/3/11 15:44 + * @throws Exception + */ + FileExportVo uploadFile(MultipartFile file) throws Exception; + + /** + * 多文件上传 + * + * @param files + * @return + */ + List uploadFiles(List files); + + /** + * 文件下载 + * + * @param fileId + * @return + */ + FileExportVo downloadFile(String fileId); + + /** + * 文件删除 + * + * @param fileId + */ + void removeFile(String fileId); + +} diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/service/impl/FileMongoServiceImpl.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/service/impl/FileMongoServiceImpl.java new file mode 100644 index 0000000..b0327be --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/service/impl/FileMongoServiceImpl.java @@ -0,0 +1,262 @@ +package com.securitycontrol.system.mongodb.service.impl; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import com.mongodb.client.gridfs.GridFSBucket; +import com.mongodb.client.gridfs.GridFSDownloadStream; +import com.mongodb.client.gridfs.model.GridFSFile; +import com.securitycontrol.common.core.utils.aes.DateTimeHelper; +import com.securitycontrol.system.mongodb.model.MongoFile; +import com.securitycontrol.system.mongodb.repository.MongoFileRepository; +import com.securitycontrol.system.mongodb.service.FileUploadService; +import com.securitycontrol.system.mongodb.util.Md5Util; +import com.securitycontrol.system.mongodb.vo.FileExportVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.bson.types.Binary; +import org.springframework.beans.factory.annotation.Autowired; +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.GridFsResource; +import org.springframework.data.mongodb.gridfs.GridFsTemplate; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * @Description MongoDB文件上传实现类 + * @author coisini + * @date Apr 17, 2022 + * @version 1.0 + */ +@Slf4j +@Service("fileMongoServiceImpl") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class FileMongoServiceImpl implements FileUploadService { + + private final MongoFileRepository mongoFileRepository; + private final MongoTemplate mongoTemplate; + private final GridFsTemplate gridFsTemplate; + private final GridFSBucket gridFSBucket; + + private static final int MAX_SIZE = 16777216; + private static final String SUFFIX = "."; + /** + * 多文件上传 + * @param files + * @return + */ + @Override + public List uploadFiles(List 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 FileExportVo uploadFile(MultipartFile file) throws Exception { + if (file.getSize() > MAX_SIZE) { + return this.saveGridFsFile(file); + } else { + return this.saveBinaryFile(file); + } + } + + /** + * 文件下载 + * @param fileId + * @return + */ + @Override + public FileExportVo downloadFile(String fileId) { + Optional option = this.getBinaryFileById(fileId); + + if (option.isPresent()) { + MongoFile mongoFile = option.get(); + if(Objects.isNull(mongoFile.getContent())){ + option = this.getGridFsFileById(fileId); + } + } + + return option.map(FileExportVo::new).orElse(null); + } + + /** + * 文件删除 + * @param fileId + */ + @Override + public void removeFile(String fileId) { + Optional 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) { + // TODO 根据id查询文件 + MongoFile mongoFile = mongoTemplate.findById(fileId, MongoFile.class ); + if(Objects.nonNull(mongoFile)){ + // TODO 根据文件ID删除fs.files和fs.chunks中的记录 + Query deleteFileQuery = new Query().addCriteria(Criteria.where("filename").is(mongoFile.getGridFsId())); + gridFsTemplate.delete(deleteFileQuery); + // TODO 删除集合mongoFile中的数据 + Query deleteQuery = new Query(Criteria.where("id").is(fileId)); + mongoTemplate.remove(deleteQuery, MongoFile.class); + } + } + + /** + * 保存Binary文件(小文件) + * @param file + * @return + * @throws Exception + */ + public FileExportVo saveBinaryFile(MultipartFile file) throws Exception { + + String suffix = getFileSuffix(file); + + MongoFile mongoFile = mongoFileRepository.save( + MongoFile.builder() + .fileName(file.getOriginalFilename()) + .fileSize(file.getSize()) + .content(new Binary(file.getBytes())) + .contentType(file.getContentType()) + .uploadDate(DateTimeHelper.getNowTime()) + .suffix(suffix) + .md5(Md5Util.getMd5(file.getInputStream())) + .build() + ); + + return new FileExportVo(mongoFile); + } + + /** + * 保存GridFs文件(大文件) + * @param file + * @return + * @throws Exception + */ + public FileExportVo saveGridFsFile(MultipartFile file) throws Exception { + String suffix = getFileSuffix(file); + + String gridFsId = this.storeFileToGridFs(file.getInputStream(), file.getContentType()); + + MongoFile mongoFile = mongoTemplate.save( + MongoFile.builder() + .fileName(file.getOriginalFilename()) + .fileSize(file.getSize()) + .contentType(file.getContentType()) + .uploadDate(DateTimeHelper.getNowTime()) + .suffix(suffix) + .md5(Md5Util.getMd5(file.getInputStream())) + .gridFsId(gridFsId) + .build() + ); + + return new FileExportVo(mongoFile); + } + + /** + * 上传文件到Mongodb的GridFs中 + * @param in + * @param contentType + * @return + */ + public String storeFileToGridFs(InputStream in, String contentType){ + String gridFsId = IdUtil.simpleUUID(); + // TODO 将文件存储进GridFS中 + gridFsTemplate.store(in, gridFsId , contentType); + return gridFsId; + } + + /** + * 获取Binary文件 + * @param id + * @return + */ + public Optional getBinaryFileById(String id) { + return mongoFileRepository.findById(id); + } + + /** + * 获取Grid文件 + * @param id + * @return + */ + public Optional getGridFsFileById(String id){ + MongoFile mongoFile = mongoTemplate.findById(id , MongoFile.class ); + if(Objects.nonNull(mongoFile)){ + Query gridQuery = new Query().addCriteria(Criteria.where("filename").is(mongoFile.getGridFsId())); + try { + // TODO 根据id查询文件 + GridFSFile fsFile = gridFsTemplate.findOne(gridQuery); + // TODO 打开流下载对象 + GridFSDownloadStream in = gridFSBucket.openDownloadStream(fsFile.getObjectId()); + if(in.getGridFSFile().getLength() > 0){ + // TODO 获取流对象 + GridFsResource resource = new GridFsResource(fsFile, in); + // TODO 获取数据 + mongoFile.setContent(new Binary(IoUtil.readBytes(resource.getInputStream()))); + return Optional.of(mongoFile); + }else { + return Optional.empty(); + } + }catch (IOException 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)) { + suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); + } + return suffix; + } + +} diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/Md5Util.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/Md5Util.java new file mode 100644 index 0000000..b7232a0 --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/Md5Util.java @@ -0,0 +1,35 @@ +package com.securitycontrol.system.mongodb.util; + +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * @author 10488 + * @Description MD5工具类 + * @date Apr 8, 2022 + * @version 1.0 + */ +public class Md5Util { + /** + * 获取该输入流的MD5值 + */ + public static String getMd5(InputStream is) throws NoSuchAlgorithmException, IOException { + StringBuffer md5 = new StringBuffer(); + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] dataBytes = new byte[1024]; + + int nread = 0; + while ((nread = is.read(dataBytes)) != -1) { + md.update(dataBytes, 0, nread); + }; + byte[] mdbytes = md.digest(); + + // convert the byte to hex format + for (int i = 0; i < mdbytes.length; i++) { + md5.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1)); + } + return md5.toString(); + } +} \ No newline at end of file diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/MongodbFileBase64Util.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/MongodbFileBase64Util.java new file mode 100644 index 0000000..91f9af1 --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/MongodbFileBase64Util.java @@ -0,0 +1,38 @@ +package com.securitycontrol.system.mongodb.util; + +import com.securitycontrol.system.mongodb.vo.FileExportVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Base64Utils; + +import java.util.Objects; + +/** + * @author:cwchen + * @date:2024-03-11-15:57 + * @version:1.0 + * @description:mongodb文件转base64工具类 + */ +@Slf4j +public class MongodbFileBase64Util { + + /** + * img图片转base64url + * @param vo + * @return String + * @description + * @author cwchen + * @date 2024/3/11 15:59 + */ + public String getImgBase64(FileExportVo vo) { + try { + byte[] bytes = vo.getData(); + if (!Objects.isNull(bytes)) { + String suffix = vo.getSuffix().replace(".", ""); + return "data:image/" + suffix + ";base64," + Base64Utils.encodeToString(bytes); + } + } catch (Exception e) { + log.error("byte流转base64", e); + } + return null; + } +} diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/MongodbFileUtil.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/MongodbFileUtil.java new file mode 100644 index 0000000..77a9474 --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/util/MongodbFileUtil.java @@ -0,0 +1,22 @@ +package com.securitycontrol.system.mongodb.util; + +import com.securitycontrol.system.mongodb.service.FileUploadService; +import org.apache.logging.log4j.util.Base64Util; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Resource; + +/** + * @author:cwchen + * @date:2024-03-11-15:55 + * @version:1.0 + * @description:mongodb文件上传-工具类 + */ +public class MongodbFileUtil { + + @Resource(name = "fileMongoServiceImpl") + private FileUploadService mongoService; + + @Autowired + private Base64Util base64Util; +} diff --git a/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/vo/FileExportVo.java b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/vo/FileExportVo.java new file mode 100644 index 0000000..b730a6f --- /dev/null +++ b/securitycontrol-model/securitycontrol-system/src/main/java/com/securitycontrol/system/mongodb/vo/FileExportVo.java @@ -0,0 +1,40 @@ +package com.securitycontrol.system.mongodb.vo; + +import cn.hutool.core.bean.BeanUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.securitycontrol.system.mongodb.model.MongoFile; +import lombok.Data; + +import java.util.Objects; + +/** + * @Description 统一文件下载vo + * @author lit@epsoft.com.cn + * @date Apr 8, 2022 + * @version 1.0 + */ +@Data +public class FileExportVo { + + private String fileId; + + private String fileName; + + private String contentType; + + private String suffix; + + private long fileSize; + + @JsonIgnore + private byte[] data; + + public FileExportVo(MongoFile mongoFile) { + BeanUtil.copyProperties(mongoFile, this); + if (Objects.nonNull(mongoFile.getContent())) { + this.data = mongoFile.getContent().getData(); + } + this.fileId = mongoFile.getId(); + } + +}