“This is the 15th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

background

Jmeter performance test is usually executed under Linux through the command line. In order to exercise my code and logic ability, I want to know whether Jmeter can be started by springBoot project. I tried to write it at home on weekends. There are still problems to deal with, the following is the corresponding code, in fact, there are online, but the key is to consciously collect knowledge, to use the time can be used to change.

precondition

Jmeter needs to be configured in Linux and Java environment variables need to be configured:

# # editor
vi ~/.bash_profile

# jmeter: The path changes according to your situationJMETER_HOME = / root/tools/apache jmeter - 5.1.1 PATH =$PATH:$HOME/bin:$JMETER_HOME/bin:
export PATH

## Execution takes effect
source ~/.bash_profile
Copy the code

Page design

Running effect

Click upload script, and the dialog box pops up. Click Upload, and the background log shows that the upload is successful.

Click Start and read the startup log.

Click stop.

Schematic illustration:

Access -> Call JAVA code -> Start shell command -> Start Jmeter -> get the start log

Reference code

The front-end code

The following reference code:

<! DOCTYPEhtml>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Jekyll v3.8.6">
    <title>Jmeter start</title>

    <link rel="canonical" href="https://v4ing.bootcss.com/docs/4.3/examples/checkout/">

    <! -- Bootstrap core CSS -->
    <! -- Bootstrap core CSS -->
    <link href="asserts/css/bootstrap.min.css" th:href="@ {/ webjars/bootstrap / 4.3.1 / CSS/bootstrap CSS}" rel="stylesheet">
    <! -- Favicons -->
    <meta name="theme-color" content="#563d7c">


    <style>
        .bd-placeholder-img {
            font-size: 1.125 rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }

        @media (min-width: 768px) {
            .bd-placeholder-img-lg {
                font-size: 3.5 rem; }}</style>
    <! -- Custom styles for this template -->
    <link href="https://v4.bootcss.com/docs/4.3/examples/checkout/form-validation.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container">
    <div class="py-5 text-center">
        <img src="https://jmeter.apache.org/images/logo.svg" class="d-block mx-auto mb-4" alt="Apache JMeter">
        <p class="lead">The Apache JMeter™ application is open source software, a 100% pure Java application designed to
            load test functional behavior and measure performance. It was originally designed for testing Web
            Applications but has since expanded to other test functions.</p>
    </div>
    <div class="col-md-8 order-md-1">
        <h4 class="mb-3">Upload script</h4>
        <form>
            <input id="jmeterId" type="file"/>
            <a class="btn btn-lg btn-primary btn-block" value="Upload script" onclick="submitupload()">Upload script</a>
        </form>
        <form>
            <input id="jmeterParam" type="file"/>
            <a class="btn btn-lg btn-primary btn-block" value="Upload parameters" onclick="submitParm()">Uploading parameter files</a>
        </form>
        <h4 class="mb-3">run</h4>
        <! -- jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]-->
        <form class="needs-validation" novalidate>
            <div class="row">
                <div class="col-md-6 mb-3">
                    <label for="jmeterName">Pressure test script</label>
                    <input type="text" class="form-control" id="jmeterName" name="jmeterName" placeholder="jmx file"
                           value="" required>
                    <div class="invalid-feedback">
                        jmx file
                    </div>
                </div>
                <div class="col-md-6 mb-3">
                    <label for="numberName">concurrency</label>
                    <input type="text" class="form-control" id="numberName" name="num" placeholder="Concurrent number" value=""
                           required>
                    <div class="invalid-feedback">concurrency</div>
                </div>
                <div class="col-md-6 mb-3">
                    <label for="duration">The execution time</label>
                    <input type="text" class="form-control" id="duration" name="duration" placeholder="Execution time" value=""
                           required>
                    <div class="invalid-feedback">concurrency</div>
                </div>
            </div>
            <hr class="mb-4">
            <a class="btn btn-success" onclick="JmeterRun()" type="submit">run</a>
            <a class="btn btn-danger" onclick="Jmeterstop()" type="submit">stop</a>
            <a class="btn btn-info" onclick="JmeterInfo()" data-toggle="modal" data-target="#myModal">Check the information</a>
        </form>
    </div>
</div>

<! -- Log Mode box -->
<div class="modal fade" id="myModal" tabindex="1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title">Jmeter run logs</h4>
            </div>
            <div class="modal-body">
               <textarea rows="30" cols="20" id="JmeterMsg"></textarea>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<! -- <button type="button" class="btn btn-primary">Save changes</button>-->
            </div>
        </div>
    </div>
