springboot使用JSch上传文件到远程服务器(下载、拷贝、删除、验证文件是否存在、执行shell命令)

背景说明

有时我们后台管理项目需要部署多个节点,文件也要存到一个统一的地方,这就需要对远程文件仓库进行上传、下载、文件拷贝、执行shell命令等操作。

接下来笔者将使用JSch来实现对远程文件仓库的操作

源码地址:https://gitcode.net/lu993356091/ftptest

代码实现

项目整体结构如下
项目结构

pom.xml文件引入以下依赖

	
	<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- sftp -->
    <dependency>
      <groupId>com.jcraft</groupId>
      <artifactId>jsch</artifactId>
      <version>0.1.55</version>
    </dependency>
    <!-- 连接池 -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
      <version>2.11.1</version>
    </dependency>

application.yml

server:
  port: 80

sftp:
  #服务器ip
  host: 192.168.xx.xx
  #ssh端口
  port: 22
  #用户名
  username: USER001
  #密码
  password: 123456
  #连接池参数
  pool:
    #对象池中管理的最多对象个数。默认值是8
    max-total: 10
    #对象池中最大的空闲对象个数。默认值是8
    max-idle: 10
    #对象池中最小的空闲对象个数。默认值是0
    min-idle: 5

创建配置类
SftpConfig.java

package org.example.config;

import com.jcraft.jsch.ChannelSftp;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.example.ftp.SftpUtil;
import org.example.pool.SftpFactory;
import org.example.pool.SftpGenericObjectPool;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SftpConfig {

    /**
     * 工厂
     *
     * @author fengfan
     * @date 2022/1/14 14:37
     * @return
     */
    @Bean
    public SftpFactory sftpFactory() {
        return new SftpFactory();
    }

    @Bean
    @ConfigurationProperties(prefix = "sftp.pool")
    public GenericObjectPoolConfig<ChannelSftp> sftpPoolConfig(){
        return new GenericObjectPoolConfig<>();
    }

    @Bean
    public SftpGenericObjectPool sftpPool(SftpFactory sftpFactory, GenericObjectPoolConfig<ChannelSftp> sftpPoolConfig){
        return new SftpGenericObjectPool(sftpFactory, sftpPoolConfig);
    }

    @Bean
    public SftpUtil sftpUtil(SftpGenericObjectPool sftpPool){
        return new SftpUtil(sftpPool);
    }

}

创建连接工厂
SftpFactory.java

package org.example.pool;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
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.Value;

import java.util.Properties;

public class SftpFactory extends BasePooledObjectFactory<ChannelSftp> {
    @Value("${sftp.host}")
    private String host;
    @Value("${sftp.port}")
    private int port;
    @Value("${sftp.username}")
    private String username;
    @Value("${sftp.password}")
    private String password;

    @Override
    public ChannelSftp create() throws JSchException {
        JSch jsch = new JSch();
        Session sshSession = jsch.getSession(username, host, port);
        sshSession.setPassword(password);
        Properties sshConfig = new Properties();
        sshConfig.put("StrictHostKeyChecking", "no");
        sshSession.setConfig(sshConfig);
        sshSession.connect();
        ChannelSftp channel = (ChannelSftp) sshSession.openChannel("sftp");
        channel.connect();
        return channel;
    }

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

    /**
     * 销毁对象
     *
     * @param p
     * @return
     * @author fengfan
     * @date 2022/1/14 15:26
     */
    @Override
    public void destroyObject(PooledObject<ChannelSftp> p) {
        ChannelSftp channelSftp = p.getObject();
        channelSftp.disconnect();
    }

    /**
     * 激活连接池里面的sftp连接
     *
     * @param p
     * @throws Exception
     */
    @Override
    public void activateObject(PooledObject<ChannelSftp> p) throws Exception {
        ChannelSftp channelSftp = p.getObject();
        if(!channelSftp.isConnected()){
            channelSftp.connect();
        }

    }
}

创建对象池
SftpGenericObjectPool.java

package org.example.pool;

import com.jcraft.jsch.ChannelSftp;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class SftpGenericObjectPool{

    private final GenericObjectPool<ChannelSftp> genericObjectPool;

    public SftpGenericObjectPool(SftpFactory sftpFactory, GenericObjectPoolConfig<ChannelSftp> sftpPoolConfig) {
        this.genericObjectPool = new GenericObjectPool<>(sftpFactory, sftpPoolConfig);
    }

    public ChannelSftp borrowObject() throws Exception {
        return genericObjectPool.borrowObject();
    }

    public void returnObject(ChannelSftp obj) {
        genericObjectPool.returnObject(obj);
    }
}

