(十三)Alian 的 Spring Cloud 生成接口调用(swagger codegen)

一、简介

  OpenAPI规范(OAS)为RESTful API定义了一个与语言无关的标准接口,使人类和计算机都可以发现和理解服务的功能,而无需访问源代码,文档或通过网络流量检查。Swagger CodeGen是一个REST 客户端生成工具,它可以从OpenAPI的规范定义文件中生成对应的REST Client代码。Spring Boot中使用Swagger CodeGen生成REST Client,然后打包发布后,即可供其他服务进行调用了。程序中处理的大致流程如下:

  • 获取指定服务的swagger文档定义(即得到api.json)
  • 通过swagger-codegen-cli的generate命令生成接口调用
  • 根据插件org.apache.maven.plugins:maven-dependency-plugin获取依赖关系
  • 发布到私服,比如nexus
  • 引用依赖并发起调用

二、Swagger Codegen

2.1、swagger-codegen-cli

  swagger-codegen-cli使用语法及说明如下:

java -jar SwaggerJarPath generate 
--library LIBRARY
-l LANGUAGE 
-i INPUTSPEC 
--output OUTPUT-DIR 
--api-package API-PACkAGE 
--model-package MODEL-PACKAGE 
--group-id GROUP-ID 
--artifact-id ARTIFACT-ID 
--artifact-version ARTIFACT-VERSION  
-t TEMPLATE-DIR
--import-mappings org.threeten.bp.OffsetDateTime=java.util.Date 
--type-mappings OffsetDateTime=Date 
  • –library:指定了实际的实现框架,比如resttemplate
  • -l :指定生成代码的变成语言,比如java
  • -i:指定了open api 定义文件的地址
  • –output:指定生成文件的目录
  • –api-package:指定api接口生成的目录,比如:cn.alian.stock.api
  • –model-package:指定model生成的目录,比如:cn.alian.stock.model
  • –group-id:指定生成的maven项目的group-id,比如:cn.alian.mall
  • –artifact-id:指定生成的maven项目的artifact-id,比如:stock
  • –artifact-version:指定生成的maven项目的version,比如:1.0.0-SNAPSHOT
  • -t:指定生成文件使用到的模板文件
  • –import-mappings:指定类型使用指定的方式进行处理
  • –type-mappings:指定swagger中规范类型和生成代码类型中的映射

  更多内容可以通过命令查看:

java -jar swagger-codegen-cli.jar help generate

2.2、获取依赖关系

mvn org.apache.maven.plugins:maven-dependency-plugin:3.2.0:get 
-Dartifact=ARCHETYPE-GROUP-ID:ARCHETYPE-ARTIFACT-ID:ARCHETYPE-VERSION:POM 
-DremoteRepositories=REMOTE-REPOSITORIES

上面的语法有四变量如下:

  • ARCHETYPE-GROUP-ID
  • ARCHETYPE-ARTIFACT-ID
  • ARCHETYPE-VERSION
  • REMOTE-REPOSITORIES

  使用示例如下:

mvn org.apache.maven.plugins:maven-dependency-plugin:RELEASE:get 
-Dartifact=cn.alian.microservice:alian-archetype-project:1.0.0-SNAPSHOT 
-DremoteRepositories=http://192.168.0.210:8081/nexus/content/groups/public

2.3、发布到私服

mvn -f  OUTPUTAPIDIR clean source:jar deploy -Dmaven.test.skip=true"

  其中OUTPUTAPIDIR 就是要打包发布的目录

三、项目整合

  其实有上述三个命令,我们就可以通过程序来实现,当然你手动调用或者通过bat也是没有问题的。

  • 生成接口调用
  • 打包发布到私服
  • 引用依赖即可

  继续改进我们的文档中心服务,增加生成API调用的接口,数据库配置如下:

在这里插入图片描述

3.1、属性配置

AppProperties.java

package cn.alian.microservice.doc.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;

@Data
@RefreshScope
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private String mvn;

    private String swaggerTemplatePath;

    private String swaggerJarPath;

    private String configUri;

    private String remoteRepositories;

    private String tmpDir;

    private Gav domain;

    private Gav project;

    @Data
    public static class Gav{
        private String groupId;
        private String artifactId;
        private String version;
        private String packaging;
    }
}

  具体的配置值,在我上面的截图里都有。不要后面用到的时候,这个参数是什么,这些都是在配置中心配置的。

