SpringBoot实战(二十六)集成SFTP

目录

    • 一、SFTP简介
    • 二、SpringBoot 集成
      • 2.1 Maven 依赖
      • 2.2 application.yml 配置
      • 2.3 DemoController.java 接口
      • 2.4 SftpService.java
      • 2.5 DemoServiceImpl.java 实现类
      • 2.6 SftpUtils.java 工具类
      • 2.7 执行结果
        • 1)上传文件
        • 2)下载文件
        • 3)重命名文件(移动)
        • 4)删除文件

一、SFTP简介

SFTP:全称 Secure File Transfer Protocol,是一种安全文件传输协议,它基于 SSH(Secure Shell)协议并为其提供了文件传输服务。相比于传统的 FTP,SFTP 提供了加密的数据传输通道,能够有效保护数据在传输过程中不被窃取和篡改,增强了安全性。

  • SFTP 服务器,在 LinuxMac 系统中是自带的,可以直接使用 Linux 的用户名/密码来登录 SFTP,windows 下默认只支持 SFTP 客户端,不支持 SFTP 服务器。

SFTP 登录命令:

# 和ssh命令一样:用户名@ip
sftp root@192.168.1.123

补充:由于 Linux 默认集成了 SFTP 服务器,所以测试 SpringBoot 集成 SFTP 的时候不需要再搭建 SFTP,直接用户名/密码连 Linux 系统即可。


二、SpringBoot 集成

2.1 Maven 依赖

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

2.2 application.yml 配置

sftp:protocol: sftphost: 192.168.1.10port: 22username: rootpassword: root

2.3 DemoController.java 接口

import com.demo.common.Result;
import com.demo.service.DemoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;/*** <p> @Title DemoController* <p> @Description 测试Controller** @author ACGkaka* @date 2023/4/24 18:02*/
@Slf4j
@RestController
@RequestMapping("/demo")
public class DemoController {@Resourceprivate DemoService demoService;/*** 上传文件*/@PostMapping("/upload")public Result<Object> upload(@RequestParam String sftpPath, @RequestParam MultipartFile file) {demoService.upload(sftpPath, file);return Result.succeed();}/*** 下载文件*/@GetMapping("/download")public void download(@RequestParam String sftpPath,  HttpServletResponse response) {demoService.download(sftpPath, response);}/*** 重命名文件(移动)*/@GetMapping("/rename")public Result<Object> rename(@RequestParam String oldPath,  @RequestParam String newPath) {demoService.rename(oldPath, newPath);return Result.succeed();}/*** 删除文件*/@GetMapping("/delete")public Result<Object> delete(@RequestParam String sftpPath) {demoService.delete(sftpPath);return Result.succeed();}
}

2.4 SftpService.java

import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;/*** <p> @Title DemoService* <p> @Description 测试Service** @author ACGkaka* @date 2023/4/24 18:13*/
public interface DemoService {/*** 上传文件* @param sftpPath 路径* @param file 文件*/void upload(String sftpPath, MultipartFile file);/*** 下载文件* @param sftpPath* @param response*/void download(String sftpPath, HttpServletResponse response);/*** 重命名文件(移动)* @param oldPath* @param newPath*/void rename(String oldPath, String newPath);/*** 删除文件* @param sftpPath*/void delete(String sftpPath);
}

2.5 DemoServiceImpl.java 实现类

