好物安利:Swagger2

8 篇文章 3 订阅
4 篇文章 0 订阅

目录

 

●What & Why

●引入依赖

●正常开发

●Swagger2配置

●编辑API接口

●Swagger-UI查看文档

●彩蛋:swagger-ui-layer

●小结


●What & Why

大家加入一个项目团队,接手一个全新的项目时有没有遇到这种情况:项目参与人数众多,开发周期长,没有很好的API文档,甚至代码中注释也寥寥无几,有时候一个方法,或者一个类只有一句话描述,必须要自己去通读代码才能理解。笔者作为新人,加入目前的项目之初就有这样的想法,当时觉得要是有一个完善的API文档该多好

但现实中,想要输出一个好的API文档其实困难重重,首先,因为团队作战,风格统一是最大的一道坎,API文档应该怎么去写,有什么格式规定,必须要保持一致,否则难以维护;其次,大家工作都很饱和,想要挤出时间来生成与维护这样一份文档,其实是蛮花费时间和精力的一件事。

笔者最近学习SpringBoot时就发现了一个利器,可以很好的解决这个问题,它就是Swagger2。它能规范API文档的格式,并且它能自动生成API文档,给大家省了很多事儿!

Swagger2在日常使用中,其实是分为两部分的。一是Swagger2-core,它的作用是提供注解,程序员在开发过程中,对方法进行注解,该方法被标记成了API文档中的一项,之后他就能生成API文档的JSON字符串;二是Swagger2-UI,它的作用是解析生成的API文档JSON字符串,并将其在页面上进行展示。

唯一需要注意的是,Swagger2是基于OpenAPI3.0规范的,换句话说,它适用的API是RESTful风格的,举个例子,就像现在很多公司的开放平台,例如阿里、百度的那样,通过Url去调用对方RESTful风格的API。大家如果觉得抽象可以去阿里云这样的开放平台看看他们的API调用相关内容就了解了。

话不多说,我们来看看如何使用。

●引入依赖

根据刚才说的,我们需要引入两部分的依赖,以maven的pom文件为例:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.8.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.8.0</version>
</dependency>

●正常开发

接下来就可以开始正常开发过程了,当然了,如果各位是在项目开发或者维护阶段,中途引入pom也是可以的,直接进行配置和注解就行。这里,我们将结合实际的开发来举例子说明。

我们使用SpringBoot工程为例,也顺便和大家一起学习下如何快速开始一个SpringBoot项目的搭建与开发。首先,我们进入https://start.spring.io/,通过官方网站快速生成一个空的SpringBoot项目,大家如果习惯用IDEA自己新建也是OK的。注意红框的地方,按需填写,然后点击Switch to the full version,选择其他相关依赖,笔者选了Web、JPA、MySQL,后期大家也可以随时根据项目需要的依赖直接添加到pom文件即可。最后点击Generate Project生成项目。

使用IDEA或者大家喜欢的IDE导入刚生成的maven项目,然后开始撸代码。假设有这么一个简单的业务场景:管理设备资源,可以对设备进行添加、删除以及查询操作。

先准备一个实体类:

@Entity
@Table(name = "device_info")
public class deviceInfo implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", unique = true, nullable = false)
    private Long id;
    
    @Column(name = "device_name")
    private String deviceName;
    @Column(name = "device_owner")
    private String deviceOwner;

    /* 篇幅有限,省略构造函数和get、set函数 */
}

dao层接口使用Spring Data JPA来写,不清楚的朋友可以查看之前的一篇文章

public interface DeviceInfoRepository extends JpaRepository<DeviceInfo, Long> {
    /**
     * 按归属者查找设备
     * @param deviceOwner
     * @return 设备列表
     */
    List<DeviceInfo> findByDeviceOwner(String deviceOwner);

    /**
     * 按名字删除设备
     * @param deviceName
     * @return 状态值
     */
    int deleteByDeviceName(String deviceName);

    /**
     * 修改设备名
     * @param deviceName
     * @param id
     * @return 状态值
     */
    @Modifying
    @Query("update DeviceInfo d set d.deviceName = ?1 where d.id = ?2")
    int modifyById(String  deviceName, Long id);
}

service层包括以下几个方法,提供设备添加、删除、修改和查询:

@Service
public class DeviceInfoService {
    @Autowired
    DeviceInfoRepository deviceInfoRepository;

    public void addDevice(List<DeviceInfo> deviceInfos){
        deviceInfoRepository.saveAll(deviceInfos);
    }

    public int deteleByDeviceName(String deviceName){
        return deviceInfoRepository.deleteByDeviceName(deviceName);
    }

    public int modifyDeviceNameById(String deviceName , Long id){
        return deviceInfoRepository.modifyById(deviceName,id);
    }

