Browse Source

2024年4月1日15:17:47

纪新园 1 year ago
parent
commit
46c1c38b9f

+ 111 - 70
blade-service/blade-los/src/main/java/org/springblade/los/edi/service/impl/EDISenderServiceImpl.java

@@ -1,16 +1,15 @@
 package org.springblade.los.edi.service.impl;
 
-import cn.hutool.core.util.CharsetUtil;
 import com.alibaba.fastjson.JSONArray;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.SftpException;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.net.ftp.FTP;
-import org.apache.commons.net.ftp.FTPClient;
-import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.pool2.PooledObject;
 import org.apache.commons.pool2.impl.GenericObjectPool;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.los.Util.RegularUtils;
@@ -25,18 +24,14 @@ import org.springblade.los.business.sea.entity.ContainersCommodity;
 import org.springblade.los.edi.dto.EdiAddress;
 import org.springblade.los.edi.dto.InttraSoDto;
 import org.springblade.los.edi.service.IEDISenderService;
-import org.springblade.los.ftp.service.FTPPoolService;
-import org.springblade.los.ftp.utils.ftp.FTPClientFactory;
+import org.springblade.los.ftp.utils.Sftp.ChannelSftpFactory;
+import org.springblade.los.ftp.utils.Sftp.SFtpConfig;
 import org.springblade.los.ftp.utils.ftp.FTPPoolConfig;