import com.demo.service.DemoService;
import com.demo.util.SftpUtils;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;/*** <p> @Title DemoServiceImpl* <p> @Description 测试ServiceImpl** @author ACGkaka* @date 2023/4/24 18:14*/
@Slf4j
@Service
public class DemoServiceImpl implements DemoService {@Resourceprivate SftpUtils sftpUtils;@Overridepublic void upload(String sftpPath, MultipartFile file) {// 上传文件ChannelSftp sftp = null;try (InputStream in = file.getInputStream()) {// 开启sftp连接sftp = sftpUtils.createSftp();// 进入sftp文件目录sftp.cd(sftpPath);log.info("修改目录为:{}", sftpPath);// 上传文件sftp.put(in, file.getOriginalFilename());log.info("上传文件成功,目标目录:{}", sftpPath);} catch (SftpException | JSchException | IOException e) {log.error("上传文件失败,原因:{}", e.getMessage(), e);throw new RuntimeException("上传文件失败");} finally {// 关闭sftpsftpUtils.disconnect(sftp);}}@Overridepublic void download(String sftpPath, HttpServletResponse response) {// 下载文件long start = System.currentTimeMillis();ChannelSftp sftp = null;try {// 开启sftp连接sftp = sftpUtils.createSftp();// 判断sftp文件存在File sftpFile = new File(sftpPath);boolean isExist = isFileExist(sftpPath, sftp);if (isExist) {// 下载文件response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(sftpFile.getName(), "utf-8"));sftp.get(sftpFile.getName(), response.getOutputStream());// 记录日志long time = System.currentTimeMillis() - start;log.info("sftp文件下载成功,目标文件:{},总耗时:{}ms.", sftpPath, time);} else {log.error("sftp文件下载失败,sftp文件不存在:" + sftpFile.getParent());throw new RuntimeException("sftp文件下载失败,sftp文件不存在:" + sftpFile.getParent());}} catch (SftpException | JSchException | IOException e) {log.error("sftp文件下载失败,目标文件名:{},原因:{}", sftpPath, e.getMessage(), e);throw new RuntimeException("sftp文件下载失败");} finally {// 关闭sftpsftpUtils.disconnect(sftp);}}@Overridepublic void rename(String oldPath, String newPath) {// 重命名文件(移动)ChannelSftp sftp = null;try {// 开启sftp连接sftp = sftpUtils.createSftp();// 修改sftp文件路径sftp.rename(oldPath, newPath);log.info("sftp文件重命名成功,历史路径:{},新路径:{}", oldPath, newPath);} catch (SftpException | JSchException e) {log.error("sftp文件重命名失败,原因:{}", e.getMessage(), e);throw new RuntimeException("sftp文件重命名失败");} finally {// 关闭sftpsftpUtils.disconnect(sftp);}}@Overridepublic void delete(String sftpPath) {// 删除文件ChannelSftp sftp = null;try {// 开启sftp连接sftp = sftpUtils.createSftp();// 判断sftp文件存在boolean isExist = isFileExist(sftpPath, sftp);if (isExist) {// 删除文件SftpATTRS sftpATTRS = sftp.lstat(sftpPath);if (sftpATTRS.isDir()) {sftp.rmdir(sftpPath);} else {sftp.rm(sftpPath);}log.info("sftp文件删除成功,目标文件:{}.", sftpPath);} else {log.error("sftp文件删除失败,sftp文件不存在:" + sftpPath);throw new RuntimeException("sftp文件删除失败,sftp文件不存在:" + sftpPath);}} catch (SftpException | JSchException e) {log.error("sftp文件删除失败,原因:{}", e.getMessage(), e);throw new RuntimeException("sftp文件删除失败");} finally {// 关闭sftpsftpUtils.disconnect(sftp);}}/*** 判断目录是否存在*/private boolean isFileExist(String sftpPath, ChannelSftp sftp) {try {// 获取文件信息SftpATTRS sftpATTRS = sftp.lstat(sftpPath);return sftpATTRS != null;} catch (Exception e) {log.error("判断文件是否存在失败,原因:{}", e.getMessage(), e);return false;}}
}

2.6 SftpUtils.java 工具类

import com.demo.config.SftpProperties;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.annotation.Resource;/*** <p> @Title SftpUtils* <p> @Description SFTP工具类** @author ACGkaka* @date 2024/1/31 17:41*/
@Slf4j
@Component
public class SftpUtils {@Resourceprivate SftpProperties sftpProperties;/*** 创建SFTP连接*/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");// 默认情况下,JSch库本身并没有会话超时时间。// 为了避免长时间无活动连接占用资源或因网络问题导致连接挂起而不被释放,通常建议设置会话超时,(单位:毫秒)session.setTimeout(30000);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;}/*** 创建 Session*/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);}}
}

2.7 执行结果

1)上传文件

