系统未初始化提示,新增清空项目缓存功能,页面分页bug,只有超级管理员才能修改超级管理员的信息,新增数据默认工作空间问题,同步项目缓存项目工作空间问题

This commit is contained in:
bwcx_jzy 2021-12-08 17:11:47 +08:00
parent 3dec2ce572
commit 83276eca54
29 changed files with 350 additions and 107 deletions

View File

@ -45,6 +45,8 @@
> 6: 用户绑定工作空间后,用户在对应工作空间下可以创建、修改、删除对应的数据(包括但不限于管理节点)
>
> 7: 此次升级启动耗时可能需要2分钟以上耗时根据数据量来决定请耐心等待和观察控制台日志输出
>
> 8: 一个节点不要被多个服务端绑定
------
# 2.7.3

View File

@ -1,3 +1,26 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2019 码之科技工作室
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
FROM centos:7
ENV LANG en_US.utf8

View File

@ -48,7 +48,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
@ -63,10 +62,15 @@ import java.util.List;
@RestController
@RequestMapping(value = "/manage/")
public class ManageEditProjectController extends BaseAgentController {
@Resource
private WhitelistDirectoryService whitelistDirectoryService;
@Resource
private JdkInfoService jdkInfoService;
private final WhitelistDirectoryService whitelistDirectoryService;
private final JdkInfoService jdkInfoService;
public ManageEditProjectController(WhitelistDirectoryService whitelistDirectoryService,
JdkInfoService jdkInfoService) {
this.whitelistDirectoryService = whitelistDirectoryService;
this.jdkInfoService = jdkInfoService;
}
/**
* 基础检查

View File

@ -1,3 +1,26 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2019 码之科技工作室
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
FROM centos:7
ENV LANG en_US.utf8

View File

@ -66,13 +66,14 @@ public class GlobalDefaultExceptionHandler {
*/
@ExceptionHandler({AuthorizeException.class, RuntimeException.class, Exception.class})
public void delExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
DefaultSystemLog.getLog().error("global handle exception: {}", request.getRequestURI(), e);
if (e instanceof AuthorizeException) {
AuthorizeException authorizeException = (AuthorizeException) e;
ServletUtil.write(response, authorizeException.getJsonMessage().toString(), MediaType.APPLICATION_JSON_VALUE);
} else if (e instanceof JpomRuntimeException) {
DefaultSystemLog.getLog().error("global handle exception: {}", request.getRequestURI(), e.getCause());
ServletUtil.write(response, JsonMessage.getString(500, e.getMessage()), MediaType.APPLICATION_JSON_VALUE);
} else {
DefaultSystemLog.getLog().error("global handle exception: {}", request.getRequestURI(), e);
boolean causedBy = ExceptionUtil.isCausedBy(e, AccessDeniedException.class);
if (causedBy) {
ServletUtil.write(response, JsonMessage.getString(500, "操作文件权限异常,请手动处理:" + e.getMessage()), MediaType.APPLICATION_JSON_VALUE);

View File

@ -34,6 +34,7 @@ import io.jpom.model.data.UserModel;
import io.jpom.service.user.UserService;
import io.jpom.system.ServerConfigBean;
import io.jpom.system.ServerExtConfigBean;
import io.jpom.system.db.DbConfig;
import io.jpom.util.JwtUtil;
import org.springframework.http.MediaType;
import org.springframework.web.method.HandlerMethod;
@ -60,6 +61,11 @@ public class LoginInterceptor extends BaseJpomInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
HttpSession session = getSession();
boolean init = DbConfig.getInstance().isInit();
if (!init) {
ServletUtil.write(response, JsonMessage.getString(100, "数据库还没有初始化成功,请耐心等待"), MediaType.APPLICATION_JSON_VALUE);
return false;
}
//
NotLogin notLogin = handlerMethod.getMethodAnnotation(NotLogin.class);
if (notLogin == null) {

View File

@ -78,6 +78,7 @@ public class InstallController extends BaseServerController {
@ValidatorConfig(value = {
@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "密码不能为空")
}) String userPwd) {
//
Assert.state(!userService.canUse(), "系统已经初始化过啦,请勿重复初始化");
if (JpomApplication.SYSTEM_ID.equalsIgnoreCase(userName) || UserModel.SYSTEM_ADMIN.equals(userName)) {

View File

@ -231,7 +231,7 @@ public class RepositoryController extends BaseServerController {
boolean exists = buildInfoService.exists(entity);
Assert.state(!exists, "当前仓库被构建关联,不能直接删除");
repositoryService.getByKey(id, getRequest());
repositoryService.delByKey(id, getRequest());
return JsonMessage.getString(200, "删除成功");
}
}

View File

@ -20,6 +20,7 @@ import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
@ -68,10 +69,12 @@ public class NodeEditController extends BaseServerController {
@Feature(method = MethodFeature.LIST)
public String nodeStatus() {
long timeMillis = System.currentTimeMillis();
JSONObject jsonObject = NodeForward.requestData(getNode(), NodeUrl.Status, getRequest(), JSONObject.class);
NodeModel node = getNode();
JSONObject jsonObject = NodeForward.requestData(node, NodeUrl.Status, getRequest(), JSONObject.class);
Assert.notNull(jsonObject, "获取信息失败");
JSONArray jsonArray = new JSONArray();
jsonObject.put("timeOut", System.currentTimeMillis() - timeMillis);
jsonObject.put("nodeId", node.getId());
jsonArray.add(jsonObject);
return JsonMessage.getString(200, "", jsonArray);
}
@ -94,7 +97,8 @@ public class NodeEditController extends BaseServerController {
@Feature(method = MethodFeature.DEL)
public String del(String id) {
// 判断分发
boolean checkNode = outGivingServer.checkNode(id, getRequest());
HttpServletRequest request = getRequest();
boolean checkNode = outGivingServer.checkNode(id, request);
Assert.state(!checkNode, "该节点存在分发项目,不能删除");
// 监控
boolean checkNode1 = monitorService.checkNode(id);
@ -104,9 +108,10 @@ public class NodeEditController extends BaseServerController {
//
ProjectInfoModel projectInfoModel = new ProjectInfoModel();
projectInfoModel.setNodeId(id);
projectInfoModel.setWorkspaceId(projectInfoCacheService.getCheckUserWorkspace(request));
boolean exists = projectInfoCacheService.exists(projectInfoModel);
Assert.state(!exists, "该节点下还存在项目,不能删除");
nodeService.delByKey(id, getRequest());
nodeService.delByKey(id, request);
return JsonMessage.getString(200, "操作成功");
}
}

View File

@ -1,13 +1,18 @@
package io.jpom.controller.node;
import cn.hutool.db.Entity;
import cn.jiangzeyin.common.JsonMessage;
import io.jpom.common.BaseServerController;
import io.jpom.model.PageResultDto;
import io.jpom.model.data.NodeModel;
import io.jpom.model.data.ProjectInfoModel;
import io.jpom.permission.SystemPermission;
import io.jpom.plugin.ClassFeature;
import io.jpom.plugin.Feature;
import io.jpom.plugin.MethodFeature;
import io.jpom.service.node.ProjectInfoCacheService;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -70,4 +75,47 @@ public class NodeProjectInfoController extends BaseServerController {
List<ProjectInfoModel> projectInfoModels = projectInfoCacheService.listByWorkspace(getRequest());
return JsonMessage.getString(200, "", projectInfoModels);
}
/**
* 同步节点项目
*
* @return json
*/
@GetMapping(value = "sync_project", produces = MediaType.APPLICATION_JSON_VALUE)
public String syncProject(String nodeId) {
NodeModel nodeModel = nodeService.getByKey(nodeId);
Assert.notNull(nodeModel, "对应的节点不存在");
String msg = projectInfoCacheService.syncExecuteNode(nodeModel);
return JsonMessage.getString(200, msg);
}
/**
* 删除节点缓存的项目信息
*
* @return json
*/
@GetMapping(value = "del_project_cache", produces = MediaType.APPLICATION_JSON_VALUE)
public String delProjectCache(String nodeId) {
NodeModel nodeModel = nodeService.getByKey(nodeId);
Assert.notNull(nodeModel, "对应的节点不存在");
int count = projectInfoCacheService.delProjectCache(nodeId, getRequest());
return JsonMessage.getString(200, "成功删除" + count + "条项目缓存");
}
/**
* 删除节点缓存的所有项目
*
* @return json
*/
@GetMapping(value = "clear_all_project", produces = MediaType.APPLICATION_JSON_VALUE)
@SystemPermission(superUser = true)
@Feature(method = MethodFeature.DEL)
public String clearAll() {
Entity where = Entity.create();
where.set("id", " <> id");
int del = projectInfoCacheService.del(where);
return JsonMessage.getString(200, "成功删除" + del + "条项目缓存");
}
}

View File

@ -158,7 +158,16 @@ public class SshController extends BaseServerController {
boolean exists = sshService.exists(entity);
Assert.state(!exists, "对应的SSH已经存在啦");
try {
Session session = add ? SshService.getSessionByModel(sshModel) : SshService.getSession(id);
SshModel model = sshService.getByKey(id, false);
if (model != null) {
if (StrUtil.isEmpty(sshModel.getPassword())) {
sshModel.setPassword(model.getPassword());
}
if (StrUtil.isEmpty(sshModel.getPrivateKey())) {
sshModel.setPrivateKey(model.getPrivateKey());
}
}
Session session = SshService.getSessionByModel(sshModel);
JschUtil.close(session);
} catch (Exception e) {
return JsonMessage.getString(505, "ssh连接失败" + e.getMessage());
@ -181,7 +190,7 @@ public class SshController extends BaseServerController {
@GetMapping(value = "check_agent.json", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public String checkAgent(String ids) {
List<SshModel> sshModels = sshService.listById(StrUtil.split(ids, StrUtil.DOT), getRequest());
List<SshModel> sshModels = sshService.listById(StrUtil.split(ids, StrUtil.COMMA), getRequest());
Assert.notEmpty(sshModels, "没有任何节点信息");
JSONObject result = new JSONObject();

View File

@ -369,7 +369,7 @@ public class OutGivingProjectEditController extends BaseServerController {
allData.put("args_" + copyId, copyArgs);
}
}
JsonMessage<String> jsonMessage = sendData(nodeModel, userModel, allData, false);
JsonMessage<String> jsonMessage = this.sendData(nodeModel, userModel, allData, false);
Assert.state(jsonMessage.getCode() == HttpStatus.HTTP_OK, nodeModel.getName() + "节点失败:" + jsonMessage.getMsg());
tuples.add(new Tuple(nodeModel, allData));
}

View File

@ -114,6 +114,13 @@ public class UserListController extends BaseServerController {
if (!systemUser) {
Assert.state(!model.isSuperSystemUser(), "不能取消超级管理员的权限");
}
UserModel optUser = getUser();
if (StrUtil.equals(model.getId(), optUser.getId())) {
Assert.state(model.isSystemUser() == optUser.isSystemUser(), "不能修改自己的管理员权限");
}
if (model.isSuperSystemUser()) {
Assert.state(optUser.isSuperSystemUser(), "超级管理员才能修改超级管理员的信息");
}
userService.update(userModel);
}
//

View File

@ -39,10 +39,8 @@ import io.jpom.common.BaseServerController;
import io.jpom.common.Const;
import io.jpom.model.BaseDbModel;
import io.jpom.model.BaseUserModifyDbModel;
import io.jpom.model.BaseWorkspaceModel;
import io.jpom.model.PageResultDto;
import io.jpom.model.data.UserModel;
import io.jpom.model.data.WorkspaceModel;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
@ -124,11 +122,6 @@ public abstract class BaseDbService<T extends BaseDbModel> extends BaseDbCommonS
modifyDbModel.setModifyUser(ObjectUtil.defaultIfNull(modifyDbModel.getModifyUser(), userModel.getId()));
}
}
if (t instanceof BaseWorkspaceModel) {
// 数据都将绑定一个默认的工作空间
BaseWorkspaceModel baseWorkspaceModel = (BaseWorkspaceModel) t;
baseWorkspaceModel.setWorkspaceId(ObjectUtil.defaultIfNull(baseWorkspaceModel.getWorkspaceId(), WorkspaceModel.DEFAULT_ID));
}
}
/**

View File

@ -33,8 +33,10 @@ import io.jpom.model.BaseWorkspaceModel;
import io.jpom.model.PageResultDto;
import io.jpom.model.data.UserBindWorkspaceModel;
import io.jpom.model.data.UserModel;
import io.jpom.model.data.WorkspaceModel;
import io.jpom.service.user.UserBindWorkspaceService;
import org.springframework.util.Assert;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
@ -93,9 +95,14 @@ public abstract class BaseWorkspaceService<T extends BaseWorkspaceModel> extends
super.fillInsert(t);
if (StrUtil.isEmpty(t.getWorkspaceId())) {
// 自动绑定 工作空间ID
HttpServletRequest request = BaseServerController.getRequestAttributes().getRequest();
String workspaceId = getCheckUserWorkspace(request);
t.setWorkspaceId(workspaceId);
ServletRequestAttributes servletRequestAttributes = BaseServerController.tryGetRequestAttributes();
if (servletRequestAttributes != null) {
HttpServletRequest request = servletRequestAttributes.getRequest();
String workspaceId = getCheckUserWorkspace(request);
t.setWorkspaceId(workspaceId);
} else {
t.setWorkspaceId(WorkspaceModel.DEFAULT_ID);
}
} else {
// 检查权限
this.checkUserWorkspace(t.getWorkspaceId());

View File

@ -14,7 +14,6 @@ import io.jpom.model.data.WorkspaceModel;
import io.jpom.monitor.NodeMonitor;
import io.jpom.service.h2db.BaseWorkspaceService;
import io.jpom.service.node.ssh.SshService;
import io.jpom.util.StringUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
@ -56,8 +55,8 @@ public class NodeService extends BaseWorkspaceService<NodeModel> {
NodeModel nodeModel = ServletUtil.toBean(request, NodeModel.class, true);
String id = nodeModel.getId();
if (StrUtil.isNotEmpty(id)) {
boolean general = StringUtil.isGeneral(id, 2, 20);
Assert.state(general, "节点id不能为空并且2-20英文字母 、数字和下划线)");
//boolean general = StringUtil.isGeneral(id, 2, 20);
//Assert.state(general, "节点id不能为空并且2-20英文字母 、数字和下划线)");
}
Assert.hasText(nodeModel.getName(), "节点名称 不能为空");
// 节点地址 重复

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
import cn.jiangzeyin.common.DefaultSystemLog;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
@ -18,6 +19,7 @@ import io.jpom.service.h2db.BaseNodeService;
import io.jpom.service.system.WorkspaceService;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@ -92,60 +94,71 @@ public class ProjectInfoCacheService extends BaseNodeService<ProjectInfoModel> {
* @param nodeModel 节点
*/
public void syncNode(final NodeModel nodeModel) {
ThreadUtil.execute(() -> this.syncExecuteNode(nodeModel));
}
/**
* 同步执行 同步节点项目信息
*
* @param nodeModel 节点信息
* @return json
*/
public String syncExecuteNode(NodeModel nodeModel) {
String nodeModelName = nodeModel.getName();
if (!nodeModel.isOpenStatus()) {
DefaultSystemLog.getLog().debug("{} 节点未启用", nodeModelName);
return;
return "节点未启用";
}
ThreadUtil.execute(() -> {
try {
JSONArray jsonArray = NodeForward.requestData(nodeModel, NodeUrl.Manage_GetProjectInfo, JSONArray.class, "notStatus", "true");
if (CollUtil.isEmpty(jsonArray)) {
DefaultSystemLog.getLog().debug("{} 节点没有拉取到任何项目项目", nodeModelName);
return;
}
// 查询现在存在的项目
ProjectInfoModel where = new ProjectInfoModel();
where.setWorkspaceId(nodeModel.getWorkspaceId());
where.setNodeId(nodeModel.getId());
List<ProjectInfoModel> projectInfoModelsCacheAll = super.listByBean(where);
projectInfoModelsCacheAll = ObjectUtil.defaultIfNull(projectInfoModelsCacheAll, Collections.EMPTY_LIST);
Set<String> cacheIds = projectInfoModelsCacheAll.stream()
.map(ProjectInfoModel::getProjectId)
.collect(Collectors.toSet());
//
List<ProjectInfoModel> projectInfoModels = jsonArray.toJavaList(ProjectInfoModel.class);
List<ProjectInfoModel> models = projectInfoModels.stream().peek(projectInfoModel -> {
projectInfoModel.setProjectId(projectInfoModel.getId());
projectInfoModel.setId(null);
projectInfoModel.setNodeId(nodeModel.getId());
if (StrUtil.isEmpty(projectInfoModel.getWorkspaceId())) {
projectInfoModel.setWorkspaceId(nodeModel.getWorkspaceId());
}
projectInfoModel.setId(projectInfoModel.fullId());
}).filter(projectInfoModel -> {
// 检查对应的工作空间 是否存在
return workspaceService.exists(new WorkspaceModel(projectInfoModel.getWorkspaceId()));
}).peek(projectInfoModel -> cacheIds.remove(projectInfoModel.getProjectId())).collect(Collectors.toList());
// 设置 临时缓存便于放行检查
BaseServerController.resetInfo(UserModel.EMPTY);
//
models.forEach(ProjectInfoCacheService.super::upsert);
// 删除项目好的
Set<String> strings = cacheIds.stream()
.map(s -> ProjectInfoModel.fullId(nodeModel.getWorkspaceId(), nodeModel.getId(), s))
.collect(Collectors.toSet());
if (CollUtil.isNotEmpty(strings)) {
super.delByKey(strings, null);
}
DefaultSystemLog.getLog().debug("{} 节点拉取到 {} 个项目,缓存 {} 个项目,删除 {} 个缓存",
nodeModelName, CollUtil.size(jsonArray), CollUtil.size(projectInfoModelsCacheAll), CollUtil.size(strings));
} catch (Exception e) {
DefaultSystemLog.getLog().error("同步节点项目失败:" + nodeModelName, e);
} finally {
BaseServerController.remove();
try {
JSONArray jsonArray = NodeForward.requestData(nodeModel, NodeUrl.Manage_GetProjectInfo, JSONArray.class, "notStatus", "true");
if (CollUtil.isEmpty(jsonArray)) {
DefaultSystemLog.getLog().debug("{} 节点没有拉取到任何项目项目", nodeModelName);
return "节点没有拉取到任何项目项目";
}
});
// 查询现在存在的项目
ProjectInfoModel where = new ProjectInfoModel();
where.setWorkspaceId(nodeModel.getWorkspaceId());
where.setNodeId(nodeModel.getId());
List<ProjectInfoModel> projectInfoModelsCacheAll = super.listByBean(where);
projectInfoModelsCacheAll = ObjectUtil.defaultIfNull(projectInfoModelsCacheAll, Collections.EMPTY_LIST);
Set<String> cacheIds = projectInfoModelsCacheAll.stream()
.map(ProjectInfoModel::getProjectId)
.collect(Collectors.toSet());
//
List<ProjectInfoModel> projectInfoModels = jsonArray.toJavaList(ProjectInfoModel.class);
List<ProjectInfoModel> models = projectInfoModels.stream().peek(projectInfoModel -> {
projectInfoModel.setProjectId(projectInfoModel.getId());
projectInfoModel.setId(null);
projectInfoModel.setNodeId(nodeModel.getId());
if (StrUtil.isEmpty(projectInfoModel.getWorkspaceId())) {
projectInfoModel.setWorkspaceId(WorkspaceModel.DEFAULT_ID);
}
projectInfoModel.setId(projectInfoModel.fullId());
}).filter(projectInfoModel -> {
// 检查对应的工作空间 是否存在
return workspaceService.exists(new WorkspaceModel(projectInfoModel.getWorkspaceId()));
}).peek(projectInfoModel -> cacheIds.remove(projectInfoModel.getProjectId())).collect(Collectors.toList());
// 设置 临时缓存便于放行检查
BaseServerController.resetInfo(UserModel.EMPTY);
//
models.forEach(ProjectInfoCacheService.super::upsert);
// 删除项目
Set<String> strings = cacheIds.stream()
.map(s -> ProjectInfoModel.fullId(nodeModel.getWorkspaceId(), nodeModel.getId(), s))
.collect(Collectors.toSet());
if (CollUtil.isNotEmpty(strings)) {
super.delByKey(strings, null);
}
String format = StrUtil.format("{} 节点拉取到 {} 个项目,已经缓存 {} 个项目,更新 {} 个项目,删除 {} 个缓存",
nodeModelName, CollUtil.size(jsonArray), CollUtil.size(projectInfoModelsCacheAll), CollUtil.size(models), CollUtil.size(strings));
DefaultSystemLog.getLog().debug(format);
return format;
} catch (Exception e) {
DefaultSystemLog.getLog().error("同步节点项目失败:" + nodeModelName, e);
return "同步节点项目失败" + e.getMessage();
} finally {
BaseServerController.remove();
}
}
/**
@ -179,6 +192,15 @@ public class ProjectInfoCacheService extends BaseNodeService<ProjectInfoModel> {
});
}
public int delProjectCache(String nodeId, HttpServletRequest request) {
String checkUserWorkspace = this.getCheckUserWorkspace(request);
Entity entity = Entity.create();
entity.set("nodeId", nodeId);
entity.set("workspaceId", checkUserWorkspace);
return super.del(entity);
}
private void fullData(ProjectInfoModel projectInfoModel, NodeModel nodeModel) {
projectInfoModel.setProjectId(projectInfoModel.getId());
projectInfoModel.setId(null);

View File

@ -99,6 +99,7 @@ public class InitDb implements DisposableBean, InitializingBean {
*/
String[] files = new String[]{
"classpath:/bin/h2-db-v1.sql",
"classpath:/bin/h2-db-v1.1.sql",
"classpath:/bin/h2-db-v2.sql",
"classpath:/bin/h2-db-v3.sql",
};

View File

@ -0,0 +1,6 @@
-- @author bwcx_jzy
ALTER TABLE USEROPERATELOGV1 ALTER COLUMN NODEID VARCHAR(50) COMMENT '节点ID';
ALTER TABLE MONITORNOTIFYLOG ALTER COLUMN NODEID VARCHAR(50) COMMENT '节点ID';

View File

@ -20,7 +20,7 @@ export default {
created() {
this.$notification.config({
top: "100px",
duration: 2,
duration: 4,
});
},
};

View File

@ -14,7 +14,6 @@ export function getDishPatchListAll() {
return axios({
url: "/outgiving/dispatch-list-all",
method: "get",
});
}

View File

@ -62,6 +62,33 @@ export function getProjectListAll() {
});
}
// 同步节点项目
export function syncProject(nodeId) {
return axios({
url: "/node/sync_project",
method: "get",
params: { nodeId: nodeId },
});
}
// 删除节点项目缓存
export function delProjectCache(nodeId) {
return axios({
url: "/node/del_project_cache",
method: "get",
params: { nodeId: nodeId },
});
}
// 删除节点项目缓存
export function delAllProjectCache() {
return axios({
url: "/node/clear_all_project",
method: "get",
params: {},
});
}
/**
* 编辑 node
* @param {

View File

@ -136,7 +136,7 @@ export default {
geteBuildHistory(this.listQuery).then((res) => {
if (res.code === 200) {
this.list = res.data.result;
this.total = res.data.total;
this.listQuery.total = res.data.total;
}
this.loading = false;
});

View File

@ -598,7 +598,7 @@ export default {
};
// javaCopyItemList
this.nodeList.forEach((node) => {
this.temp[`${node.key}_javaCopyItemList`] = [];
this.temp[`${node.id}_javaCopyItemList`] = [];
});
this.loadAccesList();

View File

@ -10,9 +10,6 @@
</div>
<!-- 表格 :scroll="{ x: 1070, y: tableHeight -60 }" scroll expandedRowRender 不兼容没法同时使用不然会多出一行数据-->
<a-table :loading="loading" :columns="columns" :data-source="list" bordered rowKey="id" @expand="expand" :pagination="(this, pagination)" @change="changePage">
<a-tooltip slot="group" slot-scope="text" placement="topLeft" :title="text">
<span>{{ text }}</span>
</a-tooltip>
<a-tooltip slot="url" slot-scope="text" placement="topLeft" :title="text">
<span>{{ text }}</span>
</a-tooltip>
@ -35,6 +32,14 @@
<a-tooltip slot="runTime" slot-scope="text" placement="topLeft" :title="text">
<span>{{ text }}</span>
</a-tooltip>
<template slot="projectCount" slot-scope="text, item">
<a-tooltip placement="topLeft" :title="节点中的所有项目数量">
<a-tag @click="syncNode(item)">{{ text }} </a-tag>
</a-tooltip>
<a-tooltip placement="topLeft" :title="清除服务端缓存节点项目信息">
<a-icon @click="delNodeCache(item)" type="delete" />
</a-tooltip>
</template>
</a-table>
</a-table>
<!-- 编辑区 -->
@ -120,7 +125,7 @@
</template>
<script>
import { mapGetters } from "vuex";
import { getNodeList, getNodeStatus, editNode, deleteNode } from "@/api/node";
import { getNodeList, getNodeStatus, editNode, deleteNode, syncProject, delProjectCache } from "@/api/node";
import { getSshListAll } from "@/api/ssh";
import NodeLayout from "./node-layout";
import Terminal from "./terminal";
@ -168,12 +173,12 @@ export default {
],
childColumns: [
{ title: "系统名", dataIndex: "osName", key: "osName", width: 100, ellipsis: true, scopedSlots: { customRender: "osName" } },
{ title: "JDK 版本", dataIndex: "javaVersion", key: "javaVersion", width: 120, ellipsis: true, scopedSlots: { customRender: "javaVersion" } },
{ title: "JVM 总内存", dataIndex: "totalMemory", key: "totalMemory", width: 150 },
{ title: "JVM 剩余内存", dataIndex: "freeMemory", key: "freeMemory", width: 180 },
{ title: "Jpom 版本", dataIndex: "jpomVersion", key: "jpomVersion", width: 140 },
{ title: "Java 程序数", dataIndex: "javaVirtualCount", key: "javaVirtualCount", width: 150 },
{ title: "项目数", dataIndex: "count", key: "count", width: 100 },
{ title: "JDK 版本", dataIndex: "javaVersion", key: "javaVersion", ellipsis: true, scopedSlots: { customRender: "javaVersion" } },
{ title: "JVM 总内存", dataIndex: "totalMemory", key: "totalMemory", width: 120 },
{ title: "JVM 剩余内存", dataIndex: "freeMemory", key: "freeMemory", width: 140 },
{ title: "Jpom 版本", dataIndex: "jpomVersion", key: "jpomVersion", width: 120 },
{ title: "Java 程序数", dataIndex: "javaVirtualCount", key: "javaVirtualCount", width: 120 },
{ title: "项目数", dataIndex: "count", key: "count", width: 90, scopedSlots: { customRender: "projectCount" } },
{ title: "响应时间", dataIndex: "timeOut", key: "timeOut", width: 120 },
{ title: "已运行时间", dataIndex: "runTime", key: "runTime", width: 150, ellipsis: true, scopedSlots: { customRender: "runTime" } },
],
@ -285,21 +290,22 @@ export default {
},
//
handleAdd() {
this.temp = {
type: "add",
cycle: 0,
protocol: "http",
openStatus: 1,
timeOut: 0,
loginName: "jpomAgent",
};
this.editNodeVisible = true;
this.$nextTick(() => {
setTimeout(() => {
this.introGuide();
}, 500);
this.$refs["editNodeForm"].resetFields();
this.$refs["editNodeForm"] && this.$refs["editNodeForm"].resetFields();
this.temp = {
type: "add",
cycle: 0,
protocol: "http",
openStatus: 1,
timeOut: 0,
loginName: "jpomAgent",
};
this.editNodeVisible = true;
});
this.loadSshList();
},
//
handleTerminal(record) {
@ -358,7 +364,7 @@ export default {
//
handleNode(record) {
this.temp = Object.assign(record);
this.drawerTitle = `${this.temp.id} (${this.temp.url})`;
this.drawerTitle = `${this.temp.name} (${this.temp.url})`;
this.drawerVisible = true;
let nodeId = this.$route.query.nodeId;
if (nodeId !== record.id) {
@ -367,6 +373,37 @@ export default {
});
}
},
syncNode(node) {
syncProject(node.nodeId).then((res) => {
if (res.code == 200) {
this.$notification.success({
message: res.msg,
duration: 4,
});
return false;
}
});
},
delNodeCache(node) {
this.$confirm({
title: "系统提示",
content: "确定要清除该节点下面的项目缓存信息吗?",
okText: "确认",
cancelText: "取消",
onOk: () => {
//
delProjectCache(node.nodeId).then((res) => {
if (res.code == 200) {
this.$notification.success({
message: res.msg,
duration: 4,
});
return false;
}
});
},
});
},
//
onClose() {
this.drawerVisible = false;

View File

@ -173,14 +173,14 @@ export default {
</script>
<style scoped>
.sider {
height: calc(100vh - 75px);
/* height: calc(100vh - 75px); */
overflow-y: auto;
}
.layout-content {
height: calc(100vh - 95px);
/* min-height: calc(100vh); */
overflow-y: auto;
}
/* .node-layout {
padding: 10px;
} */
</style>
</style>

View File

@ -12,6 +12,9 @@
<a-button type="primary" @click="batchRestart">批量重启</a-button>
<a-button type="danger" @click="batchStop">批量关闭</a-button>
状态数据是异步获取有一定时间延迟
<a-tooltip placement="topLeft" title="清除服务端缓存节点所有的项目信息, 需要重新同步">
<a-icon @click="delAll()" type="delete" />
</a-tooltip>
</div>
<a-table
:data-source="projList"
@ -50,7 +53,7 @@
</div>
</template>
<script>
import { getProjectList } from "@/api/node";
import { getProjectList, delAllProjectCache } from "@/api/node";
import { restartProject, startProject, stopProject, getRuningProjectInfo, runModeList } from "@/api/node-project";
import { mapGetters } from "vuex";
import File from "../node/node-layout/project/project-file";
@ -272,6 +275,26 @@ export default {
}
this.getNodeProjectData();
},
delAll() {
this.$confirm({
title: "系统提示",
content: "确定要清除服务端所有的项目缓存信息吗?",
okText: "确认",
cancelText: "取消",
onOk: () => {
//
delAllProjectCache().then((res) => {
if (res.code == 200) {
this.$notification.success({
message: res.msg,
duration: 4,
});
return false;
}
});
},
});
},
},
};
</script>

View File

@ -196,7 +196,7 @@ export default {
//
pagination() {
return {
total: this.total,
total: this.listQuery.total,
current: this.listQuery.page || 1,
pageSize: this.listQuery.limit || PAGE_DEFAULT_LIMIT,
pageSizeOptions: PAGE_DEFAULT_SIZW_OPTIONS,
@ -219,7 +219,7 @@ export default {
getRepositoryList(this.listQuery).then((res) => {
if (res.code === 200) {
this.list = res.data.result;
this.total = res.data.total;
this.listQuery.total = res.data.total;
}
this.loading = false;
});

View File

@ -188,7 +188,7 @@ export default {
getBackupList(this.listQuery).then((res) => {
if (res.code === 200) {
this.list = res.data.result;
this.total = res.data.total;
this.listQuery.total = res.data.total;
}
this.loading = false;
});