SpringBoot 集成Shell命令实现系统日志查询并通过API返回给前端

36 篇文章 1 订阅
19 篇文章 0 订阅

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。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 Spring Boot 中执行 shell 命令,可以使用 Java 的 `Runtime` 类或者使用 Apache Commons Exec 库。 1. 使用 `Runtime` 类: ```java import java.io.BufferedReader; import java.io.InputStreamReader; public class ShellCommandExecutor { public static void main(String[] args) { try { String command = "ls -l"; // 要执行的 shell 命令 Process process = Runtime.getRuntime().exec(command); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("Exited with error code : " + exitCode); } catch (Exception e) { e.printStackTrace(); } } } ``` 2. 使用 Apache Commons Exec 库,需要将其添加到 Maven 依赖中: ```xml <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-exec</artifactId> <version>1.3</version> </dependency> ``` 然后可以使用以下代码执行 shell 命令: ```java import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.ExecuteResultHandler; import org.apache.commons.exec.ExecuteStreamHandler; import org.apache.commons.exec.Executor; import org.apache.commons.exec.PumpStreamHandler; import java.io.ByteArrayOutputStream; import java.io.IOException; public class ShellCommandExecutor { public static void main(String[] args) { try { String command = "ls -l"; // 要执行的 shell 命令 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream errorStream = new ByteArrayOutputStream(); CommandLine commandLine = CommandLine.parse(command); ExecuteStreamHandler streamHandler = new PumpStreamHandler(outputStream, errorStream); Executor executor = new DefaultExecutor(); executor.setStreamHandler(streamHandler); // 可以使用 ExecuteResultHandler 进行异步执行 //executor.execute(commandLine, new MyExecuteResultHandler()); int exitCode = executor.execute(commandLine); String output = outputStream.toString(); String error = errorStream.toString(); System.out.println("Output:\n" + output); System.out.println("Error:\n" + error); System.out.println("Exited with error code : " + exitCode); } catch (ExecuteException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } // 异步执行的示例 ExecuteResultHandler class MyExecuteResultHandler implements ExecuteResultHandler { @Override public void onProcessComplete(int exitValue) { System.out.println("Command executed successfully."); } @Override public void onProcessFailed(ExecuteException e) { System.err.println("Command execution failed."); e.printStackTrace(); } } ``` 这样你就可以在 Spring Boot 中执行 shell 命令了。请注意,执行 shell 命令具有一定的安全风险,请谨慎使用,并确保你信任要执行的命令

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大鱼>

一分也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值