请求地址:http://localhost:8080/demo/upload

执行结果:

在这里插入图片描述

2)下载文件

请求地址:http://localhost:8080/demo/download?sftpPath=/home/root/test.pdf

下载后,文件可以正常打开:

在这里插入图片描述

3)重命名文件(移动)

请求地址:http://localhost:8080/demo/rename?oldPath=/home/root/test1.pdf&newPath=/home/root/test/test.pdf

执行结果:

在这里插入图片描述

可以去sftp上面看下,文件已经被移动了:

在这里插入图片描述

4)删除文件

请求地址:http://localhost:8080/demo/delete?sftpPath=/home/root/test/test1.pdf

执行结果:

在这里插入图片描述

可以去sftp上面看下,文件已经被成功删除了:

在这里插入图片描述

整理完毕,完结撒花~ 🌻





参考地址:

1.SFTP命令用法(上传和下载 ),https://blog.csdn.net/JacaCao/article/details/108190174

2.springBoot整合sftp,https://blog.csdn.net/winsanity/article/details/120665642

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

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

相关文章

全链游戏的未来趋势与Bridge Champ的创新之路

为了充分探索全链游戏的特点和趋势&#xff0c;以及Bridge Champ如何作为一个创新案例融入这一发展脉络&#xff0c;我们需要深入了解这两者之间的互动和相互影响。全链游戏&#xff0c;或完全基于区块链的游戏&#xff0c;代表了游戏行业的一个重要转型&#xff0c;它们利用区…

nginx反向代理----->微服务网关----->具体微服务

今天&#xff0c;做项目的时候做项目的时候配路由出现bug&#xff0c;特此理顺一下从nginx到微服务网关再到微服务这一过程。 nginx配置 upstream admin-gateway{server localhost:21217; }server {listen 8803;location / {root F:/develop/admin-web/;index index.html;}…

LeetCode--代码详解 2.两数相加

2.两数相加 题目 难度&#xff1a;中等 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数…

【django】建立python虚拟环境-20240205

1.确保已经安装pip3 install venv 2.新建虚拟环境 python -m venv myenv 3.安装虚拟环境的依赖包 pip install … 4.激活虚拟环境 cd myenv cd Scripts activate 激活activate.bat并进入虚拟环境 进入虚拟环境后&#xff0c;命令行前面显示&#xff08;myenv&#xff0…

AspNet web api 和mvc 过滤器差异

最近在维护老项目。定义个拦截器记录接口日志。但是发现不生效 最后发现因为继承的 ApiController不是Controller 只能用 System.Web.Http下的拦截器生效。所以现在总结归纳一下 Web Api: System.Web.Http.Filters.ActionFilterAttribute 继承该类 Mvc: System.Web.Mvc.Ac…

【Linux系统 01】Vim工具

目录 一、Vim概述 1. 文件打开方式 2. 模式切换 二、命令模式 1. 移动与跳转 2. 复制与粘贴 3. 剪切与撤销 三、编辑模式 1. 插入 2. 替换 四、末行模式 1. 保存与退出 2. 查找与替换 3. 分屏显示 4. 命令执行 一、Vim概述 1. 文件打开方式 vim 文件路径&#…

Android学习之路(29) Gradle初探

前言: 大家回想一下自己第一次接触Gradle是什么时候&#xff1f; 相信大家也都是和我一样&#xff0c;在我们打开第一个AS项目的时候&#xff0c; 发现有很多带gradle字样的文件&#xff1a;setting.gradle, build.gradle,gradle.warpper,以及在gradle文件中各种配置&#xff…

设计模式1-访问者模式

访问者模式是一种行为设计模式&#xff0c;它允许你定义在对象结构中的元素上进行操作的新操作&#xff0c;而无需修改这些元素的类。这种模式的主要思想是将算法与元素的结构分离开&#xff0c;使得可以在不修改元素结构的情况下定义新的操作。 所谓算法与元素结构分离&#x…

