feat: 文件存储功能开发,新增ftp、sftp支持,修改minio文件存储实现;修改原本的大屏封面存储逻辑,从而适配文件存储类型的切换

main
hong.yang 1 year ago
parent 8f50bece2e
commit fc0f733079

@ -72,5 +72,24 @@
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
<!-- ftp 连接工具包 -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>${commons-net.version}</version>
</dependency>
<!-- 连接池化技术 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${commons-dbcp2.version}</version>
</dependency>
<!-- sftp 连接依赖-->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>${jsch.version}</version>
</dependency>
</dependencies>
</project>

@ -1,94 +0,0 @@
package com.gccloud.dataroom.core.config;
import io.minio.MinioClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Minio
*
* @author Acechengui
*/
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig
{
/**
*
*/
private String url;
/**
*
*/
private String accessKey;
/**
*
*/
private String secretKey;
/**
*
*/
private String bucketName;
public String getUrl()
{
return url;
}
public void setUrl(String url)
{
this.url = url;
}
public String getAccessKey()
{
return accessKey;
}
public void setAccessKey(String accessKey)
{
this.accessKey = accessKey;
}
public String getSecretKey()
{
return secretKey;
}
public void setSecretKey(String secretKey)
{
this.secretKey = secretKey;
}
public String getBucketName()
{
return bucketName;
}
public void setBucketName(String bucketName)
{
this.bucketName = bucketName;
}
@Bean
public MinioClient getMinioClient() {
if (StringUtils.isEmpty(url) || StringUtils.isEmpty(accessKey) || StringUtils.isEmpty(secretKey)) {
// 如果未配置Minio相关的配置项则使用本地文件存储
// 或者返回一个默认的MinioClient实例用于本地文件存储
return createDefaultMinioClient();
}
return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
}
private MinioClient createDefaultMinioClient() {
return MinioClient.builder()
.endpoint("http://minio.example.com")
.credentials("accessKey", "secretKey")
.build();
}
}

@ -30,4 +30,19 @@ public class FileConfig {
"mp4", "mov", "mp3",
"rar", "zip"
);
/**
* ftp
*/
private FtpConfig ftp;
/**
* sftp
*/
private SftpConfig sftp;
/**
* minio
*/
private MinioConfig minio;
}

@ -0,0 +1,108 @@
package com.gccloud.dataroom.core.config.bean;
import lombok.Data;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author hongyang
* @version 1.0
* @date 2023/10/17 15:18
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "gc.starter.file.ftp")
public class FtpConfig extends GenericObjectPoolConfig {
/**
* ftp
*/
private String host;
/**
* ftp
*/
private Integer port;
/**
* ftp
*/
private String username;
/**
* ftp
*/
private String password;
/**
*
*/
String encoding = "utf-8";
/**
*
*/
boolean passiveMode = true;
/**
*
*/
int clientTimeout = 30000;
/**
* 0=ASCII_FILE_TYPE(ASCII)1=EBCDIC_FILE_TYPE2=LOCAL_FILE_TYPE()
*/
int transferFileType = 2;
/**
*
*/
int retryTimes;
/**
*
*/
int bufferSize = 1024;
/* 连接池配置 */
/**
*
*/
int maxTotal = DEFAULT_MAX_TOTAL;
/**
*
*/
int minIdle = DEFAULT_MIN_IDLE;
/**
*
*/
int maxIdle = DEFAULT_MAX_IDLE;
/**
* 10s
*/
int maxWait = 10000;
/**
* maxWait < 0
*/
boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED;
/**
*
*/
boolean testOnBorrow = true ;
/**
*
*/
boolean testOnReturn = true;
/**
*
*/
boolean testOnCreate = true;
/**
*
*/
boolean testWhileIdle = true;
/**
*
*/
boolean lifo = DEFAULT_LIFO;
}

@ -0,0 +1,50 @@
package com.gccloud.dataroom.core.config.bean;
import com.gccloud.common.exception.GlobalException;
import io.minio.MinioClient;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Minio
*
* @author Acechengui
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "gc.starter.file.minio")
public class MinioConfig
{
/**
*
*/
private String url;
/**
*
*/
private String accessKey;
/**
*
*/
private String secretKey;
/**
*
*/
private String bucketName;
@Bean
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "minio")
public MinioClient getMinioClient() {
if (StringUtils.isBlank(bucketName)) {
throw new GlobalException("Minio bucketName 不能为空");
}
return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
}
}

@ -0,0 +1,116 @@
package com.gccloud.dataroom.core.config.bean;
import lombok.Data;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author hongyang
* @version 1.0
* @date 2023/10/17 15:18
*/
@Configuration
@ConfigurationProperties(prefix = "gc.starter.file.sftp")
@Data
public class SftpConfig extends GenericObjectPoolConfig {
/**
* ftp
*/
private String host;
/**
* ftp
*/
private Integer port;
/**
* ftp
*/
private String username;
/**
* ftp
*/
private String password;
/**
*
*/
private String privateKey;
/**
*
*/
String encoding = "utf-8";
/**
*
*/
boolean passiveMode = true;
/**
*
*/
int clientTimeout = 30000;
/**
* 0=ASCII_FILE_TYPE(ASCII)1=EBCDIC_FILE_TYPE2=LOCAL_FILE_TYPE()
*/
int transferFileType = 2;
/**
*
*/
int retryTimes;
/**
*
*/
int bufferSize = 1024;
/* 连接池配置 */
/**
*
*/
int maxTotal = DEFAULT_MAX_TOTAL;
/**
*
*/
int minIdle = DEFAULT_MIN_IDLE;
/**
*
*/
int maxIdle = DEFAULT_MAX_IDLE;
/**
* 10s
*/
int maxWait = 10000;
/**
* maxWait < 0
*/
boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED;
/**
*
*/
boolean testOnBorrow = true ;
/**
*
*/
boolean testOnReturn = true;
/**
*
*/
boolean testOnCreate = true;
/**
*
*/
boolean testWhileIdle = true;
/**
*
*/
boolean lifo = DEFAULT_LIFO;
}

