一.背景介绍:
在项目集成测试环境中,存在多台服务器的情况,通过网关查询也需要层层定位,并且外部联调的情况下,上下游发送的流水信息有时候在特定情况下无法确定具体日期和具体服务器,所以基于此处需求,迫切需要在一个工具类,可以动态的根据流水信息查询出具体流水信息出现的文件名和服务器地址
二.场景分析:
1.流水信息存在多台服务器的情况
2.流水信息存在多个文件的情况
3.流水信息存在多个类型文件情况
三.思路和步骤分析
其实JSch具体的链接和请求的相关代码和博客已经有很多巨人完成了很详尽的描述,我们站在巨人的肩膀上,轻而易举的就可以完成战略三步走的方针,实现我们预想的战略结果
1.第一步先实现简单的链接linux服务器功能和执行shell命令,实现代码如下:
private String jschLinux(String host, String userName, String password, int port) {
//1.创建JSch对象
JSch jsch = new JSch();
String command = "grep '2222' /home/test.txt";
byte[] bytes = new byte[1024];
StringBuffer stringBuffer = new StringBuffer();
Session session= null;
ChannelExec channelExec = null;
try {
//2.从JSch中获取对应session信息
session = jsch.getSession(userName, host, port);
//3.设置session链接密码
session.setPassword(password);
//4.增加配置 取消首次确认
session.setConfig("StrictHostKeyChecking", "no");
//5.session对象链接
session.connect();
//6.链接后获取渠道对象——指定获取exec通道
channelExec = (ChannelExec) session.openChannel("exec");
//7.通道中设置可执行shell语句
channelExec.setCommand(command);
channelExec.setErrStream(System.err);
//8.获取读取流进行读取
InputStream inputStream = channelExec.getInputStream();
channelExec.connect();
while(true) {
int len = inputStream.read(bytes, 0, 1024);
if (len < 0 ) {
break;
}
stringBuffer.append(new String(bytes, 0, 1024));
}
} catch (JSchException | RuntimeException | IOException e) {
e.printStackTrace();
} finally {
channelExec.disconnect();
session.disconnect();
}
return stringBuffer.toString();
}
2.第二步循环重复第一步,完成第一步,循环第一步就是完美的第二步
public void getMsg() {
//1.服务器集合列表
List<LinuxInfo> linuxInfos = Arrays.asList(new LinuxInfo("47.110.248.x", "root", "Ys@x", 22),
new LinuxInfo("47.110.248.x", "root", "Ys@x", 22));
//2.遍历服务器列表
for (LinuxInfo linuxInfo : linuxInfos) {
jschLinux(linuxInfo.getHost(), linuxInfo.getUserName(), linuxInfo.getPassword(), linuxInfo.getPort());
}
}
3. 第三步,也是最重要的一步,长征万里最后半里,临门最后一脚,需要根据第三步返回的数据
public ArrayList<String> getMsg() {
//1.服务器集合列表
ArrayList<String> msgs = new ArrayList<>();
List<LinuxInfo> linuxInfos = Arrays.asList(new LinuxInfo("47.110.248.x", "root", "Ys@x", 22),
new LinuxInfo("47.110.248.x", "root", "Ys@x", 22));
//2.遍历服务器列表
for (LinuxInfo linuxInfo : linuxInfos) {
String msg = jschLinux(linuxInfo.getHost(), linuxInfo.getUserName(), linuxInfo.getPassword(), linuxInfo.getPort());
msgs.add(linuxInfo.getHost() + msg);
}
//3.返回对应数据信息
return msgs;
}
四.填坑时刻
实际上我们想要根据shell命令查询出来服务器中的文件中是否存在我们的数据,实际我们查询出来的并不是我们想要的ip + 文件名称这样的返回结果,那么问题是出在了那里呢?我们给linux服务器说快给我这个数据存在的信息,但是具体是哪个文件我们并没有要求linux返回,那怎么办呢,修改我们shell命令就可以达到这样的效果,上代码:
zgrep 222 /home/test.txt /home/2022.*.zar | sort -rn | awk -F ':' '{print $1}' | uniq -c
1.聊一聊:
为撒这样写,多类型文件,文件可能存在压缩包的情况,并且在实际情况中一般隔日的文件都会压缩,所以使用zgrep 既可以查询普通文件,也可以查询压缩包文件,后面跟着查询关键字,随后第一个是特定文件全路径,第二个是文件泛指路径,我是想查询2022所有的压缩文件,如果你想查询2022年一月所有的文件可以这样写2022-01.*.zar;
sort - rn 这个是为了排序,因为多文件查询情况下linux会把文件名打印在输出最前方
awk -F ':' '{print $1}' 列处理命令 根据定义的:来对列进行分割 分割完成后 输出第一列的内容
uniq -c 去重,前面做的相关操作其实都是为了去重来铺垫的,去重以后就可以展现出来我们想要的效果内容
2.效果看一看:
2 /home/2.zar.gz
1 /home/test.txt
前面是次数后面是全路径,最后我们还会在代码中增加对应的ip
3.更换代码
private String jschLinux(String host, String userName, String password, int port) {
//1.创建JSch对象
JSch jsch = new JSch();
String command = "zgrep 222 /home/test.txt /home/2022.*.zar | sort -rn | awk -F ':' '{print $1}' | uniq -c ";
byte[] bytes = new byte[1024];
StringBuffer stringBuffer = new StringBuffer();
Session session= null;
ChannelExec channelExec = null;
try {
//2.从JSch中获取对应session信息
session = jsch.getSession(userName, host, port);
//3.设置session链接密码
session.setPassword(password);
//4.增加配置 取消首次确认
session.setConfig("StrictHostKeyChecking", "no");
//5.session对象链接
session.connect();
//6.链接后获取渠道对象——指定获取exec通道
channelExec = (ChannelExec) session.openChannel("exec");
//7.通道中设置可执行shell语句
channelExec.setCommand(command);
channelExec.setErrStream(System.err);
//8.获取读取流进行读取
InputStream inputStream = channelExec.getInputStream();
channelExec.connect();
while(true) {
int len = inputStream.read(bytes, 0, 1024);
if (len < 0 ) {
break;
}
stringBuffer.append(new String(bytes, 0, 1024));
}
} catch (JSchException | RuntimeException | IOException e) {
e.printStackTrace();
} finally {
channelExec.disconnect();
session.disconnect();
}
return stringBuffer.toString();
}
五.开源工具项目如下,大家可以按需使用,如有中毒情况可以评论,在下会不定时为各位解读
springboot-jsch: SpringBoot集成JSch,动态链接Linux服务器上传文件、执行Shell相关命令