Spring Boot集成SFTP实现文件上传
Spring Boot下对SFTP文件上传将行封装,实现连接的单例模式,完成线程安全的改进,SFTP文件上传下载失败的重试。
pom.xml依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
application.yml配置文件
sftp:
ip: xxx.xxx.xxx.xxx
port: 22
username: xxx
password: ******
privateKey:
downloadSleep: 100 #文件下载失败下次超时重试时间
downloadRetry: 10 #文件下载失败重试次数
uploadSleep: 100 #文件上传失败下次超时重试时间
uploadRetry: 10 #文件上传失败重试次数
SFTPClientHelper.java
包含SFTP文件上传的一些基本方法,单个上传,批量下载,单个文件下载
@Slf4j
@Component
@ConfigurationProperties(prefix = "sftp")
public class SFTPClientHelper {
@Autowired
private SFTPConnectionFactory factory;
private int downloadSleep;
private int downloadRetry;
private int uploadSleep;
private int uploadRetry;
/**
* 文件上传
* 将文件对象上传到sftp作为文件. 文件完整路径=basePath+directory
* 目录不存在则会上传文件夹
*
* @param basePath 服务器的基础路径
* @param directory 上传到该目录
* @param sftpFileName sftp端文件名
* @param file 文件对象
*/
public synchronized boolean upload(String basePath, String directory, String filePath) {
boolean result = false;
Integer i = 0;
while (!result) {
ChannelSftp sftp = factory.makeConnection();
if (sftp != null) {
try {
sftp.cd(basePath);
sftp.cd(directory);
} catch (SftpException e) {
log.info("SFTP文件上传, 目录不存在开始创建");
String[] dirs = directory.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) continue;
tempPath += "/" + dir;
try {
sftp.cd(tempPath);
} catch (SftpException e1) {
try {
sftp.mkdir(tempPath);
sftp.cd(tempPath);
} catch (SftpException e2) {
log.error("SFTP文件上传, 目录创建失败, 错误信息: " + e1.getMessage() + e2.getMessage());
}
}
}
}
try {
File file = new File(filePath);
sftp.put(new FileInputStream(file), file.getName());
if (i > 0) {
log.info("SFTP重试文件上传成功, FTP路径:" + basePath + directory + ", 文件名称: " + file.getName());
} else {
log.info("SFTP文件上传成功, FTP路径: " + basePath + directory + ", 文件名称: " + file.getName());
}
result = true;
} catch (Exception e) {
i++;
log.error("sftp文件上传失败, 重试中...第" + i + "次, 错误信息: " + e.getMessage());
if (i > uploadRetry) {
log.error("sftp文件上传失败, 超过重试次数结束重试, 错误信息: " + e.getMessage());
return result;
}
try {
TimeUnit.MILLISECONDS.sleep(uploadSleep);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
return result;
}
/**
* 下载文件
* @param directory 下载目录
* @param downloadFile 下载的文件
* @param saveFile 存在本地的路径
*/
public synchronized boolean download(String directory, String downloadFile, String saveFile) {
boolean result = false;
Integer i = 0;
while (!result) {
ChannelSftp sftp = factory.makeConnection();
if (sftp != null) {
if (directory != null && !"".equals(directory)) {
try {
sftp.cd(sftp.getHome());
sftp.cd(directory);
} catch (SftpException e) {
log.error("SFTP文件下载, 目录不存在, 错误信息: " + e.getMessage());
}
}
File file = new File(saveFile);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
log.error("sftp文件下载失败, 本地目录不存在: " + e.getMessage());
}
try {
sftp.get(downloadFile, fileOutputStream);
if (i > 0) {
log.info("SFTP文件重试下载成功, SFTP地址:" + directory + ", 本地文件地址: " + saveFile);
} else {
log.info("SFTP文件下载成功, SFTP地址: " + directory + ", 本地文件地址: " + saveFile);
}
result = true;
} catch (SftpException e) {
i++;
log.error("SFTP文件下载失败, 重试中...第" + i + "次, 错误信息: " + e.getMessage());
if (i > downloadRetry) {
log.error("SFTP文件下载失败, 超过重试次数结束重试, 错误信息: " + e.getMessage());
return result;
}
try {
TimeUnit.MILLISECONDS.sleep(downloadSleep);
} catch (Exception e2) {
e2.printStackTrace();
}
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return result;
}
/**
* 删除文件
*
* @param directory 要删除文件所在目录
* @param deleteFile 要删除的文件
*/
public synchronized boolean delete(String directory, String deleteFile) {
boolean result = false;
ChannelSftp sftp = factory.makeConnection();
try {
sftp.cd(directory);
sftp.rm(deleteFile);
} catch (SftpException e) {
e.printStackTrace();
}
result = true;
return result;
}
}
SFTPConnectionFactory.java
是生成sftp上传对象的工场类
@Slf4j
@Component
public class SFTPConnectionFactory {
/**
* SFTP 服务器地址IP地址
*/
@Value("${sftp.ip}")
private String ip;
/**
* SFTP 端口
*/
@Value("${sftp.port}")
private int port;
/**
* SFTP 登录用户名
*/
@Value("${sftp.username}")
private String username;
/**
* SFTP 登录密码
*/
@Value("${sftp.password}")
private String password;
/**
* 私钥
*/
@Value("${sftp.privateKey}")
private String privateKey;
private ChannelSftp client;
private Session session;
public synchronized ChannelSftp makeConnection() {
if (client == null || session == null || !client.isConnected() || !session.isConnected()) {
log.info("Connect to {}, port {}, username: {}", ip, port, username);
try {
JSch jsch = new JSch();
if (privateKey != null && !StringUtils.isEmpty(privateKey)) {
jsch.addIdentity(privateKey); // 设置私钥
}
session = jsch.getSession(username, ip, port);
if (password != null) {
session.setPassword(password);
}
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
client = (ChannelSftp) channel;
log.info("SFTP服务器连接成功");
} catch (JSchException e) {
log.error("SFTP登录失败, 检测登录ip, 端口号, 用户名密码是否正确, 错误信息为: [{}]", e.getMessage());
}
}
return client;
}
/**
* 关闭连接 server
*/
public void logout() {
if (client != null) {
if (client.isConnected()) {
client.disconnect();
}
}
if (session != null) {
if (session.isConnected()) {
session.disconnect();
}
}
}
}
单元测试
@Test
public void downloadSftpFile() {
sftpClientHelper.download("test", "test.txt", "appblog.txt");
}
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/09/spring-boot-integrate-sftp-to-achieve-file-upload/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
THE END
0
二维码
打赏
海报
Spring Boot集成SFTP实现文件上传
Spring Boot下对SFTP文件上传将行封装,实现连接的单例模式,完成线程安全的改进,SFTP文件上传下载失败的重试。
pom.xml依赖
<dependency>
<gr……
文章目录
关闭
共有 0 条评论