</div>


<footer class="my-5 pt-5 text-muted text-center text-small">
    <p class="mb-1">&copy; 2017-2019 Company Name</p>
    <ul class="list-inline">
        <li class="list-inline-item"><a href="#">Privacy</a></li>
        <li class="list-inline-item"><a href="#">Terms</a></li>
        <li class="list-inline-item"><a href="#">Support</a></li>
    </ul>
</footer>
</div>
<script type="text/javascript" th:src="@ {/ webjars/jquery / 3.3.1 / jquery. Js}"></script>
<script th:src="@{/asserts/js/layer/layer.js}"></script>
<script>window.jQuery || document.write('< script SRC = "/ docs / 4.3.1 / assets/js/vendor/jquery. Slim. Min. Js" > < \ / script >')</script>
<script src="/ docs / 4.3 / dist/js/bootstrap bundle. Js." "
        th:src="@ {/ webjars/bootstrap 4.3.1 / js/bootstrap bundle. Js}"></script>
<script src="https://v4.bootcss.com/docs/4.3/examples/checkout/form-validation.js"></script>
</body>
<script>
    // Upload the script
    function submitupload() {
        var type = "file";              // Specifies the name of the parameter required for background reception
        var id = "jmeterId";            // The input ID, used to find the value
        var formData = new FormData();
        var jmeterId = $("#jmeterId").val();
        if (jmeterId == "") {
            layer.msg("Jmeter file cannot be empty, please enter", {time: 2000.icon: 5.shift: 6}, function () {});return;
        }
        formData.append(type, $("#" + id)[0].files[0]);
        $.ajax({
            type: "POST".url: '/jmeter/upload'.data: formData,
            processData: false.contentType: false.success: function (data) {
                if (data.code == 100) {
                    layer.msg("User information saved successfully", {time: 1000.icon: 6}, function () {
                        // console.log(" corresponding result :" + data.exten.file);
                        // Assign by returning the result
                        $("#jmeterName").val(data.extend.file);
                        // window.location.href = "/jmeterIndex";
                    });
                } else {
                    layer.msg("Info saved failed. Please try again." + data.err, {time: 2000.icon: 5.shift: 6}, function () {}); }}}); }// Upload parameters
    function submitParm() {
        var type = "file";              // Specifies the name of the parameter required for background reception
        var id = "jmeterParam";            // The input ID, used to find the value
        var formData = new FormData();
        var jmeterPara = $("#jmeterParam").val();
        if (jmeterPara == "") {
            layer.msg("Jmeter file cannot be empty, please enter", {time: 2000.icon: 5.shift: 6}, function () {});return;
        }
        formData.append(type, $("#" + id)[0].files[0]);
        $.ajax({
            type: "POST".url: '/jmeter/Paramupload'.data: formData,
            processData: false.contentType: false.success: function (data) {
                if (data.code == 100) {
                    layer.msg("Parameter file saved successfully", {time: 1000.icon: 6}, function () {}); }else {
                    layer.msg("Info saved failed. Please try again." + data.err, {time: 2000.icon: 5.shift: 6}, function () {}); }}}); }/ / run
    function JmeterRun() {
        let JmeterName = $("#jmeterName").val();
        let number = $("#numberName").val();
        let duration = $("#duration").val();

        console.log(JmeterName);
        console.log(number);
        $.ajax({
            type: "POST".url: '/jmeter/JmeterRun'.data: {
                "jmeterName": JmeterName,
                "numberName": number,
                "duration": duration
            },
            success: function (result) {
                if (result.code == 100) {
                    layer.msg("Startup succeeded.", {time: 1000.icon: 6}, function () {}); }else {
                    layer.msg("Startup failed. Please try again.", {time: 2000.icon: 5.shift: 6}, function () {}); }}})}/ / stop
    function Jmeterstop() {
        $.ajax({
            type: "Get".url: '/jmeter/JmeterStop'.processData: false.contentType: false.success: function (result) {
                if (result.code==100) {
                    layer.msg("Stop succeeding", {time: 1000.icon: 6}, function () {}); }else {
                    layer.msg("Stop failed. Please try again.", {time: 2000.icon: 5.shift: 6}, function () {}); }}})}// View logs
    function JmeterInfo() {
        $.ajax({
            type: "Get".url: '/jmeter/Jmeterinfo'.processData: false.contentType: false.success: function (result) {
                if (result.code == 100) {
                    layer.msg("Startup succeeded.", {time: 1000.icon: 6}, function () {$("#JmeterMsg").val(data.extend.infopage);
                    });
                } else {
                    layer.msg("Startup failed. Please try again.", {time: 2000.icon: 5.shift: 6}, function () {}); }}})}</script>
