优化定义

Davidoff Shen2022年5月11日大约 3 分钟

优化定义

在前一小节中,我们定义的AddService,发布路径、参数名映射都不是很友好,我们在AddService接口上进行优化

package org.coodex.concrete.demo.api;

import org.coodex.concrete.api.ConcreteService;
import org.coodex.util.Parameter;

@ConcreteService("Calculator")//为服务模块指定服务名
public interface AddService {
    // 为参数指定名称
    int add(@Parameter("x1") int x1, @Parameter("x2") int x2);
}

跑起来看看。

我们可以看到,服务模块和参数名都有了改变

关于参数名,虽然Concrete支持java8的--parameters编译参数来获取方法参数名,但是依然不推荐这么做,对于需要明确的方法参数名,推荐使用@Parameter来声明

使用mock

本节仅为了减少实现代码编写而引入mock,非必须

前面的案例中,我们看到使用concrete开发的大概构成,api/impl/boot,为了加快示例,我们把impl先省掉,使用coodex-mockopen in new window来提供服务。

为了减少代码量,我们在 root pom 里引入lombok

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

demo-boot中,把concrete-jaxrs-swagger的依赖调整到test作用域,并且增加concrete-core-mock

<dependency>
    <groupId>org.coodex.concrete.jaxrs</groupId>
    <artifactId>concrete-jaxrs-swagger</artifactId>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.coodex.concrete</groupId>
    <artifactId>concrete-core-mock</artifactId>
    <scope>test</scope>
</dependency>

concrete-core-mock

concrete-core-mock提供了基于coodex-mock的一个拦截器实现,开箱即用。

然后在demo-boottest代码空间里随便写个 class 来 run 之前的 application

package org.coodex.concrete.demo.boot;

import org.springframework.boot.SpringApplication;

public class MockBoot {

    public static void main(String[] args) {
        SpringApplication.run(DemoBootStarter.class, args);
    }
}

跑起来,还是上一步的操作方式,我们使用swagger提交一个 x1=1,x2=1 的请求,看看结果,这时候不是 2 了,是一个随机数了,也就是说,concrete-core-mock代理掉了实现,或者说,不需要实现也可以进行前后端接口联调

concrete-core-mock主要目的是用来支撑前后端并行开发,前端、后端都遵循 api 的约定即可。

既然我们已经有了AddService的实现,我们把它从 mock 拦截器中移除掉先。

demo-boot的test作用域的resource目录下新增mock.excepted文件

org.coodex.concrete.demo.api.AddService

再跑起来,swagger,结果正确了。

mock.excepted

mock.exceptedconcrete-core-mock的一个约定,只要在该文件中匹配命中的,不再使用mock来代理实现

进一步优化

现在正式开始优化定义,我们新建一个服务

package org.coodex.concrete.demo.api;

import org.coodex.concrete.api.ConcreteService;
import org.coodex.concrete.api.Description;
import org.coodex.concrete.demo.pojo.CarInfo;
import org.coodex.mock.Mock;
import org.coodex.mock.ext.VehicleNum;
import org.coodex.util.Parameter;

@ConcreteService("cars")
@Description(name = "车辆资源服务", description = "文档化示例")
public interface CarService {

    @ConcreteService("/{id}/PlateCode")
    @VehicleNum
    @Description(name = "获取车牌号", description = "根据一辆车的id获取它车牌号")
    String getCarNumberById(
            @Description(name = "车辆id")
            @Mock.String
            @Parameter("id")
            String id);

    @ConcreteService("/{id}")
    @Description(name = "获取一辆车的信息", description = "数据包括车牌号车牌颜色等")
    CarInfo getCarById(
            @Description(name = "车辆id")
            @Mock.String
            @Parameter("id")
            String id);
}

其中CarInfo的定义是

package org.coodex.concrete.demo.pojo;

import lombok.Data;
import org.coodex.concrete.api.Description;
import org.coodex.mock.Mock;
import org.coodex.mock.ext.FullName;
import org.coodex.mock.ext.IdCard;
import org.coodex.mock.ext.VehicleNum;

@Data
public class CarInfo {
    @VehicleNum
    @Description(name = "车牌号码")
    private String plateCode;
    @Mock.Number("[0,4],9")
    @Description(name = "车牌颜色", description = "按照国标定义")
    private Integer plateColor;

    @Description(name = "车主姓名")
    @FullName
    private String ownerName;
    @Description(name = "车主身份证号")
    @IdCard
    private String idCard;

    @Description(name = "车辆品牌")
    @Mock.String(range = {"兰博基尼", "玛莎拉蒂", "奔驰", "宾利", "Audi", "BMW"})
    private String brand;
}

run

swagger

可以看到,红框中的部分和我们之前的风格不一样了,url 贴近 restful,服务说明也更清晰。

这个案例中,我们把 api 设计的三个部分进行了统一演示:api 命名,文档化,模拟数据。

api 命名

@ConcreteService注解可以重命名服务或者模块,在 jaxrs 中,可以让你的 api 定义更贴合 restful 风格。

文档化

@Description可以对模块、服务、属性、参数进行文档化注解,把 api 设计和 api 文档合到一起。

模拟数据

定义模拟数据,让没有后端实现也可以进行接口联调。详细参见open in new window

上次编辑于:
贡献者: Davidoff Shen
Loading...