###C语言程序设计-----C语言学习(9)#函数基础

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步。 一. 基础知识的学习 1.函数的定义 函数是一个完成特定工作的独立程序模块&…

JavaWeb之HTML-CSS --黑马笔记

什么是HTML ? 标记语言&#xff1a;由标签构成的语言。 注意&#xff1a;HTML标签都是预定义好的&#xff0c;HTML代码直接在浏览器中运行&#xff0c;HTML标签由浏览器解析。 什么是CSS ? 开发工具 VS Code --安装文档和安装包都在网盘中 链接&#xff1a;https://p…

2024年混合云:趋势和预测

混合云环境对于 DevOps 团队变得越来越重要&#xff0c;主要是因为它们能够弥合公共云资源的快速部署与私有云基础设施的安全和控制之间的差距。这种环境的混合为 DevOps 团队提供了灵活性和可扩展性&#xff0c;这对于大型企业中的持续集成和持续部署 (CI/CD) 至关重要。 在混…

uniapp踩坑之项目:简易版不同角色显示不一样的tabbar和页面

1. pages下创建三个不同用户身份的“我的”页面。 显示第几个tabbar&#xff0c;0是管理员 1是财务 2是司机 2. 在uni_modules文件夹创建底部导航cc-myTabbar文件夹&#xff0c;在cc-myTabbar文件夹创建components文件夹&#xff0c;在components文件夹创建cc-myTabbar.vue组件…

Java 正则匹配sql

文章目录 正则匹配sql表名称insert intoupdate 正则表达式什么时候要加^$ 在线正则校验 正则匹配sql表名称 insert into insert into PING_TABLE (CODE, NAME) VALUES(0, 待提交),(1, 审核中),(2, 审核通过),(3, 已驳回); regex -> insert\sinto\s(\w)\s*\(?update upda…

Qt 范例阅读: QStateMachine状态机框架 和 SCXML 引擎简单记录(方便后续有需求能想到这两个东西)

一、QStateMachine 简单应用&#xff1a; 实现按钮的文本切换 QStateMachine machine; //定义状态机&#xff08;头文件定义&#xff09;QState *off new QState(); //添加off 状态off->assignProperty(ui->pushButton_2, "text", "Off"); //绑定该…

idea修改项目git地址

大家好&#xff0c;今天给大家分享的知识是如何在idea中修改项目的git地址。 一、修改地址 首先我们先找到菜单栏中Git选项&#xff0c;然后点击管理远程&#xff08;Manage Remote&#xff09; 之后双击origin之后就可以定义名称或者URL了。

wangEditor v4的简单使用

当前文档是 wangEditor v4 版本的。 wangEditor v5 已经正式发布&#xff0c;可参考文档。 v5 发布之后&#xff0c;v4 将不再开发新功能。 介绍 English documentation wangEditor4 —— 轻量级 web 富文本编辑器&#xff0c;配置方便&#xff0c;使用简单。 官网&#…

基于SpringBoot的后端导出Excel文件

后端导出Excel&#xff0c;前端下载。 系列文章指路&#x1f449; 系列文章-基于SpringBoot3创建项目并配置常用的工具和一些常用的类 文章目录 后端导出Excel引入依赖写入响应 前端下载后端导出失败和成功返回的内容类型不同&#xff0c;因此需要分别判断。 工具类ServletUti…

基于springboot智慧养老平台源码和论文

首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。本项…

第97讲:MHA高可用集群模拟主库故障以及修复过程

文章目录 1.分析主库故障后哪一个从库会切换为主库2.模拟主库故障观察剩余从库的状态2.1.模拟主库故障2.3.当前主从架构 3.修复故障的主库3.1.修复主库3.2.当前主从架构3.3.恢复MHA 1.分析主库故障后哪一个从库会切换为主库 在模拟MHA高可用集群主库故障之前&#xff0c;我们先…

全面解析:船运物流管理系统背后的技术

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…