-import org.springblade.los.ftp.utils.ftp.FTPUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
+import java.io.*;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.text.SimpleDateFormat;
@@ -54,10 +49,7 @@ public class EDISenderServiceImpl implements IEDISenderService {
 	private final IBLinesService bLinesService;
 
 	@Autowired
-	private static FTPPoolConfig config;
-
-	@Autowired
-	static FTPPoolService ftpPoolService;
+	static FTPPoolConfig config;
 
 	public static boolean createDir(String folder) {
 		if (!folder.endsWith(File.separator)) {
@@ -169,68 +161,92 @@ public class EDISenderServiceImpl implements IEDISenderService {
 
 					} else*/
 					if ("ftp".equals(item.getMode())) {
-						config.setHost(item.getHost());
-						config.setUsername(item.getUserName());
-						config.setPassword(item.getPassword());
-						config.setPort(Integer.parseInt(item.getAddress()));
-						config.setWorkingDirectory(item.getPath());
+						SFtpConfig sFtpConfig = new SFtpConfig();
+						sFtpConfig.setWorkingDirectory(item.getPath());
+						sFtpConfig.setHost(item.getHost());
+						sFtpConfig.setPort(Integer.parseInt(item.getAddress()));
+						sFtpConfig.setUsername(item.getUserName());
+						sFtpConfig.setPassword(item.getPassword());
+						sFtpConfig.setEncoding("utf-8");
+						sFtpConfig.setClientTimeout(300000);
+						sFtpConfig.setRetryTimes(1200);
+						sFtpConfig.setBufferSize(8192);
+						sFtpConfig.setMaxTotal(50);
+						sFtpConfig.setMinldle(10);
+						sFtpConfig.setMaxldle(50);
+						sFtpConfig.setMaxWait(300000);
+						sFtpConfig.setBlockWhenExhausted(true);
+						sFtpConfig.setTestOnBorrow(true);
+						sFtpConfig.setTestOnReturn(true);
+						sFtpConfig.setTestOnCreate(true);
+						sFtpConfig.setTestWhileldle(false);
+						sFtpConfig.setLifo(false);
 						try {
-							FTPClientFactory factory = new FTPClientFactory();
-							factory.makeObject();
-							GenericObjectPool<FTPClient> pool = new GenericObjectPool<FTPClient>(factory, config);
-							FTPClient ftpClient = pool.borrowObject();
-							ftpClient.changeWorkingDirectory(ftpPoolService.getFtpPoolConfig().getWorkingDirectory());
-							// 设置PassiveMode传输
-							ftpClient.enterLocalPassiveMode();
-							// 设置以二进制流的方式传输
-							ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
-							ftpClient.setControlEncoding(CharsetUtil.UTF_8);
-							FTPUtil ftpUtil = new FTPUtil();
-							FTPUtil.UploadStatus result = FTPUtil.UploadStatus.UploadNewFileFailed;
-							// 对远程目录的处理
-							String remoteFileName = item.getPath();
-							if (item.getPath().contains("/")) {
-								remoteFileName = item.getPath().substring(item.getPath().lastIndexOf("/") + 1);
-								// 创建服务器远程目录结构,创建失败直接返回
-								if (ftpUtil.createDirecroty(item.getPath(), ftpClient) == FTPUtil.UploadStatus.CreateDirectoryFail) {
-									message = "远程服务器相应目录创建失败";
-									code = "500";
-								}
+							//创建连接
+							ChannelSftpFactory factory = new ChannelSftpFactory();
+							//赋值连接配置数据
+							factory.setConfig(sFtpConfig);
+							//创建连接对象
+							ChannelSftp channelSftp = factory.createNew(sFtpConfig);
+							PooledObject<ChannelSftp> poola = factory.wrap(channelSftp);
+							if (!factory.validateObject(poola)){
+								throw new RuntimeException("无空闲连接通道,请稍后");
 							}
-							// 检查远程是否存在文件
-							FTPFile[] files = ftpClient.listFiles(new String(remoteFileName.getBytes(CharsetUtil.UTF_8), CharsetUtil.ISO_8859_1));
-							if (files.length == 1) {
-								long remoteSize = files[0].getSize();
-								long localSize = file.length();
-								if (remoteSize == localSize) { // 文件存在
-									message = "文件已经存在";
-									code = "500";
-								} else if (remoteSize > localSize) {
-									message = "远程文件大于本地文件";
-									code = "500";
-								}
-								// 尝试移动文件内读取指针,实现断点续传
-								result = ftpUtil.uploadFile(remoteFileName, file, ftpClient, remoteSize);
-								// 如果断点续传没有成功,则删除服务器上文件,重新上传
-								if (result == FTPUtil.UploadStatus.UploadFromBreakFailed) {
-									if (!ftpClient.deleteFile(remoteFileName)) {
-										message = "断点续传失败";
-										code = "500";
+							//创建Sftp连接池
+							GenericObjectPool<ChannelSftp> pool = new GenericObjectPool<>(factory, sFtpConfig);
+							//获取对象实例
+							ChannelSftp sftp = pool.borrowObject();
+							ChannelSftp sftp1 = null;
+							String filePath = item.getPath();
+							if (file.exists() && file.isFile()) {
+								//转换文件流
+								InputStream inputStream = new FileInputStream(file);
+								try {
+									sftp.cd(filePath);
+									String pwd = sftp.pwd();
+									//判断远程服务器是否存在文件夹
+									if (!(pwd.equals(filePath) || pwd.concat("/").equals(filePath))) {
+										int countFiles = 0;
+										try {
+											countFiles = sftp.ls(filePath).size();
+										} catch (SftpException e) {
+											mkdirs(sftp, filePath.split("/"), "", filePath.split("/").length, 0);
+										}
+										if (countFiles <= 1000) {
+											filePath = filePath;
+										} else {
+											String newPath = filePath + String.valueOf(System.currentTimeMillis()).substring(9);
+											mkdirs(sftp, newPath.split("/"), "", newPath.split("/").length, 0);
+											filePath = newPath;
+										}
 									}
-									result = ftpUtil.uploadFile(remoteFileName, file, ftpClient, 0);
-									if (result == FTPUtil.UploadStatus.UploadFromBreakSuccess) {
-										message = "上传失败";
-										code = "500";
+									filePath = filePath+"/";
+									//远程文件存放地址
+									filePath = filePath.concat(file.getName());
+									//判断是否sftp连接是否关闭
+									if (sftp.isClosed()) {
+										sftp.put(inputStream, filePath);
+										sftp.chmod(Integer.parseInt("755", 8), filePath);
+									} else {
+										sftp1 = pool.borrowObject();
+										sftp1.put(inputStream, filePath);
+										sftp1.chmod(Integer.parseInt("755", 8), filePath);
 									}
-								}
-							} else {
-								result = ftpUtil.uploadFile(remoteFileName, file, ftpClient, 0);
-								if (result != FTPUtil.UploadStatus.UploadFromBreakSuccess) {
-									message = "上传失败";
-									code = "500";
+								} catch (SftpException e) {
+									log.error("SFTP上传文件出错", e);
+									pool.returnObject(sftp);
+									factory.destroyObject(poola);
+								} finally {
+									if (sftp1 != null) {
+										pool.returnObject(sftp1);
+									}
+									pool.returnObject(sftp);
+									factory.destroyObject(poola);
+									inputStream.close();
 								}
 							}
 						} catch (Exception e) {
+							log.error("SFTP上传文件出错", e);
 							throw new RuntimeException(e);
 						}
 					} /*else {
@@ -5003,5 +5019,30 @@ public class EDISenderServiceImpl implements IEDISenderService {
 			throw new SecurityException("生成edi文件失败");
 		}
 	}
+
+
+	public static void mkdirs(ChannelSftp sftp, String[] dirs, String tempPath, int length, int index) {
+		// 以"/a/b/c/d"为例按"/"分隔后,第0位是"";顾下标从1开始
+		index++;
+		if (index < length) {
+			// 目录不存在,则创建文件夹
+			tempPath += "/" + dirs[index];
+		}
+		try {
+			sftp.cd(tempPath);
+			if (index < length) {
+				mkdirs(sftp, dirs, tempPath, length, index);
+			}
+		} catch (SftpException ex) {
+			try {
+				sftp.mkdir(tempPath);
+				sftp.chmod(Integer.parseInt("755", 8), tempPath);
+				sftp.cd(tempPath);
+			} catch (SftpException e) {
+				return;
+			}
+			mkdirs(sftp, dirs, tempPath, length, index);
+		}
+	}
 }
 

+ 37 - 2
blade-service/blade-los/src/main/java/org/springblade/los/ftp/utils/Sftp/ChannelSftpFactory.java

@@ -20,7 +20,7 @@ import java.util.Properties;
 @EqualsAndHashCode(callSuper = true)
 @Component
 @Slf4j
-public class ChannelSftpFactory extends BasePooledObjectFactory<ChannelSftp>{
+public class ChannelSftpFactory extends BasePooledObjectFactory<ChannelSftp> {
 	/**
 	 * 注入 sftp 连接配置
 	 */
@@ -61,6 +61,36 @@ public class ChannelSftpFactory extends BasePooledObjectFactory<ChannelSftp>{
 		return channel;
 	}
 
+	public ChannelSftp createNew(SFtpConfig config) {
+		ChannelSftp channel = null;
+		try {
+			// 用户名密码不能为空
+			if (StringUtils.isBlank(config.getUsername()) || StringUtils.isBlank(config.getPassword())) {
+				log.error("username or password is needed !!!");
+				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 失败,请检查配置", e);
+		}
+		return channel;
+	}
+
 	/**
 	 * 创建一个连接
 	 *
@@ -100,9 +130,14 @@ public class ChannelSftpFactory extends BasePooledObjectFactory<ChannelSftp>{
 
 	/**
 	 * 获取 FTP 连接配置
+	 *
 	 * @return
 	 */
-	public SFtpConfig getConfig(){
+	public SFtpConfig getConfig() {
 		return config;
 	}
+
+	public SFtpConfig setConfig(SFtpConfig config) {
+		return this.config = config;
+	}
 }

+ 1 - 1
blade-service/blade-los/src/main/java/org/springblade/los/ftp/utils/Sftp/SFTPUtil.java

@@ -489,7 +489,7 @@ public class SFTPUtil {
 	 * @param path 参数路径
 	 * @return 解析后的有效路径
 	 */
-	private String generateValidPath(String path, ChannelSftp sftp) {
+	public String generateValidPath(String path, ChannelSftp sftp) {
 		if (validatePathValid(path, sftp)) {
 			return path;
 		} else {

+ 25 - 0
blade-service/blade-los/src/main/java/org/springblade/los/ftp/utils/Sftp/SFtpConfig.java

@@ -2,6 +2,7 @@ package org.springblade.los.ftp.utils.Sftp;
 
 import lombok.Data;
 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.springblade.core.tool.utils.BeanUtil;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Configuration;
 
@@ -76,4 +77,28 @@ public class SFtpConfig extends GenericObjectPoolConfig {
 	// 后进先出
 	@Value("${sftp.client.lifo}")
 	private boolean lifo;
+
+	/*public SFtpConfig SFtpConfigNew(String workingDirectory, String host, int port, String username, String password) {
+		SFtpConfig sFtpConfig = new SFtpConfig();
+		sFtpConfig.setWorkingDirectory(workingDirectory);
+		sFtpConfig.setHost(host);
+		sFtpConfig.setPort(port);
+		sFtpConfig.setUsername(username);
+		sFtpConfig.setPassword(password);
+		sFtpConfig.setEncoding(this.encoding);
+		sFtpConfig.setClientTimeout(this.clientTimeout);
+		sFtpConfig.setRetryTimes(this.retryTimes);
+		sFtpConfig.setBufferSize(this.bufferSize);
+		sFtpConfig.setMaxTotal(this.maxTotal);
+		sFtpConfig.setMinldle(this.minldle);
+		sFtpConfig.setMaxldle(this.maxldle);
+		sFtpConfig.setMaxWait(this.maxWait);
+		sFtpConfig.setBlockWhenExhausted(this.blockWhenExhausted);
+		sFtpConfig.setTestOnBorrow(this.testOnBorrow);
+		sFtpConfig.setTestOnReturn(this.testOnReturn);
+		sFtpConfig.setTestOnCreate(this.testOnCreate);
+		sFtpConfig.setTestWhileldle(this.testWhileldle);
+		sFtpConfig.setLifo(this.lifo);
+		return sFtpConfig;
+	}*/
 }

+ 2 - 2
blade-service/blade-los/src/main/resources/application-dev.yml

@@ -47,13 +47,13 @@ sftp:
     password: Yg5YwPCe
     privateKey:
     encoding: utf-8
-    clientTimeout: 30000
+    clientTimeout: 300000
     retryTimes: 1200
     bufferSize: 8192
     maxTotal: 50
     minldle: 10
     maxldle: 50
-    maxWait: 30000
+    maxWait: 300000
     blockWhenExhausted: true
     testOnBorrow: true
     testOnReturn: true