1.目的
在做物联网项目中,为了方便产品测试人员以及第三方产品集成商能通过系统快速获取设备原始数据,因此考虑在物联网终端管理平台增加读取物联网通讯服务记录的终端日志的功能。
我的想法是直接通过Java操作Linux服务器的Shell命令,读取日志文件里面的上下行数据。
2.集成Shell命令
2.1.引入Jar包
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>2.8.0</version>
</dependency>
2.2.封装Shell方法操作类
2.2.1.核心方法
/**
* SSH linux操作类
* @author lenny
* @date 20230130
*/
public class SSHLinuxUtils {
protected SSHLinuxUtils() {
}
/**
* 执行Shell命令并返回结果
* @param conn
* @param cmd
* @param timeout
* @return
* @throws IOException
*/
public static SshResponse runCommand(SshConnection conn, String cmd, long timeout)
throws IOException {
SshClient client = SshClient.setUpDefaultClient();
try {
//Open the client
client.start();
//Connect to the server
ConnectFuture cf = client.connect(conn.getUsername(), conn.getHostname(), 22);
ClientSession session = cf.verify().getSession();
session.addPasswordIdentity(conn.getPassword());
session.auth().verify(TimeUnit.SECONDS.toMillis(timeout));
//Create the exec and channel its output/error streams
ChannelExec ce = session.createExecChannel(cmd);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
ce.setOut(out);
ce.setErr(err);
//Execute and wait
ce.open();
Set<ClientChannelEvent> events =
ce.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), TimeUnit.SECONDS.toMillis(timeout));
session.close(false);
//Check if timed out
if (events.contains(ClientChannelEvent.TIMEOUT)) {
throw new RuntimeException(conn.getHostname()+" 命令 "+cmd+ "执行超时 "+timeout);
}
return new SshResponse(out.toString(), err.toString(), ce.getExitStatus());
} finally {
client.stop();
}
}
}
2.2.2.返回数据实体对象
/**
* SSH应答结果集
* @author lenny
* @date 20230101
*/
@Data
public class SshResponse {
private String stdOutput;
private String errOutput;
private int returnCode;
public SshResponse(String stdOutput, String errOutput, int returnCode) {
this.stdOutput = stdOutput;
this.errOutput = errOutput;
this.returnCode = returnCode;
}
}
2.2.3.查询终端日志方法
这里使用Cat命令检索文件,并将检索到的文件内容进行处理
/**
* 查询终端日志
* @param terminalNum 终端ID号
* @param date 日期
* @return
*/
public SshResponse queryTerminalLog(String terminalNum, String date){
try {
Integer protocolType=808;
TerminalInfo terminalInfo=terminalDao.queryTerminalInfoByTerminalNum(terminalNum);
if(terminalInfo!=null&&terminalInfo.getProtocolType()>0){
protocolType=terminalInfo.getProtocolType();
}
SshConnection conn = new SshConnection(userName,password,host);
String filter=String.format("grep -E '%s|%s' | grep '%s'", "received:", "downlink command:", terminalNum);
String command=String.format("cat %s | %s",getTerminalLogPath(protocolType,date),filter);
SshResponse sshResponse = SSHLinuxUtils.runCommand(conn,command,60);
handleTerminalLogResponse(sshResponse);
return sshResponse;
} catch (Exception e) {
log.error("queryTerminalLog:terminalId:{},date:{}",terminalNum,date,e);
return null;
}
}
/**
* 处理返回的终端日志
* @param sshResponse
*/
private void handleTerminalLogResponse(SshResponse sshResponse){
if(sshResponse.getReturnCode()==0&& StringUtils.isNotBlank(sshResponse.getStdOutput())){
String terminalLog=sshResponse.getStdOutput();
String [] terminalLogs = terminalLog.split("\\n");
List<String> stringList=new ArrayList<>();
for (String item : terminalLogs) {
String regex;
if (item.contains("downlink command:")) {
regex ="(?<= INFO).*?(?=downlink command:)";
} else {
regex ="(?<= INFO).*?(?=received:)";
}
String result =item.replaceAll(regex,"").replace("INFO","")
.replace("downlink command","<<==")
.replace("received","==>>");
stringList.add(result.toUpperCase());
}
sshResponse.setStdOutput(JSON.toJSONString(stringList));
}
}
2.2.4.封装Controller
@PostMapping(value = "queryTerminalLog" )
public Result<Object> queryTerminalLog(@RequestBody SshParams sshParams){
if(sshParams==null||StringUtils.isBlank(sshParams.getTerminalNum())||StringUtils.isBlank(sshParams.getDate())){
return ResultGenerator.failure(ResultEnum.PARAM_ERROR);
}
SshResponse response=sshService.queryTerminalLog(sshParams.getTerminalNum(),sshParams.getDate());
if(response==null){
return ResultGenerator.failure();
}else {
if (response.getReturnCode() > 0) {
return ResultGenerator.failure(response.getErrOutput());
} else {
return ResultGenerator.success(response.getStdOutput());
}
}
}
里面的方法包含了我系统使用中的一些实体类,这里并未给出,需要针对自己的项目情况做些调整。
3.结束语
对物联网软件感兴趣的朋友,可以加我QQ:571521973。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)