springboot2整合knife4j

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot2整合knife4j相关的知识,希望对你有一定的参考价值。

knife4j官网: https://doc.xiaominfo.com/guide/useful.html#java%E5%BC%80%E5%8F%91

这玩艺就swagger的升级版,但是用起来比swagger方便多了,至少不会出现莫名的版本兼容问题

下面记录一个配置示例

 

1. 代码结构

 

2.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>knife4j-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>knife4j-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <!--在引用时请在maven中央仓库搜索最新版本号-->
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
View Code

 

3.配置类

package com.example.knife4j.demo.config;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
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.EnableSwagger2;

@Configuration
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
public class SwaggerConfiguration {
 

    @Bean(value = "defaultApi2")
    public Docket defaultApi2() {
        Docket docket=new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                //分组名称
                .groupName("2.X版本")
                .select()
                //这里指定Controller扫描包路径(项目路径也行)
                .apis(RequestHandlerSelectors.basePackage("com.example.knife4j.demo"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("不重要")
                .description("测试名称不重要")
                .termsOfServiceUrl("http://localhost:88888/")
                .contact("10086@mail.com")
                .version("1.0")
                .build();
    }
}

 

4. 模型bean

package com.example.knife4j.demo.beans;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/**
 * 创建时间: 23:09 2018/9/19
 * 修改时间:
 * 编码人员: ZhengQf
 * 版   本: 0.0.1
 * 功能描述:
 */
@ApiModel(value = "用户模型")
public class UserEntity {
    @ApiModelProperty(value="id" ,required= true,example = "123")
    private Integer id;
    @ApiModelProperty(value="用户姓名" ,required=true,example = "郑钦锋")
    private String name;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "DemoDoctor [id=" + id + ", name=" + name + "]";
    }

}
View Code

 

5.两个接口controller

package com.example.knife4j.demo.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Api(value = "IndexController测试接口")
@RestController
public class IndexController {
    @ApiOperation(value = "测试index接口", nickname = "测试IndexController的index接口")
    @GetMapping("/index")
    public String index() {
        return "测试IndexController的index接口...";
    }

}
View Code
package com.example.knife4j.demo.controller;

import com.example.knife4j.demo.beans.UserEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;

@Api(value = "用户接口")
@RestController
public class UserController {


    @ApiOperation(value = "获取用户信息接口", nickname = "根据用户ID获取用户相关信息")
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "int")
    @PostMapping("/postMember")
    public UserEntity postMember(@RequestParam Integer id) {
        UserEntity userEntity = new UserEntity();
        userEntity.setId(id);
        userEntity.setName("admin");
        return userEntity;
    }


    @ApiOperation(value = "添加用户", nickname = "添加用户接口1", notes = "入参是复杂对象", produces = "application/json")
    @PostMapping("/postUser")
    @ResponseBody
    @ApiImplicitParam(paramType = "query", name = "userId", value = "用户id", required = true, dataType = "int")
    public UserEntity postUser(@RequestBody UserEntity user, @RequestParam("userId") int userId) { // 这里用包装类竟然报错
        if (user.getId() == userId) {
            return user;
        }
        return new UserEntity();
    }


    @ApiOperation(value = "添加用户", nickname = "添加用户接口2", notes = "入参是简单对象", produces = "application/json")
    @PostMapping("/addUser")
    @ResponseBody
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "userName", value = "用户姓名", required = true, dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "id", value = "用户id", required = true, dataType = "int")})
    public UserEntity addUser(String userName, int id) {
        UserEntity userEntity = new UserEntity();
        userEntity.setName(userName);
        userEntity.setId(id);
        return userEntity;
    }

}
View Code

 

6. srpingboot项目启动类

package com.example.knife4j.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.spring.web.SpringfoxWebMvcConfiguration;

@ConditionalOnClass(SpringfoxWebMvcConfiguration.class)
@SpringBootApplication
public class Knife4jDemoApplication implements WebMvcConfigurer {

    public static void main(String[] args) {
        SpringApplication.run(Knife4jDemoApplication.class, args);
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

 

这样简单一配置,就ok了,浏览器访问: http://127.0.0.1:8080/doc.html#/home

 

不过,在项目中我使用了 ResponseBodyAdvice 接口对项目接口响应内容做统一处理, 然后使用knife4j就出问题了。

ResponseBodyAdvice接口实现如下:

import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 自定义advise ,对restful请求响应体进行统一规范
 */
@EnableWebMvc
@Configuration
@RestControllerAdvice
public class ResponseAdvise implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object object, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        if (object instanceof ResponseData) {
            return object;
        }
        return ResponseData.of().setData(object);
    }
}

 

请求报错

而且后台还说找不到映射路径 

2020-03-10 23:31:01.533  WARN 7940 --- [nio-8080-exec-1] o.s.web.servlet.PageNotFound             : No mapping for GET /service-worker.js
2020-03-10 23:31:01.560  WARN 7940 --- [nio-8080-exec-4] o.s.web.servlet.PageNotFound             : No mapping for GET /favicon.ico
2020-03-10 23:31:14.468  WARN 7940 --- [nio-8080-exec-8] o.s.web.servlet.PageNotFound             : No mapping for GET /service-worker.js

 

然后,我在 ResponseAdvise# beforeBodyWrite方法中打上断点,发现我将swagger的请求内容进行了修改,以至于报了404。

 

最后在ResponseAdvise类上声明只对本项目的响应体内容进行统一处理

@RestControllerAdvice(basePackages = "com.example.knife4j.demo")

 

这样,就完全ok!

 

以上是关于springboot2整合knife4j的主要内容,如果未能解决你的问题,请参考以下文章

Knife4j解决SpringBoot整合Knife4j 3.0.3 文件上传不显示文件域

SpringBoot2.x集成knife4j

springboot2集成knife4j

springboot整合swagger(Knife4j)(漫画)

给Swagger换个皮肤,整合Knife4j文档

springboot整合swagger2+knife4j