我们在项目开发中,往往期望做到前后端分离,也就是后端开发人员需要输出大量的服务接口,在没有Swagger之前需要我们话费大量的精力去编写接口文档。包含如接口的地址、需要传递参数情况、返回值的JSON数据格式以及每一个字段说明、当然还要考虑HTTP请求头、请求内容等信息。而随着项目的开发进度和后期进行迭代,后端输出的接口往往会面临修改、修复等问题,那也意味着接口文档又要进行相应的调整。接口文档的维护度以及可读性就大大下降。既然接口文档需要花费精力去维护,还要适当的进行面对面交流沟通。

 

Swagger为我们解决的问题:

  1. 系统接口归拢和在线管理,前端通过Swagger页面即可查看到系统中所有可用的接口,及接口的所有内容包括传递参数及返回数据结构等;
  2. API文档自动生成,不用担心修改接口代码之后忘记更新文档的尴尬;
  3. 支持在线测试,后端新增接口后需要给前端说一声增加了什么接口,前端不需要再用postman等,可以通过访问网页直接进行测试,并获取内容;

这里我推荐使用knife4j(当前最新版3.0.2),相比springfox-swagger-ui界面要美观,同时功能更完善。

1. 添加Swagger依赖

在项目pom.xml文件中增加如下依赖项:

<properties>
    <knife4j-spring-boot-starter.version>3.0.2</knife4j-spring-boot-starter.version>
  <!--其他配置代码-->
</properties>
<dependencies>
  <!--swagger2 begin-->
  <dependency>
      <groupId>com.github.xiaoymin</groupId>
      <artifactId>knife4j-spring-boot-starter</artifactId>
      <version>${knife4j-spring-boot-starter.version}</version>
  </dependency>
  <!--swagger2 end-->
</dependencies>

2. 在项目中增加SwaggerConfig代码

这里我推荐使用knife4j,相比springfox-swagger-ui界面要美观点。

package com.chqiuu.config;

import lombok.AllArgsConstructor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.resource.PathResourceResolver;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.util.UrlPathHelper;
import springfox.documentation.annotations.ApiIgnore;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiResourceController;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
import springfox.documentation.swagger2.web.Swagger2ControllerWebMvc;
import springfox.documentation.swagger2.web.WebMvcSwaggerTransformationFilter;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;

/**
 * Swagger2 前端API配置
 *
 * @author chqiu
 */
