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);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM