前言
遇到一个需要通过java代码对远程Linux系统进行远程操作的场景,其中包括远程执行命令、上传文件、下载文件。
一、maven依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.53</version>
</dependency>
二、yml配置
desensitization:
server:
ip: xxx #IP地址
user: root #登录用户名
password: xxx #登录密码
port: 22 #远程连接端口
path: /root/test_data/ #对应处理的目录
三、配置类编写
import com.xxx.fileupload.exception.BizException;
import com.xxx.fileupload.exception.CommonUtilEnum;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description: ssh远程连接配置类
* @author ZXS
* @date 2022/11/8 9:57
* @version 1.0
*/
@Configuration
public class JSchSessionConfig {
//指定的服务器地址
@Value("${desensitization.server.ip}")
private String ip;
//用户名
@Value("${desensitization.server.user}")
private String user;
//密码
@Value("${desensitization.server.password}")
private String password;
//服务器端口 默认22
@Value("${desensitization.server.port}")
private String port;
/**
* @description: 注入一个bean,jsch.Session
* @param:
* @return: com.jcraft.jsch.Session
* @author ZXS
* @date: 2022/11/8 9:58
*/
@Bean
public Session registSession(){
Session session;
try {
JSch jSch = new JSch();
//设置session相关配置信息
session = jSch.getSession(user, ip, Integer.valueOf(port));
session.setPassword(password);
//设置第一次登陆的时候提示,可选值:(ask | yes | no)
session.setConfig("StrictHostKeyChecking", "no");
} catch (JSchException e) {
throw new BizException(CommonUtilEnum.FILE_DOWNLOAD_FAIL);
}
return session;
}
}
四、组件工具类的编写
import com.xxx.fileupload.exception.BizException;
import com.xxx.fileupload.exception.CommonUtilEnum;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.*;
/**
* @description: ssh远程连接工具类
* @author ZXS
* @date 2022/9/28 17:11
* @version 1.0
*/
@Component
@Slf4j
public class SshRemoteComponent {
private ThreadLocal<Session> connContainer = new ThreadLocal<>();
@Resource
private Session session;
//上传文件到脱敏服务器的指定目录 自行修改
@Value("${desensitization.server.path}")
private String path;
/**
* @description: 根据端口号创建ssh远程连接
* @param: port 端口号
* @return: com.jcraft.jsch.Session
* @author ZXS
* @date: 2022/9/28 15:57
*/
public Session createConnection(){
try {
session.connect(30000);
connContainer.set(session);
} catch (JSchException e) {
throw new BizException(CommonUtilEnum.CONN_FAIL);
}
return connContainer.get();
}
/**
* @description: 关闭ssh远程连接
* @param:
* @return: void
* @author ZXS
* @date: 2022/9/28 15:58
*/
public void closeConnection(){
Session session=connContainer.get();
try {
if(session != null){
session.disconnect();
}
} catch (Exception e) {
throw new BizException(CommonUtilEnum.CONN_CLOSE_FAIL);
}finally {
connContainer.remove();
}
}
/**
* @description: ssh通过sftp上传文件
* @param: session,bytes文件字节流,fileName文件名,resultEncoding 返回结果的字符集编码
* @return: java.lang.String 执行返回结果
* @author ZXS
* @date: 2022/9/30 10:02
*/
public Boolean sshSftpUpload(Session session, byte[] bytes,String fileName) throws Exception{
//上传文件到指定服务器的指定目录 自行修改
//String path = "/root/test_data/";
Channel channel = null;
OutputStream outstream = null;
Boolean flag = true;
try {
//创建sftp通信通道
channel = session.openChannel("sftp");
channel.connect(1000);
ChannelSftp sftp = (ChannelSftp) channel;
//进入服务器指定的文件夹
sftp.cd(path);
//列出服务器指定的文件列表
/*Vector v = sftp.ls("*");
for(int i=0;i<v.size();i++){
System.out.println(v.get(i));
}*/
outstream = sftp.put(fileName);
outstream.write(bytes);
} catch (Exception e) {
e.printStackTrace();
flag = false;
} finally {
if(outstream != null){
outstream.flush();
outstream.close();
}
if(session != null){
closeConnection();
}
if(channel != null){
channel.disconnect();
}
}
return flag;
}
/**
* @description: ssh通过sftp下载文件
* @param: session,fileName文件名,filePath 文件下载保存路径
* @return: java.lang.String 执行返回结果
* @author ZXS
* @date: 2022/9/30 10:03
*/
public Boolean sshSftpDownload(Session session, String fileName, String filePath) throws Exception{
Channel channel = null;
InputStream inputStream = null;
FileOutputStream fileOutputStream;
Boolean flag = true;
try {
//创建sftp通信通道
channel = session.openChannel("sftp");
channel.connect(1000);
ChannelSftp sftp = (ChannelSftp) channel;
//进入服务器指定的文件夹
sftp.cd(path);
inputStream = sftp.get(fileName);
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
fileOutputStream = new FileOutputStream(filePath+"/"+fileName);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
byte[] buf = new byte[4096];
int length = bufferedInputStream.read(buf);
while (-1 != length){
bufferedOutputStream.write(buf,0,length);
length = bufferedInputStream.read(buf);
}
bufferedInputStream.close();
bufferedOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
flag = false;
} finally {
if(inputStream != null){
inputStream.close();
}
if(session != null){
closeConnection();
}
if(channel != null){
channel.disconnect();
}
}
return flag;
}
/**
* @description: 远程执行单条Linux命令
* @param: session,command命令字符串
* @return: java.lang.String
* @author ZXS
* @date: 2022/9/28 16:34
*/
public Boolean execCommand(Session session, String command){
//默认方式,执行单句命令
ChannelExec channelExec;
Boolean flag = true;
try {
channelExec = (ChannelExec) session.openChannel("exec");
channelExec.setCommand(command);
channelExec.setErrStream(System.err);
channelExec.connect();
/** 判断执行结果 **/
InputStream in = channelExec.getInputStream();
byte[] tmp = new byte[1024];
while(true){
while(in.available() > 0){
int i = in.read(tmp,0,1024);
if(i < 0) break;
log.info("脚本执行过程:"+new String(tmp,0,i));
}
//获取执行结果
if(channelExec.isClosed()){
if(in.available() > 0) continue;
if(channelExec.getExitStatus() != 0){
//脚本非正常结束,退出吗非零
flag = false;
log.info("脚本执行出错");
}
break;
}
try{
Thread.sleep(1000);
}catch (Exception e){
log.info(e.getMessage());
}
}
channelExec.disconnect();
} catch (Exception e) {
e.printStackTrace();
flag = false;
}
return flag;
}
}
五、使用测试
@SpringBootTest
@Slf4j
public class TestCase {
@Resource
private SshRemoteComponent component;
@Test
public void test(){
Session session = component.createConnection();
component.execCommand(session, "pwd");
component.closeConnection();
}
}