当前位置 博文首页 > CHQIUU的专栏:Spring Boot项目中集成Swagger knife4j并自定义访

    CHQIUU的专栏:Spring Boot项目中集成Swagger knife4j并自定义访

    作者:[db:作者] 时间:2021-07-18 16:16

    我们在项目开发中,往往期望做到前后端分离,也就是后端开发人员需要输出大量的服务接口,在没有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:用在属性上,描述响应类的属性

    ?

    cs