背景

前端有些内容需要固定传值,如逻辑实体Logic Entity(ODS表位置)对应的命名空间Name Space、业务对象Business Object;默认的展示场景Scene等信息。

每次封装一个controller接口,较为复杂;而这些内容在后端也是通过Nacos配置的,思考可以通过读取Nacos配置,开发一个通用的接口。

思路

注入Nacos的ConfigService,调用String getConfig(String dataId, String group, long timeoutMs),可以获得配置的内容,以字符串呈现;

通过org.yaml.snakeyaml.Yaml解析字符串,便可以取出对应的值;

其中,dataId对应bootstrap.yml配置中的spring.application.name;group对应bootstrap.yml配置中的spring.cloud.nacos.config.group,如:group: ${NACOS_GROUP:DEFAULT_GROUP}

实现

controller

package com.gemenyaofei.xx.metadata.client;

import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.gemenyaofei.xx.client.base.dto.Result;
import com.gemenyaofei.xx.domain.common.exception.MetadataException;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.yaml.snakeyaml.Yaml;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * @description:
 * @author: gemenyaofei
 * @create: 2023/12/19
 */
@RestController
@RequestMapping("/metadata/config")
@Api(tags = "[元数据管理]配置查询")
@Slf4j
public class ConfigQueryController { // todo 可以更新为通过service/工具类方式
    @Autowired
    private ConfigService configService;

    private final String DEFAULT_DATA_ID = "data-xx-platform.yaml";
    private final String IGNORE_DATA_ID = "data-xx-platform";
    private final String DEFAULT_GROUP = "DEFAULT_GROUP";
    private final String DEV_GROUP = "xx";


    @Deprecated
    @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
    @ApiOperation(value = "Get/Post方式查询Naocs配置")
    public Result<Object> queryConfig(@RequestBody List<String> items) throws NacosException, IOException {
        return getObjectResult(items);
    }

    private Result<Object> getObjectResult(@RequestBody List<String> items) throws NacosException {
        Map<String, Object> result = Maps.newHashMap();
        String config = Stream.of(configService.getConfig(DEFAULT_DATA_ID, DEV_GROUP, 2000),  // 默认dev的
                        configService.getConfig(IGNORE_DATA_ID, DEV_GROUP, 2000),
                        configService.getConfig(DEFAULT_DATA_ID, DEFAULT_GROUP, 2000),
                        configService.getConfig(IGNORE_DATA_ID, DEFAULT_GROUP, 2000)).filter(Objects::nonNull)
                .findFirst().orElseThrow(() -> new MetadataException("Nacos配置有问题,请联系后端调整代码"));
        Map<String, Object> yamlMap = parseConfig(config);
        items.stream().forEach(item -> result.putIfAbsent(item, getValueFromYaml(item, yamlMap)));
        return Result.success(result);
    }

    private static Map<String, Object> parseConfig(String content) {
        Yaml yaml = new Yaml();
        return yaml.load(content);
    }

    private static Object getValueFromYaml(String propertyPath, Map<String, Object> yamlMap) {
        String[] pathSegments = propertyPath.split("\\.");
        Map<String, Object> currentMap = yamlMap;
        for (int i = 0; i < pathSegments.length - 1; i++) {
            currentMap = (Map<String, Object>) currentMap.get(pathSegments[i]);
        }
        return handleType(currentMap.get(pathSegments[pathSegments.length - 1]));
    }

    @Deprecated // 使用Spring mvc的MvcConfig做转换
    private static Object handleType(Object o) {
        return o;
    }
}

调用

POST {{url}}/metadata/config
Content-Type:application/json
Cookie:{{Cookie}}

["assetConfig.er.namespaceId", "assetConfig.er.namespaceCode"]

响应

{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "assetConfig.er.namespaceCode": "ods",
        "assetConfig.er.namespaceId": "1056752105528512512"
    }
}