文章目录
- 1.Jsch简介
- 1.1 什么是Jsch
- 1.2 Jsch使用步骤和简单示例
- 2.技术关键点
- 3.Jsch实战
- 3.1 maven依赖
- 3.2 功能实现
- 3.3 效果
- 3.4 封装工具类
- 4.总结
摘要: 在一些框架开发工作中,需要为项目使用说明文档,来指导用户如何正确使用框架。比如通过markdown编写文档,同时将文档及图片等静态资源发布到nginx服务器。往往采用编译时候结合cicd脚本一起构建,推送服务器,但无法满足日常研发实时发布需要,本文介绍通过Jsch复制本地文件目录,到资源服务器得方法。
关键词: jsch;目录上传
1.Jsch简介
1.1 什么是Jsch
Jsch 是 Java Secure Channel 的缩写,是一个纯 Java 实现的 SSH2 协议客户端库。它允许在 Java 应用程序中建立与 SSH 服务器的安全连接,并进行文件传输、远程命令执行等操作.
以下是一些Jsch的主要特点和技术应用:
- SSH 连接:JSch 支持通过多种身份验证方法(如密码认证、公钥认证等)建立到 SSH 服务器的安全连接。
- 文件传输:JSch 实现了 SCP(Secure Copy)和 SFTP(SSH File Transfer Protocol)协议,允许在本地计算机和远程服务器之间进行文件的上传、下载和管理。
- 远程命令执行:JSch 允许在远程服务器上执行命令,可以通过打开远程 Shell 会话来执行命令并获取输出或处理错误。
- 端口转发:JSch 支持端口转发功能,可以将本地端口与远程端口关联,用于安全通信和访问受限资源。
1.2 Jsch使用步骤和简单示例
使用Jsch进行SSH连接和执行远程命令的一般步骤如下:
- 导入Jsch库: 首先需要将Jsch库添加到Java项目的依赖中。
- 创建Session对象: 使用Jsch库创建一个Session对象,该对象表示与远程服务器的会话。需要指定远程服务器的主机名、用户名和密码或者SSH密钥等认证信息。
- 连接到远程服务器: 调用Session对象的connect方法来连接到远程服务器。
- 创建Channel对象: 使用Session对象创建一个Channel对象,该对象表示与远程服务器的通信通道,可以是执行远程命令的Shell通道或者用于文件传输的SFTP通道等。
- 打开Channel: 调用Channel对象的open方法来打开通道。
- 执行操作: 根据需要执行相应的操作,例如执行远程命令、上传或下载文件等。
- 关闭通道和会话: 操作完成后,需要关闭Channel和Session对象,释放资源
下面是一个简单的示例代码,演示了如何使用Jsch连接到远程服务器并执行一个简单的命令:
import com.jcraft.jsch.*;
public class SSHExample {
public static void main(String[] args) {
String host = "remote_host";
String user = "username";
String password = "password";
String command = "ls -l";
try {
// 创建JSch对象
JSch jsch = new JSch();
// 创建Session对象
Session session = jsch.getSession(user, host, 22);
// 设置密码
session.setPassword(password);
// 取消默认的HostKey检查
session.setConfig("StrictHostKeyChecking", "no");
// 连接到远程服务器
session.connect();
// 打开通道
Channel channel = session.openChannel("exec");
// 设置命令
((ChannelExec) channel).setCommand(command);
// 获取输入流
channel.setInputStream(null);
// 获取输出流
((ChannelExec) channel).setErrStream(System.err);
// 连接通道
channel.connect();
// 读取命令输出
InputStream in = channel.getInputStream();
byte[] buffer = new byte[1024];
while (true) {
while (in.available() > 0) {
int bytesRead = in.read(buffer, 0, 1024);
if (bytesRead < 0) break;
System.out.print(new String(buffer, 0, bytesRead));
}
if (channel.isClosed()) {
if (in.available() > 0) continue;
System.out.println("Exit Status: " + channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}
// 关闭通道和会话
channel.disconnect();
session.disconnect();
} catch (JSchException | IOException e) {
e.printStackTrace();
}
}
}
2.技术关键点
使用jsch的sftp功能实现单文件上传难度不大,而本地目录上传问题本质上是多目录多的文件批量上传文件问题,需要额外考虑细节问题如下:
- 服务器目标根目录,不一定存在存在,需要创建。
- 本地目录中还包含子目录,需要在父级目录中上传文件,同时判断子目录。
流程如下:
3.Jsch实战
3.1 maven依赖
<!--SSH-->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
3.2 功能实现
v1.0 基础可以用版本
import com.jcraft.jsch.*;
import java.io.File;
public class LocalToRemoteFileCopy {
public static void main(String[] args) {
String localPath = "D:\\git\\demo\\note_codeup\\docs";
String remotePath = "/root/test/docker-compose-nginx/data/docs";
String hostname = "192.168.100.4";
int port = 22;
String username = "root";
String password = "123456";
copyLocalToRemote(localPath, remotePath, hostname, port, username, password);
}
private static void copyLocalToRemote(String localPath, String remotePath, String hostname, int port,
String username, String password) {
JSch jsch = new JSch();
Session session = null;
ChannelSftp channelSftp = null;
try {
// 连接到目标主机
session = jsch.getSession(username, hostname, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
// 打开目标主机的 SFTP 通道
Channel channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp) channel;
// 递归创建远程目录(如果不存在)
createRemoteDirectories(channelSftp, remotePath);
// 从本地复制文件到目标主机
copyLocalDirectory(new File(localPath), channelSftp, remotePath);
// 关闭连接
channelSftp.disconnect();
session.disconnect();
} catch (JSchException | SftpException e) {
e.printStackTrace();
}
}
// 递归创建远程目录(如果不存在)
private static void createRemoteDirectories(ChannelSftp channelSftp, String remoteDirectory) throws SftpException {
String[] dirs = remoteDirectory.split("/");
String currentDir = "/";
for (String dir : dirs) {
if (!dir.isEmpty()) {
currentDir += dir + "/";
try {
channelSftp.stat(currentDir); // 检查目录是否存在
} catch (SftpException e) {
// 目录不存在,创建目录
channelSftp.mkdir(currentDir);
}
}
}
}
// 递归上传本地文件到远程目录
private static void copyLocalDirectory(File localFile, ChannelSftp channelSftp, String remotePath)
throws SftpException {
if (localFile.isDirectory()) {
// 获取本地目录下的所有文件和子目录
File[] files = localFile.listFiles();
if (files != null) {
for (File file : files) {
copyLocalDirectory(file, channelSftp, remotePath + "/" + localFile.getName());
}
}
} else if (localFile.isFile()) {
// 上传文件,并递归创建远程目录(如果不存在)
createRemoteDirectories(channelSftp, remotePath);
System.out.println(localFile.getAbsolutePath() + " ==> " + remotePath + "/" + localFile.getName());
channelSftp.put(localFile.getAbsolutePath(), remotePath + "/" + localFile.getName());
}
}
}
3.3 效果
3.4 封装工具类
import com.jcraft.jsch.*;
import java.io.File;
public class SftpUtils {
public static void copyLocalToRemote(String localPath, String remotePath, String hostname, int port,
String username, String password) {
JSch jsch = new JSch();
Session session = null;
ChannelSftp channelSftp = null;
try {
// 连接到目标主机
session = jsch.getSession(username, hostname, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
// 打开目标主机的 SFTP 通道
Channel channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp) channel;
// 递归创建远程目录(如果不存在)
createRemoteDirectories(channelSftp, remotePath);
// 从本地复制文件到目标主机
copyLocalDirectory(new File(localPath), channelSftp, remotePath);
// 关闭连接
channelSftp.disconnect();
session.disconnect();
} catch (JSchException | SftpException e) {
e.printStackTrace();
}
}
// 递归创建远程目录(如果不存在)
private static void createRemoteDirectories(ChannelSftp channelSftp, String remoteDirectory) throws SftpException {
String[] dirs = remoteDirectory.split("/");
String currentDir = "/";
for (String dir : dirs) {
if (!dir.isEmpty()) {
currentDir += dir + "/";
try {
channelSftp.stat(currentDir); // 检查目录是否存在
} catch (SftpException e) {
// 目录不存在,创建目录
channelSftp.mkdir(currentDir);
}
}
}
}
// 递归上传本地文件到远程目录
private static void copyLocalDirectory(File localFile, ChannelSftp channelSftp, String remotePath)
throws SftpException {
if (localFile.isDirectory()) {
// 获取本地目录下的所有文件和子目录
File[] files = localFile.listFiles();
if (files != null) {
for (File file : files) {
copyLocalDirectory(file, channelSftp, remotePath + "/" + localFile.getName());
}
}
} else if (localFile.isFile()) {
// 上传文件,并递归创建远程目录(如果不存在)
createRemoteDirectories(channelSftp, remotePath);
System.out.println(localFile.getAbsolutePath() + " ==> " + remotePath + "/" + localFile.getName());
channelSftp.put(localFile.getAbsolutePath(), remotePath + "/" + localFile.getName());
}
}
}
4.总结
本文通过分析,使用jsch技术实现本地文件目录整体拷贝至服务器指定目录需求,分析关键步骤以及实现细节,并最终封装工具类。为后续实现,静态资源发布部署,文件目录定时同步功能,提供技术实现支撑。