pre-release 2.3.2

This commit is contained in:
jiangzeyin 2019-04-15 16:02:27 +08:00
parent c3c269e5aa
commit c998510ab9
18 changed files with 280 additions and 289 deletions

View File

@ -9,8 +9,8 @@
<a target="_blank" href="https://travis-ci.org/jiangzeyin/Jpom">
<img src='https://travis-ci.org/jiangzeyin/Jpom.svg?branch=master' alt='travis'></img>
</a>
<a href="https://www.codacy.com/app/jiangzeyin/Jpom?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=jiangzeyin/Jpom&amp;utm_campaign=Badge_Grade">
<img src="https://api.codacy.com/project/badge/Grade/9c97dc9925c84404b63e15fefbacc984"/>
<a target="_blank" href="https://www.codacy.com/app/jiangzeyin/Jpom?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=jiangzeyin/Jpom&amp;utm_campaign=Badge_Grade">
<img src="https://api.codacy.com/project/badge/Grade/9c97dc9925c84404b63e15fefbacc984"></img>
</a>
<a target="_blank" href="https://shang.qq.com/wpa/qunwpa?idkey=7be1882a2e2f07cd4af28bbb1f13362af270ba4615f2a6c7aaf9605fc0563d1b">
<img src='https://img.shields.io/badge/QQ%E7%BE%A4-136715345-yellowgreen.svg' alt='136715345'></img>
@ -31,7 +31,7 @@
> 当多个项目运行在同一台服务器时运维人员通常也不只一个如果每个人都登录服务器管理项目难免会造成一些不必要的麻烦甚至给服务器的安全性带来问题服务器密码知道的人越多越容易泄露因为不需要登录服务器管理项目维护人员不需要知道服务器的登录密码只需要有Jpom的账号就行Jpom本身可以通过权限管理给不同用户不同的权限这样也使得项目的稳定性得到提升。
> Jpom可以在linux和windows服务器上运行
> Jpom可以在Linux和Windows服务器上运行
### Jpom 目标

View File

