通用后台管理系统
该系统主要结合
Element
组件编辑前端,后端实现业务逻辑,组成一个简单的前后端分离项目。
该部分介绍调用远程服务器python代码功能的实现
场景:有一台远程linux服务器,存放了yolo检测的代码,将该功能包装进项目中
前端
页面
<template>
<div>
<el-col :span="12" style="padding-right: 50px;padding-left: 50px">
<el-card class="select-card">
<p style="color: #1fb1ec"> 指针式仪表识别</p>
<p style="color: #1fb1ec; margin-top:5px; margin-bottom: 30px"><br> 下方上传视频文件</p>
<!--上传视频部分-->
<el-upload
class="avatar-uploader"
:action=uploadPath
:file-list="fileList"
:before-upload="beforeUploadVideo"
:on-progress="uploadVideoProcess"
:on-success="uploadSuccess"
:show-file-list="false"
style="padding-top: 10px">
<video
v-if="videoForm.showVideoPath !== '' && !videoFlag"
v-bind:src="videoForm.showVideoPath"
class="avatar video-avatar"
controls="controls">
您的浏览器不支持视频播放
</video>
<i v-else-if="videoForm.showVideoPath === '' && !videoFlag"
class="el-icon-plus avatar-uploader-icon"
></i>
</el-upload>
<el-progress v-if="isShowUploadVideo" :percentage="videoUploadPercent"
style="margin-top: 7px; width: 520px; margin-left: 10vh"></el-progress>
<!--分析部分-->
<div class="vid">
</div>
</el-card>
</el-col>
<el-col :span="8" style="padding-right: 10px">
<el-card class="select-card">
<!--结果部分-->
<div style="top: 15vh; position: absolute">
<span style="color: #1fb1ec; margin-top: 50px">识别结果为:</span>
<span class="video-res">{
{ waterRes }}</span>
</div>
</el-card>
</el-col>
</div>
</template>
卡片效果:点击方框内选择视频上传(UI比较粗糙)
上传时会显示进度条,上传完成后的视频可以播放。
上传前的判断:
beforeUploadVideo(file) {
const fileSize = file.size / 1024 / 1024 < 50; //控制大小 修改50的值即可
if (
[
"video/mp4",
"video/ogg",
"video/flv",
"video/avi",
"video/wmv",
"video/rmvb",
"video/mov",
].indexOf(file.type) === -1 //控制格式
) {
layer.msg("请上传正确的视频格式");
return false;
}
if (!fileSize) {
layer.msg("视频大小不能超过50MB");
return false;
}
this.isShowUploadVideo = false;
},
上传完成时:上传结束调用yolo检测接口clockRec
uploadSuccess(response, file) {
console.log(file)
if (response.message === 'success') {
// 进度条
this.videoUploadPercent = 100;
setTimeout(() => {
this.isShowUploadVideo = false;
}, 2000) // 两秒钟之后将进度条去掉
this.videoForm.showVideoPath = "http://xxx.xxx.xx.x/xx/xx/" + file.name; //上传成功后端返回视频地址 回显
this.videoMessage.filename = file.name;
console.log(file.name)
clockRec({
params: {
...this.videoMessage}}).then(({
data}) => {
console.log(data)
this.waterRes = data.data
})
}
},
进度条部分:
uploadVideoProcess(event) {
this.isShowUploadVideo = true;
this.videoUploadPercent = parseInt(event.percent);
if (this.videoUploadPercent >= 100) {
this.videoUploadPercent = 99;
}
},
CSS
<style lang="less" scoped>
.el-col {
.select-card {
padding: 10px;
height: 80vh;
.avatar-uploader-icon {
border: 1px dashed #409eff !important;
}
.avatar-uploader .el-upload {
border: 1px dashed #409eff !important;
border-radius: 6px !important;
position: relative !important;
overflow: hidden !important;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
margin-left: 10vh;
margin-top: 5vh;
font-size: 28px;
color: #409eff;
width: 300px+200px;
height: 178px+200px;
line-height: 178px;
text-align: center;
}
.avatar {
margin-left: 10vh;
margin-top: 5vh;
width: 300px+200px;
height: 178px+200px;
display: block;
}
}
}
</style>
后端
前端使用的后端接口:import {clockRec} from "@/api"
接口:cmd字符串即为在linux服务器上运行的shell语句,其中
pythonEnvPath
对应服务器上conda 虚拟环境python.exe的路径,pythonCodePath
为服务器上的代码路径,–source为yolo运行配置的参数,所有路径使用绝对路径格式。
@GetMapping("/clockRec")
public ResultHelper recognizePic(@RequestParam(value = "filename", required = false) String filename) throws IOException {
String cmd = pythonEnvPath + " " + pythonCodePath + " --source " + videoPath + filename;
log.info("cmd: " + cmd);
Shell shell = new Shell(host, user, password);
String execLog = shell.execCommand(cmd);
log.info("execLog: " + execLog);
return ResultHelper.success(execLog);
}
Shell.java:
package com.example.generalback.util;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Shell {
private String host;
private String username;
private String password;
private int port = xx;
private int timeout = 60 * 60 * 1000;
public Shell(String host, String username, String password, int port, int timeout) {
this.host = host;
this.username = username;
this.password = password;
this.port = port;
this.timeout = timeout;
}
public Shell(String host, String username, String password) {
this.host = host;
this.username = username;
this.password = password;
}
public String execCommand(String cmd) {
JSch jSch = new JSch();
Session session = null;
ChannelExec channelExec = null;
BufferedReader inputStreamReader = null;
BufferedReader errInputStreamReader = null;
StringBuilder runLog = new StringBuilder("");
StringBuilder errLog = new StringBuilder("");
try {
// 1. 获取 ssh session
session = jSch.getSession(username, host, port);
session.setPassword(password);
session.setTimeout(timeout);
session.setConfig("StrictHostKeyChecking", "no");
session.connect(); // 获取到 ssh session
// 2. 通过 exec 方式执行 shell 命令
channelExec = (ChannelExec) session.openChannel("exec");
channelExec.setCommand(cmd);
channelExec.connect(); // 执行命令
// 3. 获取标准输入流
inputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getInputStream()));
// 4. 获取标准错误输入流
errInputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getErrStream()));
// 5. 记录命令执行 log
String line = null;
while ((line = inputStreamReader.readLine()) != null) {
runLog.append(line).append("\n");
}
// 6. 记录命令执行错误 log
String errLine = null;
while ((errLine = errInputStreamReader.readLine()) != null) {
errLog.append(errLine).append("\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (errInputStreamReader != null) {
errInputStreamReader.close();
}
if (channelExec != null) {
channelExec.disconnect();
}
if (session != null) {
session.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return runLog.toString();
}
}