spring boot + SFTP实现文件上传

 

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
spring boot + SFTP实现文件上传
选择好文件以后点击Try it out来实现文件的上传,这时候我们可以直接到我们的服务器去查看我们上传的文件。
源代码的地址:https://github.com/lazyboyl/sftp-demo.git

 

上一篇:利用Nginx对SFTP做负载均衡代理


下一篇:.NET(C#) 通过sftp(SSH.NET)从Linux服务器上下载文件及示例代码