</html>

Copy the code

Server interface

The reference code is as follows:

package com.sevendays.controller;


import com.sevendays.pojo.Msg;
import com.sevendays.service.JmerterScriptService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

/ * * *@author 7d
 * @Title: JmeterController
 * @Description: Jmeter startup page *@dateAt 10:32 2019/11/17 / * /

@Controller
@RequestMapping("/jmeter")
public class JmeterController {
    private static final Logger logger = LoggerFactory.getLogger(JmeterController.class);

    @Autowired
    JmerterScriptService jmerterScriptService;

    @GetMapping("/jmeterIndex")
    public String jmeterIndex(a) {
        return "jmeter/jmterIndex";
    }


    /** * Upload script **@param file
     * @return* /
    @PostMapping("/upload")
    @ResponseBody
    public Msg upload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return Msg.fail().add("err"."Upload failed");
        }
        String fileName = file.getOriginalFilename();
        logger.info("Path" + fileName);
        String filePath = "/home/7d/";
// String filePath = "E:\\test\\7d\\data\\";
        if(! fileName.endsWith(".jmx")) {
            return Msg.fail().add("err"."Script upload failed");
        }
        File dest = new File(filePath + fileName);

        String jmxName = fileName.substring(0, fileName.lastIndexOf("."));
        try {
            file.transferTo(dest);
            logger.info("Upload successful :" + jmxName);
            return Msg.success().add("file", jmxName);
        } catch (IOException e) {
            logger.error(e.toString(), e);
        }
        return Msg.fail();
    }

    /** * Upload parameter file **@param file
     * @return* /
    @PostMapping("/Paramupload")
    @ResponseBody
    public Msg uploadParam(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return Msg.fail().add("err"."Upload failed");
        }
        String fileName = file.getOriginalFilename();
        logger.info("Path" + fileName);
        String filePath = "/home/7d";
// String filePath = "E:\\test\\7d\\data\\";
        File dest = new File(filePath + fileName);
        String jmxName = fileName.substring(0, fileName.lastIndexOf("."));

        try {
            file.transferTo(dest);
            logger.info("Upload successful :" + jmxName);
            return Msg.success().add("file", jmxName);
        } catch (IOException e) {
            logger.error(e.toString(), e);
        }
        return Msg.fail();
    }


    /** * Run the script **@return* /
    @PostMapping("/JmeterRun")
    @ResponseBody
    public Msg run(@RequestParam("jmeterName") String jmeterName, @RequestParam("numberName") String numberName, @RequestParam("duration") String duration) {
        logger.info(jmeterName);
        if(! jmeterName.isEmpty() && ! numberName.isEmpty()) { jmerterScriptService.runCommand(jmeterName.trim(), numberName.trim(), duration);return Msg.success();
        } else {
            returnMsg.fail(); }}/** * Stop the script **@return* /
    @GetMapping("/JmeterStop")
    @ResponseBody
    public Msg stop(a) {
        jmerterScriptService.stopCommand();
        return Msg.success();
    }


    /** * check log **@return* /
    @GetMapping("/Jmeterinfo")
    @ResponseBody
    public Msg info(a) {
        String info = jmerterScriptService.selectInfo();
        return Msg.success().add("infopage", info); }}Copy the code

Interface layer code

package com.sevendays.service;

/ * * *@author 7d
 * @Title: JmerterScriptService
 * @Description: Jmeterj script processing *@date2019/11/17/18:06 * /

public interface JmerterScriptService {

    /** * Run the * command@param cmd
     */
    void execCommand(String cmd);

    /** * run *@paramScript script *@paramNum number *@paramSeconds Execution time */
    void runCommand(String script, String num,String seconds);

    /** * stop */
    void stopCommand(a);

