集成Swagger

集成Swagger

QuickStart

官网

Swagger: http://springfox.github.io/springfox/docs/current/

Knife4j: https://doc.xiaominfo.com/

相关依赖

1
2
3
4
5
6
7
8
9
10
11
12
<!-- swagger3 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>

Swagger相关配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ===== 自定义swagger配置 ===== #
# 是否开启swagger,生产环境一般关闭
swagger.enable=true
# title
swagger.application-name= ${spring.application.name}
# 接口文档版本
swagger.application-version=1.0
# 文档描述
swagger.application-description=swagger测试文档描述
# 联系人
swagger.contact-name=王宝建
# 联系人邮箱
swagger.contact-email=wangbaojian@okay.cn
# 组织地址
swagger.terms-url=https://okos.yuque.com

# 开启knife4j增强功能
knife4j.enable=true
# 开启basic身份认证功能
knife4j.basic.enable=true
knife4j.basic.username=root
knife4j.basic.password=123456

Swagger配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.List;

/**
* @author unclebryan
* @version 1.0
* @project ok-app-web
* @description
* @date 2022/8/19 19:39:48
*/
@Configuration
// @EnableOpenApi目的是导入OpenApiDocumentationConfiguration.class,可以省略,因为在starter中已经自动配置了OpenApiAutoConfiguration(在该类中导入了OpenApiDocumentationConfiguration.class)
@EnableOpenApi
@ConfigurationProperties("swagger")
@Data
public class SwaggerConfig implements WebMvcConfigurer {
/**
* 是否开启swagger,生产环境一般关闭
*/
private Boolean enable;

/**
* 项目应用名
*/
private String applicationName;

/**
* 项目版本信息
*/
private String applicationVersion;

/**
* 项目描述信息
*/
private String applicationDescription;

/**
* 联系人姓名
*/
private String contactName;

/**
* 联系人邮箱
*/
private String contactEmail;

/**
* 组织地址
*/
@Value("https://okos.yuque.com/dashboard")
private String termsUrl;


@Bean
public Docket docket() {
//添加head参数
RequestParameterBuilder tokenPar = new RequestParameterBuilder();
RequestParameterBuilder requestIdPar = new RequestParameterBuilder();
RequestParameterBuilder systemIdPar = new RequestParameterBuilder();
List<RequestParameter> pars = new ArrayList<RequestParameter>();
tokenPar.name("token").description("token")
.in("header")
.required(false)
.build();
requestIdPar.name("requestid").description("requestid")
.in("header")
.required(false)
.build();
systemIdPar.name("systemId").description("systemId")
.in("header")
.required(false)
.build();
pars.add(tokenPar.build());
pars.add(requestIdPar.build());
pars.add(systemIdPar.build());


return new Docket(DocumentationType.OAS_30)
.enable(enable)
.select()
// 扫描的包路径
.apis(
RequestHandlerSelectors.basePackage("com.noriental.okapp.module.coupon.controller")
.or(RequestHandlerSelectors.basePackage("com.noriental.okapp.module.user.v1.controller"))
)
// 定义要生成文档的Api的url路径规则
.paths(
PathSelectors.ant("/v1/**")
.and(PathSelectors.ant("/v1/coupon/**"))
)
.build()
.globalRequestParameters(pars)
// 可以忽略一些不需要的参数类型
.ignoredParameterTypes(HttpSession.class)
// 设置swagger-ui.html页面上的一些元素信息。
.apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(applicationName)
.description(applicationDescription)
.version(applicationVersion)
.contact(new Contact(contactName,"",contactEmail))
.termsOfServiceUrl(termsUrl)
.build();
}

// SwaggerUiWebMvcConfigurer中也对下面做了一些配置
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}

}

匹配规则说明

  1. 包匹配

    1
    2
    apis(
    RequestHandlerSelectors.basePackage("com.noriental.okapp.module.coupon.controller") .or(RequestHandlerSelectors.basePackage("com.noriental.okapp.module.user.v1.controller")))
  2. 路径匹配

    1
    2
    3
    4
    paths(
    PathSelectors.ant("/v1/**")
    .and(PathSelectors.ant("/v1/coupon/**"))
    )
  3. 正则匹配

    1
    2
    3
    4
    paths(
    PathSelectors.regex("/v1/**")
    .and(PathSelectors.regex("/v1/coupon/**"))
    )
  4. 不匹配

    使用@ApiIgnore注解,即可忽略不需要进行Swagger的类或者方法,如可以屏蔽跑数据的接口

    同时,该注解还可以忽略不需要的参数,如 (@RequestBody @Valid RequestEntity<CouponRequest> request, @ApiIgnore HttpSession session)

PS. 以上操作均可以通过Predicate的negate()方法进行取反操作

1
2
3
4
.paths(
PathSelectors.ant("/v1/**")
.and(PathSelectors.ant("/v1/coupon/**").negate())
)

文档访问地址

swagger

http://localhost:8999/swagger-ui/index.html

Knief4j

http://localhost:8999/doc.html

认证与授权(可选)

相关依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>

配置类

授权服务配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.noriental.okapp.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;


/**
* 2020/10/25 9:20
* 授权服务
*/

@Configuration
@EnableAuthorizationServer
@Order(404)
public class AuthConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final BCryptPasswordEncoder bCryptPasswordEncoder;

public AuthConfiguration(AuthenticationManager authenticationManager, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.authenticationManager = authenticationManager;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//授权码模式(authorization code)
//简化模式(implicit)
//密码模式(resource owner password credentials)
//客户端模式(client credentials)

// 内存模式存储token
clients.inMemory()
.withClient("okay").secret(bCryptPasswordEncoder.encode("123"))
//.authorizedGrantTypes("implicit")
.authorizedGrantTypes("authorization_code")
//.authorizedGrantTypes("password")
//.authorizedGrantTypes("client_credentials")
.redirectUris(
// knife4j 授权地址
"http://localhost:8999/webjars/oauth/oauth2.html",
// swagger 授权地址
"http://localhost:8999/swagger-ui/oauth2-redirect.html")
.scopes("read","write","reads","writes");
}

