springboot3.0.11-SNAPSHOT problems encountered when using knife4j-openapi3

1. Local working environment

ide2021

jdk17

springboot3.0.11-SNAPSHOT

2. Reasons for using knife4j-openapi3

After writing a project using springboot3, I want to quickly generate an interface document for myself to watch. After surfing the Internet for a while, I found that it is more suitable to use Swagger documents to complete a complex document with a small number of annotations. Just go ahead and write a demo using the information on the Internet, but found that the project could not start normally. After reading the blog, I found that Swagger2 is temporarily unable to adapt to springboot3. Later, I found in other blogs that openapi can be used to be compatible with springboot3. At the same time, knife4j is a beautification of swagger, so knife4j-openapi3 is used.

3. Configure

The corresponding dependencies are as follows:

<dependency>
     <groupId>com.github.xiaoymin</groupId>
     <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
     <version>4.1.0</version>
</dependency>

The configuration file is in yml format, so simply configure knife4j as follows in the configuration

# Online document configuration
springdoc:
  swagger-ui:
    # Configure swagger-ui interface access path
    path: /swagger-ui.html
    #Packet scanning path
  packages-to-scan: com.pjx.sys.controller
  # Enable wend by default
  api-docs:
    enabled: true

The above packages-to-scan, which is the package scanning path, scans the control layer, which is your controller layer. Just scan to the outer layer and do not go deep into the interior. The path can be copied directly.

At this time, knife4j still needs to be configured before it can be used.

Create the SwaggerConfig class in your own project for configuration

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {

    @Bean
    public OpenAPI springShopOpenAPI() {
        return new OpenAPI()
                .info(new Info().title("title")
                        //Description
                        .description("My API Documentation")
                        //Version
                        .version("v1")
                        //Author information, set by yourself
                        .contact(new Contact().name("Peng").email("11111").url("https://www.baidu.com"))
                        //Set the license information of the interface document
                        .license(new License().name("Apache 2.0").url("http://springdoc.org")));
    }

}

The basic configuration here is complete, let’s use a simple demo to demonstrate

The above is the corresponding structure, and the following are the control layer and pojo.

import com.example.test.pojo.Books;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "test", description = "description")
@RestController
@RequestMapping("/getBooks")
public class BookController {

    @GetMapping
    @Operation(summary = "Test interface")
    public Books getBooks(){
        Books books = new Books();
        books.setId(1);
        return books;
    }
}
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Schema
@Data
public class Books {
    @Schema(name = "id",description = "user id",defaultValue = "12",example = "1")
    private Integer id;
}

After the above is completed, a simple document is completed, and you can directly see the effect.

doc.html

swagger-ui

After the demo was completed and no problems were found, I started to import the configuration into my own project, and then a series of problems appeared.

4. Problems that arise in your own projects

4.1 can access swagger -ui but cannot access doc.html

I didn’t know what was going on at the time, and I was thinking, why can’t it be displayed? Why can swagger-ui be used? Why can demo be used? Programmers are confused for three consecutive times. . . Finally, after browsing a lot of blogs, I realized that I was out of my mind.

First of all, you need to know where these resources are. They are in the jar package of knife4j. Although you have imported the package, you do not tell spring boot about the resources. How can it find them? Looking for air? Secondly, swagger-ui can be used because it is configured in the yml file. The doc has no configuration and no configuration method. The demo can be used, but the one in the project cannot be used because the springboot version is too high and sometimes cannot be found. Resources, you need to tell it manually, which brings you back to question 1.

The corresponding resources are as follows:

4.1.1 Solution

Implement the WebMvcConfigurer interface in the WebConfig configuration class, override the addResourceHandlers method, and import the location of the resource.

@Component
public class WebConfig implements WebMvcConfigurer {

 /**
     * Static resource mapping
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
     registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
     registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

}

In this way, the resources are found by springboot. Of course, if the interceptor is configured, some resources need to be ignored. You can implement the addInterceptors method in the WebMvcConfigurer interface, use addInterceptor internally to define your own interceptor, and use addPathPatterns to add interception paths and excludePatterns. Ignore the path, my ignore path is as follows

"/v3/api-docs/**", "/doc.html", "/webjars/**", "/swagger-resources", "/swagger- ui/**"

If you don’t know the specific resources to be ignored, you can directly use Shift + f5 in the browser’s Network to ignore those resources that report errors. In this way, doc.html can be accessed.

4.2 Regarding the problem of not being able to find the icon in doc.html

This problem is not big at all, but I don’t like seeing the browser error message very much. After checking the information on the Internet, I found that the icon may be infringing, and then it is not allowed to be used in the future.

4.2.1 Solution

Put a favicon.ico picture in the static resource folder by yourself. Put whatever you like, but the suffix name must be the same. Must be an ico file. Download one you like from the Internet and change the suffix yourself.

After putting it in, everything is not fine. You still need to let spring boot know about this icon, otherwise it will still be inaccessible. You also need to add static resource mapping. Add in method 4.1.1

registry.addResourceHandler("favicon.ico").addResourceLocations("classpath:/static/");

At the same time, add /favicon.ico to the ignore path, which means that this image is allowed so that the browser can find it.

Finally the solution is completed. Sprinkle flowers.

Just kidding.

5. Simple application in entity classes and control layers.

5.1 Entity Class

Just go to the code, okay.

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Schema
@Data
public class User {
    //id
    @Schema(name = "id", description = "serial number", defaultValue = "1", example = "1")
    private Integer id;
    //username
    @Schema(name = "username", description = "username", defaultValue = "not null", example = "admin")
    private String username;
    //password
    @Schema(name = "password", description = "password", defaultValue = "not null", example = "******")
    private String password;
    //permission id
    @Schema(name = "roleId", description = "Permission id, determine whether you have this permission", defaultValue = "not null", example = "admin")
    private Integer roleId;
    //Whether it is default
    @Schema(name = "is_default", description = "0 is the default user, 1 is the normal user", defaultValue = "1", example = "1")
    private Integer is_default;
    //Permissions
    @Schema(hidden = true)
    private Role role;
    //token
    @Schema(name = "token", description = "storage front-end token", defaultValue = "not null", example = "dsafasdff341234123...")
    private String token;
}

The @Schema annotation is used to describe the attributes of a class, description is a description, defaultValue is the default value, example is an example, and hidden is ignored.

5.2 Control Layer

import com.pjx.sys.service.UploadService;
import com.pjx.sys.util.R;
import com.pjx.sys.util.SYSCode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileNotFoundException;

@Tag(name = "Upload picture")
@RestController
@RequestMapping("/adminapi/upload")
public class UploadController {

    //Import UploadService
    @Resource
    private UploadService uploadService;

    @Operation(method = "POST", summary = "Update background image", description = "Update the background image of the laboratory by passing in a picture with specified specifications")
    @PostMapping
    public R uploadBg(@Parameter(description = "picture object") @RequestParam("file") MultipartFile file) {
        try {
            uploadService.uploadBg(file);
            return new R(SYSCode.CODE_SUCCESS, "Upload successful");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return new R(SYSCode.CODE_ERROR, "Upload failed");
    }
}

@Tag is used to mark and group API interfaces.

@Operation is used to describe the detailed operation of API interface methods. method is the method, summary is the introduction, and description is the description.

@Parameter is used to specify the parameter list of the operation.

Other methods are incomplete, but are as follows for the time being: