springboot整合SFTP,连接池连接

一、项目结构

SFTP
	SftpProperties --配置载入
	SftpFactory ---连接工厂
	SftpPool  ----连接池
	SftpHelper ----辅助方法,下载

二、maven

		<!-- ftp远程工具 -->
		<dependency>
			<groupId>commons-net</groupId>
			<artifactId>commons-net</artifactId>
			<version>3.3</version>
		<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
		<dependency>
   			<groupId>com.jcraft</groupId>
   			<artifactId>jsch</artifactId>
   			<version>0.1.53</version>
		</dependency>
		<!-- pool 对象池 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-pool2</artifactId>
		</dependency>

三、配置文件

config:
 # 协议
    sftpClientProtocol: sftp
  # ip地址
    sftpClientHost: ip
  # 端口
    sftpClientPort: 2222
  # 用户名
    sftpClientUsername: name
  # 密码
    sftpClientPassword: password
  # 根路径
    sftpClientRoot: /
    fileBackupPaths: D:/2023/TEST/LDPBACKS/
    remotePaths: /home/LDP/
    #本地路径
    localPaths: D:/2023/TEST/LDP/

  #
    sftpClientSessionStrictHostKeyChecking: no
  # session连接超时时间
    sftpClientSessionConnectTimeout: 15000
  # channel连接超时时间
    sftpClientChannelConnectedTimeout: 15000
    sftpMaxTotal: 100
    sftpMinIdel: 2
    sftpMaxIdle: 20

四、代码

4.1 SftpProperties.class

import com.jcraft.jsch.ChannelSftp;
import lombok.Data;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @author gyDeBug
 * @description: 配置文件和实体注入
 * @param:
 * @return:
 * @date:2021/11/30
 */

@Data
@Component
@Configuration
public class SftpProperties {

    private String host;

    private int port;

    private String username;

    private String password;

    private String root;

    private String localPath;

    private String fileBackupPaths;

    private String remotePaths;

    private Integer sessionConnectTimeout;

    private Integer channelConnectedTimeout;

    private Pool pool = new Pool();


    @Value("${config.sftpClientHost}")
    public void setHost(String host) {
        this.host = host;
    }

    @Value("${config.sftpClientPort}")
    public void setPort(int port) {
        this.port = port;
    }

    @Value("${config.sftpClientUsername}")
    public void setUsername(String username) {
        this.username = username;
    }

    @Value("${config.sftpClientPassword}")
    public void setPassword(String password) {
        this.password = password;
    }

    @Value("${config.sftpClientRoot}")
    public void setRoot(String root) {
        this.root = root;
    }

    @Value("${config.localPaths}")
    public void setLocalPath(String localPath) {
        this.localPath = localPath;
    }

    @Value("${config.fileBackupPaths}")
    public void setFileBackupPaths(String fileBackupPaths) {
        this.fileBackupPaths = fileBackupPaths;
    }

    @Value("${config.remotePaths}")
    public void setRemotePaths(String remotePaths) {
        this.remotePaths = remotePaths;
    }

    @Value("${config.sftpClientSessionConnectTimeout}")
    public void setSessionConnectTimeout(Integer sessionConnectTimeout) {
        this.sessionConnectTimeout = sessionConnectTimeout;
    }

    @Value("${config.sftpClientChannelConnectedTimeout}")
    public void setChannelConnectedTimeout(Integer channelConnectedTimeout) {
        this.channelConnectedTimeout = channelConnectedTimeout;
    }

    public static class Pool extends GenericObjectPoolConfig<ChannelSftp> {
        private int maxTotal = 100;
         允许最大空闲对象数
        private int maxIdle = 80;
        // 允许最小空闲对象数
        private int minIdle = 10;
        //控制获取不到连接时超时时间,避免无限等待
        private long maxWaitMillis = 60000;

        public Pool() {
            super();
        }

        @Override
        public long getMaxWaitMillis() {
            return maxWaitMillis;
        }

        @Override
        public void setMaxWaitMillis(long maxWaitMillis) {
            this.maxWaitMillis = maxWaitMillis;
        }

        @Override
        public int getMaxTotal() {
            return maxTotal;
        }

        @Override
        public void setMaxTotal(int maxTotal) {
            this.maxTotal = maxTotal;
        }

        @Override
        public int getMaxIdle() {
            return maxIdle;
        }

        @Override
        public void setMaxIdle(int maxIdle) {
            this.maxIdle = maxIdle;
        }

        @Override
        public int getMinIdle() {
            return minIdle;
        }

        @Override
        public void setMinIdle(int minIdle) {
            this.minIdle = minIdle;
        }

    }
}

4.2 SftpFactory.class

import com.airtravel.odb.common.wechat.WechatService;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

import java.util.Properties;

@Data
@Slf4j
public class SftpFactory extends BasePooledObjectFactory<ChannelSftp> {

    private SftpProperties properties;
    @Autowired
    private Environment environment;

    public SftpFactory(SftpProperties properties) {
        this.properties = properties;
    }