@ -7,9 +7,12 @@ import com.gccloud.dataroom.core.module.biz.component.dao.DataRoomBizComponentDa
import com.gccloud.dataroom.core.module.biz.component.dto.BizComponentSearchDTO;
import com.gccloud.dataroom.core.module.biz.component.entity.BizComponentEntity;
import com.gccloud.dataroom.core.module.biz.component.service.IBizComponentService;
import com.gccloud.dataroom.core.module.file.entity.DataRoomFileEntity;
import com.gccloud.dataroom.core.module.file.service.IDataRoomOssService;
import com.gccloud.dataroom.core.utils.CodeGenerateUtils;
import com.gccloud.common.exception.GlobalException;
import com.gccloud.common.vo.PageVO;
import com.gccloud.dataroom.core.utils.PathUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
@ -17,9 +20,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.*;
import java.util.Base64;
import java.util.List;
@ -35,6 +36,9 @@ public class BizComponentServiceImpl extends ServiceImpl<DataRoomBizComponentDao
@Resource
private DataRoomConfig bigScreenConfig;
@Resource
private IDataRoomOssService ossService;
@Override
public PageVO<BizComponentEntity> getPage(BizComponentSearchDTO searchDTO) {
LambdaQueryWrapper<BizComponentEntity> queryWrapper = new LambdaQueryWrapper<>();
@ -93,10 +97,14 @@ public class BizComponentServiceImpl extends ServiceImpl<DataRoomBizComponentDao
urlPrefix += "/";
}
for (BizComponentEntity entity : list) {
if (StringUtils.isBlank(entity.getCoverPicture())) {
String coverPicture = entity.getCoverPicture();
if (StringUtils.isBlank(coverPicture)) {
continue;
}
entity.setCoverPicture(urlPrefix + entity.getCoverPicture().replace("\\", "/"));
if (coverPicture.startsWith("/")) {
coverPicture = coverPicture.substring(1);
}
entity.setCoverPicture(urlPrefix + PathUtils.normalizePath(coverPicture));
}
return bizComponentEntity;
}
@ -133,13 +141,6 @@ public class BizComponentServiceImpl extends ServiceImpl<DataRoomBizComponentDao
}
/**
* base64
*
* @param base64String
* @param fileName
* @return
*/
private String saveCoverPicture(String base64String, String fileName) {
String fileUrl = "";
if (StringUtils.isBlank(base64String)) {
@ -150,29 +151,21 @@ public class BizComponentServiceImpl extends ServiceImpl<DataRoomBizComponentDao
base64String = base64String.substring(base64String.indexOf(",") + 1);
// 解码base64字符串
byte[] imageBytes = Base64.getDecoder().decode(base64String);
String basePath = bigScreenConfig.getFile().getBasePath();
// 不是/结尾,加上/
if (!basePath.endsWith("/") || !basePath.endsWith("\\")) {
basePath += File.separator;
}
// 检查目录是否存在,不存在则创建
File file = new File(basePath + "cover");
if (!file.exists()) {
file.mkdirs();
}
// 保存为图片文件
String filePath = basePath + "cover" + File.separator + fileName + ".png";
fileUrl = "cover" + File.separator + fileName + ".png";
FileOutputStream outputStream = new FileOutputStream(filePath);
outputStream.write(imageBytes);
outputStream.close();
InputStream inputStream = new ByteArrayInputStream(imageBytes);
DataRoomFileEntity fileEntity = new DataRoomFileEntity();
String filePath = "cover" + File.separator + fileName + ".png";
ossService.upload(inputStream, filePath, 0, fileEntity);
// 封面先不保存到资源库
// fileService.save(fileEntity);
log.info("组业务件封面保存至:{}", filePath);
} catch (IOException e) {
fileUrl = fileEntity.getUrl();
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
}
return fileUrl;
}
public static final String COPY_SUFFIX = "-副本";
@Override
@ -198,11 +191,11 @@ public class BizComponentServiceImpl extends ServiceImpl<DataRoomBizComponentDao
i++;
}
copyFrom.setCode(CodeGenerateUtils.generate("bizComponent"));
boolean copy = this.copyCoverPicture(oldCode, copyFrom.getCode());
if (!copy) {
String copyUrl = this.copyCoverPicture(oldCode, copyFrom.getCode());
if (StringUtils.isBlank(copyUrl)) {
copyFrom.setCoverPicture(null);
} else {
copyFrom.setCoverPicture("cover" + File.separator + copyFrom.getCode() + ".png");
copyFrom.setCoverPicture(copyUrl);
}
this.save(copyFrom);
return copyFrom.getCode();
@ -215,26 +208,13 @@ public class BizComponentServiceImpl extends ServiceImpl<DataRoomBizComponentDao
* @param newFileName
* @return
*/
private boolean copyCoverPicture(String oldFileName, String newFileName) {
private String copyCoverPicture(String oldFileName, String newFileName) {
if (StringUtils.isBlank(oldFileName)) {
return false;
}
String basePath = bigScreenConfig.getFile().getBasePath() + File.separator;
String oldFile = basePath + "cover" + File.separator + oldFileName + ".png";
// 检查文件是否存在
File file = new File(oldFile);
if (!file.exists() || !file.isFile()) {
return false;
}
// 复制一份
String newFilePath = basePath + "cover" + File.separator + newFileName + ".png";
try {
FileUtils.copyFile(file, new File(newFilePath));
return true;
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
return "";
}
return false;
String oldFile = "cover" + File.separator + oldFileName + ".png";
String newFilePath = "cover" + File.separator + newFileName + ".png";
return ossService.copy(oldFile, newFilePath);
}
@Override

@ -1,20 +0,0 @@
package com.gccloud.dataroom.core.module.file.enums;
/**
* @Description Description
* @Author Acechengui
* @Date Created in 2023-10-14
*/
public enum FileUploadType {
LOCAL("local"),
MINIO("minio");
// 以上是枚举的成员,必须先定义,而且使用分号结束
private final String value;
FileUploadType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}

@ -1,57 +0,0 @@
package com.gccloud.dataroom.core.module.file.service;
import com.gccloud.dataroom.core.module.file.entity.DataRoomFileEntity;
import com.gccloud.dataroom.core.module.file.enums.FileUploadType;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author Acechengui
*/
@Service
@Slf4j
public class FileOperationStrategy {
private final IDataRoomOssService dataRoomOssService;
public FileOperationStrategy(IDataRoomOssService localFileService, IDataRoomOssService minioFileService) {
this.dataRoomOssService = localFileService != null ? localFileService : minioFileService;
}
public static class LocalFileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, @NotNull AnnotatedTypeMetadata metadata) {
String uploadType = context.getEnvironment().getProperty("gc.starter.file.uploadType");
return FileUploadType.LOCAL.getValue().equalsIgnoreCase(uploadType) ||
!FileUploadType.MINIO.getValue().equalsIgnoreCase(uploadType);
}
}
public static class MinioFileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, @NotNull AnnotatedTypeMetadata metadata) {
String uploadType = context.getEnvironment().getProperty("gc.starter.file.uploadType");
return FileUploadType.MINIO.getValue().equalsIgnoreCase(uploadType);
}
}
public DataRoomFileEntity upload(MultipartFile file, DataRoomFileEntity entity, HttpServletResponse response, HttpServletRequest request) {
return dataRoomOssService.upload(file, entity, response, request);
}
public void download(String fileId, HttpServletResponse response, HttpServletRequest request) {
dataRoomOssService.download(fileId, response, request);
}
public void delete(String fileId) {
dataRoomOssService.delete(fileId);
}
}

@ -6,6 +6,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
/**
*
@ -14,7 +15,7 @@ import javax.servlet.http.HttpServletResponse;
*/
public interface IDataRoomOssService {
/**
*
*
*
* @param file
* @param entity
@ -24,6 +25,18 @@ public interface IDataRoomOssService {
*/
DataRoomFileEntity upload(MultipartFile file, DataRoomFileEntity entity, HttpServletResponse response, HttpServletRequest request);
/**
* ,
* @param inputStream
* @param fileName
* @param size
* @param entity
* @return
*/
DataRoomFileEntity upload(InputStream inputStream, String fileName, long size, DataRoomFileEntity entity);
/**
*
*
@ -39,4 +52,12 @@ public interface IDataRoomOssService {
* @param fileId
*/
void delete(String fileId);
/**
*
* @param sourcePath
* @param targetPath
* @return
*/
default String copy(String sourcePath, String targetPath) {return "";}
}

