SpringBoot 搭建sftp服务 实现远程上传和下载文件

maven依赖:

<dependency>
  <groupId>com.jcraft</groupId>
  <artifactId>jsch</artifactId>
  <version>0.1.55</version>
</dependency>

application.yml

sftp:
  protocol: sftp
  host: 
  port: 22
  username: root
  password: 
  
spring:
  servlet:
    multipart:
      max-file-size: 500MB
      max-request-size: 500MB

注:springboot自带的tomcat会限制上传文件的大小,需要在yml文件里手动设置max-file-size

SftpProperties.java

@Data
@Component
@ConfigurationProperties(prefix = "sftp")
public class SftpProperties {
    private String host;
    private int port;
    private String username;
    private String password;
    private String protocol;
}

SftpUtils.java

@Slf4j
@Component
public class SftpUtils {
    @Resource
    private SftpProperties sftpProperties;

    public ChannelSftp createSftp() throws JSchException {
        JSch jsch = new JSch();
        log.info("Try to connect sftp[" + sftpProperties.getUsername() + "@" + sftpProperties.getHost() + "]");

        Session session = createSession(jsch, sftpProperties.getHost(), sftpProperties.getUsername(), sftpProperties.getPort());
        session.setPassword(sftpProperties.getPassword());
        session.setConfig("StrictHostKeyChecking", "no");

        session.connect();
        log.info("Session connected to {}.", sftpProperties.getHost());

        Channel channel = session.openChannel(sftpProperties.getProtocol());
        channel.connect();
        log.info("Channel created to {}.", sftpProperties.getHost());

        return (ChannelSftp) channel;
    }

    public Session createSession(JSch jsch, String host, String username, Integer port) throws JSchException {
        Session session = null;
        if (port <= 0) {
            session = jsch.getSession(username, host);
        } else {
            session = jsch.getSession(username, host, port);
        }
        if (session == null) {
            throw new RuntimeException(host + "session is null");
        }
        return session;
    }

    public void disconnect(ChannelSftp sftp) {
        try {
            if (sftp != null) {
                if (sftp.isConnected()) {
                    sftp.disconnect();
                } else if (sftp.isClosed()) {
                    log.error("sftp 连接已关闭");
                }
                if (sftp.getSession() != null) {
                    sftp.getSession().disconnect();
                }
            }
        } catch (JSchException e) {
            log.error("sftp 断开连接失败,原因:{}", e.getMessage(), e);
        }
    }
}

SftpController.java

@RestController
public class SftpController {

    @Autowired
    private SftpService sftpService;
    
    @PostMapping("/upload")
    public void upload(String remotePath, MultipartFile file) {
        sftpService.upload(remotePath, file);
    }

    @GetMapping("/download")
    public void download(String remotePath, String localPath) {
        sftpService.download(remotePath, localPath);
    }
}

SftpServiceImpl.java

@Service
@Slf4j
public class SftpServiceImpl implements SftpService {
    @Autowired
    private SftpUtils sftpUtils;

    @Override
    public void upload(String remotePath, MultipartFile file) {
        ChannelSftp sftp = null;
        try {
            // 开启sftp连接
            sftp = sftpUtils.createSftp();
            sftp.cd(remotePath);
            log.info("修改目录为:{}", remotePath);

            // 上传文件
            sftp.put(file.getInputStream(), file.getOriginalFilename());
            log.info("上传文件成功,目标目录:{}", remotePath);
        } catch (Exception e) {
            log.error("上传文件失败,原因:{}", e.getMessage(), e);
            throw new RuntimeException("上传文件失败");
        } finally {
            // 关闭sftp
            sftpUtils.disconnect(sftp);
        }
    }

    @Override
    public void download(String remotePath, String localPath) {
        ChannelSftp sftp = null;
        OutputStream outputStream = null;
        try {
            sftp = sftpUtils.createSftp();
            String path = remotePath.substring(0, remotePath.lastIndexOf("/"));
            String fileName = remotePath.substring(remotePath.lastIndexOf("/") + 1);
            System.out.println("path:" + path);
            System.out.println("fileName:" + fileName);
            sftp.cd(path);
            if(isFileExist(remotePath, sftp)) { //如果远程文件存在
                File localFile = new File(localPath);
                if(!localFile.exists()) { //如果本地目录不存在,则创建目录
                    localFile.mkdirs();
                }
                outputStream = new FileOutputStream(new File(localPath + "/" + fileName));
                sftp.get(fileName, outputStream);
                log.info("下载文件成功");
            } else {
                log.error("远程文件不存在");
                throw new RuntimeException("远程文件不存在");
            }
        } catch (Exception e) {
            log.error("sftp文件下载失败,目标文件名:{},原因:{}", remotePath, e.getMessage(), e);
            throw new RuntimeException("远程文件下载失败");
        } finally {
            // 关闭sftp
            sftpUtils.disconnect(sftp);
        }
    }

