修复admin后台发布文档不生效问题;业务服务启动不用依赖网关

This commit is contained in:
六如
2025-05-11 17:40:00 +08:00
parent d3d0eb4b1b
commit a162db3354
10 changed files with 183 additions and 33 deletions

View File

@@ -2,6 +2,9 @@
## 日常更新
- 2025-05-11
- 修复admin后台发布文档不生效问题
- 优化:业务服务启动不用依赖网关
- 2025-03-12优化dubbo filter
- 2025-03-09优先使用本地缓存
- 2025-03-06RouteContext新增isv对象

View File

@@ -22,6 +22,7 @@ import com.gitee.sop.admin.service.isv.event.ChangeIsvInfoEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.text.SimpleDateFormat;
@@ -96,6 +97,7 @@ public class IsvInfoService implements ServiceSupport<IsvInfo, IsvInfoMapper> {
* @param isvInfoAddDTO
* @return 返回id
*/
@Transactional(rollbackFor = Exception.class)
public long add(IsvInfoAddDTO isvInfoAddDTO) {
IsvInfo rec = CopyUtil.copyBean(isvInfoAddDTO, IsvInfo::new);
String appKey = new SimpleDateFormat("yyyyMMdd").format(new Date()) + IdGen.nextId();
@@ -106,6 +108,7 @@ public class IsvInfoService implements ServiceSupport<IsvInfo, IsvInfoMapper> {
return rec.getId();
}
@Transactional(rollbackFor = Exception.class)
public int update(IsvInfoUpdateDTO isvInfoUpdateDTO) {
IsvInfo isvInfo = new IsvInfo();
isvInfo.setId(isvInfoUpdateDTO.getId());
@@ -147,6 +150,7 @@ public class IsvInfoService implements ServiceSupport<IsvInfo, IsvInfoMapper> {
* @param statusUpdateDTO 修改值
* @return 返回影响行数
*/
@Transactional(rollbackFor = Exception.class)
public int updateStatus(StatusUpdateDTO statusUpdateDTO) {
Long isvId = statusUpdateDTO.getId();
int cnt = this.query()

View File

@@ -8,6 +8,7 @@ import com.gitee.sop.admin.dao.mapper.IsvKeysMapper;
import com.gitee.sop.admin.service.isv.dto.IsvInfoUpdateKeysDTO;
import com.gitee.sop.admin.service.isv.event.ChangeIsvKeyEvent;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
@@ -18,6 +19,7 @@ import java.util.Collections;
@Service
public class IsvKeysService implements ServiceSupport<IsvKeys, IsvKeysMapper> {
@Transactional(rollbackFor = Exception.class)
public int saveKeys(IsvInfoUpdateKeysDTO isvInfoUpdateKeysDTO) {
IsvKeys isvKeys = this.get(IsvKeys::getIsvId, isvInfoUpdateKeysDTO.getIsvId());
if (isvKeys == null) {

View File

@@ -133,7 +133,7 @@ export function useDocList() {
onConfirm(params: ButtonsCallBackParams) {
const data = {
id: params.row.id,
isPublish: params.row.isPublish === 1 ? 0 : 1
isPublish: 1
};
api.publish(data).then(() => {
ElMessage.success("保存成功");

View File

@@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collection;
import java.util.Objects;
/**
@@ -31,33 +32,38 @@ public class ApiRegisterServiceImpl implements ApiRegisterService {
private ApiInfoMapper apiInfoMapper;
@Override
public RegisterResult register(RegisterDTO registerDTO) {
log.info("收到接口注册, registerDTO={}", registerDTO);
public RegisterResult register(Collection<RegisterDTO> registerDTOS) {
try {
ApiInfoDTO apiInfoDTO = CopyUtil.copyBean(registerDTO, ApiInfoDTO::new);
apiInfoDTO.setStatus(StatusEnum.ENABLE.getValue());
ApiInfo apiInfo = apiInfoMapper.getByNameVersion(apiInfoDTO.getApiName(), apiInfoDTO.getApiVersion());
if (apiInfo == null) {
apiInfo = new ApiInfo();
} else {
check(apiInfo, registerDTO);
for (RegisterDTO registerDTO : registerDTOS) {
log.info("注册开放接口, registerDTO={}", registerDTO);
this.doReg(registerDTO);
}
CopyUtil.copyPropertiesIgnoreNull(apiInfoDTO, apiInfo);
apiInfo.setRegSource(REG_SOURCE_SYS);
// 保存到数据库
apiInfoMapper.saveOrUpdateIgnoreNull(apiInfo, data -> data.getId() != null);
apiInfoDTO.setId(apiInfo.getId());
// 保存到缓存
apiManager.save(apiInfoDTO);
return RegisterResult.success();
} catch (Exception e) {
log.error("接口注册失败, registerDTO={}", registerDTO, e);
log.error("接口注册失败", e);
return RegisterResult.error(e.getMessage());
}
}
private void doReg(RegisterDTO registerDTO) {
ApiInfoDTO apiInfoDTO = CopyUtil.copyBean(registerDTO, ApiInfoDTO::new);
apiInfoDTO.setStatus(StatusEnum.ENABLE.getValue());
ApiInfo apiInfo = apiInfoMapper.getByNameVersion(apiInfoDTO.getApiName(), apiInfoDTO.getApiVersion());
if (apiInfo == null) {
apiInfo = new ApiInfo();
} else {
check(apiInfo, registerDTO);
}
CopyUtil.copyPropertiesIgnoreNull(apiInfoDTO, apiInfo);
apiInfo.setRegSource(REG_SOURCE_SYS);
// 保存到数据库
apiInfoMapper.saveOrUpdateIgnoreNull(apiInfo, data -> data.getId() != null);
apiInfoDTO.setId(apiInfo.getId());
// 保存到缓存
apiManager.save(apiInfoDTO);
}
private void check(ApiInfo apiInfo, RegisterDTO registerDTO) {
if (!Objects.equals(apiInfo.getApplication(), registerDTO.getApplication())) {
throw new RuntimeException("接口[" + registerDTO + "]已存在于[" + apiInfo.getApplication() + "]应用中.必须保证接口全局唯一");

View File

@@ -0,0 +1,23 @@
package com.gitee.sop.support.register;
import com.gitee.sop.support.service.dto.RegisterDTO;
import java.util.List;
/**
* @author 六如
*/
public class ApiRegException extends Exception {
private static final long serialVersionUID = 241480223796854916L;
private final List<RegisterDTO> registerDTOS;
public ApiRegException(Exception e, List<RegisterDTO> registerDTOS) {
super(e);
this.registerDTOS = registerDTOS;
}
public List<RegisterDTO> getRegisterDTOS() {
return registerDTOS;
}
}

View File

@@ -4,7 +4,6 @@ import com.alibaba.fastjson2.JSON;
import com.gitee.sop.support.annotation.Open;
import com.gitee.sop.support.annotation.OpenGroup;
import com.gitee.sop.support.enums.ApiModeEnum;
import com.gitee.sop.support.message.OpenMessageFactory;
import com.gitee.sop.support.service.ApiRegisterService;
import com.gitee.sop.support.service.dto.RegisterDTO;
import com.gitee.sop.support.service.dto.RegisterResult;
@@ -12,7 +11,6 @@ import lombok.Data;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.util.StringUtils;
import java.io.Serializable;
@@ -20,6 +18,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -37,11 +36,6 @@ public class ApiRegister {
private static final Log LOG = LogFactory.getLog(ApiRegister.class);
/**
* Spring自带的参数提取工具类
*/
private static final DefaultParameterNameDiscoverer DISCOVERER = new DefaultParameterNameDiscoverer();
private final ApiRegisterService apiRegisterService;
@@ -49,18 +43,43 @@ public class ApiRegister {
this.apiRegisterService = apiRegisterService;
}
public void reg(String appName, Collection<Object> objects) {
public void reg(String appName, Collection<Object> objects) throws ApiRegException {
if (objects == null || objects.isEmpty()) {
return;
}
List<RegisterDTO> registerDTOS = new ArrayList<>();
for (Object serviceObj : objects) {
Class<?> objClass = serviceObj.getClass();
doWithMethod(objClass, (interfaceClass, method, open) ->
this.regApi(appName, interfaceClass, method, open));
{
RegisterDTO registerDTO = this.buildRegisterDTO(appName, interfaceClass, method, open);
registerDTOS.add(registerDTO);
});
}
OpenMessageFactory.initMessage();
reg(registerDTOS);
}
public void reg(List<RegisterDTO> registerDTOS) throws ApiRegException {
if (registerDTOS.isEmpty()) {
return;
}
LOG.info(">>> 开始注册开放接口");
try {
RegisterResult result = apiRegisterService.register(registerDTOS);
if (result.getSuccess()) {
LOG.info(">>> 开放接口注册成功,接口数量:" + registerDTOS.size());
for (RegisterDTO registerDTO : registerDTOS) {
LOG.info(registerDTO);
}
} else {
LOG.error(">>> 开放接口注册失败,网关处理异常:" + result.getMsg());
throw new RuntimeException(result.getMsg());
}
} catch (Exception e) {
throw new ApiRegException(e, registerDTOS);
}
}
protected void doWithMethod(Class<?> objClass, RegisterCallback callback) {
@@ -110,6 +129,23 @@ public class ApiRegister {
cache.clear();
}
private RegisterDTO buildRegisterDTO(String appName, Class<?> interfaceClass, Method method, Open open) {
List<ParamInfo> paramInfos = buildParamInfo(method);
RegisterDTO registerDTO = new RegisterDTO();
registerDTO.setApplication(appName);
registerDTO.setApiName(getApiName(interfaceClass, open));
registerDTO.setApiVersion(open.version());
registerDTO.setInterfaceClassName(interfaceClass.getName());
registerDTO.setMethodName(method.getName());
registerDTO.setParamInfo(JSON.toJSONString(paramInfos));
registerDTO.setIsPermission(parseBoolean(open.permission()));
registerDTO.setIsNeedToken(parseBoolean(open.needToken()));
registerDTO.setHasCommonResponse(parseBoolean(open.hasCommonResponse()));
OpenGroup openGroup = interfaceClass.getAnnotation(OpenGroup.class);
ApiModeEnum apiMode = openGroup == null ? ApiModeEnum.OPEN : ApiModeEnum.RESTFUL;
registerDTO.setApiMode(apiMode.getValue());
return registerDTO;
}
private void regApi(String appName, Class<?> interfaceClass, Method method, Open open) {
List<ParamInfo> paramInfos = buildParamInfo(method);

View File

@@ -0,0 +1,60 @@
package com.gitee.sop.support.register;
import com.gitee.sop.support.service.ApiRegisterService;
import com.gitee.sop.support.service.dto.RegisterDTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author 六如
*/
@Slf4j
public class ApiRegisterRunner {
private static ApiRegister apiRegister = null;
private static ScheduledExecutorService scheduledExecutorService;
private static final int PERIOD = 5;
public static void reg(
String appName,
ApiRegisterService apiRegisterService,
Collection<Object> objects
) {
if (apiRegister == null) {
apiRegister = new ApiRegister(apiRegisterService);
}
try {
apiRegister.reg(appName, objects);
} catch (ApiRegException e) {
log.warn("注册接口失败,{}秒后进行重试", PERIOD, e);
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(() -> retry(e.getRegisterDTOS()), PERIOD, PERIOD, TimeUnit.SECONDS);
}
}
private static void retry(List<RegisterDTO> registerDTOS) {
try {
apiRegister.reg(registerDTOS);
// 注册成功
scheduledExecutorService.shutdown();
} catch (Exception e) {
log.warn("注册接口失败,{}秒后进行重试", PERIOD, e);
}
}
@AllArgsConstructor
@Data
static class RetryContext {
String appName;
Collection<Object> objects;
}
}

View File

@@ -3,6 +3,9 @@ package com.gitee.sop.support.service;
import com.gitee.sop.support.service.dto.RegisterDTO;
import com.gitee.sop.support.service.dto.RegisterResult;
import java.util.Collection;
import java.util.Collections;
/**
* @author 六如
*/
@@ -12,5 +15,14 @@ public interface ApiRegisterService {
*
* @param registerDTO 接口信息
*/
RegisterResult register(RegisterDTO registerDTO);
default RegisterResult register(RegisterDTO registerDTO) {
return register(Collections.singletonList(registerDTO));
}
/**
* 接口注册批量
*
* @param registerDTOS 接口信息
*/
RegisterResult register(Collection<RegisterDTO> registerDTOS);
}

View File

@@ -1,6 +1,7 @@
package com.gitee.sop.support.springboot.config;
import com.gitee.sop.support.register.ApiRegister;
import com.gitee.sop.support.message.OpenMessageFactory;
import com.gitee.sop.support.register.ApiRegisterRunner;
import com.gitee.sop.support.service.ApiRegisterService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
@@ -34,7 +35,10 @@ public class SopAutoConfiguration implements InitializingBean {
public void afterPropertiesSet() throws Exception {
String appName = environment.getProperty("spring.application.name");
Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(DubboService.class);
new ApiRegister(apiRegisterService).reg(appName, beanMap.values());
// 注册接口
ApiRegisterRunner.reg(appName, apiRegisterService, beanMap.values());
// 初始化国际化
OpenMessageFactory.initMessage();
}