從入門到精通一文搞定SpringDoc
Swagger3.0—OpenAPI3.0
Sawgger3.0又叫OpenAPI3.0,對應(yīng)的依賴包有兩種,分別為Springfox以及SpringDoc,但是Springfox以及停止維護(hù),無法支持SpringBoot3,以下圍繞SpringDoc進(jìn)行講解。
一、集成SpringDoc
1.引入依賴
<!--swagger--> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.8.0</version> </dependency>
2.配置文檔信息
后面會解釋配置信息與文檔的對應(yīng)關(guān)系
package org.example.config; import com.google.common.collect.Maps; import io.swagger.v3.oas.models.ExternalDocumentation; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Map; /** * 文件名: SwaggerConfig.java Swagger配置類 * * @author fengqing * @version 1.0.00 * @since 2025/3/214 */ @Configuration public class SwaggerConfig { @Bean public OpenAPI openAPI() { return new OpenAPI() .info(new Info() .title("標(biāo)題---JsustPlay") .description("描述信息---JsustPlay API文檔") .version("版本說明---1.0.0") .license(new License() .name("API文檔的許可信息---這里模擬一下,轉(zhuǎn)跳百度了") .url("http://www.baidu.com")) .contact(new Contact() .name("作者name---fengqing") .email("作者email--- 可以直接跳轉(zhuǎn)郵箱發(fā)郵件,這里是假的") .extensions((Map<String, Object>) Maps.newHashMap().put("x-xxx-x","擴(kuò)展字段,key必須以x開頭")) .url("http://www.baidu.com"))) .externalDocs(new ExternalDocumentation() .description("外部文檔描述---這里也轉(zhuǎn)跳百度的") .url("http://www.baidu.com") ); } }
3.訪問(ip:端口/swagger-ui/index.html)
以上即為配置信息與文檔信息的對應(yīng)關(guān)系,每個(gè)信息類的屬性幾乎都都涉及的,還有部分非常用屬性信息為涉及,感興趣的可以看下對應(yīng)類的源碼進(jìn)行了解。
4.測試(Post請求為例)
package org.example.controller; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { @PostMapping("/demo001_1") public StudentDto demo001_1(@RequestBody StudentDto studentDto){ return BeanUtil.toBean(studentDto,StudentDto.class); } }
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 風(fēng)清 * @CreateTime: 2025-03-26 21:08 */ @Data public class StudentDto { private String name; private Integer age; }
注意:
默認(rèn)情況下,Swagger3.0會根據(jù)請求類型來映射請求參數(shù)
我們將上述請求改為Get在進(jìn)行測試
@GetMapping("/demo001_1") public StudentDto demo001_1(@RequestBody StudentDto studentDto){ return BeanUtil.toBean(studentDto,StudentDto.class); }
可以看到雖然填寫請求體的時(shí)候仍然是Json格式,但是在發(fā)請求的時(shí)候數(shù)據(jù)被當(dāng)做@RequestParam進(jìn)行映射了
二、常用注解
1.常用注解匯總
注解 | 定位 |
---|---|
@Tag | 作用在Controller類 上,用于描述API類信息。 |
@Operation | 作用在Controller類的方法 上,用于描述API方法信息,該注解可以包含一下全部注解。 |
@Parameter | 作用在Controller類的方法 上,用于描述 API 方法的參數(shù)信息。 |
@Parameters | 作用在Controller類的方法 上,用于描述API方法的多個(gè)參數(shù)。 |
@Schema | 作用在實(shí)體類 或者實(shí)體類屬性 上,用于描述實(shí)體類/實(shí)體類屬性的信息,該實(shí)體類一般作為入?yún)ⅰ?code>或者結(jié)合在一些注解的schema屬性中來描述參數(shù)信息(入?yún)?,返回值?/td> |
@ApiResponse | 作用在Controller類的方法 上,用于描述API方法單個(gè)響應(yīng)信息。 |
@ApiResponses | 作用在Controller類的方法 上,用于描述API方法多個(gè)響應(yīng)信息。 |
@Hidden | 隱藏某個(gè)類、方法或參數(shù),不將其包含在生成的文檔中。 |
@ResquestBody | 作用在Controller類的方法 上、用于描述請求體信息。 |
@Content | 通常用于 @ApiResponse 或 @Parameter 注解 中,用來定義 API 響應(yīng)或參數(shù)的具體內(nèi)容結(jié)構(gòu)。 |
2.常用注解示例
@Tag
- 作用
- 為控制器或方法分組,便于組織和分類 API。
- 常用屬性
name
:標(biāo)簽名稱。description
:標(biāo)簽描述信息。
- 示例
package org.example.controller; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { @PostMapping("/demo001_1") public void demo001_1(@RequestBody StudentDto studentDto){ return BeanUtil.toBean(studentDto,StudentDto.class); } }
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 風(fēng)清 * @CreateTime: 2025-03-26 21:08 */ @Data public class StudentDto { private String name; private Integer age; }
- Swagger呈現(xiàn)結(jié)果
這里順便說一Swagger的三大部分,如下圖
@Operation
- 作用
- 為控制器或方法分組,便于組織和分類 API。
- 常用屬性
summary
:標(biāo)簽名稱。description
:標(biāo)簽描述信息。deprecated
:標(biāo)記方法是否已廢棄。(默認(rèn)為false)
- 示例
package org.example.controller; import cn.hutool.core.bean.BeanUtil; import io.swagger.v3.oas.annotations.Operation; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { @PostMapping("/demo001_1") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1", deprecated = true) public StudentDto demo001_1(@RequestBody StudentDto studentDto){ return BeanUtil.toBean(studentDto,StudentDto.class); } @PostMapping("/demo001_2") @Operation(summary = "Sdemo001_2",description = "Ddemo001_2", deprecated = false) public StudentDto demo001_2(@RequestBody StudentDto studentDto){ return BeanUtil.toBean(studentDto,StudentDto.class); } }
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 風(fēng)清 * @CreateTime: 2025-03-26 21:08 */ @Data public class StudentDto { private String name; private Integer age; }
- Swagger呈現(xiàn)結(jié)果
@Parameter
- 作用
- 描述方法參數(shù)的含義。
- 常用屬性
name
:參數(shù)名(使用時(shí)與參數(shù)一致)description
:參數(shù)描述信息。in
:參數(shù)位置。示例代碼中進(jìn)行說明。schema
:參數(shù)類型。required
:是否必填,默認(rèn)為false。example
:示例值。
注意
- 該注解用于@RequestParam、@PathVariable參數(shù),Sawgger通過@RequestBody注解來修飾@RequestBody類型參數(shù)。
示例
package org.example.controller; import cn.hutool.core.bean.BeanUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Schema; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { /* in:參數(shù)位置,ParameterIn.PATH表示參數(shù)在路徑中, ParameterIn.QUERY表示參數(shù)在查詢字符串中, ParameterIn.HEADER表示參數(shù)在請求頭中, ParameterIn.COOKIE表示參數(shù)在cookie中。 */ @PostMapping("/{id}") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") public String demo001_1( @Parameter(name = "id", description = "學(xué)生id", in = ParameterIn.PATH, schema = @Schema(type = "integer"), required = true,example = "1") @PathVariable Integer id, @Parameter(name = "name", description = "學(xué)生姓名", in = ParameterIn.QUERY, schema = @Schema(type = "string"), required = true,example = "張三") @RequestParam String name ){ return name+":"+id; } //作用在類似修飾@RequestBody參數(shù),上面說過,swagger有對應(yīng)處理@RequestBody參數(shù)的注解@RequestBody,所以這里就不進(jìn)行展示了,記住這種方式不要用即可 @PostMapping("/demo001_1") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") @Parameter(deprecated = true,description = "學(xué)生信息", schema = @Schema(implementation = StudentDto.class), required = true,example = "{\"name\":\"張三\",\"age\":18}") public StudentDto demo001_1(@RequestBody StudentDto studentDto){ return BeanUtil.copyProperties(studentDto, StudentDto.class); }
- Swagger呈現(xiàn)結(jié)果
@Parameters
- 作用
- 作用在實(shí)體類或者實(shí)體類屬性上,用于描述實(shí)體類/實(shí)體類屬性的信息,該實(shí)體類一般作為入?yún)??;蛘呓Y(jié)合在一些注解的schema屬性中來描述參數(shù)信息(入?yún)?,返回值?/li>
- 常用屬性
value
:Parameter的集合。
- 示例
package org.example.controller; import cn.hutool.core.bean.BeanUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Schema; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { /* 3.in:參數(shù)位置,ParameterIn.PATH表示參數(shù)在路徑中, ParameterIn.QUERY表示參數(shù)在查詢字符串中, ParameterIn.HEADER表示參數(shù)在請求頭中, ParameterIn.COOKIE表示參數(shù)在cookie中。 */ @PostMapping("/{id}") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") public String demo001_1( @Parameter(name = "id", description = "學(xué)生id", in = ParameterIn.PATH, schema = @Schema(type = "integer"), required = true,example = "1") @PathVariable Integer id, @Parameter(name = "name", description = "學(xué)生姓名", in = ParameterIn.QUERY, schema = @Schema(type = "string"), required = true,example = "張三") @RequestParam String name ){ return name+":"+id; }
- Swagger呈現(xiàn)結(jié)果
@Schena
- 作用
- 作用在
實(shí)體類
或者實(shí)體類屬性
上,用于描述實(shí)體類/實(shí)體類屬性的信息,該實(shí)體類一般作為入?yún)ⅰ?code>或者結(jié)合在一些注解的schema屬性中來描述參數(shù)信息(入?yún)ⅲ祷刂担?/li>
- 作用在
- 常用屬性
- 作用于實(shí)體類/實(shí)體類屬性上:
description
:模型或?qū)傩缘拿枋觥?/li>example
:示例值。required
:必需屬性。hidden
:是否隱藏屬性。
- 結(jié)合其他注解使用上:
type
: 指定@RequestParam、@PathVariable參數(shù)類型(用法與上方@Parameter中一致)implementation
:指定JSON(@RequestBody)參數(shù)類型(于下方@RequsetBody/@ApiRequest注解中演示)
- 注意
請求體或者響應(yīng)體為json時(shí),無論對應(yīng)的Dto/Vo類無論是否被Schema注解都會被映射,Schema注解只是為響應(yīng)/請求體添加了描述信息。
- 示例
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 風(fēng)清 * @CreateTime: 2025-03-26 21:08 */ @Data //無論是否有Schema注解Swagger都會將請求參數(shù)映射到Swagger文檔上,Schema注解只是給Swagger文檔上添加一些描述信息和示例信息 @Schema(description = "學(xué)生信息", name = "StudentDto", example = "{\"name\":\"張三\",\"age\":18}") public class StudentDto { @Schema(name = "name", description = "姓名") private String name; @Schema(name = "age", description = "年齡",hidden = true) private Integer age; }
- Swagger呈現(xiàn)結(jié)果
引入Swagger前(這里的schema會在用到的進(jìn)行映射)
引入后:可以看到多了示例值,并且隱藏了age。
@ApiRequest/@Content
- 作用
- 作用在
Controller類的方法
上,用于描述API方法單個(gè)響應(yīng)信息。
- 作用在
- 常用屬性
responseCode
:HTTP 狀態(tài)碼。description
:響應(yīng)描述信息。content
:響應(yīng)的內(nèi)容類型(如 JSON、XML)。
- @Content常用屬性
mediaType
:響應(yīng)格式。schema
:響應(yīng)結(jié)果格式。
- 注意
不通過@ApiRequest的content屬性去指定響應(yīng)體時(shí),Swagger會自動映射返回體,當(dāng)響應(yīng)值非200時(shí)一般不需要顯示響應(yīng)體內(nèi)容(展示是無意義的),這個(gè)是時(shí)候就需要為content屬性賦值一個(gè)空的@Content。
- 示例
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 風(fēng)清 * @CreateTime: 2025-03-26 21:08 */ @Data //無論是否有Schema注解Swagger都會將請求參數(shù)映射到Swagger文檔上,Schema注解只是給Swagger文檔上添加一些描述信息和示例信息 @Schema(description = "學(xué)生信息", name = "StudentDto", example = "{\"name\":\"張三\",\"age\":18}") public class StudentDto { @Schema(name = "name", description = "姓名") private String name; @Schema(name = "age", description = "年齡") private Integer age; }
package org.example.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { @PostMapping("/{id}") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") // 描述1 @ApiResponse( responseCode = "200", description = "成功", content = {@Content( //響應(yīng)類型 mediaType = "application/json", //響應(yīng)對象結(jié)果描述 schema = @Schema(implementation = StudentDto.class))} ) // 描述2 這里指定了一個(gè)空的@Content來實(shí)現(xiàn)swagger文檔不展示響應(yīng)體,否則會默認(rèn)swagger會映射默認(rèn)返回內(nèi)容。 @ApiResponse(responseCode = "405", description = "非法輸入",content = @Content) public StudentDto demo001_1( @PathVariable Integer id, @RequestParam String name ){ return StudentDto.builder().name(name).age(18).build(); } }
- Swagger呈現(xiàn)結(jié)果
可以與上方默認(rèn)的響應(yīng)信息進(jìn)行對比,可以看到響應(yīng)200的描述信息由默認(rèn)的ok改成了成功
,類型有默認(rèn)的*/*改成了application/json
。
@ApiRequests
- 作用
- 作用在
Controller類的方法
上,用于描述API方法多個(gè)響應(yīng)信息。
- 作用在
- 常用屬性
value
:ApiRequests集合。
- 示例
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 風(fēng)清 * @CreateTime: 2025-03-26 21:08 */ @Data //無論是否有Schema注解Swagger都會將請求參數(shù)映射到Swagger文檔上,Schema注解只是給Swagger文檔上添加一些描述信息和示例信息 @Schema(description = "學(xué)生信息", name = "StudentDto", example = "{\"name\":\"張三\",\"age\":18}") public class StudentDto { @Schema(name = "name", description = "姓名") private String name; @Schema(name = "age", description = "年齡") private Integer age; }
package org.example.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { @PostMapping("/{id}") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") @ApiResponses({ // 描述1 @ApiResponse( responseCode = "200", description = "成功", content = {@Content( //響應(yīng)類型 mediaType = "application/json", //響應(yīng)對象結(jié)果描述 schema = @Schema(implementation = StudentDto.class))}), // 描述2 @ApiResponse(responseCode = "405", description = "非法輸入",,content = @Content) }) public StudentDto demo001_1( @PathVariable Integer id, @RequestParam String name ){ return StudentDto.builder().name(name).age(18).build(); } }
- Swagger呈現(xiàn)結(jié)果(與上述一致)
@ResquestBody
- 作用
- 作用在
Controller類的方法
上,用于描述請求體信息。
- 作用在
- 常用屬性
description
:請求體的描述。required
:是否必需。content
:請求的內(nèi)容類型(與@ApiRequest一致)。
- 示例
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Data; /** * @Description: StudentDto * @Author: 風(fēng)清 * @CreateTime: 2025-03-26 21:08 */ @Data @Builder @Schema(description = "學(xué)生信息", name = "StudentDto", example = "{\"name\":\"張三\",\"age\":18}") public class StudentDto { @Schema(name = "name", description = "姓名",example = "張三") private String name; @Schema(name = "age", description = "年齡",example = "18") private Integer age; }
package org.example.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { @PostMapping("/{id}") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") @io.swagger.v3.oas.annotations.parameters.RequestBody( content = @Content(schema = @Schema(implementation = StudentDto.class)), description = "請求體") public StudentDto demo001_1( @RequestBody StudentDto studentDto ){ return studentDto; } }
- Swagger呈現(xiàn)結(jié)果
這里的mediaType 屬性可以不進(jìn)行描述默認(rèn)就為application/json。
對了,這里在提下,在請求/響應(yīng)體的旁邊有個(gè)schema點(diǎn)擊會展示對應(yīng)的請求/響應(yīng)體信息
結(jié)合使用
上面說過@Operation可以包含幾乎全表Swagger3.0的注解,實(shí)際開發(fā)中這些注解通常也不會單獨(dú)使用,而是包含在@Operation中。如下
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Data; /** * @Description: StudentDto * @Author: 風(fēng)清 * @CreateTime: 2025-03-26 21:08 */ @Data @Builder @Schema(description = "學(xué)生信息", name = "StudentDto", example = "{\"name\":\"張三\",\"age\":18}") public class StudentDto { @Schema(name = "name", description = "姓名",example = "張三") private String name; @Schema(name = "age", description = "年齡",example = "18") private Integer age; }
package org.example.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import org.example.dto.StudentDto; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "Demo001",description = "示例001") public class Demo001 { @PostMapping("/{id}") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1", requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody( content = @Content(schema = @Schema(implementation = StudentDto.class)), description = "請求體"), responses = { @ApiResponse( responseCode = "200", description = "成功", content = @Content( mediaType = "application/json", schema = @Schema(implementation = StudentDto.class) ) ), @ApiResponse( description = "找不到指定路徑", responseCode = "404", content = @Content() ) } ) public StudentDto demo001_1( @RequestBody StudentDto studentDto ){ return studentDto; } @GetMapping("/id") @Operation( summary = "Sdemo001_2", description = "Ddemo001_2", parameters = { @Parameter( name = "id", description = "id", in = ParameterIn.QUERY, schema = @Schema(implementation = Integer.class) ) }, responses = { @ApiResponse( responseCode = "200", description = "成功", content = @Content() ), @ApiResponse( description = "找不到指定路徑", responseCode = "404", content = @Content() ) } ) public Integer demo001_2( @RequestParam(value = "id",required = false) Integer id ){ return id; } }
- Swagger呈現(xiàn)結(jié)果
擴(kuò)展@ResponseStatus
上面我們通過@ApiResponse來設(shè)定響應(yīng)信息,但實(shí)際上響應(yīng)結(jié)果的種類是比較多的一個(gè)個(gè)設(shè)置很繁瑣,而實(shí)際開發(fā)中通常會有統(tǒng)一的響應(yīng)類以及全局異常處理器,我們通常通過Swagger的ResponseStatus注解結(jié)合全局異常處理器來實(shí)現(xiàn)響應(yīng)信息的生成
。
- 示例代碼
package org.example.enums; /** * 文件名: AppHttpCodeEnum.java 響應(yīng)枚舉 * * @author fengqing * @version 1.0.00 * @since 2025/4/1 */ public enum AppHttpCodeEnum { // 成功段0 SUCCESS(200,"操作成功"), // 登錄段1~50 NEED_LOGIN(1,"需要登錄后操作"), LOGIN_PASSWORD_ERROR(2,"密碼錯(cuò)誤"), // TOKEN50~100 TOKEN_INVALID(50,"無效的TOKEN"), TOKEN_EXPIRE(51,"TOKEN已過期"), TOKEN_REQUIRE(52,"TOKEN是必須的"), // SIGN驗(yàn)簽 100~120 SIGN_INVALID(100,"無效的SIGN"), SIG_TIMEOUT(101,"SIGN已過期"), // 參數(shù)錯(cuò)誤 500~1000 PARAM_REQUIRE(500,"缺少參數(shù)"), PARAM_INVALID(501,"無效參數(shù)"), PARAM_IMAGE_FORMAT_ERROR(502,"圖片格式有誤"), SERVER_ERROR(503,"服務(wù)器內(nèi)部錯(cuò)誤"), // 數(shù)據(jù)錯(cuò)誤 1000~2000 DATA_EXIST(1000,"數(shù)據(jù)已經(jīng)存在"), AP_USER_DATA_NOT_EXIST(1001,"ApUser數(shù)據(jù)不存在"), DATA_NOT_EXIST(1002,"數(shù)據(jù)不存在"), // 數(shù)據(jù)錯(cuò)誤 3000~3500 NO_OPERATOR_AUTH(3000,"無權(quán)限操作"), NEED_ADMIND(3001,"需要管理員權(quán)限"); int code; String errorMessage; AppHttpCodeEnum(int code, String errorMessage){ this.code = code; this.errorMessage = errorMessage; } public int getCode() { return code; } public String getErrorMessage() { return errorMessage; } }
package org.example.exception; import org.example.enums.AppHttpCodeEnum; /** * 文件名: CustomException.java 自定義異常處理類 * * @author fengqing * @version 1.0.00 * @since 2025/4/1 */ public class CustomException extends RuntimeException { private AppHttpCodeEnum appHttpCodeEnum; public CustomException(AppHttpCodeEnum appHttpCodeEnum){ this.appHttpCodeEnum = appHttpCodeEnum; } public AppHttpCodeEnum getAppHttpCodeEnum() { return appHttpCodeEnum; } }
package org.example.exception; import lombok.extern.slf4j.Slf4j; import org.example.enums.AppHttpCodeEnum; import org.example.vo.ResponseResult; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; /** * 文件名: ExceptionCatch.java 自定義異常處理類 * * @author fengqing * @version 1.0.00 * @since 2025/4/1 */ @ControllerAdvice //控制器增強(qiáng)類, 表示如果在controller.service中任何一個(gè)地方出現(xiàn)了異常之后,都會自動調(diào)用該捕獲類 @Slf4j public class ExceptionCatch { /** * 處理不可控異常 * @param e * @return */ @ExceptionHandler(Exception.class) @ResponseBody @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE) public ResponseResult exception(Exception e){ e.printStackTrace(); log.error("catch exception:{}",e.getMessage()); return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR); } /** * 處理可控異常 自定義異常 * @param e * @return */ @ExceptionHandler(CustomException.class) @ResponseBody @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResponseResult exception(CustomException e){ log.error("catch exception:{}",e); return ResponseResult.errorResult(e.getAppHttpCodeEnum()); } }
package org.example.vo; import org.example.enums.AppHttpCodeEnum; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * 通用的結(jié)果返回類 * @param <T> */ public class ResponseResult<T> implements Serializable { private String host; private Integer code; private String errorMessage; private T data; public ResponseResult() { this.code = 200; } public ResponseResult(Integer code, T data) { this.code = code; this.data = data; } public ResponseResult(Integer code, String msg, T data) { this.code = code; this.errorMessage = msg; this.data = data; } public ResponseResult(Integer code, String msg) { this.code = code; this.errorMessage = msg; } public static ResponseResult errorResult(int code, String msg) { ResponseResult result = new ResponseResult(); return result.error(code, msg); } public static ResponseResult okResult(int code, String msg) { ResponseResult result = new ResponseResult(); return result.ok(code, null, msg); } public static ResponseResult okResult(Object data) { ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getErrorMessage()); if (data != null) { result.setData(data); } return result; } public static ResponseResult errorResult(AppHttpCodeEnum enums) { return setAppHttpCodeEnum(enums, enums.getErrorMessage()); } public static ResponseResult errorResult(AppHttpCodeEnum enums, String errorMessage) { return setAppHttpCodeEnum(enums, errorMessage); } public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums) { return okResult(enums.getCode(), enums.getErrorMessage()); } private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String errorMessage) { return okResult(enums.getCode(), errorMessage); } public ResponseResult<?> error(Integer code, String msg) { this.code = code; this.errorMessage = msg; return this; } public ResponseResult<?> ok(Integer code, T data) { this.code = code; this.data = data; return this; } public ResponseResult<?> ok(Integer code, T data, String msg) { this.code = code; this.data = data; this.errorMessage = msg; return this; } public ResponseResult<?> ok(T data) { this.data = data; return this; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getErrorMessage() { return errorMessage; } public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } }
- 展示結(jié)果
可以看到這里多了500和503,點(diǎn)開對應(yīng)的schema可以看到正是我們的統(tǒng)一響應(yīng)結(jié)果類信息。
三、分組
業(yè)界一般會更具不同服務(wù)模塊或功能模塊對接口進(jìn)行分組,提高可觀性和測試效率,實(shí)現(xiàn)起來很簡單,只需要在配置類中注入GroupedOpenApi示例即可。
- 示例
package org.example.config; import org.springdoc.core.GroupedOpenApi; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 文件名: SwaggerConfig.java Swagger配置類 * * @author fengqing * @version 1.0.00 * @since 2025/4/1 */ @Configuration public class SpringDocConfig { @Bean public GroupedOpenApi publicApi() { return GroupedOpenApi.builder() //設(shè)置分組名稱 .group("demo001") //設(shè)置匹配路徑 .pathsToMatch("/demo001/**") .build(); } @Bean public GroupedOpenApi adminApi() { return GroupedOpenApi.builder() //分組名稱 .group("demo002") //匹配路徑 .pathsToMatch("/demo002/**") .build(); } }
package org.example.controller; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo001.java 模型001 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/3/21 V${1.0.00} */ @RestController @RequestMapping("/demo001") @Tag(name = "demo001",description = "示例001") public class Demo001 { @GetMapping("/id") public Integer demo001( @RequestParam(value = "id",required = false) Integer id ){ return id; } }
package org.example.controller; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo002.java 模型002 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/4/1 V${1.0.00} */ @RestController @RequestMapping("/demo002") @Tag(name = "demo002",description = "示例002") public class Demo002 { @GetMapping("/id") public Integer demo002( @RequestParam(value = "id",required = false) Integer id ){ return id; } }
package org.example.controller; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; /** * 文件名: Demo002.java 模型002 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/4/1 V${1.0.00} */ @RestController @RequestMapping("/demo002") @Tag(name = "demo002",description = "示例002") public class Demo002 { @GetMapping("/id") public Integer demo002( @RequestParam(value = "id",required = false) Integer id ){ return id; } }
- 結(jié)果展示
四、認(rèn)證授權(quán)
這里淺談一下認(rèn)證授權(quán),其實(shí)就是把登錄的token放到請求中,這里我就不在舉具體的列子了,僅展示一下怎么將認(rèn)證信息放到請求中(基于JavaAPI形式)。
- 配置類
package org.example.config; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Description: SpringDocSwaggerConfig * @Author: 風(fēng)清 * @CreateTime: 2025-04-14 21:13 */ @Configuration public class SpringDocSwaggerConfig { @Bean public OpenAPI testOpenAPI() { // 創(chuàng)建一個(gè) OpenAPI 實(shí)例,并設(shè)置 API 的基本信息 OpenAPI openAPI = (new OpenAPI()).info((new Info()).title("Example API").version("1.0")); // 創(chuàng)建一個(gè) Components 實(shí)例,用于管理 API 的組件,如安全方案等 Components components = new Components(); /*添加安全要求 為OpenAPI對象添加安全要求。SecurityRequirement表示一個(gè)安全要求,這里分別添加了 server-one、server-two、server-three、server-four和server-five這五個(gè)安全要求。 */ openAPI.addSecurityItem((new SecurityRequirement()).addList("server-one")); openAPI.addSecurityItem((new SecurityRequirement()).addList("server-two")); openAPI.addSecurityItem((new SecurityRequirement()).addList("server-three")); openAPI.addSecurityItem((new SecurityRequirement()).addList("server-four")); openAPI.addSecurityItem((new SecurityRequirement()).addList("server-five")); /*定義安全方案 為Components對象添加安全方案。SecurityScheme表示一個(gè)安全方案,這里定義了五個(gè)安全方案, 名稱分別為server-one、server-two、server-three、server-four和server-five, 類型為APIKEY,即使用 API 密鑰進(jìn)行身份驗(yàn)證,并且密鑰要放在請求頭中。 */ components.addSecuritySchemes("server-one", (new SecurityScheme()).name("server-one").type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER)); components.addSecuritySchemes("server-two", (new SecurityScheme()).name("server-two").type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER)); components.addSecuritySchemes("server-three", (new SecurityScheme()).name("server-three").type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER)); components.addSecuritySchemes("server-four", (new SecurityScheme()).name("server-four").type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER)); components.addSecuritySchemes("server-five", (new SecurityScheme()).name("server-five").type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER)); openAPI.components(components); return openAPI; } }
- 在接口中打印下請求頭信息
package org.example.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import io.swagger.v3.oas.annotations.tags.Tag; import javax.servlet.http.HttpServletRequest; import java.util.Enumeration; /** * 文件名: Demo002.java 模型002 * * @author zhaochengfeng * @version 1.0.00 * @since 2025/4/1 V${1.0.00} */ @Slf4j @RestController @RequestMapping("/demo002") @Tag(name = "demo002",description = "示例002") public class Demo002 { @Autowired private HttpServletRequest request; @GetMapping("/id") public Integer demo002( @RequestParam(value = "id",required = false) Integer id ){ // 獲取請求頭 Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()){ String headName = headerNames.nextElement(); String headerValue = request.getHeader(headName); log.info(headName+":"+headerValue); } return id; } }
基于攜帶的請求信息我們就可以進(jìn)行對應(yīng)的驗(yàn)證,測試時(shí),一般會將token放入請求頭中。當(dāng)然這里的安全方案不只有這一種,感興趣可以進(jìn)行了解。
到此這篇關(guān)于從入門到精通一文搞定SpringDoc的文章就介紹到這了,更多相關(guān)SpringDoc使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java創(chuàng)建可執(zhí)行的Jar文件的方法實(shí)踐
創(chuàng)建的可執(zhí)行Jar文件實(shí)際就是在原始Jar的清單文件中添加了Main-Class的配置,本文主要介紹了Java創(chuàng)建可執(zhí)行的Jar文件的方法實(shí)踐,感興趣的可以了解一下2023-12-12Java語言實(shí)現(xiàn)簡單FTP軟件 輔助功能模塊FTP站點(diǎn)管理實(shí)現(xiàn)(12)
這篇文章主要為大家詳細(xì)介紹了Java語言實(shí)現(xiàn)簡單FTP軟,輔助功能模塊FTP站點(diǎn)管理的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04Springmvc中的轉(zhuǎn)發(fā)重定向和攔截器的示例
本篇文章主要介紹了Springmvc中的轉(zhuǎn)發(fā)重定向和攔截器的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05IDEA連接Mysql數(shù)據(jù)庫的詳細(xì)圖文教程
項(xiàng)目開發(fā)時(shí)使用Intellij IDEA連接本地?cái)?shù)據(jù)庫,將數(shù)據(jù)庫可視化,還可對數(shù)據(jù)庫表直接進(jìn)行增刪改查操作,方便快捷又清晰,下面這篇文章主要給大家介紹了關(guān)于IDEA連接Mysql數(shù)據(jù)庫的詳細(xì)圖文教程,需要的朋友可以參考下2023-03-03