优化admin功能

1.x
tanghc 5 years ago
parent 8d8e39eadf
commit 42a868b769
  1. 25
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/IsvApi.java
  2. 5
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/param/IsvKeysFormUpdate.java
  3. 51
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java
  4. 1
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/IsvRoutePermission.java
  5. 2
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/SopAdminConstants.java
  6. 124
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java
  7. 12
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/config/WebConfig.java
  8. 43
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java
  9. 4
      sop-admin/sop-admin-server/src/main/resources/application-dev.yml
  10. 2
      sop-admin/sop-admin-server/src/main/resources/public/index.html
  11. 2
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.9d8bc0b6.js
  12. 2
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-6a68a33e.b6685cb9.js
  13. 1
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.094bb2fa.js
  14. 1
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-73b2dcec.14f248eb.js
  15. 45
      sop-admin/sop-admin-server/src/test/java/com/gitee/sop/adminserver/CuratorTest.java
  16. 4
      sop-admin/sop-admin-vue/src/views/isv/index.vue
  17. 6
      sop-admin/sop-admin-vue/src/views/isv/keys.vue
  18. 4
      sop-admin/sop-admin-vue/src/views/service/route/index.vue
  19. 1
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/IsvRoutePermission.java
  20. 24
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java
  21. 15
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java

