• (十四)Alian 的 Spring Cloud 订单服务调用自动生成的API


    一、背景

      到这一步,我们已经完成了 Swagger Codegen 自动生成调用API,并且我们通过它生成了库存系统的web端和java端的接口调用,现在我们就用订单服务去调用我们自动生成调用API,看看有多方便吧。本文就使用spring-cloud方式来验证,resttemplate方式也是一样的。我们先看下它的结构:

    在这里插入图片描述
    并且我们从可以看到

    package cn.alian.mall.stock.api;
    
    import cn.alian.mall.stock.api.StockControllerApi;
    import feign.Client;
    import feign.Contract;
    import feign.Feign;
    import feign.codec.Decoder;
    import feign.codec.Encoder;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.openfeign.FeignClientsConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    @Import(FeignClientsConfiguration.class)
    @Configuration
    public class StockControllerApiClient {
    
        @Value("${StockControllerApi:${url-springcloud-stock:http://stock}}")
        private String StockControllerApi;
    
        @Bean
        @ConditionalOnMissingBean
        public StockControllerApi StockControllerApi(Decoder decoder, Encoder encoder, Client client, Contract contract) {
            return Feign.builder().client(client)
                    .encoder(encoder)
                    .decoder(decoder)
                    .contract(contract)
                    .target(StockControllerApi.class,
                    StockControllerApi);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

      默认的地址是 http://stock ,什么意思呢?就是说在 Spring Cloud 调用模式下,对应的服务的地址都是 http://${spring.application.name} ,这个地址已经映射对应的服务的ip地址了。

    二、maven依赖

    pom.xml

    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
        <parent>
            <groupId>cn.alian.microservicegroupId>
            <artifactId>parentartifactId>
            <version>1.0.0-SNAPSHOTversion>
        parent>
    
        <groupId>cn.alian.mallgroupId>
        <artifactId>orderartifactId>
        <version>1.0.0-SNAPSHOTversion>
        <name>ordername>
        <description>订单服务description>
    
        <dependencies>
    
            <dependency>
                <groupId>cn.alian.domaingroupId>
                <artifactId>domain-orderartifactId>
                <version>1.0.0-SNAPSHOTversion>
            dependency>
    
            <dependency>
                <groupId>cn.alian.microservicegroupId>
                <artifactId>common-dbartifactId>
                <version>1.0.0-SNAPSHOTversion>
            dependency>
    
            <dependency>
                <groupId>cn.alian.microservicegroupId>
                <artifactId>common-apiartifactId>
                <version>1.0.0-SNAPSHOTversion>
            dependency>
    
            <dependency>
                <groupId>cn.alian.mallgroupId>
                <artifactId>stock-sc-apiartifactId>
                <version>1.0.0-SNAPSHOTversion>
            dependency>
    
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-configartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
                <optional>trueoptional>
            dependency>
    
            <dependency>
                <groupId>com.googlecode.log4jdbcgroupId>
                <artifactId>log4jdbcartifactId>
            dependency>
    
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
            dependency>
    
        dependencies>
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

      这里看到我们引用我们上一文发布的依赖

    <dependency>
        <groupId>cn.alian.mallgroupId>
        <artifactId>stock-sc-apiartifactId>
        <version>1.0.0-SNAPSHOTversion>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    三、主要编码

    3.1、控制层

    OrderController.java

    package cn.alian.mall.order.controller;
    
    import cn.alian.mall.order.dto.OrderRequestDto;
    import cn.alian.mall.order.service.OrderService;
    import cn.alian.microservice.common.dto.ApiResponseDto;
    import com.alibaba.fastjson.JSON;
    import com.github.dozermapper.core.Mapper;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import io.swagger.annotations.ApiParam;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.tuple.Pair;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.validation.Valid;
    
    @Slf4j
    @Validated
    @RestController
    @RequestMapping({"/api/v1/order"})
    @Api(description = "订单相关接口")
    public class OrderController {
    
        @Autowired
        private OrderService orderService;
    
        @ApiOperation("下订单")
        @PostMapping("/request")
        public ApiResponseDto<String> request(@ApiParam @Valid @RequestBody OrderRequestDto dto) {
            log.info("下订单请求信息:{}", JSON.toJSONString(dto));
            try {
                Pair<Boolean, String> pair = orderService.request(dto);
                if (!pair.getLeft()){
                    return ApiResponseDto.bizErr(pair.getRight());
                }
                return ApiResponseDto.success();
            } catch (Exception e) {
                log.warn("下订单异常", e);
                return ApiResponseDto.exception("下订单异常");
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.2、服务层

    OrderService.java

    package cn.alian.mall.order.service;
    
    import cn.alian.domain.order.domain.Order;
    import cn.alian.mall.order.dto.OrderRequestDto;
    import cn.alian.mall.stock.api.StockControllerApi;
    import cn.alian.mall.stock.api.dto.ApiResponseDtoOfDeductInventoryResponseDto;
    import cn.alian.mall.stock.api.dto.DeductInventoryRequestDto;
    import cn.alian.mall.stock.api.dto.DeductInventoryResponseDto;
    import cn.alian.microservice.common.util.ApiResponse;
    import com.github.dozermapper.core.Mapper;
    import io.ebean.DB;
    import io.ebean.EbeanServer;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.tuple.Pair;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Service;
    
    @Slf4j
    @Service
    public class OrderService {
    
        @Autowired
        private EbeanServer ebeanServer;
    
        @Autowired
        private Mapper mapper;
    
        @Autowired
        private StockControllerApi stockControllerApi;
    
        public Pair<Boolean, String> request(OrderRequestDto dto) {
            try {
                //构造对象
                Order order = mapper.map(dto, Order.class);
                order.setOrderStatus(Order.StatusEnum.HANDING.getCode());
                //保存订单
                DB.save(order);
                log.info("保存订单成功,开始扣减库存");
                DeductInventoryRequestDto requestDto = mapper.map(dto, DeductInventoryRequestDto.class);
                requestDto.setOrderId(order.getId());
                //扣减库存
                ResponseEntity<ApiResponseDtoOfDeductInventoryResponseDto> responseEntity = stockControllerApi.requestUsingPOST(requestDto);
                Pair<Boolean, Object> pair = ApiResponse.check(responseEntity);
                if (!pair.getLeft()) {
                    return Pair.of(false, "请求异常");
                }
                DeductInventoryResponseDto body = (DeductInventoryResponseDto) pair.getRight();
                //扣减结果
                boolean flag = "0000".equals(body.getResultCode());
                //设置状态
                order.setOrderStatus(flag ? Order.StatusEnum.SUCCESS.getCode() : Order.StatusEnum.FAIL.getCode());
                DB.update(order);
                log.info("更新订单状态");
                return Pair.of(flag, body.getMessage());
            } catch (Exception e) {
                log.warn("下订单失败:", e);
            }
            return Pair.of(false, "下订单失败");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

      这里的 StockControllerApi 就是我们自动生成的API,自动注入就可以调用我们扣减库存的方法了。

    3.3、dto

    OrderRequestDto.java

    package cn.alian.mall.order.dto;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder(toBuilder = true)
    @ApiModel(description = "订单请求信息")
    public class OrderRequestDto {
    
        @NotNull
        @ApiModelProperty("商品id")
        private Integer goodsId;
    
        @NotNull
        @ApiModelProperty("用户id")
        private Integer userId;
    
        @NotNull
        @ApiModelProperty("单价")
        private Integer price = 0;
    
        @NotNull
        @ApiModelProperty("数量")
        private Integer num = 1;
    
        @NotBlank
        @ApiModelProperty("订单标题")
        private String title;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    3.4、主类

    OrderApplication.java

    package cn.alian.mall.order;
    
    import cn.alian.microservice.common.gracefullshutdown.GracefulSpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @EnableDiscoveryClient
    @SpringBootApplication
    public class OrderApplication {
    
        public static void main(String[] args) {
        	//优雅停服
            GracefulSpringApplication.run(OrderApplication.class, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    四、配置

    4.1、bootstrap.properties

    bootstrap.properties

    #应用名
    spring.application.name=order
    #开发环境
    spring.profiles.active=dev
    #配置标签(根据配置中心,本文全是采用master)
    spring.cloud.config.label=master
    #配置中心地址,多个用逗号分隔
    spring.cloud.config.uri=http://10.130.3.222:6666
    #设置为true时,如果服务无法连接到配置中心服务器,则服务启动失败
    spring.cloud.config.fail-fast=true
    #日志配置,通过配置中心获取
    logging.config=${spring.cloud.config.uri}/logback/${spring.application.name}.xml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.2、build.properties

    build.properties

    build.groupId=${pom.groupId}
    build.artifactId=${pom.artifactId}
    build.version=${pom.version}
    # 生成的文档说明
    build.description=${pom.description}
    # spring-boot:run -Ppack时方便生成api客户端
    build.pack=cn.alian.mall.order
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.3、ebean.properties

    ebean.packages=cn.alian.domain.order
    
    • 1

    五、验证

      启动服务后,我们直接从文档服务中心进行测试,目前文档中心效果图如下:

    在这里插入图片描述
      先看原始数据库的值(验证库存服务时,扣了 1 ,目前库存是 99

    在这里插入图片描述

      调用下订单的接口

    在这里插入图片描述

      订单服务输出结果:

    2022-07-28 21:14:45 779 [http-nio-7001-exec-10] INFO request 35:下订单请求信息:{"goodsId":10001,"num":2,"price":2000,"title":"数字藏品","userId":8001}
    2022-07-28 21:14:45 818 [http-nio-7001-exec-10] INFO request 39:保存订单成功,开始扣减库存
    2022-07-28 21:14:45 866 [http-nio-7001-exec-10] INFO request 49:调用库存系统返回结果:class DeductInventoryResponseDto {
        message: 库存扣减成功
        resultCode: 0000
    }
    2022-07-28 21:14:45 894 [http-nio-7001-exec-10] INFO request 55:更新订单状态
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

      查看数据库,(扣减前是 99 ,目前库存是 97

    在这里插入图片描述
      实际上到这里,一个简单的微服务架构流程就已经都打通了(当然没有包括三高及分布式事务),具体的就具体业务需求了。但是还有一些其他的优化,我们接着看…

  • 相关阅读:
    后端nginx报reset by peer while reading upstream
    物美与价廉,名创优品能否兼得?
    websocket拦截
    吃透BGP,永远绕不开这些基础概述,看完再也不怕BGP了!
    艾伦脑科学研究所,脑图谱,小鼠不同的功能脑区,可视化展示
    记一次hook mac地址实现伪装硬件码
    客户流失场景预测,看这两大“明星”算法模型如何实现
    C++高性能优化编程之如何测量性能(一)
    HTML+CSS 测试题部分 150
    Java中long(Long)与int(Integer)之间的转换
  • 原文地址:https://blog.csdn.net/Alian_1223/article/details/124148867