“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">© 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…