如何为 Boot 应用程序启用Swagger API端点?

cfh9epnr  于 2024-01-08  发布在  其他
关注(0)|答案(2)|浏览(335)

如何为我的微服务启用Swagger端点?根据this Baeldung article,这应该超级简单
首先,添加Springfox依赖项

  1. <dependency>
  2. <groupId>io.springfox</groupId>
  3. <artifactId>springfox-boot-starter</artifactId>
  4. <version>3.0.0</version>
  5. </dependency>

字符串
其次,您将此配置文件
应该就是这样!没有财产,什么都没有

  1. @Configuration
  2. public class SpringFoxConfig {
  3. @Bean
  4. public Docket api() {
  5. return new Docket(DocumentationType.SWAGGER_2)
  6. .select()
  7. .apis(RequestHandlerSelectors.any())
  8. .paths(PathSelectors.any())
  9. .build();
  10. }
  11. }


我就是这么做的。但是当我试图点击/v2/api-docs时,
为什么以及如何最终启用这些Swagger端点?

MRE:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>3.1.5</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>helloworldMRE</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>helloworldMRE</name>
  15. <description>helloworldMRE</description>
  16. <properties>
  17. <java.version>17</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.projectlombok</groupId>
  26. <artifactId>lombok</artifactId>
  27. <optional>true</optional>
  28. </dependency>
  29. <dependency>
  30. <groupId>io.springfox</groupId>
  31. <artifactId>springfox-boot-starter</artifactId>
  32. <version>3.0.0</version>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-starter-test</artifactId>
  37. <scope>test</scope>
  38. </dependency>
  39. </dependencies>
  40. <build>
  41. <plugins>
  42. <plugin>
  43. <groupId>org.springframework.boot</groupId>
  44. <artifactId>spring-boot-maven-plugin</artifactId>
  45. <configuration>
  46. <image>
  47. <builder>paketobuildpacks/builder-jammy-base:latest</builder>
  48. </image>
  49. <excludes>
  50. <exclude>
  51. <groupId>org.projectlombok</groupId>
  52. <artifactId>lombok</artifactId>
  53. </exclude>
  54. </excludes>
  55. </configuration>
  56. </plugin>
  57. </plugins>
  58. </build>
  59. </project>
  1. package com.example.helloworldmre;
  2. import lombok.Getter;
  3. import lombok.NoArgsConstructor;
  4. import lombok.Setter;
  5. @Getter
  6. @Setter
  7. @NoArgsConstructor
  8. public class HelloWorld {
  9. private String message = "Hello World!";
  10. }
  1. package com.example.helloworldmre;
  2. import org.springframework.web.bind.annotation.GetMapping;
  3. import org.springframework.web.bind.annotation.RestController;
  4. @RestController
  5. public class HelloWorldController {
  6. @GetMapping("/hello-world")
  7. public HelloWorld getHelloWorld() {
  8. return new HelloWorld();
  9. }
  10. }
  1. package com.example.helloworldmre;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import springfox.documentation.builders.PathSelectors;
  5. import springfox.documentation.builders.RequestHandlerSelectors;
  6. import springfox.documentation.spi.DocumentationType;
  7. import springfox.documentation.spring.web.plugins.Docket;
  8. @Configuration
  9. public class SpringFoxConfig {
  10. @Bean
  11. public Docket api() {
  12. return new Docket(DocumentationType.SWAGGER_2)
  13. .select()
  14. .apis(RequestHandlerSelectors.any())
  15. .paths(PathSelectors.any())
  16. .build();
  17. }
  18. }
  1. package com.example.helloworldmre;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class HelloworldMreApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(HelloworldMreApplication.class, args);
  8. }
  9. }

<$* 不完全是。Baeldung文章使用的是 Boot 2.4.0*

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.4.0</version>
  5. </dependency>

  • 我使用Sping Boot 3*
  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>3.1.3</version>
  5. <relativePath/> <!-- lookup parent from repository -->
  6. </parent>

  • 当我尝试降级到2.4.0时,我开始得到这个异常,所以我放弃了这个想法 *
  1. java.lang.IllegalArgumentException: Unsupported class file major version 61

k3fezbri

k3fezbri1#

SpringFox不支持Springboot v3,答案是springdoc

  1. <dependency>
  2. <groupId>org.springdoc</groupId>
  3. <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  4. <version>2.0.2</version>
  5. </dependency>

字符串
This article应该有助于转换

9ceoxa92

9ceoxa922#

或者,如果你想坚持使用spring-fox,你可以降级到Sping Boot 2。

**重要!**你真的需要这个神奇的属性(见倒数第二个片段)。关于here的更多信息