@ -41,13 +41,16 @@ import com.gitee.sop.adminserver.service.RoutePermissionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.NotBlank;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -58,7 +61,15 @@ import java.util.stream.Collectors;
@Slf4j
public class IsvApi {
public static final int SIGN_TYPE_RSA2 = 1;
public static final byte SIGN_TYPE_RSA = 1;
public static final byte SIGN_TYPE_MD5 = 2;
static Map<String, Byte> SIGN_TYPE_MAP = new HashMap<>();
static {
SIGN_TYPE_MAP.put("rsa", (byte) SIGN_TYPE_RSA);
SIGN_TYPE_MAP.put("md5", (byte) SIGN_TYPE_MD5);
}
@Autowired
IsvInfoMapper isvInfoMapper;
@ -74,6 +85,9 @@ public class IsvApi {
@Autowired
RoutePermissionService routePermissionService;
@Value("${sop.sign-type}")
private String sopSignType;
@Api(name = "isv.info.page")
@ApiDocMethod(description = "isv列表", results = {
@ApiDocField(name = "pageIndex", description = "第几页", dataType = DataType.INT, example = "1"),
@ -118,6 +132,7 @@ public class IsvApi {
CopyUtil.copyProperties(isvKeys, isvDetailVO);
}
isvDetailVO.setAppKey(appKey);
isvDetailVO.setSignType(getSignType());
return isvDetailVO;
}
@ -168,12 +183,17 @@ public class IsvApi {
IsvKeysGenVO isvKeysGenVO = this.createIsvKeys();
IsvKeys isvKeys = new IsvKeys();
isvKeys.setAppKey(appKey);
isvKeys.setSignType(getSignType());
CopyUtil.copyPropertiesIgnoreNull(isvKeysGenVO, isvKeys);
isvKeysMapper.saveIgnoreNull(isvKeys);
this.sendChannelMsg(rec.getAppKey());
}
private byte getSignType() {
return SIGN_TYPE_MAP.getOrDefault(sopSignType, SIGN_TYPE_RSA);
}
@Api(name = "isv.info.update")
@ApiDocMethod(description = "修改isv")
@Transactional(rollbackFor = Exception.class)
@ -194,6 +214,7 @@ public class IsvApi {
if (isvKeys == null) {
isvKeys = new IsvKeys();
CopyUtil.copyPropertiesIgnoreNull(param, isvKeys);
isvKeys.setSignType(getSignType());
isvKeysMapper.saveIgnoreNull(isvKeys);
} else {
CopyUtil.copyPropertiesIgnoreNull(param, isvKeys);
@ -279,7 +300,7 @@ public class IsvApi {
routePermissionService.sendIsvRolePermissionToZookeeper(isvInfo.getAppKey(), roleCodeList);
} catch (Exception e) {
log.error("保存到zookeeper中失败,isvInfo:{}, roleCodeList:{}", isvInfo, roleCodeList);
throw new BizException("保存失败,请查看日志");
throw new BizException("同步zookeeper失败,请查看网关日志");
}
}
}

@ -7,7 +7,6 @@ import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author tanghc
@ -45,8 +44,4 @@ public class IsvKeysFormUpdate {
/** 平台生成的私钥, 数据库字段:private_key_platform */
@ApiDocField(description = "平台生成的私钥")
private String privateKeyPlatform;
@ApiDocField(description = "签名类型:1:RSA2,2:MD5")
@NotNull(message = "signType不能为空")
private Byte signType;
}

@ -6,7 +6,6 @@ import com.gitee.easyopen.annotation.ApiService;
import com.gitee.easyopen.doc.annotation.ApiDoc;
import com.gitee.easyopen.doc.annotation.ApiDocMethod;
import com.gitee.easyopen.util.CopyUtil;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.sop.adminserver.api.isv.result.RoleVO;
import com.gitee.sop.adminserver.api.service.param.RouteAddParam;
import com.gitee.sop.adminserver.api.service.param.RouteDeleteParam;
@ -22,7 +21,6 @@ import com.gitee.sop.adminserver.common.ZookeeperPathExistException;
import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException;
import com.gitee.sop.adminserver.entity.ConfigRouteBase;
import com.gitee.sop.adminserver.entity.PermRole;
import com.gitee.sop.adminserver.entity.PermRolePermission;
import com.gitee.sop.adminserver.mapper.ConfigRouteBaseMapper;
import com.gitee.sop.adminserver.mapper.PermRoleMapper;
import com.gitee.sop.adminserver.mapper.PermRolePermissionMapper;
@ -30,14 +28,11 @@ import com.gitee.sop.adminserver.service.RouteConfigService;
import com.gitee.sop.adminserver.service.RoutePermissionService;
import com.gitee.sop.adminserver.service.RouteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -188,6 +183,11 @@ public class RouteApi {
return this.getRouteRole(param.getId());
}
/**
* 获取路由对应的角色
* @param id routeId
* @return
*/
private List<RoleVO> getRouteRole(String id) {
return permRolePermissionMapper.listByColumn("route_id", id)
.stream()
@ -203,33 +203,28 @@ public class RouteApi {
@Api(name = "route.role.update")
@ApiDocMethod(description = "更新路由对应的角色")
@Transactional(rollbackFor = Exception.class)
public void updateRouteRole(RoutePermissionParam param) {
String routeId = param.getRouteId();
// 删除所有数据
Query delQuery = new Query();
delQuery.eq("route_id", routeId);
permRolePermissionMapper.deleteByQuery(delQuery);
List<String> roleCodes = param.getRoleCode();
if (CollectionUtils.isNotEmpty(roleCodes)) {
List<PermRolePermission> tobeSave = new ArrayList<>(roleCodes.size());
for (String roleCode : roleCodes) {
PermRolePermission permRolePermission = new PermRolePermission();
permRolePermission.setRoleCode(roleCode);
permRolePermission.setRouteId(routeId);
tobeSave.add(permRolePermission);
}
// 批量添加
permRolePermissionMapper.saveBatch(tobeSave);
}
RoutePermissionParam oldRoutePermission = this.buildOldRoutePermission(param.getRouteId());
routePermissionService.updateRoutePermission(param);
try {
routePermissionService.sendRoutePermissionReloadMsg();
routePermissionService.sendRoutePermissionReloadMsg(oldRoutePermission);
} catch (Exception e) {
log.info("消息推送--路由权限(reload)失败", e);
throw new BizException("修改失败,请查看日志");
log.error("消息推送--路由权限(reload)失败", e);
// 回滚
routePermissionService.updateRoutePermission(oldRoutePermission);
throw new BizException(e.getMessage());
}
}
private RoutePermissionParam buildOldRoutePermission(String routeId) {
List<RoleVO> routeRole = this.getRouteRole(routeId);
List<String> roleCodeList = routeRole.stream()
.map(RoleVO::getRoleCode)
.collect(Collectors.toList());
RoutePermissionParam routePermissionParam = new RoutePermissionParam();
routePermissionParam.setRouteId(routeId);
routePermissionParam.setRoleCode(roleCodeList);
return routePermissionParam;
}
}

@ -13,4 +13,5 @@ public class IsvRoutePermission {
private String appKey;
private List<String> routeIdList;
private String routeIdListMd5;
private String listenPath;
}

@ -14,4 +14,6 @@ public class SopAdminConstants {
*/
public static final String SOP_MSG_CHANNEL_PATH = "/com.gitee.sop.channel";
public static final String RELOAD_ROUTE_PERMISSION_PATH = "/com.gitee.sop.route.permission.reload";
}

@ -4,54 +4,67 @@ import com.gitee.sop.adminserver.common.ZookeeperOperationException;
import com.gitee.sop.adminserver.common.ZookeeperPathExistException;
import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import java.io.Closeable;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import static com.gitee.sop.adminserver.bean.SopAdminConstants.SOP_MSG_CHANNEL_PATH;
/**
* @author tanghc
*/
@Configuration
@Slf4j
public class ZookeeperContext {
private static CuratorFramework client;
@Value("${spring.cloud.zookeeper.connect-string}")
private String zookeeperServerAddr;
private static Environment environment;
@Value("${spring.cloud.zookeeper.baseSleepTimeMs}")
private String baseSleepTimeMs;
public static void setEnvironment(Environment environment) {
Assert.notNull(environment, "environment不能为null");
ZookeeperContext.environment = environment;
initZookeeperClient();
}
@Value("${spring.cloud.zookeeper.maxRetries}")
private String maxRetries;
public synchronized static void initZookeeperClient() {
if (client != null) {
return;
}
setClient(createClient());
}
@PostConstruct
protected void after() {
public static CuratorFramework createClient() {
String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string");
if (StringUtils.isBlank(zookeeperServerAddr)) {
throw new IllegalArgumentException("未指定spring.cloud.zookeeper.connect-string参数");
throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数");
}
String baseSleepTimeMs = environment.getProperty("spring.cloud.zookeeper.baseSleepTimeMs");
String maxRetries = environment.getProperty("spring.cloud.zookeeper.maxRetries");
log.info("初始化zookeeper客户端,zookeeperServerAddr:{}, baseSleepTimeMs:{}, maxRetries:{}",
zookeeperServerAddr, baseSleepTimeMs, maxRetries);
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(zookeeperServerAddr)
.retryPolicy(new ExponentialBackoffRetry(NumberUtils.toInt(baseSleepTimeMs, 3000), NumberUtils.toInt(maxRetries, 3)))
.build();
client.start();
setClient(client);
return client;
}
public static String getSopRouteRootPath() {
@ -129,6 +142,7 @@ public class ZookeeperContext {
/**
* 创建新的path并赋值如果path已存在抛异常
*
* @param path 待创建的path
* @param data
* @throws ZookeeperPathExistException
@ -138,9 +152,26 @@ public class ZookeeperContext {
throw new ZookeeperPathExistException("path " + path + " 已存在");
}
try {
return getClient().create()
return addPath(path, CreateMode.PERSISTENT, data);
} catch (Exception e) {
throw new ZookeeperOperationException("addPath error path=" + path, e);
}
}
/**
* 添加节点
*
* @param path 待创建的path
* @param createMode 节点类型
* @param data 节点数据
* @return
*/
public static String addPath(String path, CreateMode createMode, String data) {
try {
return getClient().create()
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
.creatingParentContainersIfNeeded()
.withMode(createMode)
.forPath(path, data.getBytes());
} catch (Exception e) {
throw new ZookeeperOperationException("addPath error path=" + path, e);
@ -149,6 +180,7 @@ public class ZookeeperContext {
/**
* 删除节点及子节点
*
* @param path
*/
public static void deletePathDeep(String path) {
@ -157,12 +189,13 @@ public class ZookeeperContext {
.deletingChildrenIfNeeded()
.forPath(path);
} catch (Exception e) {
throw new ZookeeperOperationException("deletePathDeep error path=" + path, e);
}
}
/**
* 创建新的path并赋值如果path已存在则不创建
*
* @param path 待创建的path
* @param data
*/
@ -171,10 +204,7 @@ public class ZookeeperContext {
return path;
}
try {
return getClient().create()
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
.creatingParentContainersIfNeeded()
.forPath(path, data.getBytes());
return addPath(path, data);
} catch (Exception e) {
throw new ZookeeperOperationException("addPathQuietly error path=" + path, e);
}
@ -182,6 +212,7 @@ public class ZookeeperContext {
/**
* 新建或保存节点
*
* @param path
* @param data
* @return
@ -201,6 +232,7 @@ public class ZookeeperContext {
/**
* 获取节点内容
*
* @param path
* @return
* @throws ZookeeperPathNotExistException
@ -247,4 +279,54 @@ public class ZookeeperContext {
return childrenCache;
}
/**
* 监听一个节点
*
* @param path
* @param onChange 节点修改后触发
* @return 返回path
* @throws Exception
*/
public static void listenTempPath(String path, Consumer<String> onChange) throws Exception {
String initData = "{}";
CuratorFramework client = createClient();
client.create()
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
.creatingParentContainersIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(path, initData.getBytes());
final NodeCache cache = new NodeCache(client, path, false);
cache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
byte[] nodeData = cache.getCurrentData().getData();
String data = new String(nodeData);
if (!initData.equals(data)) {
onChange.accept(data);
new Thread(new ZKClose(cache, client)).start();
}
}
});
cache.start();
}
static class ZKClose implements Runnable {
Closeable[] closes;
public ZKClose(Closeable ...closes) {
this.closes = closes;
}
@Override
public void run() {
try {
Thread.sleep(2000);
IOUtils.closeQuietly(closes);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

@ -8,13 +8,17 @@ import com.gitee.easyopen.ApiParamParser;
import com.gitee.easyopen.ParamNames;
import com.gitee.easyopen.interceptor.ApiInterceptor;
import com.gitee.easyopen.session.ApiSessionManager;
import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.interceptor.LoginInterceptor;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
@ -29,6 +33,9 @@ public class WebConfig {
@Value("${admin.access-token.timeout-minutes}")
private String accessTokenTimeout;
@Autowired
private Environment environment;
@Bean
ApiConfig apiConfig() {
ApiConfig apiConfig = new ApiConfig();
@ -59,4 +66,9 @@ public class WebConfig {
return apiConfig;
}
@PostConstruct
public void after() {
ZookeeperContext.setEnvironment(environment);
}
}

@ -2,8 +2,10 @@ package com.gitee.sop.adminserver.service;
import com.alibaba.fastjson.JSON;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.sop.adminserver.api.service.param.RoutePermissionParam;
import com.gitee.sop.adminserver.bean.ChannelMsg;
import com.gitee.sop.adminserver.bean.IsvRoutePermission;
import com.gitee.sop.adminserver.bean.SopAdminConstants;
import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.entity.PermIsvRole;
import com.gitee.sop.adminserver.entity.PermRolePermission;
@ -16,6 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ -93,12 +96,48 @@ public class RoutePermissionService {
/**
* 推送所有路由权限到zookeeper
*/
public void sendRoutePermissionReloadMsg() throws Exception {
ChannelMsg channelMsg = new ChannelMsg("reload", null);
public synchronized void sendRoutePermissionReloadMsg(RoutePermissionParam oldRoutePermission) throws Exception {
String listenPath = SopAdminConstants.RELOAD_ROUTE_PERMISSION_PATH + "/" + System.currentTimeMillis();
ZookeeperContext.listenTempPath(listenPath, code -> {
// 0成功
if (!"0".equals(code)) {
log.error("推送所有路由权限到zookeeper失败,进行回滚,msg: {},oldRoutePermission:{}", code, JSON.toJSONString(oldRoutePermission));
// 回滚
this.updateRoutePermission(oldRoutePermission);
}
});
IsvRoutePermission isvRoutePermission = new IsvRoutePermission();
isvRoutePermission.setListenPath(listenPath);
ChannelMsg channelMsg = new ChannelMsg("reload", isvRoutePermission);
String jsonData = JSON.toJSONString(channelMsg);
String path = ZookeeperContext.getIsvRoutePermissionChannelPath();
log.info("消息推送--路由权限(reload), path:{}, data:{}", path, jsonData);
ZookeeperContext.createOrUpdateData(path, jsonData);
}
/**
* 更新路由权限
*
* @param param
*/
public synchronized void updateRoutePermission(RoutePermissionParam param) {
String routeId = param.getRouteId();
// 删除所有数据
Query delQuery = new Query();
delQuery.eq("route_id", routeId);
permRolePermissionMapper.deleteByQuery(delQuery);
List<String> roleCodes = param.getRoleCode();
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(roleCodes)) {
List<PermRolePermission> tobeSave = new ArrayList<>(roleCodes.size());
for (String roleCode : roleCodes) {
PermRolePermission permRolePermission = new PermRolePermission();
permRolePermission.setRoleCode(roleCode);
permRolePermission.setRouteId(routeId);
tobeSave.add(permRolePermission);
}
// 批量添加
permRolePermissionMapper.saveBatch(tobeSave);
}
}
}

@ -6,6 +6,10 @@ admin:
access-token:
timeout-minutes: 30
sop:
# 签名方式,rsa:支付宝开放平台签名方式,md5:淘宝开放平台签名方式
sign-type: rsa
# 不用改
spring:
application:

@ -1 +1 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.4f0872ef.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function t(t){for(var r,c,o=t[0],i=t[1],f=t[2],l=0,d=[];l<o.length;l++)c=o[l],u[c]&&d.push(u[c][0]),u[c]=0;for(r in i)Object.prototype.hasOwnProperty.call(i,r)&&(e[r]=i[r]);h&&h(t);while(d.length)d.shift()();return a.push.apply(a,f||[]),n()}function n(){for(var e,t=0;t<a.length;t++){for(var n=a[t],r=!0,c=1;c<n.length;c++){var o=n[c];0!==u[o]&&(r=!1)}r&&(a.splice(t--,1),e=i(i.s=n[0]))}return e}var r={},c={runtime:0},u={runtime:0},a=[];function o(e){return i.p+"static/js/"+({}[e]||e)+"."+{"chunk-009073d4":"28312808","chunk-238a81e9":"5955f13d","chunk-25908fca":"e7e4b6d5","chunk-29e7142c":"994a3ac0","chunk-2d2085ef":"a63a74dc","chunk-2d22c2e3":"4a098244","chunk-37401378":"4e39ec9b","chunk-4a59cbe4":"a6360c68","chunk-6a68a33e":"15951b55","chunk-73b2dcec":"094bb2fa"}[e]+".js"}function i(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,i),n.l=!0,n.exports}i.e=function(e){var t=[],n={"chunk-009073d4":1,"chunk-238a81e9":1,"chunk-25908fca":1,"chunk-29e7142c":1,"chunk-37401378":1,"chunk-6a68a33e":1,"chunk-73b2dcec":1};c[e]?t.push(c[e]):0!==c[e]&&n[e]&&t.push(c[e]=new Promise(function(t,n){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-009073d4":"0af16c7e","chunk-238a81e9":"e8e2beee","chunk-25908fca":"89ab33e8","chunk-29e7142c":"d10599db","chunk-2d2085ef":"31d6cfe0","chunk-2d22c2e3":"31d6cfe0","chunk-37401378":"a43114f3","chunk-4a59cbe4":"31d6cfe0","chunk-6a68a33e":"3b12267b","chunk-73b2dcec":"99cf6327"}[e]+".css",u=i.p+r,a=document.getElementsByTagName("link"),o=0;o<a.length;o++){var f=a[o],l=f.getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(l===r||l===u))return t()}var d=document.getElementsByTagName("style");for(o=0;o<d.length;o++){f=d[o],l=f.getAttribute("data-href");if(l===r||l===u)return t()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=t,h.onerror=function(t){var r=t&&t.target&&t.target.src||u,a=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");a.code="CSS_CHUNK_LOAD_FAILED",a.request=r,delete c[e],h.parentNode.removeChild(h),n(a)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)t.push(r[2]);else{var a=new Promise(function(t,n){r=u[e]=[t,n]});t.push(r[2]=a);var f,l=document.createElement("script");l.charset="utf-8",l.timeout=120,i.nc&&l.setAttribute("nonce",i.nc),l.src=o(e),f=function(t){l.onerror=l.onload=null,clearTimeout(d);var n=u[e];if(0!==n){if(n){var r=t&&("load"===t.type?"missing":t.type),c=t&&t.target&&t.target.src,a=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");a.type=r,a.request=c,n[1](a)}u[e]=void 0}};var d=setTimeout(function(){f({type:"timeout",target:l})},12e4);l.onerror=l.onload=f,document.head.appendChild(l)}return Promise.all(t)},i.m=e,i.c=r,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i.oe=function(e){throw console.error(e),e};var f=window["webpackJsonp"]=window["webpackJsonp"]||[],l=f.push.bind(f);f.push=t,f=f.slice();for(var d=0;d<f.length;d++)t(f[d]);var h=l;n()})([]);</script><script src=static/js/chunk-elementUI.8ebdfbab.js></script><script src=static/js/chunk-libs.9cf9cc40.js></script><script src=static/js/app.095e8b9c.js></script></body></html>
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.4f0872ef.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function t(t){for(var r,c,a=t[0],i=t[1],f=t[2],l=0,d=[];l<a.length;l++)c=a[l],u[c]&&d.push(u[c][0]),u[c]=0;for(r in i)Object.prototype.hasOwnProperty.call(i,r)&&(e[r]=i[r]);h&&h(t);while(d.length)d.shift()();return o.push.apply(o,f||[]),n()}function n(){for(var e,t=0;t<o.length;t++){for(var n=o[t],r=!0,c=1;c<n.length;c++){var a=n[c];0!==u[a]&&(r=!1)}r&&(o.splice(t--,1),e=i(i.s=n[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return i.p+"static/js/"+({}[e]||e)+"."+{"chunk-009073d4":"28312808","chunk-238a81e9":"5955f13d","chunk-25908fca":"9d8bc0b6","chunk-29e7142c":"994a3ac0","chunk-2d2085ef":"a63a74dc","chunk-2d22c2e3":"4a098244","chunk-37401378":"4e39ec9b","chunk-4a59cbe4":"a6360c68","chunk-6a68a33e":"b6685cb9","chunk-73b2dcec":"14f248eb"}[e]+".js"}function i(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,i),n.l=!0,n.exports}i.e=function(e){var t=[],n={"chunk-009073d4":1,"chunk-238a81e9":1,"chunk-25908fca":1,"chunk-29e7142c":1,"chunk-37401378":1,"chunk-6a68a33e":1,"chunk-73b2dcec":1};c[e]?t.push(c[e]):0!==c[e]&&n[e]&&t.push(c[e]=new Promise(function(t,n){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-009073d4":"0af16c7e","chunk-238a81e9":"e8e2beee","chunk-25908fca":"89ab33e8","chunk-29e7142c":"d10599db","chunk-2d2085ef":"31d6cfe0","chunk-2d22c2e3":"31d6cfe0","chunk-37401378":"a43114f3","chunk-4a59cbe4":"31d6cfe0","chunk-6a68a33e":"3b12267b","chunk-73b2dcec":"99cf6327"}[e]+".css",u=i.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var f=o[a],l=f.getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(l===r||l===u))return t()}var d=document.getElementsByTagName("style");for(a=0;a<d.length;a++){f=d[a],l=f.getAttribute("data-href");if(l===r||l===u)return t()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=t,h.onerror=function(t){var r=t&&t.target&&t.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],h.parentNode.removeChild(h),n(o)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)t.push(r[2]);else{var o=new Promise(function(t,n){r=u[e]=[t,n]});t.push(r[2]=o);var f,l=document.createElement("script");l.charset="utf-8",l.timeout=120,i.nc&&l.setAttribute("nonce",i.nc),l.src=a(e),f=function(t){l.onerror=l.onload=null,clearTimeout(d);var n=u[e];if(0!==n){if(n){var r=t&&("load"===t.type?"missing":t.type),c=t&&t.target&&t.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,n[1](o)}u[e]=void 0}};var d=setTimeout(function(){f({type:"timeout",target:l})},12e4);l.onerror=l.onload=f,document.head.appendChild(l)}return Promise.all(t)},i.m=e,i.c=r,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i.oe=function(e){throw console.error(e),e};var f=window["webpackJsonp"]=window["webpackJsonp"]||[],l=f.push.bind(f);f.push=t,f=f.slice();for(var d=0;d<f.length;d++)t(f[d]);var h=l;n()})([]);</script><script src=static/js/chunk-elementUI.8ebdfbab.js></script><script src=static/js/chunk-libs.9cf9cc40.js></script><script src=static/js/app.095e8b9c.js></script></body></html>

@ -0,0 +1,45 @@
package com.gitee.sop.adminserver;
import com.gitee.sop.adminserver.bean.SopAdminConstants;
import junit.framework.TestCase;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.data.Stat;
public class CuratorTest extends TestCase {
private static String zookeeperServerAddr = "localhost:2181";
static CuratorFramework client;
public CuratorTest() {
client = CuratorFrameworkFactory.builder()
.connectString(zookeeperServerAddr)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
client.start();
}
/**
* 递归删除节点只能在测试环境用
*
* @throws Exception
*/
public void testDel() {
try {
client.delete()
.deletingChildrenIfNeeded()
.forPath(SopAdminConstants.RELOAD_ROUTE_PERMISSION_PATH);
} catch (Exception e) {
}
}
public void testCheck() throws Exception {
String path = SopAdminConstants.RELOAD_ROUTE_PERMISSION_PATH + "/1562231019332";
Stat stat = client.checkExists().forPath(path);
System.out.println(path + (stat == null ? "不存在" : "存在"));
}
}

@ -141,10 +141,6 @@
<el-form-item :label="selfLabel('appKey')">
<span>{{ isvKeysFormData.appKey }}</span>
</el-form-item>
<el-form-item label="签名方式">
<span v-if="isvKeysFormData.signType === 1">RSA</span>
<span v-if="isvKeysFormData.signType === 2">MD5</span>
</el-form-item>
<el-form-item v-show="showKeys()" label="秘钥格式">
<span v-if="isvKeysFormData.keyFormat === 1">PKCS8(JAVA适用)</span>
<span v-if="isvKeysFormData.keyFormat === 2">PKCS1(非JAVA适用)</span>

@ -19,12 +19,6 @@
<el-form-item :label="selfLabel('appKey')">
<div>{{ isvKeysFormData.appKey }}</div>
</el-form-item>
<el-form-item label="签名方式">
<el-radio-group v-model="isvKeysFormData.signType">
<el-radio :label="1" name="status">RSA</el-radio>
<el-radio :label="2" name="status">MD5</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-show="showKeys()" label="秘钥格式">
<el-radio-group v-model="isvKeysFormData.keyFormat">
<el-radio :label="1" name="keyFormat">PKCS8(JAVA适用)</el-radio>

@ -214,8 +214,8 @@
label-width="120px"
size="mini"
>
<el-form-item label="id">
<el-input v-model="authDialogFormData.routeId" readonly="readonly" />
<el-form-item label="路由ID">
<span>{{ authDialogFormData.routeId }}</span>
</el-form-item>
<el-form-item label="角色">
<el-checkbox-group v-model="authDialogFormData.roleCode">

@ -14,5 +14,6 @@ public class IsvRoutePermission {
private String appKey;
private List<String> routeIdList = Collections.emptyList();
private String routeIdListMd5;
private String listenPath;
}

@ -28,15 +28,22 @@ public class ZookeeperContext {
private static CuratorFramework client;
private static Environment environment;
public static void setEnvironment(Environment environment) {
Assert.notNull(environment, "environment不能为null");
initZookeeperClient(environment);
ZookeeperContext.environment = environment;
initZookeeperClient();
}
public synchronized static void initZookeeperClient(Environment environment) {
public synchronized static void initZookeeperClient() {
if (client != null) {
return;
}
setClient(createClient());
}
public static CuratorFramework createClient() {
String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string");
if (StringUtils.isBlank(zookeeperServerAddr)) {
throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数");
@ -51,8 +58,7 @@ public class ZookeeperContext {
.build();
client.start();
setClient(client);
return client;
}
public static String getRouteRootPath() {
@ -100,6 +106,16 @@ public class ZookeeperContext {
.forPath(path, data.getBytes());
}
/**
* 更新节点
* @param path
* @param data
* @throws Exception
*/
public static void updatePath(String path, String data) throws Exception {
getClient().setData().forPath(path, data.getBytes());
}
/**
* 创建path如果path存在不报错静默返回path名称
*

@ -17,7 +17,6 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
@ -129,7 +128,19 @@ public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManage
switch (channelMsg.getOperation()) {
case "reload":
log.info("重新加载路由权限信息,isvRoutePermission:{}", isvRoutePermission);
load();
String listenPath = isvRoutePermission.getListenPath();
String code = "0";
try {
load();
} catch (Exception e) {
log.error("重新加载路由权限失败, channelMsg:{}", channelMsg, e);
code = e.getMessage();
}
try {
ZookeeperContext.updatePath(listenPath, code);
} catch (Exception e1) {
log.error("重新加载路由权限信息, zookeeper操作失败, path: {}", listenPath, e1);
}
break;
case "update":
log.info("更新ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);

Loading…
Cancel
Save