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
分享
二维码
打赏
海报
Spring Boot集成SFTP实现文件上传
Spring Boot下对SFTP文件上传将行封装,实现连接的单例模式,完成线程安全的改进,SFTP文件上传下载失败的重试。 pom.xml依赖 <dependency> <gr……
<<上一篇
下一篇>>
文章目录
关闭
目 录