spring boot + SFTP实现文件上传
前言
在公司开发的一个项目中需要使用到ftp来上传文件,一开始直接使用的是vsftp来实现文件的上传,后来领导要求使用sftp来实现文件的上传,然后就有了这篇SFTP实现文件上传的博客文章了。
1.相关依赖
<dependencies>
<!-- 引入swagger2依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<!-- 引入sftp的依赖 -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.相关配置
以下是application.yml中的配置
server:
port: 8388
sftp:
# 端口
port: 22
# 服务器地址
host: 10.10.120.71
# 账号
userName: taxctrl
# 密码
password: taxctrl
# 文件存储的根路径
basePath: /home/taxctrl/test
# session连接超时时间
sessionConnectTimeout: 30000
# channel连接超时时间
channelConnectedTimeout: 30000
# 协议
protocol: sftp
3.注入配置文件
package com.sftp.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author linzf
* @since 2019/10/8
* 类描述:
*/
@Component
public class SFtpConfig {
/**
* IP
*/
@Value("${sftp.host}")
private String host;
/**
* 账号
*/
@Value("${sftp.userName}")
private String userName;
/**
* 密码
*/
@Value("${sftp.password}")
private String password;
/**
* 基础路径
*/
@Value("${sftp.basePath}")
private String basePath;
/**
* 协议
*/
@Value("${sftp.protocol}")
private String protocol;
/**
* 端口
*/
@Value("${sftp.port}")
private Integer port;
/**
* session连接超时时间
*/
@Value("${sftp.sessionConnectTimeout}")
private Integer sessionConnectTimeout;
/**
* channel连接超时时间
*/
@Value("${sftp.channelConnectedTimeout}")
private Integer channelConnectedTimeout;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getBasePath() {
return basePath;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public Integer getSessionConnectTimeout() {
return sessionConnectTimeout;
}
public void setSessionConnectTimeout(Integer sessionConnectTimeout) {
this.sessionConnectTimeout = sessionConnectTimeout;
}
public Integer getChannelConnectedTimeout() {
return channelConnectedTimeout;
}
public void setChannelConnectedTimeout(Integer channelConnectedTimeout) {
this.channelConnectedTimeout = channelConnectedTimeout;
}
}
4.开启swagger2配置
package com.sftp.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author linzf
* @since 2019-10-08
* 类描述:sftp测试专用类
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.useDefaultResponseMessages(false)
.select()
.apis((input) -> {
Class<?> declaringClass = input.declaringClass();
if (declaringClass.isAnnotationPresent(RestController.class)) {
return true;
}
if (input.isAnnotatedWith(ResponseBody.class)) {
return true;
}
return false;
})
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
//大标题
.title("sftp接口测试页面!")
//版本
.version("1.0")
.build();
}
}
5.封装工具类
package com.sftp.demo.util;
import com.jcraft.jsch.*;
import com.sftp.demo.config.SFtpConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.Arrays;
/**
* @author linzf
* @since 2019/10/8
* 类描述:这是一个sftp的工具类
*/
public class SFtpUtil {
/**
* 初始化日志对象
*/
private static Logger log = LoggerFactory.getLogger(SFtpUtil.class);
/**
* 功能描述: 实现文件上传
*
* @param fileDir 文件所在的路径
* @param fileName 文件的名称
* @param inputStream 文件流
* @param sFtpConfig 文件相关的配置信息
* @return 返回上传结果
* @throws Exception
*/
public static boolean uploadFile(String fileDir, String fileName, InputStream inputStream, SFtpConfig sFtpConfig) throws Exception {
ChannelSftp sftp = getSftp(sFtpConfig);
try {
fileDir = sFtpConfig.getBasePath() + fileDir;
boolean dirs = createDirs(fileDir, sftp);
if (!dirs) {
log.info("创建文件目录失败!");
return false;
}
sftp.put(inputStream, fileName);
return true;
} catch (Exception e) {
log.info("文件上传失败:{}", e.getMessage());
return false;
} finally {
disconnect(sftp);
}
}
/**
* 功能描述: 创建文件夹
*
* @param dirPath 需要创建文件夹的路径
* @param sftp sftp对象
* @return 返回创建的结果
*/
private static boolean createDirs(String dirPath, ChannelSftp sftp) {
if (dirPath != null && !dirPath.isEmpty() && sftp != null) {
String[] dirs = Arrays.stream(dirPath.split("/"))
.filter(a -> a != null && !a.equals(""))
.toArray(String[]::new);
for (String dir : dirs) {
try {
sftp.cd(dir);
log.info("进入的目录是 {}", dir);
} catch (Exception e) {
try {
sftp.mkdir(dir);
log.info("创建的目录是 {}", dir);
} catch (SftpException e1) {
log.error("创建失败的目录是:{}", dir, e1);
e1.printStackTrace();
}
try {
sftp.cd(dir);
log.info("进入的目录是 {}", dir);
} catch (SftpException e1) {
log.error("进入失败的目录是:{}", dir, e1);
e1.printStackTrace();
}
}
}
return true;
}
return false;
}
/**
* 功能描述: 创建sftp连接
*
* @param sFtpConfig sftp连接对象
* @return 返回 sftp通道对象
* @throws Exception
*/
private static ChannelSftp getSftp(SFtpConfig sFtpConfig) throws JSchException {
JSch jsch = new JSch();
Session session = getSession(jsch, sFtpConfig.getHost(), sFtpConfig.getUserName(), sFtpConfig.getPort());
session.setPassword(sFtpConfig.getPassword());
session.connect(sFtpConfig.getSessionConnectTimeout());
Channel channel = session.openChannel(sFtpConfig.getProtocol());
channel.connect(sFtpConfig.getChannelConnectedTimeout());
return (ChannelSftp) channel;
}
/**
* 创建session
*
* @param jsch jsch对象
* @param host sftpIP地址
* @param username sftp账号
* @param port sftp端口
* @return 返回 session对象
* @throws Exception
*/
private static Session getSession(JSch jsch, String host, String username, Integer port) throws JSchException {
Session session;
if (port <= 0) {
session = jsch.getSession(username, host);
} else {
session = jsch.getSession(username, host, port);
}
if (session == null) {
return null;
}
session.setConfig("StrictHostKeyChecking", "no");
return session;
}
/**
* 功能描述: 关闭连接
*
* @param sftp sftp对象
*/
private static void disconnect(ChannelSftp sftp) {
try {
if (sftp != null) {
if (sftp.isConnected()) {
sftp.disconnect();
} else if (sftp.isClosed()) {
log.info("sftp已经关闭");
}
if (null != sftp.getSession()) {
sftp.getSession().disconnect();
}
}
} catch (JSchException e) {
e.printStackTrace();
}
}
}
6.编写上传文件的验证方法
package com.sftp.demo.controller;
import com.sftp.demo.config.SFtpConfig;
import com.sftp.demo.util.SFtpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
/**
* @author linzf
* @since 2019/10/8
* 类描述: 测试文件上传
*/
@RestController
@RequestMapping("sftp")
public class SFtpController {
@Autowired
private SFtpConfig sFtpConfig;
/**
* 功能描述: 实现文件上传
* @param file
* @return
*/
@PostMapping("uploadFile")
public String uploadFile(@RequestParam("file") MultipartFile file) throws Exception {
SFtpUtil.uploadFile("",file.getOriginalFilename(),file.getInputStream(),sFtpConfig);
return "success";
}
}
7.验证SFTP文件上传
最后我们启动我们的程序然后访问:http://127.0.0.1:8388/swagger-ui.html#!/s-ftp-controller/uploadFileUsingPOST
选择好文件以后点击Try it out来实现文件的上传,这时候我们可以直接到我们的服务器去查看我们上传的文件。
源代码的地址:https://github.com/lazyboyl/sftp-demo.git