创建文件操作工具类
SftpUtil.java

package org.example.ftp;

import com.jcraft.jsch.*;
import org.example.pool.SftpGenericObjectPool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;


public class SftpUtil {
    //连接池
    private SftpGenericObjectPool pool;

    @Value("${sftp.host}")
    private String host;
    @Value("${sftp.port}")
    private int port;
    @Value("${sftp.username}")
    private String username;
    @Value("${sftp.password}")
    private String password;


    public SftpUtil(SftpGenericObjectPool pool) {
        this.pool = pool;
    }

    public boolean isExist(String filePath) throws Exception {
        ChannelSftp sftp = pool.borrowObject();
        try {
            sftp.lstat(filePath);
        } catch (SftpException se) {
            if (se.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                return false;
            }
        } finally {
            pool.returnObject(sftp);
        }
        return true;
    }



    /**
     * 下载文件
     *
     * @param dir  远程目录
     * @param name 远程文件名
     * @return 文件字节数组
     */
    public InputStream download(String dir, String name) throws Exception {
        ChannelSftp sftp = pool.borrowObject();
        try {
            sftp.cd(dir);
            return sftp.get(name);
        } finally {
            pool.returnObject(sftp);
        }
    }

    /**
     * 根据全路径下载文件
     * @param filePath 远程文件全路径
     * @return 文件流
     * @throws Exception
     */
    public InputStream download(String filePath) throws Exception {
        ChannelSftp sftp = pool.borrowObject();
        try {
            return sftp.get(filePath);
        } finally {
            pool.returnObject(sftp);
        }
    }

    /**
     * 通过http请求下载文件
     * @param response HttpServletResponse
     * @param filePath 文件全路径
     * @param realFileName 下载出来的文件名
     * @throws Exception
     */
    public void download(HttpServletResponse response, String filePath, String realFileName) throws Exception {
        response.reset();
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(realFileName,"UTF-8"));
        ServletOutputStream os = response.getOutputStream();
        BufferedInputStream bis = new BufferedInputStream(download(filePath));
        byte[] buff = new byte[1024];
        int i = 0;
        while ((i = bis.read(buff)) != -1) {
            os.write(buff, 0, i);
            os.flush();
        }
        bis.close();
        os.close();
    }

    /**
     * 拿到了File,下载到浏览器
     * @param response HttpServletResponse
     * @param file 文件对象
     * @param realFileName 下载的文件名
     * @throws Exception
     */
    public void download(HttpServletResponse response, File file, String realFileName) throws Exception {
        response.reset();
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.setContentLength((int) file.length());
        response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(realFileName == null ? file.getName() : realFileName,"UTF-8"));
        ServletOutputStream os = response.getOutputStream();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
        byte[] buff = new byte[1024];
        int i = 0;
        while ((i = bis.read(buff)) != -1) {
            os.write(buff, 0, i);
            os.flush();
        }
        bis.close();
        os.close();
    }

    /**
     * 下载远程文件并读取每一行数据
     * @param filePath 远程文件全路径
     * @return 文件内容
     */
    public List<String> downloadAndReadAllLines(String filePath) {
        ChannelSftp sftp = null;
        try {
            sftp = pool.borrowObject();
            InputStream inputStream = sftp.get(filePath);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            ArrayList<String> result = new ArrayList<>();
            for (; ; ) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
                }
                result.add(line);
            }
            return result;
        } catch (Exception e) {
            return new ArrayList<>();
        } finally {
            if (sftp != null) {
                pool.returnObject(sftp);
            }
        }
    }

    /**
     * 上传文件
     *
     * @param dir  远程目录
     * @param name 远程文件名
     * @param in   输入流
     */
    public void upload(String dir, String name, InputStream in) throws Exception {
        ChannelSftp sftp = pool.borrowObject();
        try {
            mkdirs(sftp, dir);
            sftp.cd(dir);
            sftp.put(in, name);
        } finally {
            pool.returnObject(sftp);
        }
    }

    /**
     * 上传文件
     * @param filePath 远程文件全路径
     * @param in 文件流
     * @throws Exception
     */
    public void upload(String filePath, InputStream in) throws Exception {
        ChannelSftp sftp = pool.borrowObject();
        try {
            mkdirs(sftp, filePath);
            sftp.put(in, filePath);
        } finally {
            pool.returnObject(sftp);
        }
    }

    /**
     * 直接上传内容数据
     * @param filePath 远程文件全路径
     * @param data 数据内容
     * @throws Exception
     */
    public void upload(String filePath, String data) throws Exception {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
        this.upload(filePath, byteArrayInputStream);
    }

    /**
     * 删除文件
     *
     * @param dir  远程目录
     * @param name 远程文件名
     */
    public void delete(String dir, String name) throws Exception {
        ChannelSftp sftp = pool.borrowObject();
        try {
            sftp.cd(dir);
            sftp.rm(name);
        } finally {
            pool.returnObject(sftp);
        }
    }

    public void delete(String filePath) throws Exception {
        ChannelSftp sftp = pool.borrowObject();
        try {
            sftp.rm(filePath);
        } finally {
            pool.returnObject(sftp);
        }
    }

    /**
     * 递归创建多级目录
     *
     * @param dir 多级目录
     */
    private void mkdirs(ChannelSftp sftp, String dir) throws SftpException {
        String[] folders = dir.split("/");
        sftp.cd("/");
        for (String folder : folders) {
            if (folder.length() > 0) {
                try {
                    sftp.cd(folder);
                } catch (Exception e) {
                    sftp.mkdir(folder);
                    sftp.cd(folder);
                }
            }
        }
    }

    /**
     * 执行shell命令
     * @param command shell命令
     * 注意:执行shell命令不能使用pool来实现,否则只会第一次成功,后面执行会不起作用(也有可能是我代码的问题)
     */
    public void execShell(String command) {
        if (StringUtils.isEmpty(command)) {
            return;
        }
        command = command + " \n";

        JSch jsch = new JSch();
        Session sshSession = null;
        ChannelExec sftp = null;
        try {
            jsch.getSession(username,host,port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            sftp = (ChannelExec) sshSession.openChannel("exec");
            sftp.setCommand(command);
            OutputStream outputStream = sftp.getOutputStream();
            sftp.connect();

            outputStream.write(command.getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sftp != null) {
                sftp.disconnect();
            }
            if (sshSession != null) {
                sshSession.disconnect();
            }
        }
    }

    public void copy(String srcPath, String dstPath) {
        String command = "cp " + srcPath + " " + dstPath + ";";
        this.execShell(command);
    }

    public SftpGenericObjectPool getPool() {
        return pool;
    }

    public void setPool(SftpGenericObjectPool pool) {
        this.pool = pool;
    }
}