http://localhost:8080/swagger-ui/index.html也可以

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.6.4</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>helloworldservice</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>helloworldservice</name>
  15. <description>helloworldservice</description>
  16. <properties>
  17. <java.version>17</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.projectlombok</groupId>
  26. <artifactId>lombok</artifactId>
  27. <optional>true</optional>
  28. </dependency>
  29. <dependency>
  30. <groupId>io.springfox</groupId>
  31. <artifactId>springfox-boot-starter</artifactId>
  32. <version>3.0.0</version>
  33. </dependency>
  34. <dependency>
  35. <groupId>io.springfox</groupId>
  36. <artifactId>springfox-swagger-ui</artifactId>
  37. <version>3.0.0</version>
  38. </dependency>
  39. <dependency>
  40. <groupId>org.springframework.boot</groupId>
  41. <artifactId>spring-boot-starter-test</artifactId>
  42. <scope>test</scope>
  43. </dependency>
  44. </dependencies>
  45. <build>
  46. <plugins>
  47. <plugin>
  48. <groupId>org.springframework.boot</groupId>
  49. <artifactId>spring-boot-maven-plugin</artifactId>
  50. <configuration>
  51. <image>
  52. <builder>paketobuildpacks/builder-jammy-base:latest</builder>
  53. </image>
  54. <excludes>
  55. <exclude>
  56. <groupId>org.projectlombok</groupId>
  57. <artifactId>lombok</artifactId>
  58. </exclude>
  59. </excludes>
  60. </configuration>
  61. </plugin>
  62. </plugins>
  63. </build>
  64. </project>
  1. package com.example.helloworldmre.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import springfox.documentation.builders.PathSelectors;
  5. import springfox.documentation.builders.RequestHandlerSelectors;
  6. import springfox.documentation.spi.DocumentationType;
  7. import springfox.documentation.spring.web.plugins.Docket;
  8. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  9. @Configuration
  10. @EnableSwagger2
  11. public class SpringFoxConfig {
  12. @Bean
  13. public Docket api() {
  14. return new Docket(DocumentationType.SWAGGER_2)
  15. .select()
  16. .apis(RequestHandlerSelectors.any())
  17. .paths(PathSelectors.any())
  18. .build();
  19. }
  20. }
  1. package com.example.helloworldmre.controller;
  2. import com.example.helloworldmre.data.HelloWorld;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.RestController;
  5. @RestController
  6. public class HelloWorldController {
  7. @GetMapping("/hello-world")
  8. public HelloWorld getHelloWorld() {
  9. return new HelloWorld();
  10. }
  11. }
  1. package com.example.helloworldmre.data;
  2. import lombok.Getter;
  3. import lombok.NoArgsConstructor;
  4. import lombok.Setter;
  5. @Getter
  6. @Setter
  7. @NoArgsConstructor
  8. public class HelloWorld {
  9. private String message = "Hello World!";
  10. }
  1. package com.example.helloworldmre;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class HelloworldMreApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(HelloworldMreApplication.class, args);
  8. }
  9. }
  1. spring.mvc.pathmatch.matching-strategy=ant_path_matcher

