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

maven依赖:

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

application.yml

sftp:protocol: sftphost: port: 22username: rootpassword: spring:servlet:multipart:max-file-size: 500MBmax-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 {@Resourceprivate 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 {@Autowiredprivate 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 {@Autowiredprivate SftpUtils sftpUtils;@Overridepublic 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 {// 关闭sftpsftpUtils.disconnect(sftp);}}@Overridepublic 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 {// 关闭sftpsftpUtils.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;}}
}

接口测试:

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用API有效率地管理Dynadot域名,为文件夹中的域名进行域名停放

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

七人团购新风尚:数字化时代的购物革命

在数字化时代的浪潮中&#xff0c;购物方式正经历着前所未有的变革。其中&#xff0c;七人团购模式以其独特的互动性和价值共享理念&#xff0c;为消费者带来了全新的购物体验。下面&#xff0c;我们将深入探讨这一模式的运作机制&#xff0c;以及它如何为标价599元的热销商品创…

Python 面试【初级】

欢迎莅临我的博客 &#x1f49d;&#x1f49d;&#x1f49d;&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【算法训练记录——Day36】

Day36——贪心Ⅳ 1.leetcode_452用最少数量的箭引爆气球2.leetcode_435无重叠区间3.leetcode_763划分字母区间4.leetcode_ 1.leetcode_452用最少数量的箭引爆气球 思路&#xff1a;看了眼题解&#xff0c;局部最优&#xff1a;当气球出现重叠&#xff0c;一起射&#xff0c;所用…

快速了解GPT-4o和GPT-4区别

GPT-4o简介 在5月14日的OpenAI举行春季发布会上&#xff0c;OpenAI在活动中发布了新旗舰模型“GPT-4o”&#xff01;据OpenAI首席技术官穆里穆拉蒂&#xff08;Muri Murati&#xff09;介绍&#xff0c;GPT-4o在继承GPT-4强大智能的同时&#xff0c;进一步提升了文本、图像及语…

Tesseract Python 图片文字识别入门

1、安装tesseract Index of /tesseract https://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-w64-setup-v5.3.0.20221214.exe 2、安装中文语言包 https://digi.bib.uni-mannheim.de/tesseract/tessdata_fast/ 拷贝到C:\Program Files\Tesseract-OCR\tessdata 3、注…

昇思25天学习打卡营第3天|数据集全攻略:加载、操作与自定义

导入数据集相关库和类 首先&#xff0c;导入了 NumPy 库&#xff0c;并将其简称为 np 。要知道&#xff0c;NumPy 乃是用于科学计算的关键库&#xff0c;作用非凡。接着&#xff0c;从 mindspore.dataset 当中导入了 vision 模块。此外&#xff0c;还从 mindspore.dataset 里引…

前后端分离的后台管理系统开发模板(带你从零开发一套自己的若依框架)上

前言&#xff1a; 目前&#xff0c;前后端分离开发已经成为当前web开发的主流。目前最流行的技术选型是前端vue3后端的spring boot3&#xff0c;本次。就基于这两个市面上主流的框架来开发出一套基本的后台管理系统的模板&#xff0c;以便于我们今后的开发。 前端使用vue3ele…

Web前端

网页开发学习内容:html css JavaScript 两个框架:VUE.js ElementUI UI->user interface 用户界面 html(HyperText Markup Language):超文本标记语言 文本:文字 字符 超文本:网页内容 标记:标签 标识 例如商品上的标签,介绍了商品的信息 html语言就是一种标记语言,提供…

AWS云中的VPC启用流日志保存S3(AWS中国云)

问题 需要在AWS中国云中对VPC启用流日志操作。 步骤 创建s3桶 这里设置一个s3桶名&#xff0c;创建即可。如果出现已存在具有相同名称的存储桶错误&#xff0c;就换个桶名再试一试吧。 启用vpc流日志 找到vpc流日志入口操作&#xff0c;如下图&#xff1a; 设置vpc流日志…

eBPF技术揭秘:DeepFlow如何引领故障排查,提升运维效率

DeepFlow 实战&#xff1a;eBPF 技术如何提升故障排查效率 目录 DeepFlow 实战&#xff1a;eBPF 技术如何提升故障排查效率 微服务架构系统中各个服务、组件及其相互关系的全景 零侵扰分布式追踪&#xff08;Distributed Tracing&#xff09;的架构和工作流程 关于零侵扰持…

任务5.1 初识Spark Streaming

实战概述&#xff1a;使用Spark Streaming进行词频统计 1. 项目背景与目标 背景: Spark Streaming是Apache Spark的流处理框架&#xff0c;用于构建可伸缩、高吞吐量的实时数据处理应用。目标: 实现一个实时词频统计系统&#xff0c;能够处理流式数据并统计文本中的单词出现频…

微机原理 复习

第一章导论 1.3 冯诺依曼体系结构 &#xff08;1&#xff09;以二进制形式表示指令和数据 &#xff08;2&#xff09;程序和数据事先放在存储器中&#xff08;预存储&#xff09; &#xff08;3&#xff09;由运算器、控制器、输入设备和输出设备五大部件组成 字长、主频…

Java8新特性stream的原理和使用

这是一种流式惰性计算&#xff0c;整体过程是&#xff1a; stream的使用也异常方便&#xff0c;可以对比如List、Set之类的对象进行流式计算&#xff0c;挑出最终想要的结果&#xff1a; List<Timestamp> laterTimes allRecords.stream().map(Record::getTime).filter…

【摄像头标定】双目摄像头标定及矫正-opencv(python)

双目摄像头标定及矫正 棋盘格标定板标定矫正 棋盘格标定板 本文使用棋盘格标定板&#xff0c;可以到这篇博客中下载&#xff1a;https://blog.csdn.net/qq_39330520/article/details/107864568 标定 要进行标定首先需要双目拍的棋盘格图片&#xff0c;20张左右&#xff0c;…

30 哈希的应用

位图 概念 题目 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何判断一个数是否在这40亿个整数中 1.遍历&#xff0c;时间复杂度O(N) 2.二分查找&#xff0c;需要先排序&#xff0c;排序(N*logN)&#xff0c;二分查找&#xff0c;logN。…

装载问题(回溯法)

#include<iostream> using namespace std; int n;//货物的数量 int c;//轮船的总的载重量 int cw;//轮船当前的载重量 int r;//货物的总重量 int w[1000];//n个货物各自的重量 int x[1000];//当前最优解 int bestx[1000];//最优解 int bestw;//货物的最优载重量 void Bac…

[JS]对象

介绍 对象是一种无序的数据集合, 可以详细的描述某个事物 事物的特征在对象中用属性来表示, 事物的行为在对象中用方法来表示 使用 创建对象 let 对象名 {属性名&#xff1a;值&#xff0c;方法名&#xff1a;函数&#xff0c; } let 对象名 new Object(); 对象名.属性…

Typora failed to export as pdf. undefined

变换版本并没有用&#xff0c;调整图片大小没有用 我看到一个博客后尝试出方案 我的方法 解决&#xff1a;从上图中的A4&#xff0c;变为其他&#xff0c;然后变回A4 然后到处成功&#xff0c;Amazing&#xff01; 参考&#xff1a; Typora 导出PDF 报错 failed to export…

Rpc服务的提供方(Rpcprovider)的调用流程

首先&#xff0c;服务的提供方&#xff0c;会通过rpcprovider向rpc服务方注册rpc服务对象和服务方法&#xff0c; 那么&#xff0c;我们通过protobuf提供的抽象层的service和method&#xff0c;将服务对象和它所对应的服务方法记录在map表中&#xff0c; 当它启动以后&#xff…