创建启动类
App.java

package org.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        SpringApplication.run(App.class);
    }
}

创建测试Controller
AAController.java

package org.example.controller;

import org.example.ftp.SftpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

@RestController
public class AAController {

    @Autowired
    SftpUtil sftpUtil;

    @RequestMapping("/aaa")
    public String test(){
        return "aaa";
    }

    @GetMapping("/upload")
    public String upload() throws Exception {
        String dir = "/tmp/";
        String name = "test.txt";
        String uploadFilePath = "";
        InputStream in = new FileInputStream(new File(uploadFilePath));
        sftpUtil.upload(dir,name,in);
        return "上传成功";
    }
}

源码地址:https://gitcode.net/lu993356091/ftptest

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java使用jsch库进行远程文件下载可以实现通过SSH协议从远程服务器下载文件。下面是一个简单的示例代码: ```java import com.jcraft.jsch.*; public class RemoteFileDownloader { public static void main(String[] args) { String host = "远程服务器IP"; String username = "用户名"; String password = "密码"; String remoteFilePath = "远程文件路径"; String localFilePath = "本地保存路径"; JSch jsch = new JSch(); Session session = null; try { session = jsch.getSession(username, host, 22); session.setConfig("StrictHostKeyChecking", "no"); session.setPassword(password); session.connect(); ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp.connect(); channelSftp.get(remoteFilePath, localFilePath); channelSftp.disconnect(); } catch (JSchException | SftpException e) { e.printStackTrace(); } finally { if (session != null) { session.disconnect(); } } } } ``` 请将代码中的以下变量替换为实际的值: - `host`: 远程服务器的IP地址或域名 - `username`: 远程服务器的用户名 - `password`: 远程服务器的密码 - `remoteFilePath`: 要下载文件远程服务器上的路径 - `localFilePath`: 下载后保存到本地的路径 这段代码使用jsch库创建一个SSH会话并连接到远程服务器。然后,通过打开SFTP通道并调用`get()`方法来下载文件。最后,关闭SFTP通道和SSH会话。 请注意,为了运行这段代码,你需要将jsch库添加到你的项目中。你可以从jsch官方网站[https://www.jcraft.com/jsch/](https://www.jcraft.com/jsch/)下载该库的jar文件,并将其添加到你的项目的类路径中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值