@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()")
.allowFormAuthenticationForClients();
}
}

认证服务配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.noriental.okapp.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;


/**
* 认证服务
* @author unclebryan
* 2022年08月31日19:26:58
*/
@Configuration
@Order(300)
public class SecurityWebConfiguration extends WebSecurityConfigurerAdapter {
@Override
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/v1/coupon/**").hasAnyAuthority("coupon","ROLE_TEST","ROLE_ADMIN")
.antMatchers("/v1/**").hasAnyRole("TEST","ADMIN")
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser("admin").password(passwordEncoder().encode("123")).roles("ADMIN")
.and()
.withUser("bryan").password(passwordEncoder().encode("123")).roles("TEST")
.and()
.withUser("lijing").password(passwordEncoder().encode("123")).authorities("coupon")
;
}
}

Swagger配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package com.noriental.okapp.config;

import com.google.common.collect.Lists;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.AuthorizationCodeGrant;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.GrantType;
import springfox.documentation.service.OAuth;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.service.TokenEndpoint;
import springfox.documentation.service.TokenRequestEndpoint;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
* @author unclebryan
* @version 1.0
* @project ok-app-web
* @description
* @date 2022/8/19 19:39:48
*/
@Configuration
@ConfigurationProperties("swagger")
@Data
public class SwaggerConfig implements WebMvcConfigurer {
/**
* 是否开启swagger,生产环境一般关闭
*/
private Boolean enable;

/**
* 项目应用名
*/
private String applicationName;

/**
* 项目版本信息
*/
private String applicationVersion;

/**
* 项目描述信息
*/
private String applicationDescription;

/**
* 联系人姓名
*/
private String contactName;

/**
* 联系人邮箱
*/
private String contactEmail;

/**
* 组织地址
*/
@Value("https://okos.yuque.com/dashboard")
private String termsUrl;


@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(enable)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("com.noriental.okapp.module"))
// 扫描的包路径
.build()
// 支持的通讯协议集合
.protocols(newHashSet("https", "http"))
.securitySchemes(getSecuritySchemes())
.securityContexts(getSecurityContexts())
.globalRequestParameters(getParameters())
// 设置swagger-ui.html页面上的一些元素信息。
.apiInfo(apiInfo());
}



private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(applicationName)
.description(applicationDescription)
.version(applicationVersion)
.contact(new Contact(contactName,"",contactEmail))
.termsOfServiceUrl(termsUrl)
.build();
}


/**
* 设置请求头参数
* @return
*/
private List<RequestParameter> getParameters() {
//添加head参数
RequestParameterBuilder tokenPar = new RequestParameterBuilder();
RequestParameterBuilder requestIdPar = new RequestParameterBuilder();
RequestParameterBuilder systemIdPar = new RequestParameterBuilder();
List<RequestParameter> parameters = new ArrayList<RequestParameter>();
tokenPar.name("token").description("token")
.in("header")
.required(false)
.build();
requestIdPar.name("requestid").description("requestid")
.in("header")
.required(false)
.build();
systemIdPar.name("systemId").description("systemId")
.in("header")
.required(false)
.build();
parameters.add(tokenPar.build());
parameters.add(requestIdPar.build());
parameters.add(systemIdPar.build());
return parameters;
}


@SafeVarargs
private final <T> Set<T> newHashSet(T... ts) {
if (ts.length > 0) {
return new LinkedHashSet<>(Arrays.asList(ts));
}
return null;
}


/**
* 认证模式
* @return
*/
private List<SecurityScheme> getSecuritySchemes() {
//schema
List<GrantType> grantTypes=new ArrayList<>();
//授权码模式AuthorizationCodeGrant
TokenRequestEndpoint tokenRequestEndpoint=new TokenRequestEndpoint("/oauth/authorize","okay","123");
TokenEndpoint tokenEndpoint=new TokenEndpoint("/oauth/token","access_token");
AuthorizationCodeGrant authorizationCodeGrant=new AuthorizationCodeGrant(tokenRequestEndpoint,tokenEndpoint);
grantTypes.add(authorizationCodeGrant);
OAuth oAuth=new OAuthBuilder().name("oauth2")
.grantTypes(grantTypes).build();
List<SecurityScheme> securitySchemes=Lists.newArrayList(oAuth);
return securitySchemes;
}


/**
* 认证的安全上下文
* @return
*/
private List<SecurityContext> getSecurityContexts() {
//context
//scope方位
List<AuthorizationScope> scopes=new ArrayList<>();
scopes.add(new AuthorizationScope("read","read resources"));
scopes.add(new AuthorizationScope("write","write resources"));
scopes.add(new AuthorizationScope("reads","read all resources"));
scopes.add(new AuthorizationScope("writes","write all resources"));

SecurityReference securityReference=new SecurityReference("oauth2",scopes.toArray(new AuthorizationScope[]{}));
SecurityContext securityContext=new SecurityContext(Lists.newArrayList(securityReference),PathSelectors.any(), method->true, operation->true);
//securyContext
List<SecurityContext> securityContexts=Lists.newArrayList(securityContext);
return securityContexts;
}

// SwaggerUiWebMvcConfigurer中也对下面做了一些配置
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}

}

集成Swagger
http://example.com/2022/08/22/服务治理/swagger配置/
作者
UncleBryan
发布于
2022年8月22日
许可协议