前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >接口管理这下总会了吧?

接口管理这下总会了吧?

作者头像
架构探险之道
发布2020-09-01 14:32:55
4630
发布2020-09-01 14:32:55
举报
文章被收录于专栏:架构探险之道架构探险之道

接口管理这下总会了吧?

  • 使用方式
    • 引入依赖
    • 添加 Swagger 注解
    • 配置扫描规则 application.yaml
  • 效果
  • 实现原理
  • 小结

利用 Spring Boot 快速集成 Swagger 实现

Swagger 作为一款优秀的 API 接口文档管理框架,在过往的使用过程中,着实踩了不少坑。一开始,也在自己的博客上整理了使用说明文档,它的配置,说老实话,很多刚上手的同学还是觉得很难使用。我就这个问题思考了下,决定基于 Spring Boot 的装配机制,写个简单好用的 Api Starter Jar 包,让使用的人专注于接口自身,而非陷于一堆配置中无法自拔。

主要目的:

  • 多种扫描方式(包路径、路由前缀)
  • 自定义前缀
  • 接口分组管理
  • 无需额外配置,专注于接口文档自身

使用方式

引入依赖

pub.dsb.framework.boot:dsb-boot-api-starter:0.0.4.RELEASE

添加 Swagger 注解

  • controller
package pub.dsb.api.controller.business;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import pub.dsb.api.object.dto.ProductInfoDTO;
import pub.dsb.api.object.dto.UserInfoDTO;
import pub.dsb.framework.boot.rest.R;
import pub.dsb.framework.boot.security.annotation.Decrypt;

@Api(value = "/v1/business", tags = {"业务处理模块"})
@RestController
@RequestMapping("/v1/business")
public class BusinessController {


    /**
     * 下单
     *
     * @param productInfo
     * @return
     */
    @RequestMapping(value = "/order", method = RequestMethod.POST)
    @ApiOperation(value = "下单", notes = "下单,返回订单号", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public R<String> userInfo(ProductInfoDTO productInfo) {
        return R.ok("business_id_45454545478");
    }
}
  • dto
package pub.dsb.api.object.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(description = "商品信息:流水号、信息、数量")
public class ProductInfoDTO {

    @ApiModelProperty(value = "订单流水号", example = "20200812452404", dataType = "int")
    private int orderNumber;
    @ApiModelProperty(value = "商品名称", example = "Mac 笔记本", dataType = "string")
    private String productName;
    @ApiModelProperty(value = "数量", example = "2", dataType = "int")
    private int count;


}

配置扫描规则 application.yaml

dsb:
  webmvc:
    swagger:
     # 默认分组参数,配置了的话生成默认分组下的接口扫描文档
     # base-package: x.x.x
      # 接口分组集合
      api-groups:
        - group-name: 业务处理模块
          # 接口前缀
          path-mapping: /api/biz/
          # 包路径匹配
          apis: pub.dsb.api.controller.business
          # 路由匹配
          paths: /v1/**
          api-info:
            title: 接口文档标题
            description: 接口文档描述
            terms-of-service-url: 服务地址
            name: 接口负责人:姓名
            url: 接口负责人:个人地址
            email: abc@example.com
            license: License 授权
            license-url: License 地址
            version: 接口文档版本号
        - group-name: 基础信息管理
          # 接口前缀
          path-mapping: /api/docs/
          # 包路径匹配
          apis: pub.dsb.api.controller.user
          # 路由匹配
          paths: /v1/**
          api-info:
            title: 接口文档标题
            description: 接口文档描述
            terms-of-service-url: 服务地址
            name: 接口负责人:姓名
            url: 接口负责人:个人地址
            email: abc@example.com
            license: License 授权
            license-url: License 地址
            version: 接口文档版本号

效果

  • 访问 http://127.0.0.1:8080/swagger-ui.html

在这里插入图片描述

  • 请求参数

在这里插入图片描述

实现原理

基于 Spring Boot 的约定大于配置,根据 YAML 中配置的接口分组信息,直接生成对应所需 Docket Bean

核心源码逻辑

package pub.dsb.framework.boot.webmvc.configuration;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import pub.dsb.framework.boot.webmvc.configuration.Swagger2Configuration;
import pub.dsb.framework.boot.webmvc.properties.SwaggerProperties;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * Swagger API Docket 配置
 * </p>
 *
 * @author Yiyuery
 * @date 2020/8/21
 * @since 0.0.1
 */
@Configuration
@Import({Swagger2Configuration.class, SwaggerProperties.class})
@ConditionalOnProperty(prefix = "dsb.webmvc.swagger", value = "enabled", matchIfMissing = true)
@ConditionalOnClass(Docket.class)
public class SwaggerDocketConfiguration implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    /**
     * 注册 Docket
     *
     * @param swaggerProperties
     * @return
     */
    @Bean
    public List<Docket> registerDocket(SwaggerProperties swaggerProperties) {
        ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
        List<Docket> beans = new ArrayList();
        List<SwaggerProperties.ApiGroup> apiGroups = swaggerProperties.getApiGroups();
        if (CollectionUtils.isNotEmpty(apiGroups)) {
            registerDockets(apiGroups, beans, configurableBeanFactory);
        } else if (StringUtils.isNotEmpty(swaggerProperties.getBasePackage())) {
            //配置了默认包路径的扫描配置
            Docket docket = new Docket(DocumentationType.SWAGGER_2)
                    .groupName("DEFAULT_GROUP")
                    .select()
                    .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                    .build();
            beans.add(docket);
            configurableBeanFactory.registerSingleton(docket.getGroupName() + "_Docket", docket);
        }
        return beans;
    }