3.2、控制层

GenerateApiController.java

@Slf4j
@RequestMapping("api/v1/client")
@Api(description = "生成调用客户端")
@RestController
public class GenerateApiController {

    @Autowired
    private GenerateApiService generateApiService;

    @ApiOperation(value = "生成web调用客户端", notes = "生成web调用客户端")
    @GetMapping(value = "/generateWebApi")
    public synchronized Object generateWebApi(
            @ApiParam(value = "应用接口的json文档地址", example = "http://10.130.3.222:9999/doc-service/service/stock-10.130.3.88-8001") @RequestParam() @NotBlank String appDocUrl,
            @ApiParam(value = "生成api客户端类型,objc、android、typescript-fetch", example = "typescript-fetch") @RequestParam() @NotBlank String apiType,
            @ApiParam(value = "调用类型,1:直连服务调用,2:经网关调用,在映射上添加应用名") @RequestParam @NotNull @Pattern(regexp = "1 | 2") String invokeType) throws Exception {
        if (StringUtils.isBlank(appDocUrl)) {
            return ApiResponseDto.fail("应用接口的json文档地址不能为空");
        }
        if (!ArrayUtils.contains(new String[]{"objc", "android", "typescript-fetch"}, apiType)) {
            return ApiResponseDto.fail("暂只支持objc、android、typescript-fetch三种方式");
        }
        return generateApiService.generateWebApi(appDocUrl, apiType, invokeType);
    }

    @ApiOperation(value = "生成java调用客户端", notes = "生成java调用客户端")
    @GetMapping(value = "/generateJavaApi")
    public synchronized Object generateJavaApi(
            @ApiParam(value = "应用接口的json文档地址", example = "http://10.130.3.222:9999/doc-service/service/stock-10.130.3.88-8001") @RequestParam @NotBlank String appDocUrl,
            @ApiParam(value = "生成api客户端类型,spring-cloud、resttemplate,默认spring-cloud", example = "spring-cloud") @RequestParam @NotBlank String apiType) throws Exception {
        if (StringUtils.isBlank(appDocUrl)) {
            return ApiResponseDto.fail("应用接口的json文档地址不能为空");
        }
        if (!ArrayUtils.contains(new String[]{"spring-cloud", "resttemplate"}, apiType)) {
            return ApiResponseDto.fail("暂只支持spring-cloud、resttemplate两种方式");
        }
        Pair<Boolean, String> pair = generateApiService.generateJavaApi(appDocUrl, apiType);
        if (pair.getLeft()) {
            return ApiResponseDto.success(pair.getRight());
        }
        return ApiResponseDto.fail(pair.getRight());
    }

}

  这里提供了两个接口,一个生成web端调用的接口,一个生成java端调用的接口。这两个接口差不多,但是为了区分,我就没有合并为一个了,这样大家更加容易看懂,主要参数有:

  • swagger应用接口的json文档地址
  • 需要生成api客户端类型,比如spring-cloud、resttemplate或者其他
  • 调用的方式,直接调用,还是经网关调用

3.3、生成api的服务层

GenerateApiService.java

@Slf4j
@Service
public class GenerateApiService extends BaseService {

    @Autowired
    private AppProperties appProperties;

