package com.vci.ubcs.omd.repeater; import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosServiceManager; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.ServiceInfo; import com.vci.ubcs.common.constant.LauncherConstant; import com.vci.ubcs.omd.dto.BtmAndLinkTypeDdlDTO; import com.vci.ubcs.omd.vo.BtmTypeVO; import com.vci.ubcs.omd.vo.LinkTypeVO; import org.springblade.core.launch.constant.AppConstant; import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.tool.api.R; import org.springblade.core.tool.utils.StringPool; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.*; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import javax.annotation.PostConstruct; import java.util.*; import java.util.stream.Collectors; /** * Description: 领域转发器 * * @author LiHang * @date 2023/4/25 */ @Component public class DomainRepeater { /** * 控制器路径 */ public static final String API_PREFIX = "ddl"; /** * 新增或修改的转发路径名称 */ public static final String API_SUBMIT = API_PREFIX + StringPool.SLASH + "submit"; /** * 表名获取表信息 */ public static final String API_GET_TABLE_INFO = API_PREFIX + StringPool.SLASH + "getTableColumnByTableName"; /** * 获取全部表信息 */ public static final String API_GET_ALL_TABLE_INFO = API_PREFIX + StringPool.SLASH + "getAllTableInfo"; /** * 获取数据库和业务类型中的不同的地方 */ public static final String API_CHECK_DIFFERENT_REFLEX = API_PREFIX + StringPool.SLASH + "checkDifferentAndReflex"; /** * 用于构建静态服务类 */ public static DomainRepeater domainRepeater; /** * Nacos服务列表 */ private static NamingService namingService; @Autowired private NacosServiceManager manager; @Autowired private NacosDiscoveryProperties properties; /** * 拿取服务中的所有表信息 * @param serviceName 服务名称 * @return 返回结果 * @throws NacosException 找不到服务时抛出异常 */ public static R getFromTable(String serviceName) throws NacosException{ ResponseEntity responseEntity = executeGet(getUrl(serviceName, API_GET_ALL_TABLE_INFO), new HashMap<>()); if (responseEntity.getStatusCode().equals(HttpStatus.OK)) { R body = Objects.requireNonNull(responseEntity.getBody()); return body; } return R.fail(String.valueOf(responseEntity.getStatusCode().value())); } @PostConstruct private void init() { domainRepeater = this; namingService = manager.getNamingService(properties.getNacosProperties()); } /** * 一致性检查 * @param ddlDTO 业务类型、链接类型传输对象 * @param serviceName 服务名 * @return 执行结果,有修改的就会返回。 * @throws NacosException nacos查询服务出错时抛出异常 */ public static R checkDifferent(BtmAndLinkTypeDdlDTO ddlDTO,String serviceName) throws NacosException { try { String url = getUrl(serviceName, API_CHECK_DIFFERENT_REFLEX); ResponseEntity responseEntity = executePost(url, JSONObject.toJSONString(ddlDTO), null); if (responseEntity.getStatusCode().equals(HttpStatus.OK)) { R body = Objects.requireNonNull(responseEntity.getBody()); return body; } return R.fail(String.valueOf(responseEntity.getStatusCode().value())); }catch (HttpClientErrorException e) { if (HttpStatus.NOT_FOUND.equals(e.getStatusCode())) { R fail = R.fail("调用服务失败"); fail.setCode(HttpStatus.NOT_FOUND.value()); return fail; } } catch (Exception e) { throw new RuntimeException(e); } return R.fail("未知错误"); } /** * 根据api接口拼接url地址 * @param serviceName 服务名 * @param api 接口地址 * @return url地址 * @throws NacosException nacos查询服务出错时抛出异常 */ public static String getUrl(String serviceName,String api) throws NacosException { Instance service = namingService.selectOneHealthyInstance(AppConstant.APPLICATION_GATEWAY_NAME); return "http://" + service.getIp() + StringPool.COLON + service.getPort() + StringPool.SLASH + serviceName + StringPool.SLASH + api; } /** * 新增或修改业务类型 * @param vo 业务类型传输对象 * @param serviceName 服务名 * @return 执行结果,有修改的就会返回。 */ public static R submitBtmType(String serviceName, BtmTypeVO vo) { try { String url = getUrl(serviceName, API_SUBMIT); BtmAndLinkTypeDdlDTO ddlDTO = new BtmAndLinkTypeDdlDTO(); ddlDTO.setBtmTypeList(new ArrayList<>(Collections.singletonList(vo))); ResponseEntity responseEntity = executePost(url, JSONObject.toJSONString(ddlDTO), null); if (responseEntity.getStatusCode().equals(HttpStatus.OK)) { return responseEntity.getBody(); } return R.fail(String.valueOf(responseEntity.getStatusCode().value())); } catch (HttpClientErrorException e) { if (HttpStatus.NOT_FOUND.equals(e.getStatusCode())) { R fail = R.fail("调用服务失败"); fail.setCode(HttpStatus.NOT_FOUND.value()); return fail; } } catch (Exception e) { throw new RuntimeException(e); } return R.fail("未知错误"); } /** * 新增或修改链接类型 * @param vo 业务类型传输对象 * @param serviceName 服务名 * @return 执行结果,有修改的就会返回。 */ public static R submitLinkType(String serviceName, LinkTypeVO vo) { try { String url = getUrl(serviceName, API_SUBMIT); BtmAndLinkTypeDdlDTO ddlDTO = new BtmAndLinkTypeDdlDTO(); ddlDTO.setLinkTypeList(new ArrayList<>(Collections.singletonList(vo))); ResponseEntity responseEntity = executePost(url, JSONObject.toJSONString(ddlDTO), null); if (responseEntity.getStatusCode().equals(HttpStatus.OK)) { return responseEntity.getBody(); } return R.fail(String.valueOf(responseEntity.getStatusCode().value())); } catch (HttpClientErrorException e) { if (HttpStatus.NOT_FOUND.equals(e.getStatusCode())) { R fail = R.fail("调用服务失败"); fail.setCode(HttpStatus.NOT_FOUND.value()); return fail; } } catch (Exception e) { throw new RuntimeException(e); } return R.fail("未知错误"); } /** * 执行httpPost接口 * * @param url 地址 * @param body 请求体 * @param extraHeaders 请求头参数 * @return 执行结果 */ private static ResponseEntity executePost(String url, String body, Map extraHeaders) { RestTemplate restTemplate = new RestTemplate(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Content-Type", "application/json;charset=UTF-8"); httpHeaders.add("Blade-Auth", AuthUtil.getHeader()); Optional.ofNullable(extraHeaders).orElseGet(HashMap::new).forEach(httpHeaders::add); HttpEntity request = new HttpEntity<>(body, httpHeaders); return restTemplate.postForEntity(url, request, R.class); } /** * 执行httpGet接口 * * @param url 地址 * @param extraHeaders 请求头参数 * @return 执行结果 */ private static ResponseEntity executeGet(String url,Map extraHeaders) { RestTemplate restTemplate = new RestTemplate(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Blade-Auth", AuthUtil.getHeader()); HttpEntity request = new HttpEntity<>(httpHeaders); if (!CollectionUtils.isEmpty(extraHeaders)){ StringBuilder sb = new StringBuilder().append("?"); extraHeaders.forEach( (k,v) -> { sb.append(k).append(StringPool.EQUALS).append(v).append(StringPool.AMPERSAND); }); String str = sb.toString(); if (str.endsWith(StringPool.AMPERSAND)){ str = str.substring(0,str.length()-1); } url = url + str; } return restTemplate.exchange(url, HttpMethod.GET,request,R.class,""); } /** * 获取所有已注册的服务 * @return 不包含默认服务的其他服务 * @throws NacosException */ public static List getDomain() throws NacosException { RestTemplate restTemplate = new RestTemplate(); String url = "http://" +LauncherConstant.NACOS_DEV_ADDR + "/nacos/v1/ns/service/list?pageNo=1&pageSize=50"; String forObject = restTemplate.getForObject(url, String.class); JSONObject jsonObject = JSON.parseObject(forObject); return (List) jsonObject.get("doms"); } }