Swagger简介
Swagger是一个规范和完整的API框架,可用于生成、描述、调用Restful风格的Web服务的接口文档。如果你在SpringBoot中使用的话,在项目启动后可以自动生成在线可调用的API文档,非常方便!
在SpringBoot中集成
首先在pom.xml引入依赖
<!--springfox swagger官方Starter-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
在apllication中配置文件
spring:
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER
增加一个兼容性Bean的控制
添加Swagger的Java配置,配置好Api信息和需要生成接口文档的类扫描路径,注意在SpringBoot2.6.x以上版本整合时由于兼容性问题需要配置一个BeanPostProcessor的Bean;
/**
* @description Swagger相关配置
*/
@Configuration
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.macro.mall.tiny.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SwaggerUI演示")
.description("mall-tiny")
.contact(new Contact("macro", null, null))
.version("1.0")
.build();
}
@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) {
throw new IllegalStateException(e);
}
}
};
}
}
访问地址
访问API文档信息,访问地址:http://localhost:8088/swagger-ui/
就可以看到具体的信息
开始使用
相关注解
相关配置
以下是它的一些常用配置
springfox:
documentation:
# 是否启用Swagger扫描代码生成文档
enabled: true
open-api:
# 是否启用Swagger的open-api
enabled: false
swagger-ui:
# 是否启用Swagger的Web UI
enabled: true
# 配置文档基础路径,此时路径为:/doc/swagger-ui/index.html
base-url: /doc
基本使用
使用时我们只需把Swagger对应的注解添加到接口方法上即可
1.@Api
value:简要描述该类的作用。
tags:用于给 API 进行分组,通常用于 UI 界面展示。
@Api(value = "用户管理接口", tags = {"用户管理"})
public class UserController {
// ...
}
2.@ApiOperation
value:简要描述该操作的主要功能。
notes:对该操作的详细说明或注意事项。
@ApiOperation(value = "获取用户信息", notes = "根据用户ID获取用户详细信息")
@GetMapping("/users/{id}")
public ResponseEntity<User> getUserById(@PathVariable String id) {
// ...
}
3. @ApiModel
实体类上的注解
@ApiModel(value = "PmsBrand",description = "商品品牌")
public class PmsBrand implements Serializable {
@ApiModelProperty(value = "主键ID")
private Long id;
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "首字母")
private String firstLetter;
@ApiModelProperty(value = "排序")
private Integer sort;
@ApiModelProperty(value = "是否为品牌制造商:0->不是;1->是")
private Integer factoryStatus;
@ApiModelProperty(value = "是否显示")
private Integer showStatus;
@ApiModelProperty(value = "产品数量")
private Integer productCount;
@ApiModelProperty(value = "产品评论数量")
private Integer productCommentCount;
@ApiModelProperty(value = "品牌logo")
private String logo;
@ApiModelProperty(value = "专区大图")
private String bigPic;
@ApiModelProperty(value = "品牌故事")
private String brandStory;
}
结合Spring Security使用
我们经常会在项目中使用Spring Security实现登录认证,接下来我们来讲下如何使用Swagger整合Spring Security,实现访问需要登录认证的接口。
如何访问需要登录认证的接口?只需在访问接口时添加一个合法的Authorization请求头即可,下面是Swagger相关配置
/**
* @description Swagger相关配置(带认证)
*/
@Configuration
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.macro.mall.tiny.controller"))
.paths(PathSelectors.any())
.build()
//添加登录认证
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
private List<SecurityScheme> securitySchemes() {
//设置请求头信息
List<SecurityScheme> result = new ArrayList<>();
ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
result.add(apiKey);
return result;
}
private List<SecurityContext> securityContexts() {
//设置需要登录认证的路径
List<SecurityContext> result = new ArrayList<>();
result.add(getContextByPath("/brand/.*"));
return result;
}
private SecurityContext getContextByPath(String pathRegex) {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(pathRegex))
.build();
}
private List<SecurityReference> defaultAuth() {
List<SecurityReference> result = new ArrayList<>();
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
result.add(new SecurityReference("Authorization", authorizationScopes));
return result;
}
}
我们需要在Spring Security中配置好Swagger静态资源的无授权访问,比如首页访问路径/swagger-ui/
/**
* @auther macrozheng
* @description SpringSecurity的配置
* @date 2018/4/26
* @github https://github.com/macrozheng
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Lazy
@Autowired
private UmsAdminService adminService;
@Autowired
private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Bean
SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf()// 由于使用的是JWT,我们这里不需要csrf
.disable()
.sessionManagement()// 基于token,所以不需要session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
"/",
"/swagger-ui/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/swagger-resources/**",
"/v2/api-docs/**"
)
.permitAll()
.antMatchers("/admin/login")// 对登录注册要允许匿名访问
.permitAll()
.antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
.permitAll()
.anyRequest()// 除上面外的所有请求全部需要鉴权认证
.authenticated();
// 禁用缓存
httpSecurity.headers().cacheControl();
// 添加JWT filter
httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//添加自定义未授权和未登录结果返回
httpSecurity.exceptionHandling()
.accessDeniedHandler(restfulAccessDeniedHandler)
.authenticationEntryPoint(restAuthenticationEntryPoint);
return httpSecurity.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService() {
//获取登录用户信息
return username -> {
AdminUserDetails admin = adminService.getAdminByUsername(username);
if (admin != null) {
return admin;
}
throw new UsernameNotFoundException("用户名或密码错误");
};
}
@Bean
public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
return new JwtAuthenticationTokenFilter();
}
}