    @Override
    public ChannelSftp create() {
        try {
            JSch jsch = new JSch();
            Session sshSession = jsch.getSession(properties.getUsername(), properties.getHost(), properties.getPort());
            sshSession.setPassword(properties.getPassword());
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect(properties.getSessionConnectTimeout());
            ChannelSftp channel = (ChannelSftp) sshSession.openChannel("sftp");
            channel.connect(properties.getChannelConnectedTimeout());
            return channel;
        } catch (JSchException e) {
            log.info("连接sfpt失败:"+e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {
        return new DefaultPooledObject<>(channelSftp);
    }

    // 销毁对象
    @Override
    public void destroyObject(PooledObject<ChannelSftp> p) {
        ChannelSftp channelSftp = p.getObject();
        channelSftp.disconnect();
    }

}

4.3 SftpPool.class

import com.jcraft.jsch.ChannelSftp;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

@Data
@Slf4j
public class SftpPool {

    private GenericObjectPool<ChannelSftp> pool;
    @Autowired
    private Environment environment;

    public SftpPool(SftpFactory factory) {
        this.pool = new GenericObjectPool<>(factory, factory.getProperties().getPool());
        // 当池中对象用完时,请求新的对象所要执行的动作
//        public byte whenExhaustedAction = DEFAULT_WHEN_EXHAUSTED_ACTION;

        // 是否在从池中取出对象前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个.
        // 在从对象池获取对象时是否检测对象有效(true :) , 配置true会降低性能;
        this.pool.setTestOnBorrow(true);

        // 是否在向池中归还对象前进行检验,如果检验失败
        //在向对象池中归还对象时是否检测对象有效(true :) , 配置true会降低性能
        this.pool.setTestOnReturn(true);

        // 连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除
        this.pool.setTestWhileIdle(true);

        // 在空闲连接回收器线程运行期间休眠的时间毫秒数. 如果设置为非正数,则不运行空闲连接回收器线程.空闲连接检测的周期(单位毫秒)
        this.pool.setTimeBetweenEvictionRunsMillis(80000);

        // 设定在进行后台对象清理时,每次检查对象数,检测空闲对象线程每次运行时检测的空闲对象的数量;
//        public int numTestsPerEvictionRun =  GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
//        this.pool.setNumTestsPerEvictionRun(80000);

        // 被空闲对象回收器回收前在池中保持空闲状态的最小时间毫秒数
        this.pool.setMinEvictableIdleTimeMillis(90000);

        // 被空闲对象回收器回收前在池中保持空闲状态的最小时间毫秒数
//        public long softMinEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
        this.pool.setTimeBetweenEvictionRunsMillis(80000);

        // 是否采用后进先出策略
//        public boolean lifo = GenericObjectPool.DEFAULT_LIFO;

    }

    /**
     * 获取一个sftp连接对象
     * @return sftp连接对象
     */
    public ChannelSftp borrowObject() {
        try {
            return pool.borrowObject();
        } catch (Exception e) {
            log.info("获取sftp连接池连接失败:"+e.getMessage());
            return null;
        }
    }

    /**
     * 归还一个sftp连接对象
     * @param channelSftp sftp连接对象
     */
    public void returnObject(ChannelSftp channelSftp) {
        if (channelSftp!=null) {
            pool.returnObject(channelSftp);
        }
    }

}

4.4 SftpHelper.calss

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

import javax.annotation.Resource;
import java.io.*;
import java.util.ArrayList;
import java.util.Vector;

// sftp辅助类
@Slf4j
public class SftpHelper {
    @Resource
    private SftpProperties sftpProperties;

    private SftpPool pool;

    @Autowired
    private Environment environment;

    public SftpHelper(SftpPool pool) {
        this.pool = pool;
    }

    public ArrayList<String> downSftpFile(){
        log.info("获取SFTP连接信息");
        ChannelSftp sftp = pool.borrowObject();
        log.info("登录成功,从连接池获取SFTP连接信息"+sftp);
        ArrayList<String> fileList = new ArrayList<String>();
        if(sftp == null){
            String msg = "从连接池获取SFTP连接信息为null";
        }else{
            try {
                sftp.cd(sftpProperties.getRemotePaths());
                log.info("SFTP登录进入目录:"+sftpProperties.getRemotePaths());
                Vector<ChannelSftp.LsEntry> list = sftp.ls("*.txt");
                if(list.size() >0){
                    for (ChannelSftp.LsEntry entry : list) {
                        String filename = entry.getFilename();
                        log.info("遍历SFTP文件————————————————"+filename);
                        String routeFileName = sftpProperties.getRemotePaths()+filename;
                        //下载
                        File localFile = new File(sftpProperties.getLocalPath()+filename);
                        OutputStream outputStream = new FileOutputStream(localFile);
                        sftp.get(routeFileName, outputStream);
                        outputStream.close();
                        //备份下载
                        File localbackupFile = new File(sftpProperties.getFileBackupPaths()+filename);
                        OutputStream osputStream = new FileOutputStream(localbackupFile);
                        sftp.get(routeFileName, osputStream);
                        osputStream.close();
                        log.info("下载文件:"+filename);
                        fileList.add(sftpProperties.getLocalPath()+filename);
                        //删除文件
                        sftp.rm(filename);
                    }
                }else{
                    log.info("本次遍历文件为空");
                }
            } catch (Exception e) {
                log.info("SFTP文件下载失败:"+e.getMessage());
                e.printStackTrace();
            } finally {
                pool.returnObject(sftp);
            }
        }

        return fileList;
    }

你可能感兴趣的:(springboot,spring,boot,java,后端)