API接口管理平台解决方案

本文介绍如何利用Swagger和Knife4j实现API文档自动生成及接口测试,涵盖配置、开发规范等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景和目的

Swagger 在目前企业中作为前后端开发对接的技术已经得到了非常广泛的应用,后端开发人员只需要根据 OpenAPI 官方定义的注解就可以把接口文档非常丰富的呈现给前端接口对接人员。并且接口文档是随着代码的变动实时更新,同时提供了在线 HTML 文档辅助开发人员可以进行接口联调测试,这大大省去了技术人员写文档的烦恼,也提升了企业开发的效率,减少沟通成本。

  • 代码变,文档变。只需要少量的注解,Swagger 就可以根据代码自动生成 API 文档,很好的保证了文档的时效性。

  • 跨语言性,支持 40 多种语言。

  • Swagger UI 呈现出来的是一份可交互式的 API 文档,我们可以直接在文档页面尝试 API 的调用,省去了准备复杂的调用参数的过程。

  • 还可以将文档规范导入相关的工具(例如 PostmanSoapUI, 这些工具将会为我们自动地创建自动化测试。

Knife4j 是一个 SwaggerUI 的增强工具,同时也提供了一些增强功能,使用 Java+Vue 进行开发,帮助开发者能在编写接口注释时更加完善,基于 OpenAPI 的规范完全重写 UI 界面,左右布局的方式也更加适合国人的习惯。

1.、URI

URI 表示资源,资源一般对应服务器端领域模型中的实体类。

URI规范

不用大写;
用中杠-不用下杠_
参数列表要encode
URI中的名词表示资源集合,使用复数形式。

2、Request

GET:查询

GET /zoos

POST:创建单个资源。POST一般向资源集合uri发起

POST /animals  //新增动物

PUT:更新单个资源(全量),客户端提供完整的更新后的资源。与之对应的是 PATCHPATCH 负责部分更新,客户端提供要更新的那些字段。PUT/PATCH一般向单个资源uri发起

PUT /animals/1

DELETE:删除

DELETE /zoos/1/animals  //删除id为1的动物园内的所有动物

HEAD / OPTION 用的不多,就不多解释了。

安全性和幂等性

安全性:不会改变资源状态,可以理解为只读的;

幂等性:执行1次和执行N次,对资源状态改变的效果是等价的。

.

安全性

幂等性

GET

POST

×

×

PUT

×

DELETE

×

安全性和幂等性均不保证反复请求能拿到相同的response。以 DELETE 为例,第一次DELETE返回200表示删除成功,第二次返回404提示资源不存在,这是允许的。

3、环境

场景1:测试环境

便于开发人员调试,后台和前端开发人员协作,以及对外公布API使用

application.yml

swagger:
  show: true

场景2:生产环境

在生产环境也会启用,就会存在一定的安全风险。

application.yml

swagger:
  show: false
package com.xiaominfo.swagger.service.user.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

@Configuration
@EnableSwagger2WebMvc
@Import(BeanValidatorPluginsConfiguration.class)
public class SwaggerConfiguration {
    @Value("${swagger.show}")
    private boolean swaggerShow;

    @Bean(value = "userApi")
    @Order(value = 1)
    public Docket groupRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(groupApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xiaominfo.swagger.service.user.controller"))
                .paths(swaggerShow == true ? PathSelectors.any() : PathSelectors.none())
                .build();
    }

    private ApiInfo groupApiInfo() {
        return new ApiInfoBuilder()
                .title("swagger-bootstrap-ui很棒~~~!!!")
                .description("<div style='font-size:14px;color:red;'>swagger-bootstrap-ui-demo RESTful APIs</div>")
                .termsOfServiceUrl("http://www.group.com/")
                .contact("group@qq.com")
                .version("1.0")
                .build();
    }
}

或者使用knife4j的增强特性

生产环境屏蔽资源

knife4j:
  # 开启增强配置
  enable: true
  # 开启生产环境屏蔽
  production: true

访问页面加权控制

knife4j:
  # 开启增强配置 
  enable: true
 # 开启Swagger的Basic认证功能,默认是false
  basic:
      enable: true
      # Basic认证用户名
      username: test
      # Basic认证密码
      password: 123

二、API文档自动生成

代码地址:https://gitee.com/xiaoym/swagger-bootstrap-ui-demo.git

整体项目结构如下:

|-knife4j-spring-cloud-gateway

|-----service-doc //文档聚合中心,是所有微服务文档的出口

|-----service-order //订单服务,包含所有与订单业务模块相关的接口

|-----service-server //eureka 注册中心

|-----service-user //用户服务,包含所有的用户接口

eureka注册中心

注册中心几乎没有代码,只是在pom.xml文件中引入了eureka服务的jar

<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>
项目的application.yml配置文件如下:
server:
  port: 10000
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
  application:
    name: knife4j-gateway-server

定义注册中心访问地址,端口号等属性

最后通过注解@EnableEurekaServer来启用注册中心

@EnableEurekaServer
@SpringBootApplication
public class ServiceServerApplication {

服务接口(订单order & 用户User)

由于服务接口订单和用户两个模块其实属性是差不多,只是接口不一样,因此就随便挑一个服务的配置来说吧

service-user:用户服务的接口

每个微服务只需要引入和swagger相关的后端jar包即可,不需要引入swagger的前端Ui,knife4j为我们提供了微服务项的starter,供开发者使用

当然,作为子服务,还需要引入eureka-clientjar,所以,pom.xml文件相关配置如下:


		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
			<version>5.4.6</version>
		</dependency>
		<dependency>
			<groupId>com.github.xiaoymin</groupId>
			<artifactId>knife4j-micro-spring-boot-starter</artifactId>
		</dependency>

项目的jar包引入完成后,接下来是配置swagger的相关配置,SwaggerConfiguration.java配置如下:

package com.xiaominfo.swagger.service.user.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

@Configuration
@EnableSwagger2WebMvc
@Import(BeanValidatorPluginsConfiguration.class)
public class SwaggerConfiguration {
    @Value("${swagger.show}")
    private boolean swaggerShow;

    @Bean(value = "userApi")
    @Order(value = 1)
    public Docket groupRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(groupApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xiaominfo.swagger.service.user.controller"))
                .paths(swaggerShow == true ? PathSelectors.any() : PathSelectors.none())
                .build();
    }

    private ApiInfo groupApiInfo() {
        return new ApiInfoBuilder()
                .title("swagger-bootstrap-ui很棒~~~!!!")
                .description("<div style='font-size:14px;color:red;'>swagger-bootstrap-ui-demo RESTful APIs</div>")
                .termsOfServiceUrl("http://www.group.com/")
                .contact("group@qq.com")
                .version("1.0")
                .build();
    }
}

配置扫描目录包

通过@EnableSwagger2@EnableSwaggerBootstrapUi来开启swagger和增强特性

配置项目的application.yml文件,如下:

server:
  port: 10001
  servlet:
    context-path: /aub
spring:
  application:
    name: service-user
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10000/eureka/

swagger:
  show: true

指定注册中心地址即可

最后,启用eureka客户端

@EnableEurekaClient
@SpringBootApplication
public class ServiceUserApplication {

当然,在服务的模块中还有和自己服务相关的业务接口(Controller代码),在这里就不列举了

订单模块(service-order)的代码配置和用户是类似的

文档聚合

有了eureka注册中心,服务模块的接口也已完成,最后一步是把我们所有的微服务都聚合到一个文档,统一输出到前端,供开发者调用了

pom引入相关jar包

service-doc也是一个eureka客户端,首先引入相关的jar,pom.xml配置文件如下:

<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
		<dependency>
			<groupId>com.github.xiaoymin</groupId>
			<artifactId>knife4j-spring-boot-starter</artifactId>
		</dependency>

spring-cloud-starter-netflix-eureka-client:eureka客户端

spring-cloud-starter-gatewaygateway网关

knife4j-spring-boot-starterknife4j提供的前端ui和后端代码

另外,其实在文档这里,如果没有后端代码编写的话,仅仅引入一个swagger的前端ui模块也是可以的

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-ui</artifactId>
</dependency>

Application文件配置

配置我们的网关属性,路由规则等,application.yml配置文件如下:

server:
  port: 10003
spring:
  application:
    name: service-doc
  cloud:
    gateway:
      discovery:
        locator:
          #          enabled: true
          lowerCaseServiceId: true
      routes:
        - id: service-user
          uri: lb://service-user
          predicates:
            - Path=/user/aub/**
          #            - Header=Cookie,Set-Cookie
          filters:
            #- SwaggerHeaderFilter
            - StripPrefix=1
        - id:  service-order
          uri: lb://service-order
          predicates:
            - Path=/order/**
          filters:
            #- SwaggerHeaderFilter
            - StripPrefix=1


eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10000/eureka/

logging:
  level:
    org.springframework:cloud.gateway: debug

文档聚合业务编码

在我们使用Spring Boot等单体架构集成swagger项目时,是通过对包路径进行业务分组,然后在前端进行不同模块的展示,而在微服务架构下,我们的一个服务就类似于原来我们写的一个业务组

springfox-swagger提供的分组接口是swagger-resource,返回的是分组接口名称、地址等信息

Spring Cloud微服务架构下,我们需要重写该接口,主要是通过网关的注册中心动态发现所有的微服务文档,代码如下:

public class SwaggerResourceConfig implements SwaggerResourcesProvider {

    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;


    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> {
            route.getPredicates().stream()
                    .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                    .forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(),
                            predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                    .replace("**", "v2/api-docs"))));
        });

        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {
        log.info("name:{},location:{}",name,location);
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }
}

接口:

@RestController
public class SwaggerHandler {

    @Autowired(required = false)
    private SecurityConfiguration securityConfiguration;

    @Autowired(required = false)
    private UiConfiguration uiConfiguration;

    private final SwaggerResourcesProvider swaggerResources;

    @Autowired
    public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
        this.swaggerResources = swaggerResources;
    }


    @GetMapping("/swagger-resources/configuration/security")
    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/swagger-resources/configuration/ui")
    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/swagger-resources")
    public Mono<ResponseEntity> swaggerResources() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }
}

启动配置

最后,项目启动类添加相关注解,代码如下:

@EnableDiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class ServiceDocApplication {

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

}

文档展示

最后分别依次启动项目:

service-server

service-user

service-order

service-doc

打开文档地址:http://localhost:10003/doc.html

查看文档效果如下: 

三、API 开发规范

1、@Api 

@Api注解放在类上面,这里的value是没用的,tags表示该controller的介绍。

但是tags如果有多个值,会生成多个list

@Api(tags = "用户模块")
@RestController
@RequestMapping("/user")
public class UserController {

2、@ApiOperation

@ApiOperation注解用于放在方法上面,其中value是该类的简短的叙述,notes一般是该方法的详细描述。

@ApiOperation(value = "查询用户列表")
    @PostMapping(value = "/list")
    public Rest<List<User>> list(){

3、@ApiImplicitParams

@ApiImplicitParams:用在请求的方法上,包含一组参数说明

    @ApiImplicitParam:对单个参数的说明     

        name:参数名

        value:参数的汉字说明、解释

        required:参数是否必须传

        paramType:参数放在哪个地方

            · header --> 请求参数的获取:@RequestHeader

            · query --> 请求参数的获取:@RequestParam

            · path(用于restful接口)--> 请求参数的获取:@PathVariable

            · body(请求体)-->  @RequestBody User user

            · form(普通表单提交)    

        dataType:参数类型,默认String,其它值dataType="int"      

        defaultValue:参数的默认值

@ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户ID", required = false, dataType = "String", paramType = "query", example = "1")
    })
    @ApiOperation(value = "根据用户id查询用户详情")
    @GetMapping("/queryById")
    public Rest<User> queryById(@RequestParam(value = "id") String id) {
        Rest<User> userRest = new Rest<>();
        userRest.setData(new User("user5", "总经理", "公司1"));
        return userRest;
    }

4、@ApiResponses

@ApiResponses:方法返回对象的说明

    @ApiResponse:每个参数的说明

        code:数字,例如400

        message:信息,例如"请求参数没填好"

        response:抛出异常的类

@ApiResponses(value = {
            @ApiResponse(code = 200, message = "接口返回成功状态"),
            @ApiResponse(code = 500, message = "接口返回未知错误,请联系开发人员调试")
    })
    @ApiOperation(value = "文件上传 测试接口", notes = "访问此接口,执行文件上传,测试接口")
    @PostMapping("upload")
    public void upload(@RequestParam("file") MultipartFile file) {
    }

5、@ApiModel

这里的Data Type Model,此时我们可以在实体类的代码中添加注解,选择我们需要在这里显示的属性。如下:

@ApiModelProperty(hidden = true)表示不需要在swagger页面进行展示,required表示该属性为必需的属性。

@ApiModel(value = "用户")
public class User {

    @ApiModelProperty(value = "姓名")
    private String name;

    @ApiModelProperty(value = "年龄")
    private Integer age;

    @ApiModelProperty(value = "工作")
    private String worker;

    @ApiModelProperty(value = "单位")
    private String company;

四、部署方式

1、前端打包成静态文件夹

dist文件夹下的内容拷贝到后端项目中resources/static目录下

2、前端页面放行

springsucurity的拦截器里面加上以下代码,放行这些静态文件

@Override

    public void configure(WebSecurity web) throws Exception {

        web.ignoring().antMatchers("/login","/css/**","/js/**","/index.html","/img/**","/fonts/**","/favicon.ico");

    }

3、使用maven的package打包项目

 

生成jar文件

 

4、把文件传到服务器主机

运行以下命令

nohup java -jar plms-0.0.1-SNAPSHOT.

 

5、在浏览器访问

http://服务器主机的ip:8080/index.html

五、在线测试

1、测试环境地址的配置管理

2、测试数据的模拟

Mock数据属性说明:

  1. 数据类型(MIME):响应结果类型,如JSONXML等;
  2. 结果数据:响应结果的数据,如响应结果类型为JSON时可设置响应结果数据为一段JSON数据;

 

六、授权

授权,是指授予某个APP调用某个API的权限。您的APP需要获得API的授权才能调用该API

七、监控

API Monitor是一个免费软件,可以让你监视和控制应用程序和服务,取得了API调用。 它是一个强大的工具,看到的应用程序和服务是如何工作的,或跟踪,你在自己的应用程序的问题。

1

八、统计

Dubbo-Monitor主要用来统计服务的调用次数和调用时间,服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心,监控中心则使用数据绘制图表来显示

点击Statistics,成功的次数,失败的次数,平均花费的时间,最大花费的时间,并发的次数

点击Charts,可以看到请求和响应的图表

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值