Master Swagger: Build, Customize, and Secure Your Spring Boot API Docs

This guide explains what Swagger is, why it’s useful for RESTful APIs, and provides step‑by‑step instructions for integrating Swagger 3.0 with Spring Boot 2.7, handling version conflicts, customizing documentation, adding security, and using annotations to enrich API metadata.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Master Swagger: Build, Customize, and Secure Your Spring Boot API Docs

What is Swagger?

Swagger is a popular RESTful‑style API documentation tool that helps developers create readable, interactive API docs automatically.

It provides a set of tools and specifications that make it easy to generate and maintain clear API documentation.

title: Swagger
desc: Swagger 官方网站
logo: https://static1.smartbear.co/swagger/media/assets/images/swagger_logo.svg
link: https://swagger.io/

Why Use Swagger?

Before tools like Swagger, developers had to write and maintain API docs manually, which often became outdated when the API changed.

Key features of Swagger include:

Automatic generation of API docs from code annotations, eliminating manual writing.

An executable web UI that supports online testing of APIs without extra tools.

Support for multiple programming languages such as Java, PHP, and Python.

Overall, Swagger lets you focus more on coding and less on documentation maintenance.

Setting Up Swagger

Maven Dependencies

The example uses Swagger 3.0 with Spring Boot 2.7.6. Note the change in artifact names between Swagger 2.0 and 3.0.

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

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

Configuration Class

Create a simple controller TestController with a /test endpoint.

@RestController
public class TestController {
    @RequestMapping("/test")
    public String test(String name) {
        return name;
    }
}

Then create a configuration class SwaggerConfig annotated with @EnableSwagger2 to enable Swagger.

import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
}

Startup Errors

When using Spring Boot 2.7.x with Swagger 3.0, a conflict may occur between Spring Boot’s PathPatternMatcher and Springfox’s AntPathMatcher, leading to a bean initialization exception.

Springfox uses AntPathMatcher while Spring Boot 2.7.x uses PathPatternMatcher ; the mismatch causes the error.
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181)
    ... (stack trace omitted for brevity)

Solutions

Four common solutions are provided:

1. Downgrade Versions

Use Spring Boot 2.5.x and a compatible Springfox version, though this is not recommended.

2. Unify Path‑Matching Strategy

Configure Spring MVC to use ant_path_matcher in application.yml:

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

3. Add @EnableWebMvc

Annotate SwaggerConfig with @EnableWebMvc to register a RequestMappingHandlerMapping bean compatible with Swagger.

@EnableWebMvc
@Configuration
@EnableSwagger2
public class SwaggerConfig {
}

4. Register a BeanPostProcessor

Implement a custom BeanPostProcessor to filter out handler mappings that use PathPatternParser, ensuring Swagger can register its mappings.

@Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
    return new BeanPostProcessor() {
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
                customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
            }
            return bean;
        }
        private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
            List<T> copy = mappings.stream()
                .filter(mapping -> mapping.getPatternParser() == null)
                .collect(Collectors.toList());
            mappings.clear();
            mappings.addAll(copy);
        }
        @SuppressWarnings("unchecked")
        private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
            try {
                Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                field.setAccessible(true);
                return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
        }
    };
}

Accessing Swagger UI

After fixing the issue, open http://127.0.0.1:9002/swagger-ui/index.html to view the generated documentation. Note that the /test endpoint appears with all HTTP methods because @RequestMapping does not specify a method; using specific mapping annotations (e.g., @GetMapping) avoids redundant entries.

API Documentation Configuration

Swagger’s Docket object allows fine‑grained configuration of the generated docs.

select()

Returns an ApiSelectorBuilder to specify which APIs and paths to include via apis() and paths().

apis

By default, Swagger scans the whole project. You can limit scanning to a specific base package:

@Bean
public Docket docket(Environment environment) {
    return new Docket(DocumentationType.SWAGGER_2)
        .select()
        .apis(RequestHandlerSelectors.basePackage("com.springboot101.controller"))
        .build();
}

paths