    //判断文件是否存在
    private boolean isFileExist(String remotePath, ChannelSftp sftp) {
        try {
            SftpATTRS lstat = sftp.lstat(remotePath);
            return lstat != null;
        } catch (Exception e) {
            log.error("判断文件是否存在失败,原因:{}", e.getMessage(), e);
            return false;
        }
    }
}

接口测试:

上传接口:
请添加图片描述
下载接口:
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/733522.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【CSS in Depth2精译】1.4 简写属性

文章目录 1.4 简写属性1.4.1 当心简写属性悄悄覆盖其他样式1.4.2 记住简写值的顺序1 上、右、下、左顺序2 先水平、再垂直的顺序 1.4 简写属性 简写属性&#xff08;Shorthand properties&#xff09; 是可以一次性设置多个属性值的样式属性。例如&#xff0c; font 就是一个简…

考前刷题练手感(北航期末往年数据结构编程题)

本次因为是考前一天极速刷题&#xff0c;所以没有讲解&#xff0c;若有问题可私信。 目录 一、 查找同时空人员二、 老鼠回家-无回路三、函数调⽤关系四、东二食堂模拟五、栈帧 一、 查找同时空人员 【问题描述】 假设一共有6个手机基站&#xff0c;都具有记录手机连接基站状…

【MMSegmentation 环境配置】

MMSegmentation 环境配置 1. 创建python 环境2. 安装pytorch3. 安装MMCV4. 安装 MMSegmentation.5. 测试是否安装成功 1. 创建python 环境 conda create --name openmmlab python3.8 -y conda activate openmmlab2. 安装pytorch On GPU platforms: conda install pytorch tor…

C语言第17篇:预处理详解

1、预定义符号 C语言设置了一些预定义符号&#xff0c;可以直接使用。预定义符号也是在预处理期间处理的。 __FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATE__ //文件被编译的日期 __TIME__ //文件被编译的时间 __STDC__ //如果编译器遵循ANSI…

国产化操作系统杂谈

目录 操作系统国产化背景国产化操作系统名录优秀操作系统介绍1.深度Linux&#xff08;deepin&#xff09;2.FydeOS3.AliOS&#xff08;openAliOS&#xff09;4.openEuler5.红旗Linux6. startOS 总结 操作系统国产化背景 官方的说法是为了打破长期以来国外对中国的操作系统的垄…

高级算法入门必看—21个NPC问题及其证明

文章目录 前言一、布尔可满足性问题二、每子句至多3个变量的布尔可满足性问题&#xff08;3-SAT&#xff09;三、0-1整数规划&#xff08;0-1 integer programming&#xff09;四、Set packing&#xff08;Set packing&#xff09;五、最小顶点覆盖问题&#xff08;Vertex cove…

FOC方案大合集!

获取链接&#xff01;&#xff01;&#xff01; 本次小编给大家带来了一份FOC的方案大合集。此套方案是基于峰岹科技FU68系列MCU的系列方案&#xff0c;包含常用的无感&#xff0c;有感无刷电机的应用&#xff0c;每份方案都包含了原理图&#xff0c;PCB&#xff0c;代码文件&…

GWO-CNN-SVM,基于GWO灰狼优化算法优化卷积神经网络CNN结合支持向量机SVM数据分类(多特征输入多分类)

GWO-CNN-SVM&#xff0c;基于GWO灰狼优化算法优化卷积神经网络CNN结合支持向量机SVM数据分类(多特征输入多分类) 1. GWO灰狼优化算法 灰狼优化算法&#xff08;Grey Wolf Optimizer, GWO&#xff09;是一种启发式优化算法&#xff0c;模拟了灰狼群体的社会行为&#xff0c;包…

2024山东大学软件学院创新项目实训(9)使用OpenCompass进行模型评估