    public List<DeviceInfo> findByOwner(String deviceOwner){
        return deviceInfoRepository.findByDeviceOwner(deviceOwner);
    }

    public DeviceInfo findById(Long id){
        return deviceInfoRepository.findById(id).orElseGet(() -> new DeviceInfo());
    }
}

最后是controller层,也就是对外提供API的地方,值得注意的是,RESTful的接口命名要规范,不要在URL中暴露动词:

@RestController
@RequestMapping(value="/device_info")
public class DeviceInfoController {
    @Autowired
    DeviceInfoService deviceInfoService;

    @RequestMapping(value="/{owner}", method=RequestMethod.GET)
    public List<DeviceInfo> getDeviceListByDeviceOwner(@PathVariable String owner) {
        // 处理"/device_info/"的GET请求,用来获取设备列表
        List<DeviceInfo> r = deviceInfoService.findByOwner(owner);
        return r;
    }

    
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public DeviceInfo getDeviceById(@PathVariable Long id) {
        // 处理"/device_info/{id}"的GET请求,用来获取url中id值的User信息
        return deviceInfoService.findById(id);
    }

    
    @RequestMapping(value="/", method=RequestMethod.POST)
    public String addDevice(@ModelAttribute DeviceInfo deviceInfo) {
        // 处理"/device_info/"的POST请求,用来新增设备
        List<DeviceInfo> deviceInfos = new ArrayList<>();
        deviceInfos.add(deviceInfo);
        deviceInfoService.addDevice(deviceInfos);
        return "success";
    }

    
    @RequestMapping(value="/{deviceName}", method=RequestMethod.DELETE)
    public String deleteDevice(@PathVariable String deviceName) {
        // 处理"/device_info/{deviceName}"的DELETE请求,用来删除设备
        deviceInfoService.deteleByDeviceName(deviceName);
        return "success";
    }

    
    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public String modifyDevice(@PathVariable String deviceName,@PathVariable Long id) {
        // 处理"/device_info/{id}"的PUT请求,用来更新设备信息
        deviceInfoService.modifyDeviceNameById(deviceName,id);
        return "success";
    }
}

以上,就是常规的从domain→dao→service→controller分层的写法,大家应该已经很熟悉了,至此我们就模拟了一个已经开发了的项目。接下来我们要做的就是对这个已经存在的项目进行一定的改造,让Swagger2为我们自动生成API文档。

Swagger2配置

Swagger2的配置很简单,我们采用java类的形式来写。直接在项目的启动类同级新建一个Swagger2类,如下:

@Configuration
@EnableSwagger2
public class Swagger2 {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xenophon.swagger2demo.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring Boot中使用Swagger2构建RESTful APIs")
                .description("第一个Swagger2自动构建演示项目")
                .termsOfServiceUrl("https://blog.csdn.net/jui121314?t=1")
                .contact("色诺芬")
                .version("1.0")
                .build();
    }
}

需要注意RequestHandlerSelectors.basePackage()中填写需要扫描的API所在的包名,apiInfo()中填写相关的信息即可。

●编辑API接口

我们选择需要加入API文档的接口,添加上注解就OK了,是不是很简单。我们来学习一下Swagger2提供的注解以及用法,我们将刚才controller层中的接口全部添加到文档中:

@RestController
@RequestMapping(value="/device_info")
@Api(tags = "设备信息相关API")
public class DeviceInfoController {
    @Autowired
    DeviceInfoService deviceInfoService;

    @ApiOperation(value="获取归属者设备列表", notes="")
    @ApiImplicitParam(name = "owner", value = "设备归属者姓名", required = true, dataType = "String")
    @RequestMapping(value="/{owner}", method=RequestMethod.GET)
    public List<DeviceInfo> getDeviceListByDeviceOwner(@PathVariable String owner) {
        // 处理"/device_info/"的GET请求,用来获取设备列表
        // 还可以通过@RequestParam从页面中传递参数来进行查询条件或者翻页信息的传递
        List<DeviceInfo> r = deviceInfoService.findByOwner(owner);
        return r;
    }

    @ApiOperation(value="获取设备详细信息", notes="根据url的id来获取设备详细信息")
    @ApiImplicitParam(name = "id", value = "设备ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public DeviceInfo getDeviceById(@PathVariable Long id) {
        // 处理"/device_info/{id}"的GET请求,用来获取url中id值的User信息
        // url中的id可通过@PathVariable绑定到函数的参数中
        return deviceInfoService.findById(id);
    }