关于http://localhost:8080/v2/api-docs

  1. {
  2. "swagger": "2.0",
  3. "info": {
  4. "description": "Api Documentation",
  5. "version": "1.0",
  6. "title": "Api Documentation",
  7. "termsOfService": "urn:tos",
  8. "contact": { },
  9. "license": {
  10. "name": "Apache 2.0",
  11. "url": "http://www.apache.org/licenses/LICENSE-2.0"
  12. }
  13. },
  14. "host": "localhost:8080",
  15. "basePath": "/",
  16. "tags": [
  17. {
  18. "name": "basic-error-controller",
  19. "description": "Basic Error Controller"
  20. },
  21. {
  22. "name": "hello-world-controller",
  23. "description": "Hello World Controller"
  24. }
  25. ],
  26. "paths": {
  27. "/error": {
  28. "get": {
  29. "tags": [
  30. "basic-error-controller"
  31. ],
  32. "summary": "error",
  33. "operationId": "errorUsingGET",
  34. "produces": [
  35. "*/*"
  36. ],
  37. "responses": {
  38. "200": {
  39. "description": "OK",
  40. "schema": {
  41. "type": "object",
  42. "additionalProperties": {
  43. "type": "object"
  44. }
  45. }
  46. },
  47. "401": {
  48. "description": "Unauthorized"
  49. },
  50. "403": {
  51. "description": "Forbidden"
  52. },
  53. "404": {
  54. "description": "Not Found"
  55. }
  56. }
  57. },
  58. "head": {
  59. "tags": [
  60. "basic-error-controller"
  61. ],
  62. "summary": "error",
  63. "operationId": "errorUsingHEAD",
  64. "consumes": [
  65. "application/json"
  66. ],
  67. "produces": [
  68. "*/*"
  69. ],
  70. "responses": {
  71. "200": {
  72. "description": "OK",
  73. "schema": {
  74. "type": "object",
  75. "additionalProperties": {
  76. "type": "object"
  77. }
  78. }
  79. },
  80. "204": {
  81. "description": "No Content"
  82. },
  83. "401": {
  84. "description": "Unauthorized"
  85. },
  86. "403": {
  87. "description": "Forbidden"
  88. }
  89. }
  90. },
  91. "post": {
  92. "tags": [
  93. "basic-error-controller"
  94. ],
  95. "summary": "error",
  96. "operationId": "errorUsingPOST",
  97. "consumes": [
  98. "application/json"
  99. ],
  100. "produces": [
  101. "*/*"
  102. ],
  103. "responses": {
  104. "200": {
  105. "description": "OK",
  106. "schema": {
  107. "type": "object",
  108. "additionalProperties": {
  109. "type": "object"
  110. }
  111. }
  112. },
  113. "201": {
  114. "description": "Created"
  115. },
  116. "401": {
  117. "description": "Unauthorized"
  118. },
  119. "403": {
  120. "description": "Forbidden"
  121. },
  122. "404": {
  123. "description": "Not Found"
  124. }
  125. }
  126. },
  127. "put": {
  128. "tags": [
  129. "basic-error-controller"
  130. ],
  131. "summary": "error",
  132. "operationId": "errorUsingPUT",
  133. "consumes": [
  134. "application/json"
  135. ],
  136. "produces": [
  137. "*/*"
  138. ],
  139. "responses": {
  140. "200": {
  141. "description": "OK",
  142. "schema": {
  143. "type": "object",
  144. "additionalProperties": {
  145. "type": "object"
  146. }
  147. }
  148. },
  149. "201": {
  150. "description": "Created"
  151. },
  152. "401": {
  153. "description": "Unauthorized"
  154. },
  155. "403": {
  156. "description": "Forbidden"
  157. },
  158. "404": {
  159. "description": "Not Found"
  160. }
  161. }
  162. },
  163. "delete": {
  164. "tags": [
  165. "basic-error-controller"
  166. ],
  167. "summary": "error",
  168. "operationId": "errorUsingDELETE",
  169. "produces": [
  170. "*/*"
  171. ],
  172. "responses": {
  173. "200": {
  174. "description": "OK",
  175. "schema": {
  176. "type": "object",
  177. "additionalProperties": {
  178. "type": "object"
  179. }
  180. }
  181. },
  182. "204": {
  183. "description": "No Content"
  184. },
  185. "401": {
  186. "description": "Unauthorized"
  187. },
  188. "403": {
  189. "description": "Forbidden"
  190. }
  191. }
  192. },
  193. "options": {
  194. "tags": [
  195. "basic-error-controller"
  196. ],
  197. "summary": "error",
  198. "operationId": "errorUsingOPTIONS",
  199. "consumes": [
  200. "application/json"
  201. ],
  202. "produces": [
  203. "*/*"
  204. ],
  205. "responses": {
  206. "200": {
  207. "description": "OK",
  208. "schema": {
  209. "type": "object",
  210. "additionalProperties": {
  211. "type": "object"
  212. }
  213. }
  214. },
  215. "204": {
  216. "description": "No Content"
  217. },
  218. "401": {
  219. "description": "Unauthorized"
  220. },
  221. "403": {
  222. "description": "Forbidden"
  223. }
  224. }
  225. },
  226. "patch": {
  227. "tags": [
  228. "basic-error-controller"
  229. ],
  230. "summary": "error",
  231. "operationId": "errorUsingPATCH",
  232. "consumes": [
  233. "application/json"
  234. ],
  235. "produces": [
  236. "*/*"
  237. ],
  238. "responses": {
  239. "200": {
  240. "description": "OK",
  241. "schema": {
  242. "type": "object",
  243. "additionalProperties": {
  244. "type": "object"
  245. }
  246. }
  247. },
  248. "204": {
  249. "description": "No Content"
  250. },
  251. "401": {
  252. "description": "Unauthorized"
  253. },
  254. "403": {
  255. "description": "Forbidden"
  256. }
  257. }
  258. }
  259. },
  260. "/hello-world": {
  261. "get": {
  262. "tags": [
  263. "hello-world-controller"
  264. ],
  265. "summary": "getHelloWorld",
  266. "operationId": "getHelloWorldUsingGET",
  267. "produces": [
  268. "*/*"
  269. ],
  270. "responses": {
  271. "200": {
  272. "description": "OK",
  273. "schema": {
  274. "$ref": "#/definitions/HelloWorld"
  275. }
  276. },
  277. "401": {
  278. "description": "Unauthorized"
  279. },
  280. "403": {
  281. "description": "Forbidden"
  282. },
  283. "404": {
  284. "description": "Not Found"
  285. }
  286. }
  287. }
  288. }
  289. },
  290. "definitions": {
  291. "HelloWorld": {
  292. "type": "object",
  293. "properties": {
  294. "message": {
  295. "type": "string"
  296. }
  297. },
  298. "title": "HelloWorld"
  299. },
  300. "ModelAndView": {
  301. "type": "object",
  302. "properties": {
  303. "empty": {
  304. "type": "boolean"
  305. },
  306. "model": {
  307. "type": "object"
  308. },
  309. "modelMap": {
  310. "type": "object",
  311. "additionalProperties": {
  312. "type": "object"
  313. }
  314. },
  315. "reference": {
  316. "type": "boolean"
  317. },
  318. "status": {
  319. "type": "string",
  320. "enum": [
  321. "ACCEPTED",
  322. "ALREADY_REPORTED",
  323. "BAD_GATEWAY",
  324. "BAD_REQUEST",
  325. "BANDWIDTH_LIMIT_EXCEEDED",
  326. "CHECKPOINT",
  327. "CONFLICT",
  328. "CONTINUE",
  329. "CREATED",
  330. "DESTINATION_LOCKED",
  331. "EXPECTATION_FAILED",
  332. "FAILED_DEPENDENCY",
  333. "FORBIDDEN",
  334. "FOUND",
  335. "GATEWAY_TIMEOUT",
  336. "GONE",
  337. "HTTP_VERSION_NOT_SUPPORTED",
  338. "IM_USED",
  339. "INSUFFICIENT_SPACE_ON_RESOURCE",
  340. "INSUFFICIENT_STORAGE",
  341. "INTERNAL_SERVER_ERROR",
  342. "I_AM_A_TEAPOT",
  343. "LENGTH_REQUIRED",
  344. "LOCKED",
  345. "LOOP_DETECTED",
  346. "METHOD_FAILURE",
  347. "METHOD_NOT_ALLOWED",
  348. "MOVED_PERMANENTLY",
  349. "MOVED_TEMPORARILY",
  350. "MULTIPLE_CHOICES",
  351. "MULTI_STATUS",
  352. "NETWORK_AUTHENTICATION_REQUIRED",
  353. "NON_AUTHORITATIVE_INFORMATION",
  354. "NOT_ACCEPTABLE",
  355. "NOT_EXTENDED",
  356. "NOT_FOUND",
  357. "NOT_IMPLEMENTED",
  358. "NOT_MODIFIED",
  359. "NO_CONTENT",
  360. "OK",
  361. "PARTIAL_CONTENT",
  362. "PAYLOAD_TOO_LARGE",
  363. "PAYMENT_REQUIRED",
  364. "PERMANENT_REDIRECT",
  365. "PRECONDITION_FAILED",
  366. "PRECONDITION_REQUIRED",
  367. "PROCESSING",
  368. "PROXY_AUTHENTICATION_REQUIRED",
  369. "REQUESTED_RANGE_NOT_SATISFIABLE",
  370. "REQUEST_ENTITY_TOO_LARGE",
  371. "REQUEST_HEADER_FIELDS_TOO_LARGE",
  372. "REQUEST_TIMEOUT",
  373. "REQUEST_URI_TOO_LONG",
  374. "RESET_CONTENT",
  375. "SEE_OTHER",
  376. "SERVICE_UNAVAILABLE",
  377. "SWITCHING_PROTOCOLS",
  378. "TEMPORARY_REDIRECT",
  379. "TOO_EARLY",
  380. "TOO_MANY_REQUESTS",
  381. "UNAUTHORIZED",
  382. "UNAVAILABLE_FOR_LEGAL_REASONS",
  383. "UNPROCESSABLE_ENTITY",
  384. "UNSUPPORTED_MEDIA_TYPE",
  385. "UPGRADE_REQUIRED",
  386. "URI_TOO_LONG",
  387. "USE_PROXY",
  388. "VARIANT_ALSO_NEGOTIATES"
  389. ]
  390. },
  391. "view": {
  392. "$ref": "#/definitions/View"
  393. },
  394. "viewName": {
  395. "type": "string"
  396. }
  397. },
  398. "title": "ModelAndView"
  399. },
  400. "View": {
  401. "type": "object",
  402. "properties": {
  403. "contentType": {
  404. "type": "string"
  405. }
  406. },
  407. "title": "View"
  408. }
  409. }
  410. }

展开查看全部

相关问题