@Configuration
@EnableSwagger2
@AutoConfigureAfter({WebMvcConfig.class})
@AllArgsConstructor
public class Swagger2Config {
    private final VrihProperties properties;
    private static final String DEFAULT_PATH = "/swagger";

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(properties.isSwaggerEnable())
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.chquu.xxx"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("XX项目API接口管理")
                .description("XX项目API接口管理")
                .termsOfServiceUrl("127.0.0.1")
                .contact(new Contact("xxx", "http://www.apache.org", "xxx@qq.com"))
                .version("1.0.0").license("Apache 2.0").licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
                .build();
    }

    /**
     * SwaggerUI资源访问
     *
     * @param servletContext
     * @param order
     * @return
     * @throws Exception
     */
    @Bean
    public SimpleUrlHandlerMapping swaggerUrlHandlerMapping(ServletContext servletContext,
                                                            @Value("${swagger.mapping.order:10}") int order) throws Exception {
        SimpleUrlHandlerMapping urlHandlerMapping = new SimpleUrlHandlerMapping();
        Map<String, ResourceHttpRequestHandler> urlMap = new HashMap<>();
        {
            PathResourceResolver pathResourceResolver = new PathResourceResolver();
            pathResourceResolver.setAllowedLocations(new ClassPathResource("META-INF/resources/webjars/"));
            pathResourceResolver.setUrlPathHelper(new UrlPathHelper());

            ResourceHttpRequestHandler resourceHttpRequestHandler = new ResourceHttpRequestHandler();
            resourceHttpRequestHandler.setLocations(Arrays.asList(new ClassPathResource("META-INF/resources/webjars/")));
            resourceHttpRequestHandler.setResourceResolvers(Arrays.asList(pathResourceResolver));
            resourceHttpRequestHandler.setServletContext(servletContext);
            resourceHttpRequestHandler.afterPropertiesSet();
            //设置新的路径
            urlMap.put(DEFAULT_PATH + "/webjars/**", resourceHttpRequestHandler);
        }
        {
            PathResourceResolver pathResourceResolver = new PathResourceResolver();
            pathResourceResolver.setAllowedLocations(new ClassPathResource("META-INF/resources/"));
            pathResourceResolver.setUrlPathHelper(new UrlPathHelper());

            ResourceHttpRequestHandler resourceHttpRequestHandler = new ResourceHttpRequestHandler();
            resourceHttpRequestHandler.setLocations(Arrays.asList(new ClassPathResource("META-INF/resources/")));
            resourceHttpRequestHandler.setResourceResolvers(Arrays.asList(pathResourceResolver));
            resourceHttpRequestHandler.setServletContext(servletContext);
            resourceHttpRequestHandler.afterPropertiesSet();
            //设置新的路径
            urlMap.put(DEFAULT_PATH + "/**", resourceHttpRequestHandler);
        }
        urlHandlerMapping.setUrlMap(urlMap);
        //调整DispatcherServlet关于SimpleUrlHandlerMapping的排序
        urlHandlerMapping.setOrder(order);
        return urlHandlerMapping;
    }

    /**
     * SwaggerUI接口访问
     */
    @Controller
    @ApiIgnore
    @RequestMapping(DEFAULT_PATH)
    public static class SwaggerResourceController implements InitializingBean {
        private final ApiResourceController apiResourceController;
        private final DocumentationCache documentationCache;
        private final ServiceModelToSwagger2Mapper mapper;
        private final JsonSerializer jsonSerializer;
        private final PluginRegistry<WebMvcSwaggerTransformationFilter, DocumentationType> transformations;
        private static final String HAL_MEDIA_TYPE = "application/hal+json";
        private Swagger2ControllerWebMvc swagger2ControllerWebMvc;

        public SwaggerResourceController(ApiResourceController apiResourceController, DocumentationCache documentationCache, ServiceModelToSwagger2Mapper mapper, JsonSerializer jsonSerializer, PluginRegistry<WebMvcSwaggerTransformationFilter, DocumentationType> transformations) {
            this.apiResourceController = apiResourceController;
            this.documentationCache = documentationCache;
            this.mapper = mapper;
            this.jsonSerializer = jsonSerializer;
            this.transformations = transformations;
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            swagger2ControllerWebMvc = new Swagger2ControllerWebMvc(documentationCache, mapper, jsonSerializer, transformations);
        }
        /**
         * Swagger API首页地址
         *
         * @return 首页地址
         */
        @RequestMapping
        public ModelAndView index() {
            return new ModelAndView("redirect:" + DEFAULT_PATH + "/doc.html");
        }

        @RequestMapping("/swagger-resources/configuration/security")
        @ResponseBody
        public ResponseEntity<SecurityConfiguration> securityConfiguration() {
            return apiResourceController.securityConfiguration();
        }

        @RequestMapping("/swagger-resources/configuration/ui")
        @ResponseBody
        public ResponseEntity<UiConfiguration> uiConfiguration() {
            return apiResourceController.uiConfiguration();
        }

        @RequestMapping("/swagger-resources")
        @ResponseBody
        public ResponseEntity<List<SwaggerResource>> swaggerResources() {
            return apiResourceController.swaggerResources();
        }

        @RequestMapping(value = "/v2/api-docs", method = RequestMethod.GET, produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE})
        @ResponseBody
        public ResponseEntity<Json> getDocumentation(
                @RequestParam(value = "group", required = false) String swaggerGroup,
                HttpServletRequest servletRequest) {
            return swagger2ControllerWebMvc.getDocumentation(swaggerGroup, servletRequest);
        }
    }
}

3. 在Controller层接口增加Swagger注解

@Api(tags = "接口服务", value = "/api/v1/swagger/**")
@RestController
@RequestMapping("/api/v1/swagger")
public class ApiController {

    @ApiOperation("保存用户信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", value = "名字", required = true, paramType = "path"),
            @ApiImplicitParam(name = "age", dataType = "int", value = "年龄", required = true, paramType = "query")
    })
    @PostMapping("/{name}")
    @ResponseBody
    public Boolean save(
            @PathVariable("name") String name,
            @RequestParam("age") Integer age
    ) {
        userInfo.put(name, new User(name, age));
        return true;
    }
}

启动项目访问Swagger页面 http://localhost+端口名+项目名+/swagger/doc.html 呈现效果如下:

image.png

4. Swagger常用注解使用说明

@Api:用在请求的类上,表示对类的说明
    tags="说明该类的作用,可以在UI界面上看到的注解"
    value="该参数没什么意义,在UI界面上也看到,所以不需要配置"

@ApiOperation:用在请求的方法上,说明方法的用途、作用
    value="说明方法的用途、作用"
    notes="方法的备注说明"

@ApiImplicitParams:用在请求的方法上,表示一组参数说明
    @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
        name:参数名
        value:参数的汉字说明、解释
        required:参数是否必须传
        paramType:参数放在哪个地方
            · header --> 请求参数的获取:@RequestHeader
            · query --> 请求参数的获取:@RequestParam
            · path(用于restful接口)--> 请求参数的获取:@PathVariable
            · body(不常用)
            · form(不常用)    
        dataType:参数类型,默认String,其它值dataType="Integer"       
        defaultValue:参数的默认值

@ApiResponses:用在请求的方法上,表示一组响应
    @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
        code:数字,例如400
        message:信息,例如"请求参数没填好"
        response:抛出异常的类

@ApiModel:用于响应类上,表示一个返回响应数据的信息
            (这种一般用在post创建的时候,使用@RequestBody这样的场景,
            请求参数无法使用@ApiImplicitParam注解进行描述的时候)
    @ApiModelProperty:用在属性上,描述响应类的属性

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