最近因为安全方面的原因给原来的项目进行升级,把原来的spring boot2.3.x升级到2.6.x,升级过程不在赘述。
一、整合knife4j 3.0.x到项目当中。
1.放入依赖
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
2.进行swagger的相关配置
package com.yi.swagger.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.pathMapping("/")
// 指定构建api文档的详细信息的方法:apiInfo()
.apiInfo(apiInfo())
.groupName("默认")
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
/**
* 构建api文档的详细信息
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// 设置页面标题
.title("系统接口总览")
// 设置接口描述
.description("接口调用测试")
// 设置联系方式
.contact(new Contact("接口测试","http://localhost:8011/","kml"))
// 设置版本
.version("1.0")
//服务地址
.termsOfServiceUrl("http://www.baidu.com")
// 构建
.build();
}
}
二、运行后出现的问题
1.启动Application后报错Failed to start bean 'documentationPluginsBootstrapper'
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181)
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54)
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155)
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at com.yi.FlandApplication.main(FlandApplication.java:19)
Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56)
at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113)
at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89)
at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.base/java.util.TimSort.sort(TimSort.java:234)
at java.base/java.util.Arrays.sort(Arrays.java:1306)
at java.base/java.util.ArrayList.sort(ArrayList.java:1721)
at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:392)
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107)
at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91)
at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82)
at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100)
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178)
... 14 common frames omitted
看到这个错误后,马上尝试了各种办法去解决,最后还是去百度找了一篇文章,解决办法是修改springfox,就是在swagger的配置文件里面加上一段代码,这里贴上代码
@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);
}
}
};
}
然后运行项目,发现报错没有了,可以正常打开浏览knife4j的页面
因为项目集入了springSecurity还碰到了加载knife4j页面资源被拦截的问题,这里很好解决,去配置文件里面配置跳过对应的登录验证
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/*.html").permitAll()
.antMatchers("/*.mp4").permitAll()
.antMatchers("/*.png").permitAll()
.antMatchers("/*.jpg").permitAll()
.antMatchers("/*.jpeg").permitAll()
.antMatchers("/*.css").permitAll()
.antMatchers("/*.js").permitAll()
.antMatchers("/*.ico").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/swagger/**").permitAll()
.antMatchers("/swagger-ui/**").permitAll()
.antMatchers("/v2/**").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.anyRequest()
.authenticated()
.and()
.apply(securityConfigurerAdapter());
// 开启跨域
http.cors().and().csrf().disable();
}
这样就能正常打开knife4j的页面了
下面就可以添加swagger的注解进行接口测试了。首先是实体类
package com.yi.service.domains.fland;
import com.yi.common.params.LoginParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(description = "用户登录请求实体类")
public class FlandLoginParam extends LoginParam{
/**
*
*/
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
其次是controller
package com.yi.controllers.fland;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.yi.common.result.ResultStatus;
import com.yi.common.result.ResultUtils;
import com.yi.service.domains.fland.FlandLoginParam;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* 登录验证
*
*/
@Api(tags = "用户登录测试接口")
@RestController
public class SysApiLoginController2
{
/**
* 登录方法
*
* @param loginBody 登录信息
* @return 结果
*/
@ApiOperation(value = "用户登录")
@RequestMapping(value = "/apilogin", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> login(@RequestBody FlandLoginParam user, HttpServletRequest request){
try {
return ResultUtils.combinationResult(ResultStatus.SUCCESS, 0);
} catch (Exception e) {
return ResultUtils.combinationResult(ResultStatus.FAILED, e.toString());
}
}
}
再次启动项目。
2.测试接口在knife4j页面不出来,注解失效。
正常来说当我们加入了上面的代码后,应该能在knife4j的页面看得到我们注解的实体类信息和接口信息,但是我启动项目打开页面得到的是空空如也。
不得已,又去各种百度查资料翻文章,最后额解决方式是在properties文件加入一个配置
spring.mvc.pathmatch.matching-strategy = ANT_PATH_MATCHER
好吧,问题终于解决。启动项目,打开网页,它终于出来了。
千辛万苦,问题总算得到了解决。