SFTP上传文件的小工具

SFTP上传文件的小工具

临时需要将生成的数据上传到文件服务器,但是baidu出来的工具都有点局限,写个小池子方便后续使用

  1. 创建SFTP的连接池,主要用到一下几个主要依赖:jsch(java编写的实用SFTP包)、commons-pool(apache出品的一款连接池包)
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>
  1. 创造一个对象获取yml或者properties文件中的属性:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix="sftp")
@Data
public class SftpConfig {
    private int ftpPort;
    private String ftpHost;
    private String ftpUserName;
    private String password;
    private String projectName;
    private String charSet;
    private int timeout;
    private int maxTotal;
    private int maxIdle;
    private int minIdle;
    private int maxWaitMillis;
}

  1. 创建连接对象工厂,便于生产连接对象
import com.jcraft.jsch.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.apache.commons.pool2.PooledObjectFactory;
import java.util.Properties;

/**
 * @ClassName SftpFactory
 * @Description
 * @Author 80290644
 * @Date 2020/11/2 19:54
 */
@Component
public class SftpFactory implements PooledObjectFactory<ChannelSftp> {

    @Autowired
    SftpConfig config;

    //创建连接到池中
    @Override
    public PooledObject<ChannelSftp> makeObject() throws JSchException {
        // 创建JSch
        JSch jsch = new JSch();
        // 根据用户名,主机ip,端口获取一个Session
        Session session = jsch.getSession(config.getFtpUserName(), config.getFtpHost(), config.getFtpPort());
        if (!StringUtils.isEmpty(config.getPassword())) {
            // 设置密码
            session.setPassword(config.getPassword());
        }
        Properties properties = new Properties();
        properties.put("StrictHostKeyChecking", "no");
        // 为Session对象设置properties
        session.setConfig(properties);
        // 设置timeout时间
        session.setTimeout(config.getTimeout());
        // 通过Session建立链接
        session.connect(5000);
        // 打开SFTP通道
        Channel channel = session.openChannel("sftp");
        //创建客户端实例
        return new DefaultPooledObject<>((ChannelSftp) channel);
    }

    //销毁连接,当连接池空闲数量达到上限时,调用此方法销毁连接
    @Override
    public void destroyObject(PooledObject<ChannelSftp> pooledObject) {
        ChannelSftp sftpObj = pooledObject.getObject();
        if (sftpObj != null) {
            try {
                if (sftpObj.getSession() != null) {
                    sftpObj.getSession().disconnect();
                    if (sftpObj.isConnected()) {
                        sftpObj.exit();
                    }
                }
            } catch (JSchException e) {
                e.printStackTrace();
            }
            if (sftpObj.isConnected()) {
                sftpObj.exit();
            }
        }
    }

    //链接状态检查
    @Override
    public boolean validateObject(PooledObject<ChannelSftp> pooledObject) {
        ChannelSftp sftpObj = pooledObject.getObject();
        return sftpObj.isConnected();
    }

    //初始化连接
    @Override
    public void activateObject(PooledObject<ChannelSftp> pooledObject) throws Exception {
        ChannelSftp sftpObject = pooledObject.getObject();
        sftpObject.connect();
    }

    //钝化连接,使链接变为可用状态
    @Override
    public void passivateObject(PooledObject<ChannelSftp> pooledObject) throws Exception {
        //FTPClient有此种钝化的方式,但是jsch不具备,不写了
    }

    //用于连接池中获取pool属性
    public SftpConfig getConfig() {
        return config;
    }
}
  1. 再写一个池子(主角登场)
import com.jcraft.jsch.ChannelSftp;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * fileName:ftpPool
 * description:FTP连接池
 * 1.可以获取池中空闲链接
 * 2.可以将链接归还到池中
 * 3.当池中空闲链接不足时,可以创建链接
 *
 * @ClassName SftpPool
 * @Description
 * @Author 80290644
 * @Date 2020/11/2 20:21
 */
@Component
public class SftpPool {
    SftpFactory factory;
    private final GenericObjectPool<ChannelSftp> internalPool;

