摘要: 在一些框架开发工作中,需要为项目使用说明文档,来指导用户如何正确使用框架。比如通过markdown编写文档,同时将文档及图片等静态资源发布到nginx服务器。往往采用编译时候结合cicd脚本一起构建,推送服务器,但无法满足日常研发实时发布需要,本文介绍通过Jsch复制本地文件目录,到资源服务器得方法。
关键词: jsch;目录上传
Jsch 是 Java Secure Channel 的缩写,是一个纯 Java 实现的 SSH2 协议客户端库。它允许在 Java 应用程序中建立与 SSH 服务器的安全连接,并进行文件传输、远程命令执行等操作.
 以下是一些Jsch的主要特点和技术应用:
使用Jsch进行SSH连接和执行远程命令的一般步骤如下:
下面是一个简单的示例代码,演示了如何使用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();         }     } }  使用jsch的sftp功能实现单文件上传难度不大,而本地目录上传问题本质上是多目录多的文件批量上传文件问题,需要额外考虑细节问题如下:
流程如下:
                              com.jcraft              jsch              0.1.55             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());         }     } }  
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());         }     } }  本文通过分析,使用jsch技术实现本地文件目录整体拷贝至服务器指定目录需求,分析关键步骤以及实现细节,并最终封装工具类。为后续实现,静态资源发布部署,文件目录定时同步功能,提供技术实现支撑。