Spring Boot集成SFTP实现文件上传

Spring Boot下对SFTP文件上传将行封装,实现连接的单例模式,完成线程安全的改进,SFTP文件上传下载失败的重试。

pom.xml依赖

1
2
3
4
5
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>

application.yml配置文件

1
2
3
4
5
6
7
8
9
10
sftp:
ip: xxx.xxx.xxx.xxx
port: 22
username: xxx
password: ******
privateKey:
downloadSleep: 100 #文件下载失败下次超时重试时间
downloadRetry: 10 #文件下载失败重试次数
uploadSleep: 100 #文件上传失败下次超时重试时间
uploadRetry: 10 #文件上传失败重试次数

SFTPClientHelper.java

包含SFTP文件上传的一些基本方法,单个上传,批量下载,单个文件下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
@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上传对象的工场类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
@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();
}
}
}
}

单元测试

1
2
3
4
@Test
public void downloadSftpFile() {
sftpClientHelper.download("test", "test.txt", "appblog.txt");
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :