[转]性能工具之Jmeter通过springboot工程启动
背景
Jmeter平时性能测试工作一般都是通过命令行在linux下执行,为了锻炼自己代码与逻辑能力,想jmeter是否可以通过springboot工程启动,周末在家尝试写一写,一写原来需要处理很多事情,才可以启动起来,起来还是有很问题需要处理,下面是相应的代码,其实网上也有,但关键的是自己有意识收集知识,到用的时候能拿来改一改就用。
启动页面:
前置条件
需要在linux中配置Jmeter成功,并且配置环境变量: 环境配置: 编辑: vi ~/.bash_profile #jmeter:路径 根据自己事情情况修改 JMETER_HOME=/root/tools/apache-jmeter-5.1.1 PATH=$PATH:$HOME/bin:$JMETER_HOME/bin: export PATH 执行生效: source ~/.bash_profile
点击上传脚本,弹出对话框,点击上传,后台日志显示上传成功:
点击启动:并且读取启动日志
点击停止:
上面脚本停止
图画说明:
通过访问--》调用java代码--》启动shell命令--》启动jmeter-获取启动日志
前端代码
以下参考代码,大家可以学习学习
<a class="btn btn-success" onclick="JmeterRun()" type="submit">运行</a> <a class="btn btn-danger" onclick="Jmeterstop()" type="submit">停止</a> <a class="btn btn-info" onclick="JmeterInfo()" data-toggle="modal" data-target="#myModal">查看信息</a> <script> //上传脚本 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 () { }); } } }) } </script>
后端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中还是一个问题没有解决就是在页面实时参看日志,目前还没实现,不过总体上实现自己想的功能。