欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring boot + SFTP实现文件上传

程序员文章站 2022-07-12 10:03:26
...

前言

在公司开发的一个项目中需要使用到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