1、引入pom.xml配置:

Maven依赖

        <!-- SFTP  -->
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.55</version>
        </dependency>
        <!-- SSH  -->
        <dependency>
            <groupId>ch.ethz.ganymed</groupId>
            <artifactId>ganymed-ssh2</artifactId>
            <version>build210</version>
        </dependency>

2、SFTP工具类:

SftpUtil

package com.demo.utils;

import com.jcraft.jsch.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.Properties;


/**
 * @Author zf
 * @ClassName SftpUtil.java
 * @ProjectName Demo
 */
public class SftpUtil {

    private SftpUtil() {
    }

    /**
     * 每个目录下最大子文件(夹)数量
     */
    private static final int MAX_CHILD_FILE_NUMBER = 1000;
    private static volatile ChannelSftp sftp = null;
    private static volatile Session sshSession = null;

    /**
     * @Description 附件上传
     * @param sftpConfig 配置信息
     * @param fileName 文件名
     * @param inputStream 文件流
     * @return
     * @throws SftpException
     * @throws JSchException
     */
    public static String upload(SftpConfig sftpConfig, String fileName, InputStream inputStream) throws SftpException, JSchException {
        return upload(sftpConfig,null, fileName, inputStream);
    }

    /**
     * @Description 文件上传
     * @param sftpConfig 配置信息
     * @param relativePath 文件保存的相对路径(最后一级目录)
     * @param fileName 文件名
     * @param inputStream 文件流
     * @return
     * @throws JSchException
     * @throws SftpException
     */
    public static String upload(SftpConfig sftpConfig, String relativePath, String fileName, InputStream inputStream)
            throws JSchException, SftpException {
        init(sftpConfig);
        createFolder(sftpConfig.getPath());
        String filePath = sftpConfig.getPath();
        if (relativePath != null && !relativePath.trim().isEmpty()) {
            filePath = sftpConfig.getPath() + "/" + relativePath;
        }
        filePath = generateValidPath(filePath);
        filePath = filePath + "/" + fileName;
        sftp.put(inputStream, filePath);
        return filePath.substring(sftpConfig.getPath().length() + 1);
    }

    /**
     * @Description 文件下载
     * @param sftpConfig 配置信息
     * @param fileName  文件名
     * @return
     * @throws JSchException
     * @throws SftpException
     */
    public static byte[] download(SftpConfig sftpConfig, String fileName) throws JSchException, SftpException,
            IOException {
        init(sftpConfig);
        InputStream inputStream = sftp.get(sftpConfig.getPath() + "/" + fileName);
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int n;
        byte[] data = new byte[1024];
        while ((n = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, n);
        }
        buffer.flush();
        return buffer.toByteArray();
    }

    /**
     * @Description 判断是否关闭
     * @return
     */
    public static boolean isClosed() {
        if (Objects.isNull(sshSession) || Objects.isNull(sftp)) {
            return false;
        }
        if (Objects.nonNull(sshSession) && sshSession.isConnected() && Objects.nonNull(sftp) && sftp.isConnected()) {
            return true;
        }
        return false;
    }

    /**
     * @Description 关闭
     */
    public static void close(){
        if (sshSession != null && sshSession.isConnected()) {
            sshSession.disconnect();
        }
        if (sftp != null && sftp.isConnected()) {
            sftp.disconnect();
        }
    }

    /**
     * @Description 初始化
     * @throws JSchException
     */
    private static void init(SftpConfig sftpConfig) throws JSchException {
        if (!isClosed()) {
            synchronized (SftpUtil.class) {
                if (!isClosed()) {
                    JSch jsch = new JSch();
                    jsch.getSession(sftpConfig.getUsername(), sftpConfig.getHost(), sftpConfig.getPort());
                    sshSession = jsch.getSession(sftpConfig.getUsername(), sftpConfig.getHost(), sftpConfig.getPort());
                    sshSession.setPassword(sftpConfig.getPassword());
                    Properties sshConfig = new Properties();
                    sshConfig.put("StrictHostKeyChecking", "no");
                    sshSession.setConfig(sshConfig);
                    sshSession.connect();
                    Channel channel = sshSession.openChannel("sftp");
                    channel.connect();
                    sftp = (ChannelSftp) channel;
                }
            }
        }
    }

    /**
     * @Description 创建目录
     * @param path 目录路径
     * @return
     */
    private static boolean createFolder(String path) {
        try {
            sftp.mkdir(path);
        } catch (SftpException e) {
            return false;
        }
        return true;
    }

    /**
     * @Description 删除指定文件
     * @param sftpConfig  配置信息
     * @param fileName  文件名
     * @return boolean  删除结果
    */
    public static boolean rm(SftpConfig sftpConfig, String fileName) throws JSchException {
        init(sftpConfig);
        Boolean result = false;
        try {
            sftp.cd(sftpConfig.getPath());
            sftp.rm(fileName);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
            result = false;
        }
        return result;
    }


    /**
     * @Description 统计目录下文件(夹)数量
     * @param path  目录路径
     * @return
     */
    private static int countFiles(String path) throws SftpException {
        sftp.cd(path);
        return sftp.ls(path).size();
    }

    /**
     * @Description 校验路径是否可用
     * @param path  目录路径
     * @return
     */
    private static boolean validatePathValid(String path) {
        int countFiles = 0;
        try {
            countFiles = countFiles(path);
        } catch (SftpException e) {
            createFolder(path);
        }
        if (countFiles <= MAX_CHILD_FILE_NUMBER) {
            return true;
        }
        return false;
    }

