link: https://swagger.io/
<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>配置类
@RestController public class TestController { @RequestMapping("/test") public String test(String name) { return name; } }接下来创建配置类SwaggerConfig,类标注@EnableSwagger2注解是关键,到这最简单的Swagger文档环境就搭建好了。
import org.springframework.context.annotation.Configuration; import springfox.documentation.swagger2.annotations.EnableSwagger2; // 堆代码 duidaima.com @Configuration @EnableSwagger2 public class SwaggerConfig { }启动报错
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) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.24.jar:5.3.24] at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_341] at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.24.jar:5.3.24] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) [spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) [spring-boot-2.7.6.jar:2.7.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) [spring-boot-2.7.6.jar:2.7.6] at com.springboot101.SwaggerApplication.main(SwaggerApplication.java:10) [classes/:na]解决方案
spring: mvc: pathmatch: matching-strategy: ant_path_matcher3、@EnableWebMvc注解
@EnableWebMvc @Configuration @EnableSwagger2 public class SwaggerConfig { }4、注册 BeanPostProcessor
@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 (IllegalArgumentException | IllegalAccessException e) { log.warn("修改WebMvcRequestHandlerProvider的属性:handlerMappings出错,可能导致swagger不可用", e); throw new IllegalStateException(e); } } }; }访问 swagger-ui
@Bean public Docket docket(Environment environment) { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.springboot101.controller")) .build(); }paths
@Bean public Docket docket(Environment environment) { return new Docket(DocumentationType.SWAGGER_2) .select() .paths(PathSelectors.ant("/test/**")) .build(); }groupName
@Bean public Docket docket(Environment environment) { return new Docket(DocumentationType.SWAGGER_2) .groupName("用户分组") .build(); }
@Bean public Docket docket1(Environment environment) { return new Docket(DocumentationType.SWAGGER_2) .groupName("商家分组") .select() .paths(PathSelectors.ant("/test1/**")) .build(); }
@Bean public Docket docket(Environment environment) { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()); // 文档基础配置 } // 堆代码 duidaima.com private ApiInfo apiInfo() { Contact contact = new Contact("小富", "http://fire100.top", "email@example.com"); return new ApiInfoBuilder() .title("Swagger学习") .description("程序员小富-带你一起学习 Swagger") .version("v1.0.1") .termsOfServiceUrl("http://fire100.top") .contact(contact) .license("许可证") .licenseUrl("许可链接") .extensions(Arrays.asList( new StringVendorExtension("我是", "小富"), new StringVendorExtension("你是", "谁") )) .build(); }对应的Swagger文档页面上展示的位置
@Bean public Docket docket(Environment environment) { // 可显示 swagger 文档的环境 Profiles of = Profiles.of("dev", "test","pre"); boolean enable = environment.acceptsProfiles(of); return new Docket(DocumentationType.SWAGGER_2) .enable(enable) .apiInfo(apiInfo()); // 文档基础配置 }host
@Bean public Docket docket(Environment environment) { return new Docket(DocumentationType.SWAGGER_2) .host("http://test.com") // 请求地址 .apiInfo(apiInfo()); // 文档基础配置 }securitySchemes
@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") ) ); }这样配置后,Swagger文档将会包含一个Authorize按钮,供用户输入我们设定的Bearer 、Authorization、Basic进行身份验证。
@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(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(); }现在在测试调用API接口时,header中可以正常加上鉴权字段和值了。
@Bean public Docket docket(Environment environment) { return new Docket(DocumentationType.SWAGGER_2) .tags(new Tag("小富接口", "小富相关的测试接口")) }授权登录
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>登录配置
spring: security: user: name: admin password: 123456再次访问文档就会出现如下的登录页
@ApiIgnore @GetMapping("/user2/{id}") public User test2(@PathVariable Integer id, @RequestBody User user) { return user; }@ApiModel
@ApiModel(value = "用户实体类", description = "用于存放用户登录信息") @Data public class User { @ApiModelProperty(value = "用户名字段", required = true, example = "#公众号:程序员小富") private String name; @ApiModelProperty(value = "年龄", required = true, example = "19") private Integer age; @ApiModelProperty(value = "邮箱", required = true, example = "#公众号:程序员小富") private String email; }
@Api(value = "用户管理接口描述", description = "用户管理接口描述", hidden = false, produces = "application/json", consumes = "application/json", protocols = "https", tags = {"用户管理"}, authorizations = { @Authorization(value = "apiKey", scopes = { @AuthorizationScope(scope = "read:user", description = "读权限"), @AuthorizationScope(scope = "write:user", description = "写权限") }), @Authorization(value = "basicAuth") }) @RestController public class TestController { }
@ApiOperation( value = "获取用户信息", notes = "通过用户ID获取用户的详细信息", hidden = false, response = UserDto.class, tags = {"用户管理"}, produces = "application/json", consumes = "application/json", protocols = "https", authorizations = { @Authorization(value = "apiKey", scopes = {@AuthorizationScope(scope = "read:user", description = "读权限")}), @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(); }@ApiImplicitParams
@ApiImplicitParams({ @ApiImplicitParam(name = "用户名", value = "用户名称信息", required = true, dataType = "String", paramType = "query") }) @GetMapping("/user") public String user(String name) { return name; }@ApiParam()
@GetMapping("/user4") public String user4(@ApiParam(name = "主键ID", value = "@ApiParam注解测试", required = true) String id) { return id; }@ApiResponses
@ApiResponses(value = { @ApiResponse(code = 200, message = "@ApiResponse注解测试通过", response = String.class), @ApiResponse(code = 401, message = "可能参数填的有问题", response = String.class), @ApiResponse(code = 404, message = "可能请求路径写的有问题", response = String.class) }) @GetMapping("/user4") public String user4(@ApiParam(name = "主键ID", value = "@ApiParam注解测试", required = true) String id) { return id; } ......总结