安全漏洞修復(fù)導(dǎo)致SpringBoot2.7與Springfox不兼容的偽命題解決
項(xiàng)目基于 springboot2.5.2 實(shí)現(xiàn)的,用 springfox-swagger2 生成與前端對(duì)接的 API 文檔;pom.xml 中依賴如下
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
啟動(dòng)服務(wù)后,就可以訪問 Swagger UI
http://localhost:8080/swagger-ui/index.html

前端同事就可以訪問這個(gè)來對(duì)接接口了,后端省去了寫接口文檔的工作,一切都是那么美好!可突然有一天,安全部門發(fā)來報(bào)告,說服務(wù)存在很多安全漏洞
CVE-2023-20860、CVE-2022-45143、CVE-2023-46589、...
讓我們根據(jù)報(bào)告中的建議進(jìn)行修復(fù),然后就開始了我的踩坑之旅!
springboot 與 springfox 兼容問題
粗略看了一眼,將 spring-boot 升級(jí),可以解決很多漏洞,既然要升,那就升到可升的最高版本;因?yàn)槭腔?nbsp;JDK8,所以 spring-boot 最高能升級(jí)到 2.7.8。那就升嘛,不要慫就是干!
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
啟動(dòng)服務(wù),第一個(gè)坑來了:NullPointerException
2025-05-30 21:13:42.264|ERROR|main|818|o.s.boot.SpringApplication :Application run failed org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182) at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:357) at java.lang.Iterable.forEach(Iterable.java:75) at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:156) at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:124) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:946) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:594) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:409) at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) at com.qsl.Application.main(Application.java:16) Caused by: java.lang.NullPointerException: 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.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) at java.util.TimSort.sort(TimSort.java:220) at java.util.Arrays.sort(Arrays.java:1512) at java.util.ArrayList.sort(ArrayList.java:1454) at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:387) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) 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:179) ... 14 common frames omitted
遇到問題不要怕
查詢問題并解決問題嘛;從哪查,我想大家已經(jīng)達(dá)成了統(tǒng)一的共識(shí):大數(shù)據(jù)模型。deepseek 就是熱門之一,我們直接將堆棧信息扔給他,讓他提供解決方案。他一針見血分析出了原因
這個(gè)錯(cuò)誤通常是由于 Springfox Swagger(
springfox-swagger2)與 Spring Boot 版本不兼容 或 Spring MVC 路徑匹配策略沖突 導(dǎo)致的。以下是幾種解決方案
降級(jí) Spring Boot 版本
Spring Boot 2.6+開始與springfox不兼容,但Springfox Swagger 2.x已經(jīng)停止維護(hù)了,所以說通過升級(jí) Springfox Swagger 來適配 Spring Boot 2.6+ 是不行了。我們的目的是升級(jí) Spring Boot,那么降級(jí) Spring Boot 這個(gè)方案肯定是行不通的。
升級(jí)到 SpringDoc OpenAPI
SpringDoc 是 Swagger 的替代方案,支持 OpenAPI 3.0,兼容 Spring Boot 2.6+ 和 3.x
考慮到注解變動(dòng)大,需要調(diào)整的地方太多,這個(gè)方案不到萬(wàn)不得已不采用
修改路徑匹配策略
如果不想降級(jí) Spring Boot,可以調(diào)整路徑匹配策略
spring: mvc: pathmatch: matching-strategy: ant_path_matcher這個(gè)調(diào)整簡(jiǎn)單,感覺可行,試試發(fā)現(xiàn)雀氏可以,采用這種方案
Swagger 配置是否正確
確保
@EnableSwagger2和Docket配置正確@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.your.package")) // 替換成你的 Controller 包名 .paths(PathSelectors.any()) .build(); } }這個(gè)確定是配置正確的,不是這個(gè)問題
deepseek 還給了其他方案,大家可以結(jié)合自己的實(shí)際情況,看看方案是否適用。如果你們以為坑就這么填平了,那只能說你們還是太年輕啦
我再加個(gè)依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
啟動(dòng)服務(wù),同樣的問題又來了
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182) at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:357) at java.lang.Iterable.forEach(Iterable.java:75) at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:156) at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:124) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:946) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:594) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:409) at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) at com.qsl.Application.main(Application.java:16) Caused by: java.lang.NullPointerException: 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.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) at java.util.TimSort.sort(TimSort.java:220) at java.util.Arrays.sort(Arrays.java:1512) at java.util.ArrayList.sort(ArrayList.java:1454) at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:387) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) 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:179) ... 14 common frames omitted
同個(gè)問題出現(xiàn)一次也就算了,換個(gè)方式出現(xiàn)第二次,有點(diǎn)欺負(fù)人了!
此時(shí)我們?cè)偃?nbsp;deepseek,給出的解決方案,嘗試了都不對(duì),好在在網(wǎng)上找到了解決方案,增加如下配置
@Configuration
@EnableSwagger2
public class SwaggerConfig {
/**
* springboot 2.7.x不支持swagger2,注冊(cè)bean進(jìn)行兼容
* 該方法在Spring Boot 2.7.x中手動(dòng)注冊(cè)WebMvcEndpointHandlerMapping,用于解決Swagger無法直接訪問Actuator端點(diǎn)的問題。下面詳細(xì)說明其作用:
* 1. 收集所有可暴露的端點(diǎn)
* 使用以下組件獲取不同類型的端點(diǎn):
* webEndpointsSupplier.getEndpoints():獲取所有基于Web的端點(diǎn)(如/actuator/health)。
* servletEndpointsSupplier.getEndpoints():獲取Servlet類型的端點(diǎn)(如/actuator/servlet)。
* controllerEndpointsSupplier.getEndpoints():獲取Controller類型的端點(diǎn)。
* 將這些端點(diǎn)統(tǒng)一添加到allEndpoints列表中,以便后續(xù)處理。
* 2. 設(shè)置端點(diǎn)的基礎(chǔ)路徑
* 從WebEndpointProperties中獲取配置的端點(diǎn)基礎(chǔ)路徑(basePath),默認(rèn)值通常是/actuator。
* 創(chuàng)建一個(gè)EndpointMapping對(duì)象,并傳入基礎(chǔ)路徑,用于定義端點(diǎn)的URL映射規(guī)則。
* 3. 判斷是否需要注冊(cè)端點(diǎn)鏈接映射
* 判斷條件如下:
* 如果啟用了端點(diǎn)發(fā)現(xiàn)(webEndpointProperties.getDiscovery().isEnabled())。
* 并且設(shè)置了有效的基礎(chǔ)路徑(StringUtils.hasText(basePath)),或者管理端口與應(yīng)用端口不同(ManagementPortType.DIFFERENT)。
* 如果滿足條件,則創(chuàng)建端點(diǎn)鏈接映射,用于生成包含所有可用端點(diǎn)的首頁(yè)鏈接(例如/actuator)。
* 4. 構(gòu)建并返回WebMvcEndpointHandlerMapping
* 創(chuàng)建WebMvcEndpointHandlerMapping實(shí)例時(shí)傳入以下參數(shù):
* endpointMapping:定義端點(diǎn)的基礎(chǔ)路徑。
* webEndpoints:需要注冊(cè)的Web類型端點(diǎn)集合。
* endpointMediaTypes:定義端點(diǎn)支持的媒體類型(如JSON、YAML等)。
* corsConfiguration:跨域資源共享(CORS)配置。
* new EndpointLinksResolver(allEndpoints, basePath):用于生成端點(diǎn)鏈接的解析器。
* shouldRegisterLinksMapping:是否注冊(cè)端點(diǎn)鏈接映射。
* null:通常用于指定自定義的請(qǐng)求謂詞,此處為默認(rèn)值。
* 返回的WebMvcEndpointHandlerMapping使Swagger能夠正常訪問和展示Actuator端點(diǎn)的信息。
* 5. 兼容性適配
* Spring Boot 2.7.x之后,Swagger 2不再直接支持訪問Actuator端點(diǎn),此方法通過手動(dòng)注冊(cè)WebMvcEndpointHandlerMapping來恢復(fù)兼容性,確保Swagger UI可以正確顯示和調(diào)用這些監(jiān)控和管理接口。
* 總結(jié)
* 此方法的核心目的是手動(dòng)注冊(cè)端點(diǎn)處理器映射,以確保Swagger能夠正確訪問Spring Boot Actuator提供的各種監(jiān)控和管理端點(diǎn)。通過整合多種端點(diǎn)類型、設(shè)置基礎(chǔ)路徑、啟用鏈接映射等方式,使得開發(fā)者能夠在Swagger UI中方便地測(cè)試和使用這些端點(diǎn)。
*/
@Bean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier,
ControllerEndpointsSupplier controllerEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes,
CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties,
Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath);
boolean shouldRegisterLinksMapping =
webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
shouldRegisterLinksMapping, null);
}
}
啟動(dòng)服務(wù),不再報(bào)錯(cuò),Swagger UI 也能正常訪問

