目录

1. 什么是SFTP

2.java项目中使用JSch

3.Jsch文件上传示例

4.秘钥登录方式怎么传文件的路径呢?


1. 什么是SFTP

SFTP是一个安全文件传送协议,可以为传输文件提供一种安全的加密方法。SFTP 为 SSH的一部份,是一种传输文件到服务器的安全方式。SFTP是使用加密传输认证信息和传输的数据,所以,使用SFTP是非常安全的。但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低得多,如果您对网络安全性要求更高时,可以使用SFTP代替FTP。

2.java项目中使用JSch

Jsch是一个纯粹的用java实现SSH功能的java library,支持密码登录方式和秘钥登录方式。用密码登录,就是和我们用ftp的账号密码登录一样,比较简单。秘钥登录方式,就需要把客户端的公钥放到SFTP服务器,然后客户端需要用秘钥登录。

3.Jsch文件上传示例

import com.jcraft.jsch.*;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

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

/**
 * 功能简述:<br>
 * 详细描述:<br>
 *
 * @since SFtp工具类
 */
@Data
@Configuration
@Component
public class SFtpUtils {
    private static Logger log = LoggerFactory.getLogger(SFtpUtils.class);

    /**
     * 将指定流文件上传到FTP服务器
     *
     * @param ftpAddress  ftp地址
     * @param ftpPort     ftp端口
     * @param ftpUserName ftp账号
     * @param ftpPassowrd ftp密码
     * @param ftpFileName 上传到FTP服务器的文件名
     * @param ftpPath     上传到FTP服务器指定目录下(如果目录在FTP服务器上不存在,则自动创建)
     * @param localFile   本地文件流
     * @param privateKeyFile 私钥
     * @return
     */
    public static boolean uploadFile(String ftpAddress, int ftpPort, String ftpUserName, String ftpPassowrd, String privateKeyFile, String ftpFileName, String ftpPath, InputStream localFile) throws JSchException {
        boolean success = false;
        ChannelSftp channelSftp = null;
        Session jschSession = null;
        try {
            JSch jsch = new JSch();
            // 私钥非空的时候使用私钥进行验证
            if (StringUtils.isNotEmpty(privateKeyFile)) {
                jsch.addIdentity(privateKeyFile);
            }
            // 获取到jSch的session, 根据用户名、主机ip、端口号获取一个Session对象
            jschSession = jsch.getSession(ftpUserName, ftpAddress, ftpPort);
            if (StringUtils.isNotEmpty(privateKeyFile)) {
                jschSession.setUserInfo(new SftpAuthKeyUserInfo(privateKeyFile));
            } else if (StringUtils.isNotEmpty(ftpPassowrd)) {
                jschSession.setPassword(ftpPassowrd);
            }

            // 通过Session建立连接
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            jschSession.setConfig(sshConfig);
            jschSession.connect();
            channelSftp = (ChannelSftp) jschSession.openChannel("sftp");
            // sftp管道连接
            channelSftp.connect();
            // 进入到目标目录,目标目录如果不存在则创建
            String[] paths = ftpPath.split("/");
            StringBuffer sb = new StringBuffer();
            for (String p : paths) {
                if (StringUtils.isEmpty(p)) {
                    continue;
                }
                sb = sb.append("/" + p);
                //循环创建路径
                try {
                    channelSftp.cd(sb.toString());
                } catch (SftpException ex) {
                    channelSftp.mkdir(sb.toString());
                    channelSftp.cd(sb.toString());
                }
            }
            // 上传文件
            channelSftp.put(localFile, ftpFileName);
            channelSftp.exit();
            success = true;
        } catch (SftpException e) {
            e.printStackTrace();
            log.error("IOException", e);
        } finally {
            if (channelSftp != null) {
                channelSftp.disconnect();
            }
            if (jschSession != null) {
                jschSession.disconnect();
            }
            if (localFile != null) {
                try {
                    localFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return success;
    }

    /**
     * 获取一个已经connect的ChannelSftp对象
     * @param ftpAddress Sftp地址
     * @param ftpPort 端口号
     * @param ftpUserName 账号
     * @param ftpPassowrd 密码
     * @return
     */
    public static ChannelSftp getChannelSftp(String ftpAddress, int ftpPort, String ftpUserName, String ftpPassowrd) {
        ChannelSftp channelSftp = null;
        Session jschSession = null;
        try {
            JSch jsch = new JSch();
            // 获取到jSch的session, 根据用户名、主机ip、端口号获取一个Session对象
            jschSession = jsch.getSession(ftpUserName, ftpAddress, ftpPort);
            jschSession.setPassword(ftpPassowrd);
            // 通过Session建立连接
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            jschSession.setConfig(sshConfig);
            jschSession.connect();
            channelSftp = (ChannelSftp) jschSession.openChannel("sftp");
            // sftp管道连接
            channelSftp.connect();
            return channelSftp;
        } catch (JSchException e) {
            e.printStackTrace();
            log.error("IOException", e);
            if (channelSftp != null) {
                channelSftp.disconnect();
            }
            if (jschSession != null) {
                jschSession.disconnect();
            }
        } finally {
        }
        return null;
    }

    public static void close(ChannelSftp channelSftp) {
        if (channelSftp != null) {
            channelSftp.disconnect();
        }
    }

	/**
	 * UserInfo是jsch包的一个接口
	 */
    static class SftpAuthKeyUserInfo implements UserInfo{
        /**
         * ssh private key passphrase
         */
        private String passphrase;
		
		/**
         * 构造函数需要传秘钥的路径,是秘钥的文件路径,不是流也不是秘钥内容
         */
        public SftpAuthKeyUserInfo (String passphrase) {
            this.passphrase = passphrase;
        }

        @Override
        public String getPassphrase() {
            return passphrase;
        }

        @Override
        public String getPassword() {
            return null;
        }

        @Override
        public boolean promptPassword(String message) {
            return false;
        }

        @Override
        public boolean promptPassphrase(String message) {
            return true;
        }

        @Override
        public boolean promptYesNo(String message) {
            return true;
        }

        @Override
        public void showMessage(String message) {
            log.info ("SSH Message:{}", message);
        }
    }
}

4.秘钥登录方式怎么传文件的路径呢?

我在项目中是把秘钥文件放在了resource资源目录下。然后根据项目环境取不同环境的秘钥。

Java sftp 的文件夹 获取 java调用sftp传输文件_java

 

// 获取私钥文件路径
ClassPathResource classPathResource = new ClassPathResource(privateKeyPathEnv + "/id_rsa");
String sftpPrivatePath = classPathResource.getFile().getAbsolutePath();

至于是否还有其他更好获取秘钥文件路径的方式请留言。或者JSch使用秘钥登录还有其他的写法请留言。