    public Object generateWebApi(String appDocUrl, String apiType, String invokeType) {
        try {
            //获取swagger文档定义json
            String json = getSwaggerByAppDocUrl(appDocUrl);
            Swagger swagger = JSON.parseObject(json, Swagger.class);
            if (swagger == null) {
                return ApiResponseDto.fail("未获取到文档定义内容");
            }
            Swagger.Info info = swagger.getInfo();
            //网关调用时增加应用名
            if ("01".equals(invokeType)) {
                JSONObject jsonObject = JSON.parseObject(json, Feature.DisableSpecialKeyDetect);
                JSONObject paths = (JSONObject) jsonObject.remove("paths");
                Map<String, Object> newPaths = paths.entrySet().stream().map(e -> Pair.of("/" + info.getAppName() + e.getKey(), e.getValue())).collect(Collectors.toMap(Pair::getLeft, Pair::getValue));
                JSONObject pathJson = new JSONObject(newPaths);
                jsonObject.put("paths", pathJson);
                json = JSON.toJSONString(jsonObject);
                log.info("更新后的 json is {}", json);
            }
            //接口生成目录
            String outputDir = appProperties.getTmpDir() + File.separator + "webApi" + System.currentTimeMillis();
            log.info("webApi接口生成目录:{}", outputDir);
            //要输出的api.json
            String outputJson = outputDir + File.separator + "api.json";
            log.info("api.json生成目录:{}", outputJson);
            // 获取的json写入到文件
            FileUtils.writeStringToFile(new File(outputJson), json, StandardCharsets.UTF_8);
            // swagger模板目录
            String templateDir = this.appProperties.getSwaggerTemplatePath() + File.separator + apiType;
            log.info("swagger模板目录:{}", templateDir);
            // 压缩包生成的目录
            String outputApiDir = outputDir + File.separator + info.getArtifactId() + "-api";
            log.info("压缩包生成的目录:{}", outputApiDir);
            // 获取生成webApi的命令
            String cmd = CmdUtil.getSwaggerCodegenCliCmd(appProperties.getSwaggerJarPath(),false, apiType, outputApiDir, outputJson, templateDir, info);
            // 执行命令
            Process process = Runtime.getRuntime().exec(cmd);
            // 打印日志(必须打印)
            boolean generateApi = printProcess(process);
            if (!generateApi) {
                return ApiResponseDto.fail("生成webapi失败");
            }
            // 返回压缩包
            return generateZipReponse(outputApiDir + ".zip", info.getArtifactId() + "-api-" + info.getVersion(), outputApiDir);
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseDto.fail("生成webapi异常");
        }
    }