@ -0,0 +1,154 @@
package com.gccloud.dataroom.core.module.file.service.impl;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.gccloud.common.exception.GlobalException;
import com.gccloud.dataroom.core.config.DataRoomConfig;
import com.gccloud.dataroom.core.config.bean.FileConfig;
import com.gccloud.dataroom.core.module.file.entity.DataRoomFileEntity;
import com.gccloud.dataroom.core.module.file.service.IDataRoomFileService;
import com.gccloud.dataroom.core.module.file.service.IDataRoomOssService;
import com.gccloud.dataroom.core.utils.FtpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
/**
* ftp
* ftpftp
* url访nginxftp访gc.starter.file.urlPrefix
* @author hongyang
* @version 1.0
* @date 2023/10/17 15:12
*/
@Service
@Slf4j
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "ftp")
public class DataRoomFtpFileServiceImpl implements IDataRoomOssService {
@Resource
private FtpClientUtil ftpUtil;
@Resource
private DataRoomConfig bigScreenConfig;
@Resource
private IDataRoomFileService sysFileService;
@Override
public DataRoomFileEntity upload(MultipartFile file, DataRoomFileEntity fileEntity, HttpServletResponse response, HttpServletRequest request) {
String originalFilename = file.getOriginalFilename();
// 提取文件后缀名
String extension = FilenameUtils.getExtension(originalFilename);
FileConfig fileConfig = bigScreenConfig.getFile();
if (!fileConfig.getAllowedFileExtensionName().contains("*") && !fileConfig.getAllowedFileExtensionName().contains(extension)) {
log.error("不支持 {} 文件类型",extension);
throw new GlobalException("不支持的文件类型");
}
// 重命名
String id = IdWorker.getIdStr();
String newFileName = id + "." + extension;
long size = file.getSize();
InputStream inputStream;
try {
inputStream = file.getInputStream();
} catch (IOException e) {
log.error("上传文件到FTP服务失败获取文件流失败");
log.error(ExceptionUtils.getStackTrace(e));
throw new GlobalException("获取文件流失败");
}
return this.upload(inputStream, newFileName, size, fileEntity);
}
@Override
public DataRoomFileEntity upload(InputStream inputStream, String fileName, long size, DataRoomFileEntity fileEntity) {
// 提取文件后缀名
String extension = FilenameUtils.getExtension(fileName);
// 上传的目标路径
String basePath = bigScreenConfig.getFile().getBasePath();
// 上传文件到ftp
boolean upload = ftpUtil.upload(basePath, fileName, inputStream);
if (!upload) {
log.error("上传文件到ftp失败");
throw new GlobalException("上传文件到ftp失败");
}
fileEntity.setOriginalName(fileName);
fileEntity.setNewName(fileName);
fileEntity.setPath(basePath);
fileEntity.setSize(size);
fileEntity.setExtension(extension);
fileEntity.setUrl("/" + fileName);
return fileEntity;
}
@Override
public void download(String fileId, HttpServletResponse response, HttpServletRequest request) {
DataRoomFileEntity fileEntity = sysFileService.getById(fileId);
if (fileEntity == null) {
response.setStatus(HttpStatus.NOT_FOUND.value());
log.error("下载的文件不存在");
return;
}
response.setContentType("application/x-msdownload");
response.setContentType("multipart/form-data");
// 不设置前端无法从header获取文件名
response.setHeader("Access-Control-Expose-Headers", "filename");
try {
response.setHeader("filename", URLEncoder.encode(fileEntity.getOriginalName(), "UTF-8"));
// 解决下载的文件不携带后缀
response.setHeader("Content-Disposition", "attachment;fileName="+URLEncoder.encode(fileEntity.getOriginalName(),"UTF-8"));
} catch (UnsupportedEncodingException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
OutputStream outputStream;
try {
outputStream = response.getOutputStream();
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return;
}
boolean download = ftpUtil.download(fileEntity.getPath(), fileEntity.getNewName(), outputStream);
if (!download) {
log.error("下载文件失败");
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
try {
outputStream.close();
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
sysFileService.updateDownloadCount(1, fileId);
}
@Override
public void delete(String fileId) {
DataRoomFileEntity fileEntity = sysFileService.getById(fileId);
if (fileEntity == null) {
log.error("删除的文件不存在");
return;
}
sysFileService.removeById(fileId);
// 删除ftp上的文件
ftpUtil.delete(fileEntity.getPath(), fileEntity.getNewName());
}
@Override
public String copy(String sourcePath, String targetPath) {
String basePath = bigScreenConfig.getFile().getBasePath() + File.separator;
boolean copySuccess = ftpUtil.copy(basePath + sourcePath, basePath + targetPath);
if (!copySuccess) {
return "";
}
return targetPath;
}
}

@ -1,19 +1,18 @@
package com.gccloud.dataroom.core.module.file.service.impl;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.gccloud.common.exception.GlobalException;
import com.gccloud.dataroom.core.config.DataRoomConfig;
import com.gccloud.dataroom.core.config.bean.FileConfig;
import com.gccloud.dataroom.core.module.file.entity.DataRoomFileEntity;
import com.gccloud.dataroom.core.module.file.service.FileOperationStrategy;
import com.gccloud.dataroom.core.module.file.service.IDataRoomFileService;
import com.gccloud.dataroom.core.module.file.service.IDataRoomOssService;
import com.gccloud.common.exception.GlobalException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Conditional;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@ -21,19 +20,15 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.io.*;
import java.net.URLEncoder;
/**
*
*/
@Conditional(FileOperationStrategy.LocalFileCondition.class)
@Service("localFileService")
@Slf4j
@ConditionalOnProperty(prefix = "gc.starter.dataroom.component", name = "IDataRoomOssService", havingValue = "DataRoomLocalFileServiceImpl", matchIfMissing = true)
@Service
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "local", matchIfMissing = true)
public class DataRoomLocalFileServiceImpl implements IDataRoomOssService {
@Resource
@ -75,6 +70,44 @@ public class DataRoomLocalFileServiceImpl implements IDataRoomOssService {
return fileEntity;
}
@Override
public DataRoomFileEntity upload(InputStream inputStream, String fileName, long size, DataRoomFileEntity fileEntity) {
// 上传文件保存到的路径, 从配置文件获取
String basePath = bigScreenConfig.getFile().getBasePath();
// 提取文件后缀名
String extension = FilenameUtils.getExtension(fileName);
String destPath = basePath + File.separator + fileName;
try {
File dest = new File(destPath);
// 检查文件所在的目录是否存在,不存在则创建
String parent = dest.getParent();
File parentFile = new File(parent);
if (!parentFile.exists()) {
FileUtils.forceMkdir(parentFile);
}
FileOutputStream outputStream = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
outputStream.close();
inputStream.close();
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
log.error(String.format("文件 %s 存储到 %s 失败", fileName, destPath));
throw new GlobalException("文件上传失败");
}
fileEntity.setOriginalName(fileName);
fileEntity.setNewName(fileName);
fileEntity.setPath(basePath);
fileEntity.setSize(size);
fileEntity.setExtension(extension);
fileEntity.setUrl("/" + fileName);
return fileEntity;
}
@Override
public void download(String fileId, HttpServletResponse response, HttpServletRequest request) {
DataRoomFileEntity fileEntity = sysFileService.getById(fileId);
@ -131,4 +164,29 @@ public class DataRoomLocalFileServiceImpl implements IDataRoomOssService {
}
file.delete();
}
@Override
public String copy(String sourcePath, String targetPath) {
String basePath = bigScreenConfig.getFile().getBasePath() + File.separator;
File sourceFile = new File(basePath + sourcePath);
File targetFile = new File(basePath + targetPath);
// 检查源文件是否存在
if (!sourceFile.exists()) {
log.error("复制源文件不存在:{}", sourcePath);
return "";
}
// 检查源文件是否是文件夹
if (sourceFile.isDirectory()) {
log.error("源文件为文件夹:{},无法复制", sourcePath);
return "";
}
try {
FileUtils.copyFile(sourceFile, targetFile);
} catch (IOException e) {
log.error(String.format("文件 %s 复制到 %s 失败", sourcePath, targetPath));
log.error(ExceptionUtils.getStackTrace(e));
return "";
}
return targetPath;
}
}

@ -3,21 +3,20 @@ package com.gccloud.dataroom.core.module.file.service.impl;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.gccloud.common.exception.GlobalException;
import com.gccloud.dataroom.core.config.DataRoomConfig;
import com.gccloud.dataroom.core.config.MinioConfig;
import com.gccloud.dataroom.core.config.bean.FileConfig;
import com.gccloud.dataroom.core.config.bean.MinioConfig;
import com.gccloud.dataroom.core.module.file.entity.DataRoomFileEntity;
import com.gccloud.dataroom.core.module.file.service.FileOperationStrategy;
import com.gccloud.dataroom.core.module.file.service.IDataRoomFileService;
import com.gccloud.dataroom.core.module.file.service.IDataRoomOssService;
import com.gccloud.dataroom.core.utils.MinioFileInterface;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.SneakyThrows;
import com.gccloud.dataroom.core.utils.PathUtils;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Conditional;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@ -26,6 +25,7 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@ -35,14 +35,11 @@ import java.time.format.DateTimeFormatter;
*
* @author Acechengui
*/
@Service("minioFileService")
@Conditional(FileOperationStrategy.MinioFileCondition.class)
@Slf4j
@Service
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "minio")
public class DataRoomMinioServiceImpl implements IDataRoomOssService {
@Resource
private MinioConfig minioConfig;
@Resource
private MinioClient minioclient;
@ -51,14 +48,13 @@ public class DataRoomMinioServiceImpl implements IDataRoomOssService {
@Resource
private IDataRoomFileService sysFileService;
@Resource
private MinioFileInterface minioFileInterface;
/**
*
*
*/
@SneakyThrows
@Override
public DataRoomFileEntity upload(MultipartFile file, DataRoomFileEntity fileEntity, HttpServletResponse response, HttpServletRequest request) {
String originalFilename = file.getOriginalFilename();
@ -66,7 +62,7 @@ public class DataRoomMinioServiceImpl implements IDataRoomOssService {
String extension = FilenameUtils.getExtension(originalFilename);
FileConfig fileConfig = bigScreenConfig.getFile();
if (!fileConfig.getAllowedFileExtensionName().contains("*") && !fileConfig.getAllowedFileExtensionName().contains(extension)) {
log.error("不支持 {} 文件类型",extension);
log.error("不支持 {} 文件类型", extension);
throw new GlobalException("不支持的文件类型");
}
String module = request.getParameter("module");
@ -77,31 +73,74 @@ public class DataRoomMinioServiceImpl implements IDataRoomOssService {
// 重命名
String newFileName = IdWorker.getIdStr() + "." + extension;
// 组装路径:获取当前日期并格式化为"yyyy/mm/dd"格式的字符串
String filePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")) + "/" + newFileName;
InputStream inputStream = file.getInputStream();
PutObjectArgs args = PutObjectArgs.builder()
String basePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
String filePath = basePath + "/" + newFileName;
MinioConfig minioConfig = bigScreenConfig.getFile().getMinio();
try (InputStream inputStream = file.getInputStream()) {
PutObjectArgs args = PutObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(filePath)
.stream(inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build();
minioclient.putObject(args);
String url = minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + filePath;
minioclient.putObject(args);
} catch (Exception e) {
log.error("上传文件到Minio失败");
log.error(ExceptionUtils.getStackTrace(e));
throw new GlobalException("上传文件失败");
}
// 现在url存储文件的相对路径对于minio来说就是bucketName/文件名
String url = "/" + minioConfig.getBucketName() + "/" + filePath;
fileEntity.setOriginalName(originalFilename);
fileEntity.setNewName(newFileName);
fileEntity.setPath(filePath);
fileEntity.setSize(file.getSize());
fileEntity.setExtension(extension);
fileEntity.setUrl(url);
fileEntity.setModule(module);
fileEntity.setBucket(minioConfig.getBucketName());
return fileEntity;
}
@Override
public DataRoomFileEntity upload(InputStream inputStream, String fileName, long size, DataRoomFileEntity entity) {
fileName = PathUtils.normalizePath(fileName);
String extension = FilenameUtils.getExtension(fileName);
MinioConfig minioConfig = bigScreenConfig.getFile().getMinio();
long fileSize = size == 0 ? -1 : size;
// 使用minio的最小分片大小
long partSize = fileSize == -1 ? ObjectWriteArgs.MIN_MULTIPART_SIZE : -1;
try {
PutObjectArgs args = PutObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(fileName)
.stream(inputStream, fileSize, partSize)
.contentType("image/png")
.build();
minioclient.putObject(args);
} catch (Exception e) {
log.error("上传文件到Minio失败");
log.error(ExceptionUtils.getStackTrace(e));
throw new GlobalException("上传文件失败");
} finally {
IOUtils.closeQuietly(inputStream);
}
// 现在url存储文件的相对路径对于minio来说就是bucketName/文件名
String url = "/" + minioConfig.getBucketName() + "/" + fileName;
entity.setOriginalName(fileName);
entity.setNewName(fileName);
entity.setPath(fileName);
entity.setSize(fileSize);
entity.setExtension(extension);
entity.setUrl(url);
entity.setBucket(minioConfig.getBucketName());
return entity;
}
/**
*
*
*/
@SneakyThrows
@Override
public void download(String fileId, HttpServletResponse response, HttpServletRequest request) {
DataRoomFileEntity fileEntity = sysFileService.getById(fileId);
@ -114,9 +153,14 @@ public class DataRoomMinioServiceImpl implements IDataRoomOssService {
response.setContentType("multipart/form-data");
// 不设置前端无法从header获取文件名
response.setHeader("Access-Control-Expose-Headers", "filename");
response.setHeader("filename", URLEncoder.encode(fileEntity.getOriginalName(), "UTF-8"));
// 解决下载的文件不携带后缀
response.setHeader("Content-Disposition", "attachment;fileName="+URLEncoder.encode(fileEntity.getOriginalName(), "UTF-8"));
try {
response.setHeader("filename", URLEncoder.encode(fileEntity.getOriginalName(), "UTF-8"));
// 解决下载的文件不携带后缀
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileEntity.getOriginalName(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
log.error("文件名编码失败");
log.error(ExceptionUtils.getStackTrace(e));
}
try {
InputStream is = minioFileInterface.download(fileEntity.getPath());
IOUtils.copy(is, response.getOutputStream());
@ -124,7 +168,8 @@ public class DataRoomMinioServiceImpl implements IDataRoomOssService {
response.getOutputStream().close();
} catch (Exception e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
log.error(String.format("下载文件%s失败", fileEntity.getOriginalName()));
log.error("下载文件失败: {}", fileEntity.getPath());
log.error(ExceptionUtils.getStackTrace(e));
} finally {
sysFileService.updateDownloadCount(1, fileId);
}
@ -133,10 +178,39 @@ public class DataRoomMinioServiceImpl implements IDataRoomOssService {
/**
*
*/
@SneakyThrows
@Override
public void delete(String fileId) {
String path = sysFileService.getById(fileId).getPath();
minioFileInterface.deleteObject(path.substring(path.indexOf(minioConfig.getBucketName())+minioConfig.getBucketName().length()+1));
DataRoomFileEntity fileEntity = sysFileService.getById(fileId);
if (fileEntity == null) {
log.error("删除的文件不存在");
return;
}
sysFileService.removeById(fileId);
String path = fileEntity.getPath();
try {
minioFileInterface.deleteObject(path);
} catch (Exception e) {
log.error("删除Minio文件失败: {}", path);
log.error(ExceptionUtils.getStackTrace(e));
}
}
@Override
public String copy(String sourcePath, String targetPath) {
MinioConfig minioConfig = bigScreenConfig.getFile().getMinio();
CopySource source = CopySource.builder().bucket(minioConfig.getBucketName()).object(sourcePath).build();
CopyObjectArgs args = CopyObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(PathUtils.normalizePath(targetPath))
.source(source)
.build();
try {
minioclient.copyObject(args);
} catch (Exception e) {
log.error("复制Minio文件失败: {}", sourcePath);
log.error(ExceptionUtils.getStackTrace(e));
return "";
}
return minioConfig.getBucketName() + "/" + targetPath;
}
}

@ -0,0 +1,157 @@
package com.gccloud.dataroom.core.module.file.service.impl;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.gccloud.common.exception.GlobalException;
import com.gccloud.dataroom.core.config.DataRoomConfig;
import com.gccloud.dataroom.core.config.bean.FileConfig;
import com.gccloud.dataroom.core.module.file.entity.DataRoomFileEntity;
import com.gccloud.dataroom.core.module.file.service.IDataRoomFileService;
import com.gccloud.dataroom.core.module.file.service.IDataRoomOssService;
import com.gccloud.dataroom.core.utils.SftpClientUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
/**
* sftp
* sftpsftp
* url访nginxsftp访gc.starter.file.urlPrefix
* @author hongyang
* @version 1.0
* @date 2023/10/17 15:12
*/
@Slf4j
@Service
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "sftp")
public class DataRoomSftpFileServiceImpl implements IDataRoomOssService {
@Resource
private SftpClientUtils sftpUtil;
@Resource
private DataRoomConfig bigScreenConfig;
@Resource
private IDataRoomFileService sysFileService;
@Override
public DataRoomFileEntity upload(MultipartFile file, DataRoomFileEntity fileEntity, HttpServletResponse response, HttpServletRequest request) {
String originalFilename = file.getOriginalFilename();
// 提取文件后缀名
String extension = FilenameUtils.getExtension(originalFilename);
FileConfig fileConfig = bigScreenConfig.getFile();
if (!fileConfig.getAllowedFileExtensionName().contains("*") && !fileConfig.getAllowedFileExtensionName().contains(extension)) {
log.error("不支持 {} 文件类型",extension);
throw new GlobalException("不支持的文件类型");
}
long size = file.getSize();
// 重命名
String id = IdWorker.getIdStr();
String newFileName = id + "." + extension;
InputStream inputStream;
try {
inputStream = file.getInputStream();
} catch (IOException e) {
log.error("上传文件到SFTP服务失败获取文件流失败");
log.error(ExceptionUtils.getStackTrace(e));
throw new GlobalException("获取文件流失败");
}
this.upload(inputStream, newFileName, size, fileEntity);
return fileEntity;
}
@Override
public DataRoomFileEntity upload(InputStream inputStream, String fileName, long size, DataRoomFileEntity fileEntity) {
// 提取文件后缀名
String extension = FilenameUtils.getExtension(fileName);
// 上传的目标路径
String basePath = bigScreenConfig.getFile().getBasePath();
// 上传文件到sftp
boolean upload = sftpUtil.upload(basePath, fileName, inputStream);
if (!upload) {
log.error("上传文件到sftp失败");
throw new GlobalException("上传文件到sftp失败");
}
fileEntity.setOriginalName(fileName);
fileEntity.setNewName(fileName);
fileEntity.setPath(basePath);
fileEntity.setSize(size);
fileEntity.setExtension(extension);
fileEntity.setUrl("/" + fileName);
return fileEntity;
}
@Override
public void download(String fileId, HttpServletResponse response, HttpServletRequest request) {
DataRoomFileEntity fileEntity = sysFileService.getById(fileId);
if (fileEntity == null) {
response.setStatus(HttpStatus.NOT_FOUND.value());
log.error("下载的文件不存在");
return;
}
response.setContentType("application/x-msdownload");
response.setContentType("multipart/form-data");
// 不设置前端无法从header获取文件名
response.setHeader("Access-Control-Expose-Headers", "filename");
try {
response.setHeader("filename", URLEncoder.encode(fileEntity.getOriginalName(), "UTF-8"));
// 解决下载的文件不携带后缀
response.setHeader("Content-Disposition", "attachment;fileName="+URLEncoder.encode(fileEntity.getOriginalName(),"UTF-8"));
} catch (UnsupportedEncodingException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
OutputStream outputStream;
try {
outputStream = response.getOutputStream();
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return;
}
boolean download = sftpUtil.download(fileEntity.getPath(), fileEntity.getNewName(), outputStream);
if (!download) {
log.error("下载文件失败");
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
try {
outputStream.close();
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
sysFileService.updateDownloadCount(1, fileId);
}
@Override
public void delete(String fileId) {
DataRoomFileEntity fileEntity = sysFileService.getById(fileId);
if (fileEntity == null) {
log.error("删除的文件不存在");
return;
}
sysFileService.removeById(fileId);
// 删除sftp上的文件
sftpUtil.delete(fileEntity.getPath(), fileEntity.getNewName());
}
@Override
public String copy(String sourcePath, String targetPath) {
String basePath = bigScreenConfig.getFile().getBasePath() + File.separator;
boolean copySuccess = sftpUtil.copy(basePath + sourcePath, basePath + targetPath);
if (!copySuccess) {
return "";
}
return targetPath;
}
}

@ -0,0 +1,153 @@
package com.gccloud.dataroom.core.module.file.service.pool.ftp;
import com.gccloud.dataroom.core.config.DataRoomConfig;
import com.gccloud.dataroom.core.config.bean.FtpConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* FtpClient
* @author hongyang
* @version 1.0
* @date 2023/10/18 10:17
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "ftp")
public class FtpClientFactory implements PooledObjectFactory<FTPClient> {
/**
* ftp
*/
@Resource
private DataRoomConfig config;
/**
*
*
* @return
* @throws Exception
*/
@Override
public PooledObject<FTPClient> makeObject() throws Exception {
log.info("创建ftp连接");
FtpConfig ftp = config.getFile().getFtp();
FTPClient ftpClient = new FTPClient();
ftpClient.setConnectTimeout(ftp.getClientTimeout());
ftpClient.connect(ftp.getHost(), ftp.getPort());
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
return null;
}
boolean success;
if (StringUtils.isBlank(ftp.getUsername())) {
success = ftpClient.login("anonymous", "anonymous");
} else {
success = ftpClient.login(ftp.getUsername(), ftp.getPassword());
}
if (!success) {
return null;
}
ftpClient.setFileType(ftp.getTransferFileType());
ftpClient.setBufferSize(1024);
ftpClient.setControlEncoding(ftp.getEncoding());
if (ftp.isPassiveMode()) {
ftpClient.enterLocalPassiveMode();
}
log.debug("创建ftp连接");
return new DefaultPooledObject<>(ftpClient);
}
/**
*
*
* @param pool
* @return
*/
@Override
public boolean validateObject(PooledObject<FTPClient> pool) {
FTPClient ftpClient = pool.getObject();
try {
return ftpClient != null && ftpClient.sendNoOp();
} catch (Exception e) {
return false;
}
}
/**
*
*
* @param pool
* @throws Exception
*/
@Override
public void destroyObject(PooledObject<FTPClient> pool) throws Exception {
FTPClient ftpClient = pool.getObject();
if (ftpClient != null) {
try {
ftpClient.disconnect();
log.debug("销毁ftp连接");
} catch (Exception e) {
log.error("销毁FtpClient异常");
log.error(ExceptionUtils.getStackTrace(e));
}
}
}
/**
*
*
* @param p
* @throws Exception
*/
@Override
public void passivateObject(PooledObject<FTPClient> p) throws Exception{
FTPClient ftpClient = p.getObject();
try {
ftpClient.changeWorkingDirectory(config.getFile().getBasePath());
// 钝化链接时如果logout下次再使用重新连接时间会长所以先不做logout操作
/*
* ftpClient.logout();
* if (ftpClient.isConnected()) {
* ftpClient.disconnect();
* }
*/
} catch (Exception e) {
log.error("钝化FtpClient异常");
log.error(ExceptionUtils.getStackTrace(e));
}
}
/**
*
*
* @param pool
* @throws Exception
*/
@Override
public void activateObject(PooledObject<FTPClient> pool) throws Exception {
FtpConfig ftp = config.getFile().getFtp();
FTPClient ftpClient = pool.getObject();
if (!ftpClient.isConnected()) {
log.info("ftp连接已关闭重新连接");
ftpClient.connect(ftp.getHost(),ftp.getPort());
ftpClient.login(ftp.getUsername(), ftp.getPassword());
}
ftpClient.setControlEncoding(ftp.getEncoding());
ftpClient.changeWorkingDirectory(config.getFile().getBasePath());
// 设置上传文件类型为二进制,否则将无法打开文件
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
}
}

@ -0,0 +1,79 @@
package com.gccloud.dataroom.core.module.file.service.pool.ftp;
import com.gccloud.dataroom.core.config.bean.FtpConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* @author hongyang
* @version 1.0
* @date 2023/10/18 10:20
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "ftp")
public class FtpPoolServiceImpl {
/**
* ftp
*/
private GenericObjectPool<FTPClient> pool;
/**
* ftp
*/
@Resource
private FtpConfig config;
/**
* ftp
*/
@Resource
private FtpClientFactory factory;
/**
* pool
*/
@PostConstruct
private void initPool() {
log.info("初始化FTP连接池");
this.pool = new GenericObjectPool<FTPClient>(this.factory, this.config);
}
/**
* ftpClient
*/
public FTPClient borrowObject() {
log.info("获取 FTPClient");
if (this.pool != null) {
try {
return this.pool.borrowObject();
} catch (Exception e) {
log.error("获取 FTPClient 失败 ", e);
}
}
return null;
}
/**
* ftpClient
*/
public void returnObject(FTPClient ftpClient) {
if (this.pool == null || ftpClient == null) {
return;
}
try {
ftpClient.changeWorkingDirectory("/");
} catch (Exception e) {
log.error("FTPClient 重置目录失败 ", e);
}
this.pool.returnObject(ftpClient);
}
}

@ -0,0 +1,105 @@
package com.gccloud.dataroom.core.module.file.service.pool.sftp;
import com.gccloud.dataroom.core.config.bean.SftpConfig;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Properties;
/**
* SFTP
* @author hongyang
* @version 1.0
* @date 2023/10/18 15:17
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "sftp")
public class SftpClientFactory extends BasePooledObjectFactory<ChannelSftp>{
@Resource
private SftpConfig config;
/**
*
*/
@Override
public ChannelSftp create() {
ChannelSftp channel = null;
try {
// 用户名密码不能为空
if (StringUtils.isBlank(config.getUsername()) || StringUtils.isBlank(config.getPassword())) {
log.error("SFTP用户名密码不能为空");
return null;
}
JSch jsch = new JSch();
// 设置私钥
if (StringUtils.isNotBlank(config.getPrivateKey())) {
jsch.addIdentity(config.getPrivateKey());
}
// jsch的session需要补充设置sshConfig.put("PreferredAuthentications", "publickey,keyboard-interactive,password")来跳过Kerberos认证同样的HutoolSFTPUtil工具类里面也有这个问题
Session sshSession = jsch.getSession(config.getUsername(), config.getHost(), config.getPort());
sshSession.setPassword(config.getPassword());
Properties sshConfig = new Properties();
// “StrictHostKeyChecking”如果设置成“yes”ssh就不会自动把计算机的密匙加入“$HOME/.ssh/known_hosts”文件并且一旦计算机的密匙发生了变化就拒绝连接。
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect();
channel = (ChannelSftp) sshSession.openChannel("sftp");
channel.connect();
} catch (Exception e) {
log.error("连接 sftp 失败,请检查配置");
log.error(ExceptionUtils.getStackTrace(e));
}
return channel;
}
/**
*
*
* @param channelSftp
* @return
*/
@Override
public PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {
return new DefaultPooledObject<>(channelSftp);
}
/**
*
*
* @param p
*/
@Override
public void destroyObject(PooledObject<ChannelSftp> p) {
ChannelSftp channelSftp = p.getObject();
channelSftp.disconnect();
}
@Override
public boolean validateObject(final PooledObject<ChannelSftp> p) {
final ChannelSftp channelSftp = p.getObject();
try {
if (channelSftp.isClosed()) {
return false;
}
channelSftp.cd("/");
} catch (Exception e) {
log.error("ChannelSftp 不可用");
log.error(ExceptionUtils.getStackTrace(e));
return false;
}
return true;
}
}

@ -0,0 +1,74 @@
package com.gccloud.dataroom.core.module.file.service.pool.sftp;
import com.gccloud.dataroom.core.config.bean.SftpConfig;
import com.jcraft.jsch.ChannelSftp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* Sftp
* @author hongyang
* @version 1.0
* @date 2023/10/18 15:21
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "sftp")
public class SftpPoolService {
/**
* ftp
*/
private GenericObjectPool<ChannelSftp> pool;
/**
* ftp
*/
@Resource
private SftpConfig config;
/**
* ftp
*/
@Resource
private SftpClientFactory factory;
/**
* pool
*/
@PostConstruct
private void initPool() {
log.info("初始化SFTP连接池");
this.pool = new GenericObjectPool<ChannelSftp>(this.factory, this.config);
}
/**
* sftp
*/
public ChannelSftp borrowObject() {
if (this.pool != null) {
try {
return this.pool.borrowObject();
} catch (Exception e) {
log.error("获取 ChannelSftp 失败", e);
e.printStackTrace();
}
}
return null;
}
/**
* sftp
*/
public void returnObject(ChannelSftp channelSftp) {
if (this.pool != null && channelSftp != null) {
this.pool.returnObject(channelSftp);
}
}
}

@ -10,6 +10,9 @@ import com.gccloud.dataroom.core.module.basic.entity.PagePreviewEntity;
import com.gccloud.dataroom.core.module.chart.bean.Chart;
import com.gccloud.dataroom.core.module.chart.bean.Linkage;
import com.gccloud.dataroom.core.module.chart.components.datasource.DataSetDataSource;
import com.gccloud.dataroom.core.module.file.entity.DataRoomFileEntity;
import com.gccloud.dataroom.core.module.file.service.IDataRoomFileService;
import com.gccloud.dataroom.core.module.file.service.IDataRoomOssService;
import com.gccloud.dataroom.core.module.manage.dto.DataRoomPageDTO;
import com.gccloud.dataroom.core.module.manage.dto.DataRoomSearchDTO;
import com.gccloud.dataroom.core.module.manage.extend.DataRoomExtendClient;
@ -23,6 +26,7 @@ import com.gccloud.common.exception.GlobalException;
import com.gccloud.common.utils.AssertUtils;
import com.gccloud.common.utils.BeanConvertUtils;
import com.gccloud.common.vo.PageVO;
import com.gccloud.dataroom.core.utils.PathUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
@ -30,12 +34,13 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.*;
import java.util.Base64;
import java.util.List;
import java.util.Map;
@ -67,6 +72,9 @@ public class DataRoomPageServiceImpl extends ServiceImpl<DataRoomPageDao, PageEn
@Resource
private IDataRoomPagePreviewService previewService;
@Resource
private IDataRoomOssService ossService;
@Override
public PageEntity getByCode(String code) {
if (code.startsWith(IDataRoomPagePreviewService.PREVIEW_KEY)) {
@ -124,24 +132,15 @@ public class DataRoomPageServiceImpl extends ServiceImpl<DataRoomPageDao, PageEn
base64String = base64String.substring(base64String.indexOf(",") + 1);
// 解码base64字符串
byte[] imageBytes = Base64.getDecoder().decode(base64String);
String basePath = bigScreenConfig.getFile().getBasePath();
// 不是/结尾,加上/
if (!basePath.endsWith("/") || !basePath.endsWith("\\")) {
basePath += File.separator;
}
// 检查目录是否存在,不存在则创建
File file = new File(basePath + "cover");
if (!file.exists()) {
file.mkdirs();
}
// 保存为图片文件
String filePath = basePath + "cover" + File.separator + fileName + ".png";
fileUrl = "cover" + File.separator + fileName + ".png";
FileOutputStream outputStream = new FileOutputStream(filePath);
outputStream.write(imageBytes);
outputStream.close();
InputStream inputStream = new ByteArrayInputStream(imageBytes);
DataRoomFileEntity fileEntity = new DataRoomFileEntity();
String filePath = "cover" + File.separator + fileName + ".png";
ossService.upload(inputStream, filePath, 0, fileEntity);
// 封面先不保存到资源库
// fileService.save(fileEntity);
log.info("大屏封面保存至:{}", filePath);
} catch (IOException e) {
fileUrl = fileEntity.getUrl();
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
}
return fileUrl;
@ -154,26 +153,13 @@ public class DataRoomPageServiceImpl extends ServiceImpl<DataRoomPageDao, PageEn
* @param newFileName
* @return
*/
private boolean copyCoverPicture(String oldFileName, String newFileName) {
private String copyCoverPicture(String oldFileName, String newFileName) {
if (StringUtils.isBlank(oldFileName)) {
return false;
}
String basePath = bigScreenConfig.getFile().getBasePath() + File.separator;
String oldFile = basePath + "cover" + File.separator + oldFileName + ".png";
// 检查文件是否存在
File file = new File(oldFile);
if (!file.exists() || !file.isFile()) {
return false;
return "";
}
// 复制一份
String newFilePath = basePath + "cover" + File.separator + newFileName + ".png";
try {
FileUtils.copyFile(file, new File(newFilePath));
return true;
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
return false;
String oldFile = "cover" + File.separator + oldFileName + ".png";
String newFilePath = "cover" + File.separator + newFileName + ".png";
return ossService.copy(oldFile, newFilePath);
}
@Override
@ -265,10 +251,14 @@ public class DataRoomPageServiceImpl extends ServiceImpl<DataRoomPageDao, PageEn
urlPrefix += "/";
}
for (PageEntity pageEntity : list) {
if (StringUtils.isBlank(pageEntity.getCoverPicture())) {
String coverPicture = pageEntity.getCoverPicture();
if (StringUtils.isBlank(coverPicture)) {
continue;
}
pageEntity.setCoverPicture(urlPrefix + pageEntity.getCoverPicture().replace("\\", "/"));
if (coverPicture.startsWith("/")) {
coverPicture = coverPicture.substring(1);
}
pageEntity.setCoverPicture(urlPrefix + PathUtils.normalizePath(coverPicture));
}
return page;
}
@ -352,11 +342,11 @@ public class DataRoomPageServiceImpl extends ServiceImpl<DataRoomPageDao, PageEn
component.setComponentKey(newCode);
}
}
boolean copy = this.copyCoverPicture(oldCode, screenEntity.getCode());
if (!copy) {
String copyUrl = this.copyCoverPicture(oldCode, screenEntity.getCode());
if (StringUtils.isBlank(copyUrl)) {
screenEntity.setCoverPicture(null);
} else {
screenEntity.setCoverPicture("cover" + File.separator + screenEntity.getCode() + ".png");
screenEntity.setCoverPicture(copyUrl);
}
this.save(screenEntity);
dataRoomExtendClient.afterAdd(screenEntity.getCode());

@ -0,0 +1,242 @@
package com.gccloud.dataroom.core.utils;
import com.gccloud.dataroom.core.config.bean.FtpConfig;
import com.gccloud.dataroom.core.module.file.service.pool.ftp.FtpPoolServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 2023/2/5 15:04
*
* @author HZ
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "ftp")
public class FtpClientUtil {
@Resource
private FtpConfig config;
/**
* ftp
*/
@Resource
private FtpPoolServiceImpl ftpPoolService;
/**
*
*
* @param uploadPath
* @param fileName
* @param input
* @return
*/
public boolean upload(String uploadPath, String fileName, InputStream input) {
String[] paths = PathUtils.handlePath(uploadPath, fileName);
uploadPath = paths[0];
fileName = paths[1];
boolean success = false;
FTPClient ftpClient = ftpPoolService.borrowObject();
try {
boolean changeSuccess = this.changeWorkingDirectory(uploadPath, ftpClient);
if (!changeSuccess) {
log.info("切换目录失败,目录:{}", uploadPath);
return false;
}
String workingDir = ftpClient.printWorkingDirectory();
log.info("当前工作目录:{}", workingDir);
ftpClient.enterLocalPassiveMode();
ftpClient.setControlEncoding("UTF-8");
ftpClient.setBufferSize(config.getBufferSize());
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
success = ftpClient.storeFile(fileName, input);
if (success) {
log.info("文件上传成功:{}", uploadPath + "/" + fileName);
} else {
log.info("文件上传失败:{}", uploadPath + "/" + fileName);
}
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
} finally {
if (null != input){
try {
input.close();
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
}
ftpPoolService.returnObject(ftpClient);
}
return success;
}
/**
*
* @param ftpPath FTP
* @param ftpFileName
* @param outputStream
* @return
*/
public boolean download(String ftpPath, String ftpFileName, OutputStream outputStream) {
String[] paths = PathUtils.handlePath(ftpPath, ftpFileName);
ftpPath = paths[0] + "/";
ftpFileName = paths[1];
FTPClient ftpClient = ftpPoolService.borrowObject();
try {
// 检查目标文件是否存在
String finalFtpFileName = ftpFileName;
FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath, file -> file.isFile() && file.getName().equals(finalFtpFileName));
if (ftpFiles == null || ftpFiles.length == 0) {
log.info("FTP服务器文件不存在:{}", ftpPath + ftpFileName);
return false;
}
ftpClient.setControlEncoding("UTF-8");
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
ftpClient.changeWorkingDirectory(ftpPath);
boolean success = ftpClient.retrieveFile(finalFtpFileName, outputStream);
if (!success) {
log.info("FTP文件下载失败:{}", ftpPath + ftpFileName);
return false;
}
log.info("FTP文件下载成功:{}", ftpPath + ftpFileName);
return true;
} catch (Exception e) {
log.info("FTP文件下载失败:{}", ftpPath + ftpFileName);
log.error(ExceptionUtils.getStackTrace(e));
} finally {
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
ftpPoolService.returnObject(ftpClient);
}
return false;
}
/**
* FTP
*
*
* @param ftpPath
* @param fileName
* @return
*/
public boolean delete(String ftpPath, String fileName) {
String[] paths = PathUtils.handlePath(ftpPath, fileName);
ftpPath = paths[0] + "/";
fileName = paths[1];
FTPClient ftpClient = ftpPoolService.borrowObject();
try {
// 在 ftp 目录下获取文件名与 fileName 匹配的文件信息
String finalFileName = fileName;
FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath, file -> file.isFile() && file.getName().equals(finalFileName));
if (ftpFiles == null || ftpFiles.length == 0) {
log.error("FTP服务器文件不存在:{},", ftpPath + fileName);
return false;
}
// 删除文件
boolean del;
ftpClient.changeWorkingDirectory(ftpPath);
del = ftpClient.deleteFile(finalFileName);
log.info(del ? "文件:{}删除成功" : "文件:{}删除失败", ftpPath + fileName);
return del;
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
} finally {
ftpPoolService.returnObject(ftpClient);
}
return false;
}
/**
*
* @param sourcePath
* @param targetPath
*/
public boolean copy(String sourcePath, String targetPath) {
sourcePath = PathUtils.normalizePath(sourcePath);
targetPath = PathUtils.normalizePath(targetPath);
// 分割路径和文件名
String[] sourceSplit = sourcePath.split("/");
String[] targetSplit = targetPath.split("/");
sourcePath = sourcePath.substring(0, sourcePath.length() - sourceSplit[sourceSplit.length - 1].length());
targetPath = targetPath.substring(0, targetPath.length() - targetSplit[targetSplit.length - 1].length());
String sourceFileName = sourceSplit[sourceSplit.length - 1];
String targetFileName = targetSplit[targetSplit.length - 1];
FTPClient ftpClient = ftpPoolService.borrowObject();
try {
// 检查目标文件是否存在
FTPFile[] ftpFiles = ftpClient.listFiles(sourcePath, file -> file.isFile() && file.getName().equals(sourceFileName));
if (ftpFiles == null || ftpFiles.length == 0) {
log.error("FTP服务器文件不存在:{}", sourcePath + sourceFileName);
return false;
}
ftpClient.setControlEncoding("UTF-8");
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
ftpClient.changeWorkingDirectory(sourcePath);
boolean success = ftpClient.retrieveFile(sourceFileName, new FileOutputStream(targetPath + targetFileName));
if (!success) {
log.error("FTP文件复制失败:{}", sourcePath + sourceFileName);
return false;
}
log.info("FTP文件复制成功:{}", targetPath + targetFileName);
return true;
} catch (Exception e) {
log.info("FTP文件复制失败:{}", sourcePath + sourceFileName);
log.error(ExceptionUtils.getStackTrace(e));
} finally {
ftpPoolService.returnObject(ftpClient);
}
return false;
}
/**
*
*
* @param workPath
* @return
*/
private boolean changeWorkingDirectory(String workPath, FTPClient ftpClient) throws IOException {
boolean success = ftpClient.changeWorkingDirectory(workPath);
if (!success) {
String[] dirs = workPath.split("/");
for (String str : dirs) {
if(StringUtils.isBlank(str)) {
continue;
}
if (!ftpClient.changeWorkingDirectory(str)) {
boolean makeDirectory = ftpClient.makeDirectory(str);
log.info("创建目录:{}, 结果: {}", str, makeDirectory ? "成功" : "失败");
success = ftpClient.changeWorkingDirectory(str);
}
}
}
return success;
}
}

@ -1,6 +1,6 @@
package com.gccloud.dataroom.core.utils;
import com.gccloud.dataroom.core.config.MinioConfig;
import com.gccloud.dataroom.core.config.bean.MinioConfig;
import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.GetPresignedObjectUrlArgs;

@ -0,0 +1,56 @@
package com.gccloud.dataroom.core.utils;
import org.apache.commons.lang3.StringUtils;
/**
* @author hongyang
* @version 1.0
* @date 2023/10/18 17:29
*/
public class PathUtils {
/**
* \,/,//
* @param path
* @return
*/
public static String normalizePath(String path) {
if (StringUtils.isBlank(path)) {
return path;
}
path = path.replace("\\", "/");
while (path.contains("//")) {
path = path.replace("//", "/");
}
return path;
}
/**
*
* filePath
* @param filePath
* @param fileName
* @return
*/
public static String[] handlePath(String filePath, String fileName) {
filePath = normalizePath(filePath);
// 去除路径最后的/
if (filePath.endsWith("/")) {
filePath = filePath.substring(0, filePath.length() - 1);
}
fileName = normalizePath(fileName);
// 去除文件名前的/
if (fileName.startsWith("/")) {
fileName = fileName.substring(1);
}
// fileName可能包含路径需要将路径分离出来转移到filePath下
String[] split = fileName.split("/");
if (split.length > 1) {
String fileNameTemp = split[split.length - 1];
String filePathTemp = fileName.substring(0, fileName.length() - fileNameTemp.length());
filePath = filePath + "/" + filePathTemp;
fileName = fileNameTemp;
}
return new String[]{filePath, fileName};
}
}

@ -0,0 +1,242 @@
package com.gccloud.dataroom.core.utils;
import com.gccloud.dataroom.core.config.bean.SftpConfig;
import com.gccloud.dataroom.core.module.file.service.pool.sftp.SftpPoolService;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Sftp
* @author hongyang
* @version 1.0
* @date 2023/10/18 15:28
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "gc.starter.file", name = "type", havingValue = "sftp")
public class SftpClientUtils {
@Resource
private SftpConfig config;
@Resource
private SftpPoolService sFtpPoolService;
/**
*
* @param uploadPath
* @param fileName
* @param inputStream
* @return
*/
public boolean upload(String uploadPath, String fileName, InputStream inputStream) {
ChannelSftp sftp = sFtpPoolService.borrowObject();
String[] paths = PathUtils.handlePath(uploadPath, fileName);
uploadPath = paths[0];
// TODO 检查目录是否存在,不存在则创建
if (!this.exist(uploadPath)) {
try {
sftp.mkdir(uploadPath);
} catch (SftpException e) {
log.error(ExceptionUtils.getStackTrace(e));
return false;
}
}
fileName = "/" + paths[1];
String filePath = uploadPath.concat(fileName);
try {
sftp.put(inputStream, filePath);
/**
*
*/
String permission = "755";
sftp.chmod(Integer.parseInt(permission, 8), filePath);
log.info("文件上传成功:{}", filePath);
return true;
} catch (SftpException e) {
log.error("文件上传失败:{}", filePath);
log.error(ExceptionUtils.getStackTrace(e));
} finally {
if (null != inputStream){
try {
inputStream.close();
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
}
sFtpPoolService.returnObject(sftp);
}
return false;
}
/**
*
* @param sftpPath
* @param fileName
* @param outputStream
* @return
*/
public boolean download(String sftpPath, String fileName, OutputStream outputStream) {
ChannelSftp sftp = sFtpPoolService.borrowObject();
String[] paths = PathUtils.handlePath(sftpPath, fileName);
sftpPath = paths[0];
fileName = "/" + paths[1];
String filePath = sftpPath.concat(fileName);
try (InputStream inputStream = sftp.get(filePath)){
// 将输入流的数据复制到输出流中
byte[] bytes = new byte[config.getBufferSize()];
int len;
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
log.info("文件下载成功:{}", filePath);
return true;
} catch (Exception e ) {
log.info("文件下载失败:{}", filePath);
log.error(ExceptionUtils.getStackTrace(e));
} finally {
if (null != outputStream){
try {
outputStream.close();
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
}
sFtpPoolService.returnObject(sftp);
}
return false;
}
/**
* SFTP
*
*
* @param sftpPath
* @param fileName
* @return
*/
public boolean delete(String sftpPath, String fileName) {
ChannelSftp sftp = sFtpPoolService.borrowObject();
String[] paths = PathUtils.handlePath(sftpPath, fileName);
sftpPath = paths[0];
fileName = "/" + paths[1];
String filePath = sftpPath.concat(fileName);
// 检查文件是否存在
if (!this.exist(filePath)) {
log.info("文件不存在:{}", filePath);
return true;
}
// 检查是否为文件夹
if (this.isDirectory(filePath)) {
log.info("该路径为文件夹:{},无法删除", filePath);
return false;
}
try {
sftp.rm(filePath);
log.info("文件删除成功:{}", filePath);
return true;
} catch (SftpException e) {
log.info("文件删除失败:{}", filePath);
log.error(ExceptionUtils.getStackTrace(e));
} finally {
sFtpPoolService.returnObject(sftp);
}
return false;
}
/**
*
* @param sourcePath
* @param targetPath
*/
public boolean copy(String sourcePath, String targetPath) {
ChannelSftp sftp1 = sFtpPoolService.borrowObject();
ChannelSftp sftp2 = sFtpPoolService.borrowObject();
sourcePath = PathUtils.normalizePath(sourcePath);
targetPath = PathUtils.normalizePath(targetPath);
// 检查源文件是否存在
if (!this.exist(sourcePath)) {
log.error("复制源文件不存在:{}", sourcePath);
return false;
}
// 检查源文件是否为文件夹
if (this.isDirectory(sourcePath)) {
log.error("源文件为文件夹:{},无法复制", sourcePath);
return false;
}
// 复制
InputStream inputStream = null;
try {
inputStream = sftp1.get(sourcePath);
sftp2.put(inputStream, targetPath);
log.info("文件复制成功:{}", sourcePath);
return true;
} catch (SftpException e) {
log.error("文件复制失败:{}", sourcePath);
log.error(ExceptionUtils.getStackTrace(e));
} finally {
if (null != inputStream){
try {
inputStream.close();
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
}
sFtpPoolService.returnObject(sftp1);
sFtpPoolService.returnObject(sftp2);
}
return false;
}
/**
* SFTPpath
* :false
*
* @param path SFTP
* @return
*/
public boolean isDirectory(String path) {
ChannelSftp sftp = sFtpPoolService.borrowObject();
// 合法的错误id
// int legalErrorId = 4;
try {
sftp.cd(path);
return true;
} catch (SftpException e) {
// 如果 path不存在那么报错信息为【No such file】错误id为【2】
// 如果 path存在但是不能cd进去那么报错信息形如【Can't change directory: /files/sqljdbc4-3.0.jar】错误id为【4】
return false;
} finally {
sFtpPoolService.returnObject(sftp);
}
}
/**
*
* @param filePath
* @return
*/
private boolean exist(String filePath) {
ChannelSftp sftp = sFtpPoolService.borrowObject();
try {
sftp.lstat(filePath);
return true;
} catch (SftpException e) {
return false;
} finally {
sFtpPoolService.returnObject(sftp);
}
}
}

@ -30,18 +30,6 @@ spring:
resources:
static-locations: classpath:/static/,classpath:/META-INF/resources/,classpath:/META-INF/resources/webjars/,file:${gc.starter.file.basePath}
gc:
starter:
file:
# minio | local
uploadType: local
# Minio配置
#minio:
# url: http://192.168.20.98:9000
# accessKey: admin
# secretKey: 123456
# bucketName: test
mybatis-plus:
# mybatis plus xml配置文件扫描多个通过分号隔开

@ -47,6 +47,9 @@
<minio.version>8.2.2</minio.version>
<dataset.core.version>2.0.0.RELEASE</dataset.core.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<commons-net.version>3.6</commons-net.version>
<commons-dbcp2.version>2.10.0</commons-dbcp2.version>
<jsch.version>0.1.55</jsch.version>
</properties>
<dependencyManagement>

Loading…
Cancel
Save