    /**
     * @Description 校验文件是否存在
     * @param sftpConfig 配置信息
     * @param fileName  文件名
     * @return  1.文件已存在、-1.文件不存在
    */
    public static int validateFileValid(SftpConfig sftpConfig, String fileName) throws JSchException {
        init(sftpConfig);
        try {
            sftp.get(sftpConfig.getPath() + fileName);
            return 1;
        }catch (Exception e){
            //文件不存在
            if ("No such file".equals(e.getMessage())){
                return -1;
            }
        }
        return 0;
    }


    /**
     * @Description 生成有效路径
     * @param path  目录路径
     * @return
     */
    private static String generateValidPath(String path) {
        if (validatePathValid(path)) {
            return path;
        } else {
            String newPath = path + String.valueOf(System.currentTimeMillis()).substring(9);
            createFolder(newPath);
            return newPath;
        }
    }

    /**
     * 配置信息
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class SftpConfig {
        /**
         * 主机地址
         */
        private String host;
        /**
         * sftp 连接端口
         */
        private int port;
        /**
         * 用户名
         */
        private String username;
        /**
         * 密码
         */
        private String password;
        /**
         * 文件保存根路径
         */
        private String path;

    }


    public static SftpConfig sftpConfig() {
        return new SftpUtil().new SftpConfig();
    }

    /**
     * @Description 配置信息
     * @param host  主机地址
     * @param port  主机端口
     * @param username  用户名
     * @param password  密码
     * @param path  目录路径
     * @return 配置信息
    */
    public static SftpConfig sftpConfig(String host, int port, String username, String password, String path) {
        return new SftpUtil().new SftpConfig(host, port, username, password, path);
    }
}

3、Compress工具类:

CompressUtil

package com.demo.utils;


import java.io.IOException;
import java.io.PrintWriter;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.demo.config.SftpUploadConfig;

/**
 * @Author zf
 * @Description 通过名称远程压缩指定目录下的文件
 * @ClassName CompressUtil.java
 * @ProjectName Demo
 */
public class CompressUtil {

    /*
     * @param fileName 文件名称
     */
    public static Boolean remoteZipToFile(String fileName, SftpUploadConfig uploadConfig) {
        Boolean result = false;
        try {
            SftpUtil.SftpConfig sftpConfig = SftpUtil.sftpConfig();
            BeanUtil.copyProperties(uploadConfig, sftpConfig, CopyOptions.create().ignoreNullValue().ignoreError());
            Connection connection = new Connection(sftpConfig.getHost());// 创建一个连接实例
            connection.connect();// Now connect
            //连接状态
            boolean isAuthenticated = connection.authenticateWithPassword(sftpConfig.getUsername(),
                    sftpConfig.getPassword());// Authenticate
            if (isAuthenticated == false)
                throw new IOException("user and password error");
            Session sess = connection.openSession();// Create a session
            System.out.println("start exec command.......");
            sess.requestPTY("bash");
            sess.startShell();
            PrintWriter out = new PrintWriter(sess.getStdin());
            out.println("cd /" + sftpConfig.getPath());
            out.println("ll");
            out.println("zip -r " + fileName + ".zip " + fileName + "-*");  //压缩文件
            out.println("ll");
            out.println("exit");
            out.close();
            System.out.println("ExitCode: " + sess.getExitStatus());
            sess.close();/* Close this session */
            connection.close();/* Close the connection */
            result = true;
        } catch (IOException e) {
            e.printStackTrace(System.err);
            result =false;
            System.exit(2);
        }
        return result;
    }
}

4、配置类:

SftpUploadConfig

package com.demo.config;

import lombok.Getter;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;


/**
 * @Author zf
 * @ClassName SftpUploadConfig.java
 * @ProjectName Demo
 */
@ToString
@Getter
@Configuration
public class SftpUploadConfig {

    /**
     * 主机地址
     */
    @Value("${uploadSftp.host}")
    private String host;
    /**
     * sftp 连接端口
     */
    @Value("${uploadSftp.port}")
    private int port;
    /**
     * 用户名
     */
    @Value("${uploadSftp.username}")
    private String username;
    /**
     * 密码
     */
    @Value("${uploadSftp.password}")
    private String password;
    /**
     * 文件保存路径
     */
    @Value("${uploadSftp.path}")
    private String path;
}

5、application.yml:

application.yml

uploadSftp:
  host:
  port:
  username:
  password:
  path:

6、Service:

Service

    @Resource
    private SftpUploadConfig uploadConfig;

    /**
     * @Description 下载文件
     * @param month 月份(例如:2022-06)
    */
    @SneakyThrows
    public ResponseEntity<byte[]> downFile(String month) {
        String fileName = month + ".zip";
        SftpUtil.SftpConfig sftpConfig = SftpUtil.sftpConfig();
        BeanUtil.copyProperties(uploadConfig, sftpConfig, CopyOptions.create().ignoreNullValue().ignoreError());
        //如果压缩包已存在,则删除历史文件。
        if (SftpUtil.validateFileValid(sftpConfig, fileName) == 1) {
            SftpUtil.rm(sftpConfig, fileName);
        }
        //重新执行压缩流程。
        Boolean is = CompressUtil.remoteZipToFile(month, uploadConfig);
        //如果压缩完成,则下载文件。
        if (is){
            byte[] bytes = SftpUtil.download(sftpConfig, fileName);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(new MediaType("application", "zip"));
            headers.setContentDispositionFormData("attachment", fileName);
            return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
        }
        return null;
    }

7、Controller:

Controller

    @ApiOperation(value = "文件(下载)")
    @GetMapping(value = "/downFile", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    @SneakyThrows
    public ResponseEntity<byte[]> downFile (String month) {
        ResponseEntity<byte[]> responseEntity = downServer.downFile(month);
        return responseEntity;
    }

最后修改:2022 年 06 月 17 日
给我一点小钱钱也很高兴啦!o(* ̄▽ ̄*)ブ