    //初始化连接池
    public SftpPool(@Autowired SftpFactory factory) {
        this.factory = factory;
        SftpConfig config = factory.getConfig();
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(config.getMaxTotal());
        poolConfig.setMinIdle(config.getMinIdle());
        poolConfig.setMaxIdle(config.getMaxIdle());
        poolConfig.setMaxWaitMillis(config.getMaxWaitMillis());
        this.internalPool = new GenericObjectPool<>(factory, poolConfig);
    }

    //从连接池中取连接
    public ChannelSftp getSftpClient() {
        try {
            return internalPool.borrowObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //将链接归还到连接池
    public void returnSftpClient(ChannelSftp sftpObject) {
        try {
            internalPool.returnObject(sftpObject);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 销毁池子
     */
    public void destroy() {
        try {
            internalPool.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. 接下来利用这个池子封装方法就好了,写一个Util吧。因为只想上传,所以这只写了通过流上传的方法,其他下载等操作可以自定义类比实现。
/**
 * 上传合并
 * <pre>
 *  ----------命令集合---------------------
 *  可参考链接(官方示例程序):http://www.jcraft.com/jsch/examples/Sftp.java
 *  ChannelSftp c = (ChannelSftp) channel;
 *  c.quit();
 *  c.exit();
 *  c.cd("/home/example");
 *  c.lcd("/home/example");
 *  c.rm("/home/example.gz");
 *  c.rmdir("/home/example");
 *  c.mkdir("/home/example");
 *  c.chgrp(777, "/home/example");
 *  c.chown(777, "/home/example");
 *  c.chmod(777, "/home/example");
 *  c.pwd();
 *  c.lpwd();
 *  c.ls("/home/example");
 *
 *  SftpProgressMonitor monitor = new MyProgressMonitor(); //显示进度
 *  //文件下载
 *  c.get("srcPath", "dstPath", monitor, ChannelSftp.OVERWRITE);
 *  //断点续传
 *  c.get("srcPath", "dstPath", monitor, ChannelSftp.RESUME); 
 *  //文件上传
 *  c.get("srcPath", "dstPath", monitor, ChannelSftp.APPEND);

 *  c.put("srcPath", "dstPath", monitor, ChannelSftp.APPEND);
 *  c.put("srcPath", "dstPath", monitor, ChannelSftp.APPEND);
 *  c.put("srcPath", "dstPath", monitor, ChannelSftp.APPEND);
 *
 *  c.hardlink("oldPath", "newPath");
 *  c.rename("oldPath", "newPath");
 *  c.symlink("oldPath", "newPath");
 *  c.readlink("Path");
 *  c.realpath("Path");
 *  c.version();
 *
 *  //df 命令
 *  SftpStatVFS stat = c.statVFS("path");  
 *  long size = stat.getSize();
 *  long used = stat.getUsed();
 *  long avail = stat.getAvailForNonRoot();
 *  long root_avail = stat.getAvail();
 *  long capacity = stat.getCapacity();
 *
 *  c.stat("path");
 *  c.lstat("path");
 * ----------------------------------------------------------------------
 * </pre>
 */
@Slf4j
@Component
public class SftpUtil {

    @Resource
    private SftpFactory sftpFactory;
    @Resource
    private SftpPool sftpPool;

    public void uploadFileByFilePath(String src, String dst) {
        try {
            ChannelSftp channelSftp = sftpPool.getSftpClient();
            channelSftp.put(src, dst, new SftpMonitor(), ChannelSftp.RESUME);
            sftpPool.returnSftpClient(channelSftp);
        } catch (SftpException e) {
            e.printStackTrace();
        }
    }

    public void uploadFileByResume(InputStream src, String dst) throws Exception {
        ChannelSftp channelSftp = sftpPool.getSftpClient();
        channelSftp.put(src, dst, new SftpMonitor(), ChannelSftp.OVERWRITE);
        sftpPool.returnSftpClient(channelSftp);
    }

    public void uploadFileByAppend(InputStream src, String dst) throws Exception {
        ChannelSftp channelSftp = sftpPool.getSftpClient();
        channelSftp.put(src, dst, new SftpMonitor(), ChannelSftp.OVERWRITE);
        sftpPool.returnSftpClient(channelSftp);
    }
}
posted @ 2020-11-02 21:39  AaronPi  阅读(750)  评论(0编辑  收藏  举报