    /**
     * 解析配置 注册 Docket
     *
     * @param apiGroups
     * @param beans
     * @param configurableBeanFactory
     */
    private void registerDockets(List<SwaggerProperties.ApiGroup> apiGroups, List<Docket> beans, ConfigurableBeanFactory configurableBeanFactory) {

        for (SwaggerProperties.ApiGroup apiGroup : apiGroups) {
            SwaggerProperties.ApiInfo apiInfo = apiGroup.getApiInfo();
            Docket docket = new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(new ApiInfoBuilder()
                            .contact(new Contact(apiInfo.getName(), apiInfo.getUrl(), apiInfo.getEmail()))
                            .description(apiInfo.getDescription())
                            .title(apiInfo.getTitle())
                            .version(apiInfo.getVersion())
                            .termsOfServiceUrl(apiInfo.getTermsOfServiceUrl())
                            .license(apiInfo.getLicense())
                            .licenseUrl(apiInfo.getLicenseUrl()).build())
                    .groupName(apiGroup.getGroupName());
            ApiSelectorBuilder select = docket.select();
            if (CollectionUtils.isNotEmpty(apiGroup.getApis())) {
                Predicate<RequestHandler>[] apis = new Predicate[apiGroup.getApis().size()];
                int index = 0;
                for (String pack : apiGroup.getApis()) {
                    apis[index++] = RequestHandlerSelectors.basePackage(pack);
                }
                select.apis(Predicates.or(apis));
            }
            if (CollectionUtils.isNotEmpty(apiGroup.getPaths())) {
                Predicate<String>[] paths = new Predicate[apiGroup.getPaths().size()];
                int index = 0;
                for (String path : apiGroup.getPaths()) {
                    paths[index++] = PathSelectors.ant(path);
                }
                select.paths(Predicates.or(paths));
            }
            
            select.build();
            if (StringUtils.isNotEmpty(apiGroup.getPathMapping())) {
                docket.pathMapping(apiGroup.getPathMapping());
            }
            beans.add(docket);
            configurableBeanFactory.registerSingleton(docket.getGroupName() + "_Docket", docket);
        }
    }
}

小结

基于 dsb-boot-api-starter,对于接口文档的提供便只剩接口的注解扫描路径等必要的配置工作了,是不是忍不住要赶快试试了呢?

适用场景:

  • 敏捷开发
  • 微服务 API 过多
  • 前后端分离
  • ...

Tips:使用过程中遇到问题可以直接加小编反馈哦,光速修复信不信?

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构探险之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 接口管理这下总会了吧?
    • 使用方式
      • 引入依赖
      • 添加 Swagger 注解
      • 配置扫描规则 application.yaml
    • 效果
      • 实现原理
        • 小结
        相关产品与服务
        项目管理
        CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档