    public Pair<Boolean, String> generateJavaApi(String appDocUrl, String apiType) {
        try {
            //获取swagger文档定义json
            String json = getSwaggerByAppDocUrl(appDocUrl);
            Swagger swagger = JSON.parseObject(json, Swagger.class);
            if (swagger == null) {
                return Pair.of(false, "未获取到文档定义内容");
            }
            Swagger.Info info = swagger.getInfo();
            //接口生成目录
            String outputDir = appProperties.getTmpDir() + File.separator + "javaApi" + System.currentTimeMillis();
            log.info("javaApi接口生成目录:{}", outputDir);
            String outputJson = outputDir + File.separator + "api.json";
            log.info("api.json生成目录:{}", outputJson);
            // 获取的json写入到文件
            FileUtils.writeStringToFile(new File(outputJson), json, StandardCharsets.UTF_8);
            // swagger模板目录
            String templateDir = this.appProperties.getSwaggerTemplatePath() + File.separator + apiType;
            log.info("swagger模板目录:{}", templateDir);
            // 压缩包生成的目录
            String outputApiDir = outputDir + File.separator + info.getArtifactId() + "-" + GlobalConstant.immutableMap.get(apiType) + "-api";
            log.info("webApi压缩包生成的目录:{}", outputApiDir);
            // 获取生成javaApi的命令
            String cmd = CmdUtil.getSwaggerCodegenCliCmd(appProperties.getSwaggerJarPath(),true, apiType, outputApiDir, outputJson, templateDir, info);
            // 执行命令
            Process process = Runtime.getRuntime().exec(cmd);
            // 打印输出(必须打印)
            boolean generateApi = printProcess(process);
            if (!generateApi) {
                return Pair.of(false, "生成webapi失败");
            }
            String pack = info.getPack();
            if ("spring-cloud".equals(apiType)) {
                String mainDir = outputApiDir + File.separator + "src" + File.separator + "main";
                log.info("spring-cloud主目录:{}", mainDir);
                FileUtils.deleteDirectory(new File(mainDir + File.separator + "java" + File.separator + "io"));
                List<Swagger.Tag> tags = swagger.getTags();
                String finalPack = pack;
                String clients = tags.stream().map(t -> finalPack + ".api." + CaseUtils.toCamelCase(t.getName(), true, new char[]{'-'}) + "ApiClient").collect(Collectors.joining(","));
                FileUtils.writeStringToFile(new File(mainDir + File.separator + "resources" + File.separator + "META-INF" + File.separator + "spring.factories"), "org.springframework.boot.autoconfigure.EnableAutoConfiguration=" + clients, StandardCharsets.UTF_8);
            } else if ("resttemplate".equals(apiType)) {
                String mainDir = outputApiDir + File.separator + "src" + File.separator + "main";
                log.info("resttemplate主目录:{}", mainDir);
                FileUtils.writeStringToFile(new File(mainDir + File.separator + "java" + File.separator + pack.replace(".", File.separator) + File.separator + "Config.java"), "package " + pack + ";\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.client.RestTemplate;@Configuration\n@ComponentScan(\"" + pack + "\")\npublic class Config {\n    @Bean\n    @ConditionalOnMissingBean\n    public RestTemplate restTemplate(){\n        return new RestTemplate();\n    }}\n", StandardCharsets.UTF_8);
                FileUtils.writeStringToFile(new File(mainDir + File.separator + "resources" + File.separator + "META-INF" + File.separator + "spring.factories"), "org.springframework.boot.autoconfigure.EnableAutoConfiguration=" + pack + ".Config", StandardCharsets.UTF_8);
            }
            AppProperties.Gav parentGav = new AppProperties.Gav();
            parentGav.setGroupId("cn.alian.microservice");
            parentGav.setArtifactId("parent");
            parentGav.setVersion("1.0.0-SNAPSHOT");
            parentGav.setPackaging("pom");
            String mvnDependencyCmd = CmdUtil.getMvnDependencyCmd(appProperties.getMvn(), appProperties.getRemoteRepositories(), parentGav);
            //执行获取mvn依赖命令
            Process dependencyProcess = Runtime.getRuntime().exec(mvnDependencyCmd);
            //返回结果
            printProcess(dependencyProcess);

            //发布的命令
            String mvnCmd = this.appProperties.getMvn() + " -f " + outputApiDir + " clean source:jar deploy -Dmaven.test.skip=true";
            log.info("发布的命令是:{}", mvnCmd);
            Process generateProcess = Runtime.getRuntime().exec(mvnCmd);
            boolean deploy = printProcess(generateProcess);
            if (!deploy) {
                return Pair.of(false, "生成javaApi客户端失败,请检查swagger定义");
            }
            String dependency = "<dependency><groupId>" + info.getGroupId() + "</groupId><artifactId>" + info.getArtifactId() + "-api</artifactId><version>" + info.getVersion() + "</version></dependency>";
            return Pair.of(true, "生成javaApi客户端的依赖是 :" + dependency);
        } catch (Exception e) {
            return Pair.of(false, "生成javaApi客户端异常");
        }
    }

}

3.4、公共服务类

BaseService.java

@Slf4j
@Service
public class BaseService {

    @Autowired
    private RestTemplate restTemplate;

    public String getSwaggerByAppDocUrl(String appDocUrl) {
        ResponseEntity<String> responseEntity = this.restTemplate.getForEntity(appDocUrl, String.class, new Object[0]);
        String json = responseEntity.getBody();
        log.info("json is {}", json);
        return json;
    }

    public boolean printProcess(Process process) throws Exception {
        log.info("打印进程信息"); //process.getErrorStream()  process.getInputStream()
        // 错误流输出
        PrintProcessInfoThread errorStreamThread = new PrintProcessInfoThread(process.getErrorStream(), "ERRORSTREAM");
        // 标准流输出
        PrintProcessInfoThread outputStreamThread = new PrintProcessInfoThread(process.getInputStream(), "OUTPUTSTREAM");
        // 启动线程
        errorStreamThread.start();
        outputStreamThread.start();
        // 等待进程执行完毕
        int exitVal = process.waitFor();
        log.info("执行的结果: " + exitVal);
        return errorStreamThread.getBuild() && outputStreamThread.getBuild();
    }