也許你們會(huì)覺得這個(gè)坑解決的也快呀,沒什么大不了的,可實(shí)際是項(xiàng)目中有眾多的依賴,你如何知道是因?yàn)?nbsp;spring-boot-starter-actuator 導(dǎo)致的?我實(shí)際排查這個(gè)問題的過程,可不是如上所說的那般容易,但有一點(diǎn)我們要清楚
我們遇到的坑,肯定有前輩遇到過
所以我們要做的是想清楚關(guān)鍵詞,到大數(shù)據(jù)模型搜索,或者到搜索引擎搜索
總結(jié)
歸根結(jié)底,還是
Springfox沒有去適配Spring Boot的升級(jí),所以可能的話,還是推薦大家用SpringDoc OpenAPI不到萬(wàn)不得已,不要去升級(jí)組件
坑我已經(jīng)替你們踩過
都是血的教訓(xùn),希望大家引以為戒
遇到問題,當(dāng)下推薦的做法是用
大數(shù)據(jù)模型,關(guān)鍵詞給的好,得到的回答八九不離十就是正確的解決方案
到此這篇關(guān)于安全漏洞修復(fù)導(dǎo)致SpringBoot2.7與Springfox不兼容的偽命題解決的文章就介紹到這了,更多相關(guān)SpringBoot2.7與Springfox不兼容內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java中的方法重載知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理了關(guān)于java中的方法重載知識(shí)點(diǎn)總結(jié),有興趣的朋友們可以跟著學(xué)習(xí)參考下。2020-02-02
通過weblogic API解析如何獲取weblogic中服務(wù)的IP和端口操作
這篇文章主要介紹了通過weblogic API解析如何獲取weblogic中服務(wù)的IP和端口操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
spring boot application properties配置實(shí)例代碼詳解
本文通過代碼給大家介紹了spring boot application properties配置方法,需要的的朋友參考下吧2017-07-07
Spring JdbcTemplate執(zhí)行數(shù)據(jù)庫(kù)操作詳解
JdbcTemplate是Spring框架自帶的對(duì)JDBC操作的封裝,目的是提供統(tǒng)一的模板方法使對(duì)數(shù)據(jù)庫(kù)的操作更加方便、友好,效率也不錯(cuò),這篇文章主要介紹了Spring JdbcTemplate執(zhí)行數(shù)據(jù)庫(kù)操作,需要的朋友可以參考下2022-10-10
關(guān)于解決iReport4.1.1無法正常啟動(dòng)或者閃退或者JDK8不兼容的問題
在安裝使用iReport的過程中遇到一個(gè)問題,我的iReport始終不能打開,困擾了我好久。接下來通過本文給大家介紹iReport4.1.1無法正常啟動(dòng)或者閃退或者JDK8不兼容的問題,需要的朋友可以參考下2018-09-09
Java解析調(diào)用webservice服務(wù)的返回XML串詳解
這篇文章主要介紹了Java解析調(diào)用webservice服務(wù)的返回XML串詳解的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
SpringBoot3整合Druid數(shù)據(jù)源的實(shí)現(xiàn)過程
文章介紹了一個(gè)基于Spring?Boot?3的程序?qū)崿F(xiàn)過程,包括創(chuàng)建項(xiàng)目、引入依賴、編寫啟動(dòng)類、配置文件、Controller、啟動(dòng)測(cè)試以及問題解決,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2025-11-11

