diff --git a/changelog.md b/changelog.md index acbddb8a..33220000 100755 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,9 @@ ## 日常更新 +- 2025-05-11: + - 修复:admin后台发布文档不生效问题 + - 优化:业务服务启动不用依赖网关 - 2025-03-12:优化dubbo filter - 2025-03-09:优先使用本地缓存 - 2025-03-06:RouteContext新增isv对象 diff --git a/sop-admin/sop-admin-backend/admin-service/src/main/java/com/gitee/sop/admin/service/isv/IsvInfoService.java b/sop-admin/sop-admin-backend/admin-service/src/main/java/com/gitee/sop/admin/service/isv/IsvInfoService.java index 271af57e..13041935 100755 --- a/sop-admin/sop-admin-backend/admin-service/src/main/java/com/gitee/sop/admin/service/isv/IsvInfoService.java +++ b/sop-admin/sop-admin-backend/admin-service/src/main/java/com/gitee/sop/admin/service/isv/IsvInfoService.java @@ -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 { * @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 { 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 { * @param statusUpdateDTO 修改值 * @return 返回影响行数 */ + @Transactional(rollbackFor = Exception.class) public int updateStatus(StatusUpdateDTO statusUpdateDTO) { Long isvId = statusUpdateDTO.getId(); int cnt = this.query() diff --git a/sop-admin/sop-admin-backend/admin-service/src/main/java/com/gitee/sop/admin/service/isv/IsvKeysService.java b/sop-admin/sop-admin-backend/admin-service/src/main/java/com/gitee/sop/admin/service/isv/IsvKeysService.java index 539b62f6..3300966a 100755 --- a/sop-admin/sop-admin-backend/admin-service/src/main/java/com/gitee/sop/admin/service/isv/IsvKeysService.java +++ b/sop-admin/sop-admin-backend/admin-service/src/main/java/com/gitee/sop/admin/service/isv/IsvKeysService.java @@ -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 { + @Transactional(rollbackFor = Exception.class) public int saveKeys(IsvInfoUpdateKeysDTO isvInfoUpdateKeysDTO) { IsvKeys isvKeys = this.get(IsvKeys::getIsvId, isvInfoUpdateKeysDTO.getIsvId()); if (isvKeys == null) { diff --git a/sop-admin/sop-admin-frontend/src/views/doc/list/index.ts b/sop-admin/sop-admin-frontend/src/views/doc/list/index.ts index ec50167d..648bffd5 100755 --- a/sop-admin/sop-admin-frontend/src/views/doc/list/index.ts +++ b/sop-admin/sop-admin-frontend/src/views/doc/list/index.ts @@ -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("保存成功"); diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/service/dubbo/ApiRegisterServiceImpl.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/service/dubbo/ApiRegisterServiceImpl.java index 00fdb90a..e7f3799e 100755 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/service/dubbo/ApiRegisterServiceImpl.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/service/dubbo/ApiRegisterServiceImpl.java @@ -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 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() + "]应用中.必须保证接口全局唯一"); diff --git a/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegException.java b/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegException.java new file mode 100644 index 00000000..0e787b7b --- /dev/null +++ b/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegException.java @@ -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 registerDTOS; + + public ApiRegException(Exception e, List registerDTOS) { + super(e); + this.registerDTOS = registerDTOS; + } + + public List getRegisterDTOS() { + return registerDTOS; + } +} diff --git a/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegister.java b/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegister.java index 40aa352c..f48cbeaf 100755 --- a/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegister.java +++ b/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegister.java @@ -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 objects) { + public void reg(String appName, Collection objects) throws ApiRegException { if (objects == null || objects.isEmpty()) { return; } + List 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 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 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 paramInfos = buildParamInfo(method); diff --git a/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegisterRunner.java b/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegisterRunner.java new file mode 100644 index 00000000..930b1743 --- /dev/null +++ b/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/register/ApiRegisterRunner.java @@ -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 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 registerDTOS) { + try { + apiRegister.reg(registerDTOS); + // 注册成功 + scheduledExecutorService.shutdown(); + } catch (Exception e) { + log.warn("注册接口失败,{}秒后进行重试", PERIOD, e); + } + } + + @AllArgsConstructor + @Data + static class RetryContext { + String appName; + Collection objects; + } +} diff --git a/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/service/ApiRegisterService.java b/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/service/ApiRegisterService.java index eaeb680a..4b40d44d 100755 --- a/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/service/ApiRegisterService.java +++ b/sop-support/sop-service-support/src/main/java/com/gitee/sop/support/service/ApiRegisterService.java @@ -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 registerDTOS); } diff --git a/sop-support/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/springboot/config/SopAutoConfiguration.java b/sop-support/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/springboot/config/SopAutoConfiguration.java index 3909f23f..9813cfd6 100755 --- a/sop-support/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/springboot/config/SopAutoConfiguration.java +++ b/sop-support/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/springboot/config/SopAutoConfiguration.java @@ -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 beanMap = applicationContext.getBeansWithAnnotation(DubboService.class); - new ApiRegister(apiRegisterService).reg(appName, beanMap.values()); + // 注册接口 + ApiRegisterRunner.reg(appName, apiRegisterService, beanMap.values()); + // 初始化国际化 + OpenMessageFactory.initMessage(); }