    /** * Get log *@return* /
    String selectInfo(a);

}
Copy the code

Interface implementation layer

package com.sevendays.service.impl;

import com.sevendays.controller.JmeterController;
import com.sevendays.service.JmerterScriptService;
import com.sevendays.utils.LogSvrReadInput;
import com.sevendays.utils.execCmd;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;

/ * * *@author 7d
 * @Title: JmerterScriptServiceImpl
 * @Description: Run the * command@date2019/11/17/18:49 * /

@Service
public class JmerterScriptServiceImpl implements JmerterScriptService {

    private static final Logger logger = LoggerFactory.getLogger(JmerterScriptServiceImpl.class);


    @Override
    public void execCommand(String cmd) {
        try {
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(cmd, null.null);
            InputStream stderr = proc.getInputStream();
            InputStreamReader isr = new InputStreamReader(stderr, "GBK");
            BufferedReader br = new BufferedReader(isr);
            String line = "";
            while((line = br.readLine()) ! =null) { logger.info(line); }}catch(Exception e) { e.printStackTrace(); }}@Override
    public void runCommand(String script, String num, String seconds) {

        // Number of executions
        String numThread = "<stringProp name=\"ThreadGroup.num_threads\">#numThread</stringProp>";
        // Execution time
        String time = "<stringProp name=\"ThreadGroup.duration\">#timeDuration</stringProp>";
        String bak = "cp /home/7d/" + script + ".jmx /home/7d/" + script + "bak.jmx";
        String old = "/home/7d/" + script + ".jmx";
        execCmd.execCmd(bak);
        logger.info("Path: {}", old);
        // Replace the number of executions
        execCmd.replacTextContent(old, "#numThread", num);
        // Replace the execution time
        execCmd.replacTextContent(old, "#timeDuration", seconds);
        String runcmd = "nohup jmeter -n -t /home/7d/#scriptName.jmx -l /home/7d/#scriptName.jtl -j /home/7d/jmeter.log > /home/7d/jmeterlog.log&".replaceAll("#scriptName", script);
        logger.info("Run command {}", runcmd);
        execCmd.execCmd(runcmd);
    }

    @Override
    public void stopCommand(a) {
        String stoprunm = "/ root/tools/apache jmeter - 5.1.1 / bin/shutdown. Sh";
        execCmd.execCmd(stoprunm);
    }

    @Override
    public String selectInfo(a) {
        String tail = "tail -f /home/7d/jmeterlog.log";
        File file = new File("/home/7d/jmeterlog.log");
        String s = LogSvrReadInput.realtimeShowLog(file);
        logger.info("Output log: --" {}",s);
        returns; }}Copy the code

Utility class

package com.sevendays.utils;

import com.sevendays.service.impl.JmerterScriptServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

/ * * *@author 7d
 * @Title: execCmd
 * @Description: Directly executes the * command@date2019/11/17 / * / michal

public class execCmd {

    private static final Logger logger = LoggerFactory.getLogger(execCmd.class);

    public execCmd(a) {}/** * Directly executes the ** command@param cmd
     */
    public static void execCmd(String cmd) {
        try {
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(cmd, null.null);
            InputStream stderr = proc.getInputStream();
            InputStreamReader isr = new InputStreamReader(stderr, "GBK");
            BufferedReader br = new BufferedReader(isr);
            String line = "";
            while((line = br.readLine()) ! =null) { logger.info(line); }}catch(Exception e) { e.printStackTrace(); }}/** * replaces the invalid string ** in the text file@paramThe path path *@paramSrcStr original contents *@paramNewStr What to replace */
    public static void replacTextContent(String path, String srcStr, String newStr) {
        File file = new File(path);
        if(! file.exists() && ! file.isFile()) { logger.info("File {}, does not exist :", path);
            return;
        }
        try {
            FileReader in = new FileReader(file);
            BufferedReader bufIn = new BufferedReader(in);
            // Memory stream, as temporary stream
            CharArrayWriter tempStream = new CharArrayWriter();
            / / replace
            String line = null;
            while((line = bufIn.readLine()) ! =null) {
                // Replace the string in each line
                line = line.replaceAll(srcStr, newStr);
                // Write the line to memory
                tempStream.write(line);
                // Add a newline character
                tempStream.append(System.getProperty("line.separator"));
            }
            // Close the input stream
            bufIn.close();
            // Write the stream in memory to a file
            FileWriter out = new FileWriter(file);
            tempStream.writeTo(out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.info("====path:"+ path); }}Copy the code

Jmeter script

Scripts are nothing but rules defined so they can be easily replaced.

summary

In the Demo above, there is still a problem that has not been solved, which is to see the log in real time on the page. It has not been implemented yet, but in general, it can achieve its own function.

Source code address:

  • Github.com/zuozewei/bl…