@ -16,7 +16,7 @@ import cn.keepbx.jpom.common.commander.impl.LinuxCommander;
import cn.keepbx.jpom.common.commander.impl.WindowsCommander;
import cn.keepbx.jpom.model.NetstatModel;
import cn.keepbx.jpom.model.ProjectInfoModel;
import cn.keepbx.jpom.service.manage.CommandService;
import cn.keepbx.jpom.service.manage.ConsoleService;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
@ -255,9 +255,9 @@ public abstract class AbstractCommander {
public String status(String tag) throws Exception {
VirtualMachine virtualMachine = getVirtualMachine(tag);
if (virtualMachine == null) {
return CommandService.STOP_TAG;
return ConsoleService.STOP_TAG;
}
return StrUtil.format("{}:{}", CommandService.RUNING_TAG, virtualMachine.id());
return StrUtil.format("{}:{}", ConsoleService.RUNING_TAG, virtualMachine.id());
}
/**
@ -314,7 +314,7 @@ public abstract class AbstractCommander {
* @return int
*/
protected static int parsePid(String result) {
if (result.startsWith(CommandService.RUNING_TAG)) {
if (result.startsWith(ConsoleService.RUNING_TAG)) {
return Convert.toInt(result.split(":")[1]);
}
return 0;
@ -329,7 +329,7 @@ public abstract class AbstractCommander {
*/
public boolean isRun(String tag) throws Exception {
String result = status(tag);
return result.contains(CommandService.RUNING_TAG);
return result.contains(ConsoleService.RUNING_TAG);
}
/***

View File

@ -4,7 +4,6 @@ import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.commander.AbstractCommander;
import cn.keepbx.jpom.model.UserModel;
import cn.keepbx.jpom.system.TopManager;
import com.alibaba.fastjson.JSONArray;
import org.springframework.http.MediaType;
@ -24,8 +23,6 @@ public class WelcomeController extends BaseController {
@RequestMapping(value = "welcome", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String welcome() {
UserModel userName = getUser();
setAttribute("userInfo", userName.getUserMd5Key());
return "welcome";
}

View File

@ -8,7 +8,7 @@ import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.interceptor.ProjectPermission;
import cn.keepbx.jpom.model.ProjectInfoModel;
import cn.keepbx.jpom.service.manage.CommandService;
import cn.keepbx.jpom.service.manage.ConsoleService;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.service.oss.OssManagerService;
import com.alibaba.fastjson.JSONArray;
@ -36,7 +36,7 @@ public class BuildController extends BaseController {
@Resource
private ProjectInfoService projectInfoService;
@Resource
private CommandService commandService;
private ConsoleService consoleService;
@RequestMapping(value = "build", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String build(String id) {
@ -86,7 +86,7 @@ public class BuildController extends BaseController {
// 修改使用状态
projectInfoModel.setUseLibDesc("build");
projectInfoService.updateItem(projectInfoModel);
String result = commandService.execCommand(CommandService.CommandOp.restart, projectInfoModel);
String result = consoleService.execCommand(ConsoleService.CommandOp.restart, projectInfoModel);
return JsonMessage.getString(200, "安装成功,已自动重启,当前状态是:" + result);
}
}

View File

@ -37,7 +37,6 @@ public class ConsoleController extends BaseController {
if (projectInfoModel != null) {
UserModel userName = getUser();
setAttribute("projectInfo", projectInfoModel);
setAttribute("userInfo", userName.getUserMd5Key());
String logSize = projectInfoService.getLogSize(id);
setAttribute("logSize", logSize);
setAttribute("manager", userName.isProject(id));
@ -52,5 +51,4 @@ public class ConsoleController extends BaseController {
}
}

View File

@ -86,6 +86,11 @@ public class JpomManifest {
return version;
}
/**
* 判断当前是否为调试模式
*
* @return jar 为非调试模式
*/
public boolean isDebug() {
return "dev".equals(getVersion());
}

View File

@ -7,12 +7,13 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 控制台
* Created by jiangzeyin on 2018/9/28.
*
* @author jiangzeyin
*/
@Service
public class CommandService {
public class ConsoleService {
public static final String RUNING_TAG = "running";
public static final String STOP_TAG = "stopped";

View File

@ -58,19 +58,16 @@ public class CertService extends BaseOperService<CertModel> {
*/
public boolean delete(String id) {
try {
JSONObject jsonObject = getJSONObject(ConfigBean.CERT);
if (jsonObject == null) {
return false;
}
JSONObject cert = jsonObject.getJSONObject(id);
if (cert == null) {
CertModel certModel = getItem(id);
if (certModel == null) {
return true;
}
String keyPath = cert.getString("key");
String keyPath = certModel.getCert();
deleteJson(ConfigBean.CERT, id);
if (StrUtil.isNotEmpty(keyPath)) {
// 删除证书文件
File parentFile = FileUtil.file(keyPath).getParentFile();
return FileUtil.del(parentFile);
FileUtil.del(parentFile);
}
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);

View File

@ -7,7 +7,7 @@ import cn.jiangzeyin.common.JsonMessage;
import cn.jiangzeyin.common.spring.SpringUtil;
import cn.keepbx.jpom.model.ProjectInfoModel;
import cn.keepbx.jpom.model.UserModel;
import cn.keepbx.jpom.service.manage.CommandService;
import cn.keepbx.jpom.service.manage.ConsoleService;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.service.user.UserService;
import cn.keepbx.jpom.system.TopManager;
@ -32,7 +32,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class LogWebSocketHandle {
public static final String SYSTEM_ID = "system";
private CommandService commandService;
private ConsoleService consoleService;
private static volatile AtomicInteger onlineCount = new AtomicInteger();
private static final ConcurrentHashMap<String, UserModel> USER = new ConcurrentHashMap<>();
@ -45,8 +45,8 @@ public class LogWebSocketHandle {
*/
@OnOpen
public void onOpen(@PathParam("userInfo") String userInfo, @PathParam("projectId") String projectId, Session session) {
if (commandService == null) {
commandService = SpringUtil.getBean(CommandService.class);
if (consoleService == null) {
consoleService = SpringUtil.getBean(ConsoleService.class);
}
// 通过用户名和密码的Md5值判断是否是登录的
try {
@ -100,8 +100,8 @@ public class LogWebSocketHandle {
String projectId = json.getString("projectId");
ProjectInfoService projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
ProjectInfoModel projectInfoModel = projectInfoService.getItem(projectId);
CommandService.CommandOp commandOp = CommandService.CommandOp.valueOf(op);
if (projectInfoModel == null && commandOp != CommandService.CommandOp.top) {
ConsoleService.CommandOp commandOp = ConsoleService.CommandOp.valueOf(op);
if (projectInfoModel == null && commandOp != ConsoleService.CommandOp.top) {
SocketSessionUtil.send(session, "没有对应项目");
return;
}
@ -114,8 +114,8 @@ public class LogWebSocketHandle {
case start:
case restart:
logUser = true;
strResult = commandService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(CommandService.RUNING_TAG)) {
strResult = consoleService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(ConsoleService.RUNING_TAG)) {
resultData = JsonMessage.toJson(200, "操作成功:" + strResult);
} else {
resultData = JsonMessage.toJson(400, strResult);
@ -124,8 +124,8 @@ public class LogWebSocketHandle {
case stop:
logUser = true;
// 停止项目
strResult = commandService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(CommandService.STOP_TAG)) {
strResult = consoleService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(ConsoleService.STOP_TAG)) {
resultData = JsonMessage.toJson(200, "操作成功");
} else {
resultData = JsonMessage.toJson(500, strResult);
@ -133,8 +133,8 @@ public class LogWebSocketHandle {
break;
case status:
// 获取项目状态
strResult = commandService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(CommandService.RUNING_TAG)) {
strResult = consoleService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(ConsoleService.RUNING_TAG)) {
resultData = JsonMessage.toJson(200, "运行中", strResult);
} else {
resultData = JsonMessage.toJson(404, "未运行", strResult);

View File

@ -6,10 +6,8 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.Scheduler;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.spring.SpringUtil;
import cn.jiangzeyin.pool.ThreadPoolService;
import cn.keepbx.jpom.common.commander.AbstractCommander;
import cn.keepbx.jpom.service.manage.CommandService;
import cn.keepbx.jpom.socket.SocketSessionUtil;
import cn.keepbx.jpom.util.JvmUtil;
import com.alibaba.fastjson.JSONArray;
@ -39,9 +37,11 @@ public class TopManager {
private static final Set<Session> SESSIONS = new HashSet<>();
private static final String CRON_ID = "topMonitor";
private static CommandService commandService;
private static boolean watch = false;
private static ExecutorService executorService = ThreadPoolService.newCachedThreadPool(TopManager.class);
/**
* 是否开启首页监听自动刷新
*/
private static final AtomicBoolean WATCH = new AtomicBoolean(false);
/**
* 锁定查看进程信息
*/
@ -71,12 +71,9 @@ public class TopManager {
* 创建定时执行top
*/
private static void addCron() {
if (watch) {
if (WATCH.get()) {
return;
}
if (commandService == null) {
commandService = SpringUtil.getBean(CommandService.class);
}
CronUtil.remove(CRON_ID);
CronUtil.schedule(CRON_ID, "0/5 * * * * ?", () -> {
//发送监控信息
@ -99,7 +96,7 @@ public class TopManager {
if (!scheduler.isStarted()) {
CronUtil.start();
}
watch = true;
WATCH.set(true);
}
@ -500,6 +497,6 @@ public class TopManager {
}
//
CronUtil.remove(CRON_ID);
watch = false;
WATCH.set(false);
}
}

View File

@ -100,7 +100,36 @@
$.ajax(defData);
}
## 静默ajax
function silentAjax(data) {
loadingAjax(data, true);
}
## 默认表格渲染
function tableRender(data) {
var done = data.done;
delete data.done;
//
const defData = {
even: true,
loading: true,
method: 'POST',
response: {
statusCode: 200
},
done: function (data) {
if (data.code == 800) {
## 用户信息失效
layer.msg(data.msg);
setTimeout(function () {
top.location.reload();
}, 1500);
return;
}
done && done(data);
}
};
$.extend(defData, data);
table.render(defData);
}
</script>

View File

@ -90,7 +90,7 @@
function loadSuccess() {
const showLogDom = $('.console .terminal');
if ('WebSocket' in window) {
const ws = new WebSocket(getSocketHost() + "/console/$userInfo/$!projectInfo.id");
const ws = new WebSocket(getSocketHost() + "/console/$user.getUserMd5Key()/$!projectInfo.id");
ws.onopen = function () {
showLogDom.append('WebSocket连接成功<br/>');
setMsg('status');

View File

@ -41,13 +41,10 @@
function loadSuccess() {
layui.use(['upload'], function () {
var upload = layui.upload;
table.render({
tableRender({
id: 'table_file',
elem: '#tab_file',
url: './getFileList',
method: 'post',
// height: 'full',
even: true,
where: {
id: '$id'
},
@ -65,10 +62,6 @@
{field: 'filesize', title: '文件大小', sort: true, width: '15%'},
{field: 'op', title: '操作', toolbar: '#bar_projects'}
]],
loading: true,
response: {
statusCode: 200
},
done: function () {
}

View File

@ -91,13 +91,11 @@
if (project && project.group) {
apiWhere.group = project.group;
}
table.render({
tableRender({
id: 'table_project',
elem: '#tab_project',
url: './getProjectInfo',
// height: 'full-52',
toolbar: '#toolbarDemo',
even: true,
where: apiWhere,
cols: [[{
field: 'name', title: '项目名称', width: '15%', sort: true, templet: function (d) {
@ -124,11 +122,6 @@
},
{field: 'op', title: '操作', toolbar: '#bar_projects'}
]],
loading: true,
method: 'POST',
response: {
statusCode: 200
},
done: function (data) {
var projects = data.data;
var ids = [];

View File

@ -170,24 +170,30 @@
layer.msg("上传失败");
}
});
table.render({
tableRender({
id: 'tab_certificate',
elem: '#tab_certificate',
url: './getCertList',
// height: 'full-52',
even: true,
cols: [[
{field: 'id', title: 'id', width: '10%'},
{field: 'name', title: '名称'},
{field: 'domain', title: '域名'},
{field: 'effectiveTime', templet: "#tem_effectiveTime", title: '生效时间', width: '14%'},
{field: 'expirationTime', templet: "#tem_expirationTime", title: '到期时间', width: '14%'},
{field: 'id', title: 'id', width: '10%', sort: true},
{field: 'name', title: '名称', sort: true},
{field: 'domain', title: '域名', sort: true},
{
field: 'effectiveTime',
templet: "#tem_effectiveTime",
title: '生效时间',
width: '14%',
sort: true
},
{
field: 'expirationTime',
templet: "#tem_expirationTime",
title: '到期时间',
width: '14%',
sort: true
},
{field: 'op', title: '操作', align: 'center', toolbar: '#bar_cert', fixed: 'right'}
]],
loading: true,
response: {
statusCode: 200
}
]]
});
// 表格工具条事件

View File

@ -79,27 +79,21 @@
});
}
table.render({
tableRender({
id: 'tab_ngx',
elem: '#tab_ngx',
url: './list_data.json',
method: 'POST',
even: true,
cols: [[
{field: 'name', title: '文件名'},
{field: 'serverCount', title: '数量', width: "5%"},
{field: 'server_name', title: '域名'},
{field: 'location', title: '根location'},
{field: 'listen', title: '监听端口', width: "10%"},
{field: 'time', title: '最后修改时间'},
{field: 'name', title: '文件名', sort: true},
{field: 'serverCount', title: '数量', width: "5%", sort: true},
{field: 'server_name', title: '域名', sort: true},
{field: 'location', title: '根location', sort: true},
{field: 'listen', title: '监听端口', width: "10%", sort: true},
{field: 'time', title: '最后修改时间', sort: true},
{
field: 'op', title: '操作', align: 'center', toolbar: '#bar_ngx', fixed: 'right'
}
]],
loading: true,
response: {
statusCode: 200
}
]]
});
// 删除

View File

@ -122,24 +122,17 @@
<script type="text/javascript">
function loadSuccess() {
table.render({
tableRender({
id: 'tab_user',
elem: '#tab_user',
url: './getUserList',
// height: 'full-52',
method: 'POST',
even: true,
cols: [[
{field: 'id', title: 'id'},
{field: 'name', title: '昵称'},
{field: 'manage', templet: "#manager_status", title: '是否是管理员'},
{field: 'parent', title: '创建人'},
{field: 'op', title: '操作', align: 'center', toolbar: '#bar_projects', fixed: 'right'}
]],
loading: true,
response: {
statusCode: 200
}
]]
});
// 编辑用户信息

View File

@ -72,34 +72,10 @@
<table class="layui-table" id="tab_monitor" lay-filter="tab_monitor"></table>
</body>
<script type="application/javascript">
function loadSuccess() {
var ws, myEcharts;
loadData();
function loadData() {
var top = layui.data('top');
var openTop = false;
if (top) {
openTop = top.openTop;
}
//加载进程信息
loadProcessList();
if (openTop) {
$("#monitor").attr("checked", true);
linkSocket(openTop);
} else {
$("#monitor").attr("checked", false);
loadFirstEcharts();
}
form.render();
}
var config = {
id: 'tab_monitor',
elem: '#tab_monitor',
// height: 'full-52',
even: true,
cols: [[
{field: 'pid', title: '进程id', sort: true, width: '6%'},
{field: 'COMMAND', title: '进程名称'},
@ -115,93 +91,37 @@
{field: 'VIRT', title: '虚拟内存', width: '8%', sort: true},
{field: 'SHR', title: '共享内存', width: '8%', sort: true},
]],
loading: true,
method: 'POST',
response: {
statusCode: 200
},
done: function (data) {
}
};
table.render(config);
function loadFirstEcharts() {
silentAjax({
url: './getTop',
success: function (data) {
if (200 == data.code) {
if (data.data) {
var top = JSON.parse(data.data);
loadEcharts(top);
function loadSuccess() {
var top = layui.data('top');
var openTop = false;
if (top) {
openTop = top.openTop;
}
} else {
layer.alert(data.msg);
//加载进程信息
loadProcessList();
//
loadTop();
$("#monitor").attr("checked", openTop);
if (openTop) {
linkSocket(openTop);
}
}
});
}
function loadProcessList() {
silentAjax({
url: './processList',
success: function (data) {
if (200 == data.code) {
if (data.data) {
config.data = data.data;
table.render(config);
}
} else {
layer.alert(data.msg);
}
}
});
}
function linkSocket(status) {
if (!ws) {
ws = new WebSocket(getSocketHost() + "/console/$userInfo/system");
}
if (status) {
if (ws.readyState != 1 && ws.readyState != 0) {
ws = new WebSocket(getSocketHost() + "/console/$userInfo/system");
}
ws.onopen = function () {
ws.send('{"op": "top", "projectInfo":{}}');
};
ws.onmessage = function (data) {
try {
if (data.data) {
var top = JSON.parse(data.data);
if (top.top) {
loadEcharts(top);
}
if (top.processList) {
var processList = top.processList;
config.data = processList;
table.render(config);
}
}
} catch (e) {
return;
}
};
ws.onerror = function (ev) {
};
} else {
ws.close();
}
}
form.render();
//
tableRender(config);
// 切换
form.on('switch(filter)', function (data) {
var check = data.elem.checked;
layui.data('top', {
key: 'openTop',
value: check
});
if ('WebSocket' in window) {
linkSocket(check);
});
}
})
//加载病状图
function loadEcharts(top) {
@ -274,6 +194,74 @@
myEcharts.setOption(option);
}
function loadTop() {
silentAjax({
url: './getTop',
success: function (data) {
if (200 == data.code) {
if (data.data) {
var top = JSON.parse(data.data);
loadEcharts(top);
}
} else {
layer.alert(data.msg);
}
}
});
}
function loadProcessList() {
silentAjax({
url: './processList',
success: function (data) {
if (200 == data.code && data.data) {
config.data = data.data;
tableRender(config);
} else if (data.msg && data.msg != "") {
layer.alert(data.msg);
}
}
});
}
function linkSocket(status) {
if (!('WebSocket' in window)) {
layer.msg("不支持WebSocket");
return;
}
if (!ws) {
ws = new WebSocket(getSocketHost() + "/console/$user.getUserMd5Key()/system");
}
if (status) {
if (ws.readyState != 1 && ws.readyState != 0) {
ws = new WebSocket(getSocketHost() + "/console/$user.getUserMd5Key()/system");
}
ws.onopen = function () {
ws.send('{"op": "top", "projectInfo":{}}');
};
ws.onmessage = function (data) {
try {
if (data.data) {
var top = JSON.parse(data.data);
if (top.top) {
loadEcharts(top);
}
if (top.processList) {
var processList = top.processList;
config.data = processList;
tableRender(config);
}
}
} catch (e) {
return;
}
};
ws.onerror = function (ev) {
layer.msg("socket 异常");
};
} else {
ws.close();
}
}
</script>