zoukankan      html  css  js  c++  java
  • 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);
        }
    }
    
  • 相关阅读:
    教你作一份高水准的简历
    python并发
    阻塞,非阻塞,同步,异步
    python三层架构
    paramiko与ssh
    python-进程
    生产者消费者模型
    python-线程
    python-socket
    python-mysql
  • 原文地址:https://www.cnblogs.com/pipicai96/p/13916678.html
Copyright © 2011-2022 走看看