做网站分为哪些功能的网站,网站建设黄页免费在线观看,光明建网站的公司,推广图片制作背景 开发一个基于jsch的sftp工具类#xff0c;方便在以后的项目中使用。写代码的过程记录下来#xff0c;作为备忘录。。。
Maven依赖
springboot依赖
parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-par…背景 开发一个基于jsch的sftp工具类方便在以后的项目中使用。写代码的过程记录下来作为备忘录。。。
Maven依赖
springboot依赖
parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.0/version
/parentjsch依赖 dependencygroupIdcom.jcraft/groupIdartifactIdjsch/artifactIdversion0.1.55/version
/dependency完整依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdorg.example/groupIdartifactIdjsch-sftp/artifactIdversion1.0-SNAPSHOT/versionpropertiesmaven.compiler.source8/maven.compiler.sourcemaven.compiler.target8/maven.compiler.target/propertiesparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.0/version/parentdependencies!-- web应用相关 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- 单元测试 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdjunit/groupIdartifactIdjunit/artifactId/dependency!-- jsch SFTP --dependencygroupIdcom.jcraft/groupIdartifactIdjsch/artifactIdversion0.1.55/version/dependency!-- lombok --dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency/dependencies/project项目结构 Sftp连接工具类
JschSftpRun 项目启动类
package cn.com.soulfox;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;/*** 启动类** author xxxx* create 2024/7/5 11:50*/
SpringBootApplication
public class JschSftpRun {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(JschSftpRun.class, args);}
}
JschSftpConneciton: 创建sftp连接工具类 用于创建sftp连接类中提供了创建sftp连接的方法另外还提供了在创建sftp连接失败后重新尝试创建连接的方法
package cn.com.soulfox.jsch;import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;/*** author xxxx* create 2024/7/4 12:15*/
Slf4j
public class JschSftpConneciton {private static final String SFTP_PROTOCOL sftp;private static final Integer DEFAULT_RETRY_COUNT_5 5;private static final Long SLEEP_ITME_1000 1000L;//每次重试的时间间隔private String host;private Integer port;private String username;private String password;private Integer sessionTimeout;private Integer connectionTimeout;public JschSftpConneciton setHost(String host) {this.host host;return this;}public JschSftpConneciton setPort(Integer port) {this.port port;return this;}public JschSftpConneciton setUsername(String username) {this.username username;return this;}public JschSftpConneciton setPassword(String password) {this.password password;return this;}public JschSftpConneciton setSessionTimeout(Integer sessionTimeout) {this.sessionTimeout sessionTimeout;return this;}public JschSftpConneciton setConnectionTimeout(Integer connectionTimeout) {this.connectionTimeout connectionTimeout;return this;}/*** 返回SftpWrapper对象是为了方便释放SessionChannel,ChannelSftp资源* SFTP连接服务器*/public SftpWrapper connect() throws Exception {JSch jsch new JSch();Session session null;Channel channel null;ChannelSftp sftp null;try {session jsch.getSession(username, host, port);if (session null) {throw new JSchException(create session error);}//设置登陆主机的密码session.setPassword(password);//设置第一次登陆的时候提示可选值(ask | yes | no)session.setConfig(StrictHostKeyChecking, no);//设置登陆超时时间session.connect(sessionTimeout);session.sendKeepAliveMsg();//创建sftp通信通道channel session.openChannel(SFTP_PROTOCOL);channel.connect(connectionTimeout);sftp (ChannelSftp) channel;return new SftpWrapper(session, channel, sftp);}catch (JSchException e){log.error(SFTP连接异常, e);if (sftp ! null ) {sftp.disconnect();}if (channel ! null ) {channel.disconnect();}if (session ! null ) {session.disconnect();}throw e;} catch (Exception e1) {log.error(SFTP连接异常, e1);if (sftp ! null ) {sftp.disconnect();}if (channel ! null ) {channel.disconnect();}if (session ! null ) {session.disconnect();}throw e1;}}/*** 获取sftp连接获取连接失败时会重试* 默认重试次数5次* return* throws Exception*/public SftpWrapper connectWithRetry() throws Exception {return connectWithRetry(DEFAULT_RETRY_COUNT_5);}public SftpWrapper connectWithRetry(int retryCount) throws Exception {//最大重试次数int maxRetryCount DEFAULT_RETRY_COUNT_5;if(retryCount 0){maxRetryCount retryCount;}int retry 0;Throwable t null;do {try {SftpWrapper channelSftpWrapper this.connect();if(channelSftpWrapper ! null){t null;return channelSftpWrapper;}} catch (Exception e) {t e;}try {Thread.sleep(SLEEP_ITME_1000);//休息1秒} catch (InterruptedException e) {}}while (retry maxRetryCount);if(t ! null){throw new Exception(t);}return null;}}
SftpWrapper sftp连接对象包装类属性包括SessionChannelChannelSftp 执行sftp操作有ChannelSftp就可以了使用Sftp包装类是为了方便关闭资源
package cn.com.soulfox.jsch;import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import lombok.AllArgsConstructor;
import lombok.Data;/*** SftpWrapper类简单包装ChannelSftl对象方便关闭资源* author xxxx* create 2024/7/4 14:26*/
AllArgsConstructor//生成全字段构造方法
Data //生成 getter,setter方法
public class SftpWrapper {private Session session null;private Channel channel null;private ChannelSftp sftp null;/*** 关闭资源*/public void disconnect() {if (sftp ! null sftp.isConnected()) {sftp.disconnect();}if (channel ! null channel.isConnected()) {channel.disconnect();}if (session ! null session.isConnected()) {session.disconnect();}}
}
JschSftpConfig jsch sftp配置类 初始化 jsch sftp
package cn.com.soulfox.config;import cn.com.soulfox.jsch.JschSftpConneciton;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;/*** author xxxx* create 2024/7/4 12:12*/
Configuration
public class JschSftpConfig {Value(${jsch.sftp.host})private String host;Value(${jsch.sftp.port:22})private Integer port;Value(${jsch.sftp.username})private String username;Value(${jsch.sftp.password})private String password;Value(${jsch.sftp.session-timeout:60000})private Integer sessionTimeout;//单位毫秒Value(${jsch.sftp.connect-timeout:5000})private Integer connectTimeout;//单位毫秒BeanLazypublic JschSftpConneciton jschSftpConneciton(){return new JschSftpConneciton().setHost(host).setPort(port).setUsername(username).setPassword(password).setSessionTimeout(sessionTimeout).setConnectionTimeout(connectTimeout);}}sftp连接信息配置在文件application.yml里 jsch: sftp: host: 172.168.xxx.xx port: 1221 #默认22,1221公司自己定义的这里要配置正确 username: xxxx #远程服务器用户名 password: xxxx #远程服务器密码
SftpUitl 工具类提供下载上传文件功能
package cn.com.soulfox.jsch;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.stereotype.Component;import java.io.*;/*** author xxxx* create 2024/7/4 14:28*/
Component
Slf4j
public class JschSftpUtil {private static JschSftpConneciton jschSftpConneciton;Autowiredpublic void setJschSftpConneciton(JschSftpConneciton jschSftpConneciton) {JschSftpUtil.jschSftpConneciton jschSftpConneciton;}/*** 下载文件* param remotePath 远程目录* param downloadFileName 待下载的远程文件名称* param localSavePath 下载文件保存的本地目录*/public static void downloadFile(String remotePath, String downloadFileName, String localSavePath) {SftpWrapper sftpWrapper null;try {//sftp连接对象sftpWrapper jschSftpConneciton.connectWithRetry();//进入远程服务器指定的目录sftpWrapper.getSftp().cd(remotePath);if (!checkLocalPath(localSavePath)) {log.info(本地目录[{}]不存在且新建失败, localSavePath);return;}String localFile checkPathEnd(localSavePath) downloadFileName;File outFile new File(localFile);sftpWrapper.getSftp().get(downloadFileName, new FileOutputStream(outFile));log.info(从远程目录[{}]下载文件[{}]到本地目录[{}]成功, remotePath, downloadFileName, localSavePath);} catch (SftpException e) {log.info(从远程目录[{}]下载文件[{}]到本地目录[{}]失败, remotePath, downloadFileName, localSavePath);log.error(下载文件失败: , e);} catch (Exception e) {log.info(从远程目录[{}]下载文件[{}]到本地目录[{}]失败, remotePath, downloadFileName, localSavePath);log.error(下载文件失败: , e);} finally {if (sftpWrapper ! null) {sftpWrapper.disconnect();}}}/**** param localDir 保存上传文件的本地目录* param uploadFileName 上传文件名称* param remoteSaveDir 保存上传文件的远程目录, 建议使用绝对路径* 如果使用相对路径建议基准目录使用sfpt登录后所在的目录* 这个目录使用channelSftp.goHome()可以获取*/public static void uploadFile(String localDir, String uploadFileName, String remoteSaveDir) {String uploadFilePath checkPathEnd(localDir) uploadFileName;File uploadFile new File(uploadFilePath);uploadFile(uploadFile, remoteSaveDir);}/*** 上传文件* param uploadFilePath 本地文件的路径* param remoteSaveDir 保存上传文件的远程目录, 建议使用绝对路径* 如果使用相对路径建议基准目录使用sfpt登录后所在的目录* 这个目录使用channelSftp.goHome()可以获取*/public static void uploadFile(String uploadFilePath, String remoteSaveDir) {File uploadFile new File(uploadFilePath);uploadFile(uploadFile, remoteSaveDir);}/*** 上传文件* param uploadFile 上传文件的File对象* param remoteSavePath 保存上传文件的远程目录, 建议使用绝对路径* 如果使用相对路径建议基准目录使用sfpt登录后所在的目录* 这个目录使用channelSftp.goHome()可以获取*/public static void uploadFile(File uploadFile, String remoteSavePath) {if(uploadFile null ){log.info(本地文件对象不存在);return;}if(!uploadFile.exists()){log.info(本地文件[{}]不存在, uploadFile.getAbsoluteFile());return;}InputStream is null;try {is new FileInputStream(uploadFile);} catch (FileNotFoundException e) {log.info(获取本地文件[{}]的文件流失败, uploadFile.getAbsoluteFile());log.error(获取文件流失败: , e);if(is ! null){try {is.close();} catch (IOException ioException) {}}return;}SftpWrapper sftpWrapper null;try {//sftp连接对象sftpWrapper jschSftpConneciton.connectWithRetry();//检查远程目录,不存在则创建createLinuxRemoteDirs(sftpWrapper.getSftp(), remoteSavePath);//进入用户home目录sftpWrapper.getSftp().cd(sftpWrapper.getSftp().getHome());//保证当前目录在上传文件保存的目录sftpWrapper.getSftp().cd(remoteSavePath);//上传文件sftpWrapper.getSftp().put(is, uploadFile.getName());} catch (SftpException e) {log.info(上传本地文件[{}]到远程目录[{}]失败, uploadFile.getAbsoluteFile(), remoteSavePath);log.error(上传本地文件失败: , e);} catch (Exception e) {log.info(上传本地文件[{}]到远程目录[{}]失败, uploadFile.getAbsoluteFile(), remoteSavePath);log.error(上传本地文件失败: , e);} finally {if (sftpWrapper ! null) {sftpWrapper.disconnect();}if(is ! null){try {is.close();} catch (IOException e) {}}}}/*** 检查目录结是否以目录分隔符结尾* 如果不是则加上目录分隔符结尾** param localPath 本地目录* return*/private static String checkPathEnd(String localPath) {if (localPath.endsWith(/) || localPath.endsWith(\\)) {return localPath;}return localPath File.separator;}/*** 检查本地目录是否存在不存在就创建。* 为了防止其他线程已创建目录加上了重试代码** param localPath 本地目录* return*/private static boolean checkLocalPath(String localPath) {int maxRetryCount 5;int retry 0;do {File localDir new File(localPath);if (localDir.exists()) {return true;}boolean result localDir.mkdirs();if (result) {return true;}try {Thread.sleep(1000L);//休息1秒} catch (InterruptedException e) {}} while (retry maxRetryCount);return false;}/*** 检查和创建[ linux系统 ]的远程多级目录,* 外部调用, 单纯的创建远程目录不作其他操作* param remoteDir 远程目录* throws SftpException*/public static void createLinuxRemoteDirs( String remoteDir) throws SftpException {SftpWrapper sftpWrapper null;try {sftpWrapper jschSftpConneciton.connectWithRetry();createLinuxRemoteDirs(sftpWrapper.getSftp(), remoteDir);} catch (SftpException e) {log.info(创建Linux远程目录[{}]失败, remoteDir);log.error(创建Linux远程目录失败: , e);} catch (Exception e) {log.info(创建Linux远程目录[{}]失败, remoteDir);log.error(创建Linux远程目录失败: , e);} finally {if (sftpWrapper ! null) {sftpWrapper.disconnect();}}}/*** 检查和创建[ linux系统 ]的远程多级目录,* linux系统目录分隔符是 “/”* 内部上传文件的方法调用** param sftpChannel* param remoteDir 远程目录* throws SftpException*/public static void createLinuxRemoteDirs(ChannelSftp sftpChannel, String remoteDir) throws SftpException {if(remoteDir null || .equals(remoteDir)){log.info(待创建的远程目录为空);return;}String[] dirs remoteDir.split(/);;if(dirs null || dirs.length 0){log.info(拆分目录[{}]失败没有获取到目录数组, remoteDir);return;}//进入用户home目录保证初始目录正确sftpChannel.cd(sftpChannel.getHome());if( dirs.length 1){//只有一层目录直接处理try {sftpChannel.cd(dirs[0]);} catch (SftpException e) {if (e.id ChannelSftp.SSH_FX_NO_SUCH_FILE) {log.info(开始创建远程目录[{}], dirs[0]);sftpChannel.mkdir(dirs[0]);} else {throw e;}}return;}StringBuilder sb new StringBuilder();//处理第一个元素if(remoteDir.startsWith(.)){//相对路径,把缺少的路径补上sb.append(sftpChannel.getHome()).append(/);}else if(remoteDir.startsWith(/)){//绝对路径把/放到目录开头sb.append(/);}else {//既不是”/“开头也不是”.“开头//属于相对路径的一种情况try {//先处理第一层目录sftpChannel.cd(dirs[0]);} catch (SftpException e) {if (e.id ChannelSftp.SSH_FX_NO_SUCH_FILE) {log.info(开始创建远程目录[{}], dirs[0]);sftpChannel.mkdir(dirs[0]);} else {throw e;}}//把已处理的目录加上sb.append(sftpChannel.getHome()).append(/).append(dirs[0]).append(/);}//从第二个元素开始创建不存在的目录for (int i 1; i dirs.length; i) {String dir dirs[i];if (dir.isEmpty() ) {//跳过空字符串continue;}sb.append(dir /);try {sftpChannel.cd(sb.toString());} catch (SftpException e) {if (e.id ChannelSftp.SSH_FX_NO_SUCH_FILE) {log.info(开始创建远程目录[{}], sb.toString());sftpChannel.mkdir(sb.toString());} else {throw e;}}}
// for (String dir : dirs) {
// if (dir.isEmpty() || dir.contains(.)) {
// //跳过空字符串和.字符串
// continue;
// }
// sb.append(dir /);
// try {
// sftpChannel.cd(sb.toString());
// } catch (SftpException e) {
// if (e.id ChannelSftp.SSH_FX_NO_SUCH_FILE) {
// sftpChannel.mkdir(sb.toString());
// } else {
// throw e;
// }
// }
// }}
}
单元测试
JschSftpConfigTest 测试类
package cn.com.soulfox.config;import cn.com.soulfox.JschSftpRun;
import cn.com.soulfox.jsch.JschSftpConneciton;
import cn.com.soulfox.jsch.JschSftpUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;/*** author xxxx* create 2024/7/5 12:57*/
RunWith(SpringRunner.class)
SpringBootTest(classes JschSftpRun.class,webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)
public class JschSftpConfigTest {Autowiredprivate JschSftpConneciton sftpConneciton;/*** 下载文件*/Testpublic void testDownload(){//从远程服务器上的下载 /home/jiyh/ 目录下的 testabc.txt//下载文件保存到 d:\jiyhString remotePath /home/jiyh/;String downloadFileName testabc.txt;String localSavePath d:\\jiyh;JschSftpUtil.downloadFile(remotePath, downloadFileName, localSavePath);}/*** 上传文件*/Testpublic void testUpload(){//上传传本地 d:\jiyh 目录下的 test123.txt文件//到远程 /home/jiyh/test/test 目录//目录不存在会自动创建JschSftpUtil.uploadFile(d:\\jiyh, test123.txt, /home/jiyh/test/test);}
} 在远程服务器准备测试文件 文件内容随便这里我准备的内容为“112dadfdefee” 测试下载功能 测试结果 测试上传功能 在本地 d:/jiyh 目录准备测试文件“test123.txt”内容为“dfdfdfdfdaerwrt” 测试结果