    public ResponseEntity generateZipReponse(String outputZip, String fileName, String... dirsAddToZip) throws Exception {
        log.info("zip");
        ZipFile zipFile = new ZipFile(outputZip);
        ZipParameters parameters = new ZipParameters();
        // 压缩方式
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        // 压缩级别
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
        for (String dir : dirsAddToZip) {
            zipFile.addFolder(dir, parameters);
        }
        File file = zipFile.getFile();
        HttpHeaders header = new HttpHeaders();
        header.set("Content-Disposition", "attachment; filename=" + fileName + ".zip");
        header.setContentLength(file.length());
        header.setContentType(MediaType.parseMediaType("application/octet-stream"));
        InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
        return new ResponseEntity(isr, header, HttpStatus.OK);
    }

}

  这里都是公共的方法,通过appDocUrl获取swagger文档定义,打印或者返回结果。特别需要注意的是打印的方法,如果不读取流信息,那么执行的命令就会一直堵住,也就是卡主了,真正只有读取错误流输出才会完整的输出。我这里采用了线程输出的方式,应该算是比较好的一个方式了。

3.5、进程信息打印线程

PrintProcessInfoThread.java

package cn.alian.microservice.doc.thread;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;

@Slf4j
public class PrintProcessInfoThread extends Thread {

    private InputStream inputStream;
    private String streamType;
    private boolean build = true;

    public PrintProcessInfoThread(InputStream inputStream, String streamType) {
        this.inputStream = inputStream;
        this.streamType = streamType;
    }

