背景
Jmeter平时性能测试工作一般都是通过命令行在linux下执行,为了锻炼自己代码与逻辑能力,想jmeter是否可以通过springboot工程启动,周末在家尝试写一写,一写原来需要处理很多事情,才可以启动起来,起来还是有很问题需要处理,下面是相应的代码,其实网上也有,但关键的是自己有意识收集知识,到用的时候能拿来改一改就用。
启动页面:
前置条件
需要在linux中配置Jmeter成功,并且配置环境变量:
环境配置:
编辑:
vi ~/.bash_profile#jmeter:路径 根据自己事情情况修改
JMETER_HOME=/root/tools/apache-jmeter-5.1.1PATH=$PATH:$HOME/bin:$JMETER_HOME/bin:
export PATH
执行生效:
source ~/.bash_profile
点击上传脚本,弹出对话框,点击上传,后台日志显示上传成功:
点击启动:并且读取启动日志
点击停止:
上面脚本停止
图画说明:
通过访问--》调用java代码--》启动shell命令--》启动jmeter-获取启动日志
前端代码
以下参考代码,大家可以学习学习
class="btn btn-success" onclick="JmeterRun()" type="submit">运行
class="btn btn-danger" onclick="Jmeterstop()" type="submit">停止
class="btn btn-info" onclick="JmeterInfo()" data-toggle="modal" data-target="#myModal">查看信息
//上传脚本
function submitupload() {
var type = "file"; //后台接收时需要的参数名称,自定义即可
var id = "jmeterId"; //即input的id,用来寻找值
var formData = new FormData();
var jmeterId = $("#jmeterId").val();
if (jmeterId == "") {
layer.msg("Jmeter文件不能为空,请输入", {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("用户信息保存成功", {time: 1000, icon: 6}, function () {
// console.log("相应结果:" + data.extend.file);
//通过返回结果进行赋值
$("#jmeterName").val(data.extend.file);
// window.location.href = "/jmeterIndex";
});
} else {
layer.msg("信息保存失败,请重新操作" + data.err, {time: 2000, icon: 5, shift: 6}, function () {
});
}
}
});
}
//上传参数
function submitParm() {
var type = "file"; //后台接收时需要的参数名称,自定义即可
var id = "jmeterParam"; //即input的id,用来寻找值
var formData = new FormData();
var jmeterPara = $("#jmeterParam").val();
if (jmeterPara == "") {
layer.msg("Jmeter文件不能为空,请输入", {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("参数文件保存成功", {time: 1000, icon: 6}, function () {
});
} else {
layer.msg("信息保存失败,请重新操作" + data.err, {time: 2000, icon: 5, shift: 6}, function () {
});
}
}
});
}
//运行
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("启动成功成功", {time: 1000, icon: 6}, function () {
});
} else {
layer.msg("启动失败,请重新操作", {time: 2000, icon: 5, shift: 6}, function () {
});
}
}
})
}
//停止
function Jmeterstop() {
$.ajax({
type: "Get",
url: '/jmeter/JmeterStop',
processData: false,
contentType: false,
success: function (result) {
if (result.code==100) {
layer.msg("停止成功", {time: 1000, icon: 6}, function () {
});
} else {
layer.msg("停止失败,请重新操作", {time: 2000, icon: 5, shift: 6}, function () {
});
}
}
})
}
//查看日志
function JmeterInfo() {
$.ajax({
type: "Get",
url: '/jmeter/Jmeterinfo',
processData: false,
contentType: false,
success: function (result) {
if (result.code == 100) {
layer.msg("启动成功成功", {time: 1000, icon: 6}, function () {
$("#JmeterMsg").val(data.extend.infopage);
});
} else {
layer.msg("启动失败,请重新操作", {time: 2000, icon: 5, shift: 6}, function () {
});
}
}
})
}
后端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 liwen
* @Title: JmeterController
* @Description: Jmeter启动页面
* @date 2019/11/17 / 10:32
*/
@Controller
@RequestMapping("/jmeter")
public class JmeterController {
private static final Logger logger = LoggerFactory.getLogger(JmeterController.class);
@Autowired
JmerterScriptService jmerterScriptService;
@GetMapping("/jmeterIndex")
public String jmeterIndex() {
return "jmeter/jmterIndex";
}
/**
* 上传脚本
*
* @param file
* @return
*/
@PostMapping("/upload")
@ResponseBody
public Msg upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Msg.fail().add("err", "上传失败");
}
String fileName = file.getOriginalFilename();
logger.info("路径" + fileName);
String filePath = "/home/7d/";
// String filePath = "E:\\test\\7d\\data\\";
if (!fileName.endsWith(".jmx")) {
return Msg.fail().add("err", "脚本上传失败");
}
File dest = new File(filePath + fileName);
String jmxName = fileName.substring(0, fileName.lastIndexOf("."));
try {
file.transferTo(dest);
logger.info("上传成功:" + jmxName);
return Msg.success().add("file", jmxName);
} catch (IOException e) {
logger.error(e.toString(), e);
}
return Msg.fail();
}
/**
* 上传参数文件
*
* @param file
* @return
*/
@PostMapping("/Paramupload")
@ResponseBody
public Msg uploadParam(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Msg.fail().add("err", "上传失败");
}
String fileName = file.getOriginalFilename();
logger.info("路径" + 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("上传成功:" + jmxName);
return Msg.success().add("file", jmxName);
} catch (IOException e) {
logger.error(e.toString(), e);
}
return Msg.fail();
}
/**
* 运行脚本
*
* @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 {
return Msg.fail();
}
}
/**
* 停止脚本
*
* @return
*/
@GetMapping("/JmeterStop")
@ResponseBody
public Msg stop() {
jmerterScriptService.stopCommand();
return Msg.success();
}
/**
* 查看日志
*
* @return
*/
@GetMapping("/Jmeterinfo")
@ResponseBody
public Msg info() {
String info = jmerterScriptService.selectInfo();
return Msg.success().add("infopage", info);
}
}
interface层代码
/**
* @author liwen
* @Title: JmerterScriptService
* @Description: Jmeterj脚本处理
* @date 2019/11/17 / 18:06
*/
public interface JmerterScriptService {
/**
* 执行命令
* @param cmd
*/
void execCommand(String cmd);
/**
* 运行
* @param script 脚本
* @param num 数量
* @param seconds 执行时间
*/
void runCommand(String script, String num,String seconds);
/**
* 停止
*/
void stopCommand();
/**
* 获取日志
* @return
*/
String selectInfo();
}
接口实现层
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 liwen
* @Title: JmerterScriptServiceImpl
* @Description: 执行命令
* @date 2019/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) {
String bak = "cp /home/7d/" + script + ".jmx /home/7d/" + script + "bak.jmx";
String old = "/home/7d/" + script + ".jmx";
execCmd.execCmd(bak);
logger.info("路径:{}", old);
//替换执行数量
execCmd.replacTextContent(old, "#numThread", num);
//替换执行时间
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("运行命令{}", runcmd);
execCmd.execCmd(runcmd);
}
@Override
public void stopCommand() {
String stoprunm = "/root/tools/apache-jmeter-5.1.1/bin/shutdown.sh";
execCmd.execCmd(stoprunm);
}
@Override
public String selectInfo() {
String tail = "tail -f /home/7d/jmeterlog.log";
File file = new File("/home/7d/jmeterlog.log");
String s = LogSvrReadInput.realtimeShowLog(file);
logger.info("输出日志:--》{}",s);
return s;
}
}
工具类
/**
* 直接执行命令
*
* @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();
}
}
jmeter脚本:
脚本其实也没有什么东西,只有定义好规则,这样方便替换。
GitHub 地址:
https://github.com/357712148/bodygit.git
小结:
做性能测试代码能力,不是关键,但是是晋升一个必要条件,而且在项目性能分析还是需要懂一些代码能力,这样与研发,DBA、运维能谈的来。
善用时间,珍惜时间意味着生命的延长,人生的卓越。
上面存在的问题:
上面deme中还是一个问题没有解决就是在页面实时参看日志,目前还没实现,不过总体上实现自己想的功能。
送大家一句诗:
蜀道难
【作者】李白 【朝代】唐
噫吁嚱,危乎高哉!蜀道之难,难于上青天!蚕丛及鱼凫,开国何茫然!尔来四万八千岁,不与秦塞通人烟。西当太白有鸟道,可以横绝峨眉巅。地崩山摧壮士死,然后天梯石栈相钩连。上有六龙回日之高标,下有冲波逆折之回川。黄鹤之飞尚不得过,猿猱欲度愁攀援。青泥何盘盘,百步九折萦岩峦。扪参历井仰胁息,以手抚膺坐长叹。
好消息
7D第五期线下性能实战专家班(北京)-11月30日