    @ApiOperation(value="新增设备", notes="根据Device对象创建设备")
    @ApiImplicitParam(name = "deviceInfo", value = "设备详细实体deviceInfo", required = true, dataType = "DeviceInfo")
    @RequestMapping(value="/", method=RequestMethod.POST)
    public String addDevice(@ModelAttribute DeviceInfo deviceInfo) {
        // 处理"/device_info/"的POST请求,用来新增设备
        // 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数
        List<DeviceInfo> deviceInfos = new ArrayList<>();
        deviceInfos.add(deviceInfo);
        deviceInfoService.addDevice(deviceInfos);
        return "success";
    }

    @ApiOperation(value="删除设备", notes="根据url的设备名来指定删除对象")
    @ApiImplicitParam(name = "deviceName", value = "设备名", required = true, dataType = "String")
    @RequestMapping(value="/{deviceName}", method=RequestMethod.DELETE)
    public String deleteDevice(@PathVariable String deviceName) {
        // 处理"/device_info/{deviceName}"的DELETE请求,用来删除设备
        deviceInfoService.deteleByDeviceName(deviceName);
        return "success";
    }

    @ApiOperation(value="更新设备名", notes="根据url的id来指定更新对象,并根据传过来的deviceName来更新设备名")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "deviceName", value = "设备名", required = true, dataType = "String"),
            @ApiImplicitParam(name = "id", value = "设备ID", required = true, dataType = "Long"),
    })
    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public String modifyDevice(@PathVariable String deviceName, @PathVariable Long id) {
        // 处理"/device_info/{id}"的PUT请求,用来更新设备信息
        deviceInfoService.modifyDeviceNameById(deviceName,id);
        return "success";
    }
}

相比之前,变化仅仅在于方法之前添加的几个注解。我们逐一解释一下:

首先,我们在类上加了一个@Api的注解。该注解用在请求的类上,表示对类的说明。其中,常用的参数包括:tags,用来对类的作用进行说明;hidden,默认为false, 配置为true 将在文档中隐藏(下面几个注解都具备,不再一一解释)。

其次,我们在方法上加了一个@ApiOperation的注解。该注解用在请求的方法上,说明方法的用途、作用。其中,常用的参数包括:value,说明方法的用途、作用;notes,方法的备注说明;response,响应类型。

然后,我们在方法上加了一个@ApiImplicitParam(s)的注解。如果是多个请求的情况,@ApiImplicitParams用在请求的方法上,表示一组参数说明;@ApiImplicitParam用在@ApiImplicitParams注解中,指定一个请求参数的说明。常用的参数包括:name,参数名;value,参数的说明、解释;required,参数是否必须传,默认为false,进行POST等请求必须要求参数时为true;dataType,参数类型,默认String,可以是任意Java对象,例如刚才定义的设备实体类DeviceInfo;defaultValue,参数的默认值。

至此,程序员需要人工做的就全部完成了

●Swagger-UI查看文档

现在,Swagger2已经帮我们生成好API文档了,我们要做的就是启动项目,进入http://localhost:8080/swagger-ui.html。当然,根据配置的IP、端口、路径,这个访问地址会有所不同,笔者仅举例默认情况下的访问路径。打开后我们就可以通过网页查看API文档了,如图:

每个方法都可以具体点开查看,甚至还能点击Try it out直接调用!

至此,Swagger2就算成功使用了,大家完全可以拿出以前的项目来试试,仅仅是导入依赖,添加配置,给方法写注解这么简单。

●彩蛋:swagger-ui-layer

正片结束,给大家放送一个彩蛋,第三方开源UI组件swagger-ui-layer。只需要引入一个依赖,就可以给Swagger2的UI界面换一套衣服。实际用下来,感觉还是蛮不错的,看上去挺舒服的。也许是Swagger2当时考虑用户会自己开发UI,所以随意给了个将就看得过去的页面设计。

swagger-ui-layer需要引入的依赖如下:

dependency>
    <groupId>com.github.caspar-chen</groupId>
    <artifactId>swagger-ui-layer</artifactId>
    <version>1.1.0</version>
</dependency>

打开默认的访问链接http://localhost:8080/docs.html界面如下:

对的!你没看错,只需要引入一个依赖,更换一个访问地址就行,其余地方完全不用修改。页面更舒服耐看,同样也支持调试。唯一需要注意的是,该第三方组件截止撰文时依旧没有支持Swagger2的分组,因此大家在配置的时候,如果有group的设置,需要去掉。

●小结

其实Swagger2的可用性还是蛮高的。例如可以自己开发SwaggerUI页面,可以用更多的注解,可以分组,可以搭配其他框架(例如spring security)加入权限,等等,笔者只介绍了最简单的使用方法。大家如何真的需要使用的话,可以参考官方的文档进行。今天,你学会了吗?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值