    public void run() {
        try {
            StringBuilder sb = new StringBuilder();
            //获取进程中的输入流转为缓存字节流
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                log.info("{}>>>{}", streamType, line);
                sb.append(line).append(File.separatorChar);
            }
            String message = sb.toString();
            if (StringUtils.isNotBlank(message)) {
                build = !message.contains("BUILD FAILURE") || !message.contains("[ERROR]");
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    public boolean getBuild(){
        return this.build;
    }
}

3.6、工具类

GlobalConstant.java

public class GlobalConstant {

    public static ImmutableMap<Object, Object> langMap = ImmutableMap.builder()
            .put("resttemplate", "java")
            .put("spring-cloud", "spring")
            .build();

    public static ImmutableMap<Object, Object> immutableMap = ImmutableMap.builder()
            .put("resttemplate", "rt")
            .put("spring-cloud", "sc")
            .build();
}

CmdUtil.java

@Slf4j
public class CmdUtil {

    public static String getMvnDependencyCmd(String mvnPath, String remoteRepositories, AppProperties.Gav gav) {
        String cmd = "MVNCMD org.apache.maven.plugins:maven-dependency-plugin:3.2.0:get -Dartifact=ARCHETYPE-GROUP-ID:ARCHETYPE-ARTIFACT-ID:ARCHETYPE-VERSION:POM -DremoteRepositories=REMOTE-REPOSITORIES";
        cmd = cmd.replace("MVNCMD", mvnPath)
                .replace("ARCHETYPE-GROUP-ID", gav.getGroupId())
                .replace("ARCHETYPE-ARTIFACT-ID", gav.getArtifactId())
                .replace("ARCHETYPE-VERSION", gav.getVersion())
                .replace(":POM", StringUtils.isNotBlank(gav.getPackaging()) ? (":" + gav.getPackaging()) : "")
                .replace("REMOTE-REPOSITORIES", remoteRepositories);
        log.info("getMvnDependency cmd is: {}", cmd);
        //返回结果
        return cmd;
    }

    public static String getSwaggerCodegenCliCmd(String swaggerJarPath, boolean javaApi, String apiType, String outputApiDir, String outputJson, String templateDir, Swagger.Info info) {
        String cmd = "java -jar SwaggerJarPath generate --library -l LANGUAGE -i INPUTSPEC --output OUTPUT-DIR" +
                " --api-package API-PACkAGE --model-package MODEL-PACKAGE --group-id GROUP-ID --artifact-id ARTIFACT-ID --artifact-version ARTIFACT-VERSION " +
                " -t TEMPLATE-DIR --import-mappings org.threeten.bp.OffsetDateTime=java.util.Date --type-mappings OffsetDateTime=Date";
        cmd = cmd.replace("SwaggerJarPath", swaggerJarPath)
                .replace("--library", (javaApi ? ("--library " + apiType) : ""))
                .replace("LANGUAGE", (javaApi ? "" + GlobalConstant.langMap.get(apiType) : apiType))
                .replace("INPUTSPEC", outputJson)
                .replace("OUTPUT-DIR", outputApiDir)
                .replace("API-PACkAGE", info.getPack() + ".api")
                .replace("MODEL-PACKAGE", info.getPack() + ".api.dto")
                .replace("GROUP-ID", info.getGroupId())
                .replace("ARTIFACT-ID", (javaApi ? (info.getArtifactId() + "-" + GlobalConstant.immutableMap.get(apiType) + "-api") : info.getArtifactId()))
                .replace("ARTIFACT-VERSION", info.getVersion())
                .replace("TEMPLATE-DIR", templateDir);
        log.info("getSwaggerCodegenCliCmd is: {}", cmd);
        return cmd;
    }

    public static String getGenerateProjectCmd(String mvnPath, String groupId, String artifactId, String version, AppProperties.Gav gav, String outputDir, String configUri) {
        log.info("generate groupId = [" + groupId + "], artifactId = [" + artifactId + "], version = [" + version + "], gav = [" + gav + "]");
        String command = "MVNCMD archetype:generate  -DarchetypeGroupId=ARCHETYPE-GROUP-ID -DarchetypeArtifactId=ARCHETYPE-ARTIFACT-ID -DarchetypeVersion=ARCHETYPE-VERSION -DinteractiveMode=false -DarchetypeCatalog=local -DgroupId=PROJECT-GROUP-ID -DartifactId=PROJECT-ARTIFACT-ID -Dversion=PROJECT-VERSION -Dpackage=PROJECT-PACKAGE -Dapp=PROJECT-APP -DconfigUri=CONFIG-URI -DoutputDirectory=OUTPUTDIRECTORY";
        command = command.replace("MVNCMD", mvnPath)
                .replace("ARCHETYPE-GROUP-ID", gav.getGroupId())
                .replace("ARCHETYPE-ARTIFACT-ID", gav.getArtifactId())
                .replace("ARCHETYPE-VERSION", gav.getVersion())
                .replace("PROJECT-GROUP-ID", groupId)
                .replace("PROJECT-ARTIFACT-ID", artifactId)
                .replace("PROJECT-VERSION", version)
                .replace("PROJECT-PACKAGE", groupId + "." + artifactId)
                .replace("PROJECT-APP", StringUtils.capitalize(artifactId))
                .replace("CONFIG-URI", configUri)
                .replace("OUTPUTDIRECTORY", outputDir);
        log.info("getGenerateProjectCmd is {}", command);
        return command;
    }
}

  把本章第二大点看懂了,转化为程序就容易懂了,现在开始重新启动我们的文档服务,准备验证。

四、验证

4.1、文档服务中心

我们需要通过网关进入文档中心:http://10.130.3.222:8888/gateway/doc-service/swagger-ui.html

在这里插入图片描述
可以看到库存系统appDocUrl为:http://10.130.3.222:8888/gateway/doc-service/service/stock-10.130.3.88-8001

4.2、生成web客户端调用

输入参数:

  • apiType: spring-cloud
  • appDocUrl: http://10.130.3.222:8888/gateway/doc-service/service/stock-10.130.3.88-8001
  • invokeTye: 2

在这里插入图片描述
  执行后结果如下:
在这里插入图片描述
  前端只需要把生成的typescript文件拷贝及可以实现调用,是不是很方便?

4.3、生成java客户端调用

输入参数:

  • apiType: spring-cloud
  • appDocUrl: http://10.130.3.222:8888/gateway/doc-service/service/stock-10.130.3.88-8001

在这里插入图片描述
  我们生成了接口调用并且自动发布到了私服,直接引用依赖即可

<dependency>
    <groupId>cn.alian.mall</groupId>
    <artifactId>stock-sc-api</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

  如果你这里希望使用resttemplate方式调用,也很简单,就只要把参数apiType: spring-cloud改成apiType: resttemplate,就会生成新的接口调用,并且发布到私服,你只需要引用如下依赖即可

<dependency>
    <groupId>cn.alian.mall</groupId>
    <artifactId>stock-rs-api</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

  至于使用哪种方式,你可以根据你的需求或者网络环境去决定,一个是直接调用,一个是经过网关调用。既然接口调用都生成了,我们去订单服务去调用我们的库存服务试试吧。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值