Filter by URL pattern, e.g., only include /test/** paths:

@Bean
public Docket docket(Environment environment) {
    return new Docket(DocumentationType.SWAGGER_2)
        .select()
        .paths(PathSelectors.ant("/test/**"))
        .build();
}

groupName

Assign a group name to separate multiple documentation sets.

@Bean
public Docket docket(Environment environment) {
    return new Docket(DocumentationType.SWAGGER_2)
        .groupName("User Group")
        .build();
}

apiInfo

Set basic information such as title, description, version, and contact.

@Bean
public Docket docket(Environment environment) {
    return new Docket(DocumentationType.SWAGGER_2)
        .apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
    Contact contact = new Contact("小富", "http://fire100.top", "[email protected]");
    return new ApiInfoBuilder()
        .title("Swagger学习")
        .description("程序员小富-带你一起学习 Swagger")
        .version("v1.0.1")
        .termsOfServiceUrl("http://fire100.top")
        .contact(contact)
        .license("许可证")
        .licenseUrl("许可链接")
        .build();
}

enable

Enable or disable documentation generation based on the active Spring profile.

@Bean
public Docket docket(Environment environment) {
    Profiles profiles = Profiles.of("dev", "test", "pre");
    boolean enable = environment.acceptsProfiles(profiles);
    return new Docket(DocumentationType.SWAGGER_2)
        .enable(enable)
        .apiInfo(apiInfo());
}

host

Specify the host name or IP displayed in the docs.

@Bean
public Docket docket(Environment environment) {
    return new Docket(DocumentationType.SWAGGER_2)
        .host("http://test.com")
        .apiInfo(apiInfo());
}

securitySchemes

Configure authentication fields (e.g., Bearer, Authorization, Basic) that appear in the Swagger UI.

@Bean
public Docket docket(Environment environment) {
    return new Docket(DocumentationType.SWAGGER_2)
        .securitySchemes(Arrays.asList(
            new ApiKey("Bearer鉴权", "Bearer", "header"),
            new ApiKey("Authorization鉴权", "Authorization", "header"),
            new ApiKey("Basic鉴权", "Basic", "header")
        ));
}

securityContexts

Define which APIs require the security schemes defined above.

@Bean
public Docket docket(Environment environment) {
    return new Docket(DocumentationType.SWAGGER_2)
        .securitySchemes(...)
        .securityContexts(Collections.singletonList(securityContext()));
}

private SecurityContext securityContext() {
    return SecurityContext.builder()
        .securityReferences(Arrays.asList(
            new SecurityReference("Authorization", new AuthorizationScope[0]),
            new SecurityReference("Bearer", new AuthorizationScope[0]),
            new SecurityReference("Basic", new AuthorizationScope[0])
        ))
        .build();
}

tags

Add custom tags to group APIs in the UI.

@Bean
public Docket docket(Environment environment) {
    return new Docket(DocumentationType.SWAGGER_2)
        .tags(new Tag("小富接口", "小富相关的测试接口"));
}

Authorization Login

For security, you can protect the Swagger UI with Spring Security credentials.

Dependency

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

Login Configuration

Add a username and password in application.yml:

spring:
  security:
    user:
      name: admin
      password: 123456

Visiting the docs now shows a login page.

Documentation Annotations

Swagger provides many annotations to enrich API metadata, such as @ApiIgnore, @ApiModel, @ApiModelProperty, @Api, @ApiOperation, @ApiImplicitParams, @ApiParam, @ApiResponses, and @ApiResponse. These allow you to hide endpoints, describe models, define operation details, specify parameter information, and document response codes.

Example: @ApiOperation

@ApiOperation(
    value = "Get user info",
    notes = "Retrieve detailed user information by ID",
    response = UserDto.class,
    tags = {"User Management"},
    produces = "application/json",
    consumes = "application/json",
    protocols = "https",
    authorizations = {
        @Authorization(value = "apiKey", scopes = {@AuthorizationScope(scope = "read:user", description = "Read permission")}),
        @Authorization(value = "Basic")
    },
    responseHeaders = {@ResponseHeader(name = "X-Custom-Header", description = "Custom header", response = String.class)},
    code = 200,
    httpMethod = "GET"
)
@GetMapping("/user1")
public UserDto user1(@RequestBody User user) {
    return new UserDto();
}

Example: @ApiResponses

@ApiResponses({
    @ApiResponse(code = 200, message = "@ApiResponse test passed", response = String.class),
    @ApiResponse(code = 401, message = "Possible parameter issue", response = String.class),
    @ApiResponse(code = 404, message = "Possible path issue", response = String.class)
})
@GetMapping("/user4")
public String user4(@ApiParam(name = "Primary Key ID", value = "@ApiParam test", required = true) String id) {
    return id;
}

Conclusion

Even though Swagger may not appear in many interview questions, maintaining clear and comprehensive API documentation is an essential habit for developers. Whether using Swagger or another tool, well‑structured documentation improves code readability and collaboration.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootAPI documentationSwagger
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.