下载好OpenCompassData-core-20231110.zip 之后&#xff0c;解压压缩包 unzip OpenCompassData-core-20231110.zip 运行代码&#xff1a; python run.py --datasets ceval_gen --hf-path /hy-tmp/7B21/merged --tokenizer-path /hy-tmp/7B21/merged --tokenizer-kwargs p…

com域名注册多少钱

COM域名注册价格视具体注册商而定&#xff0c;不同的注册商可能会有不同的收费标准。一般来说&#xff0c;COM域名注册价格在10美元到20美元之间&#xff0c;可根据不同的需求选择注册时间的长短&#xff0c;从1年到10年等不同时间段的注册费用也不同。以下是关于COM域名注册价…

vue3 computed与watch,watchEffect比较

相同点 都是要根据一个或多个响应式数据进行监听 不同点 computed 如要return回来一个新的响应式值&#xff0c;且这个值不允许直接修改&#xff0c;想要修改的话可以设置set函数&#xff0c;在函数里面去修改所依赖的响应式数据&#xff0c;然后计算属性值会基于其响应式依…

板凳-------第58章SOCKET:TCP/IP网络基础

58.1 互联网 互联网会将不同的计算机网络连接起来并允许位于网络中的主机相互之间进行通信。互联网的目标是隐藏不同物理网络的细节以便向互联网中的所有主机呈现一个统一的网络架构&#xff0c;TCP/IP已经成了使用最为广泛的协议套件了&#xff0c; 术语Internet被用来指将全球…

LayoutSystem布局系统

简介: LayoutSystem,是UGUI中由CanvasUpdateSystem发起(m_LayoutRebuildQueue中大部分都是LayoutRebuilder)的关于布局排列的处理系统。 类图: 布局过程 核心代码讲解: LayoutRebuilder

【C++】STL中优先级队列的使用与模拟实现

前言&#xff1a;在前面我们学习了栈和队列的使用与模拟实现&#xff0c;今天我们来进一步的学习优先级队列使用与模拟实现 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:高质量&#xff23;学习 &#x1f448; &#x1f4af;代码仓库:卫…

51单片机定时器中断配置

测试环境 单片机型号&#xff1a;STC8G1K08-38I-TSSOP20&#xff0c;其他型号请自行测试&#xff1b; IDE&#xff1a;Keil C51&#xff1b; 定时器配置及主要代码 以定时器T0为例&#xff0c;查看手册&#xff0c;有4种工作模式&#xff1a;模式0&#xff08;16位自动重装载…

免费Syslog日志接收工具

如果您想知道您的网络中发生了什么&#xff0c;以便洞察潜在的威胁并在它们变成攻击之前阻止它们&#xff0c;那么您需要查看您的日志。Syslog日志是网络设备、操作系统和应用程序生成的一种重要日志数据&#xff0c;通过有效地收集和监视Syslog日志&#xff0c;企业可以及时发…

android | studio的UI布局和代码调试 | UI调试 (用于找到项目源码)

网上找到一个项目&#xff0c;想快速的搞懂是怎么实现的&#xff0c;搞了半天发现原来android都升级到Jetpack Compose了&#xff0c;然后去找源码挺不容易的&#xff0c;摸索中发现了这个调试的方法&#xff0c;还可以。 https://developer.android.com/studio/debug/layout-i…

LaTeX中添加矩阵分块虚线并设置虚线疏密

对于大型矩阵&#xff0c;有时需要添加分块虚线。 方法为使用arydshln宏包&#xff0c;然后在array环境中设置虚线。需要注意的是&#xff0c;使用矩阵环境需要搭配amsmath宏包使用&#xff0c;且需放在amsmath宏包之后。即导言区设置为 \usepackage{amsmath} \usepackage{ary…

OpenCV 特征点检测与匹配

一 OpenCV特征场景 ①图像搜索&#xff0c;如以图搜图&#xff1b; ②拼图游戏&#xff1b; ③图像拼接&#xff0c;将两长有关联得图拼接到一起&#xff1b; 1 拼图方法 寻找特征 特征是唯一的 可追踪的 能比较的 二 角点 在特征中最重要的是角点 灰度剃度的最大值对应的…

内容安全复习 7 - 对抗攻击与防御

文章目录 概述攻击对抗性攻击的目的攻击的损失函数如何攻击FGSM黑盒与白盒真实世界的攻击 防御被动防御主动防御 概述 动机 &#xff08;1&#xff09;不仅要在实验室中部署机器学习分类器&#xff0c;也要在现实世界中部署&#xff1b;实际应用 &#xff08;2&#xff09;分类…