SpringDoc详解(从入门到精通,一文搞定)
Swagger3.0—OpenAPI3.0
Sawgger3.0又叫OpenAPI3.0,对应的依赖包有两种,分别为Springfox以及SpringDoc,但是Springfox以及停止维护,无法支持SpringBoot3,以下围绕SpringDoc进行讲解。
文章目录
- Swagger3.0---OpenAPI3.0
- 一、集成SpringDoc
- 1.引入依赖
- 2.配置文档信息
- 3.访问(ip:端口/swagger-ui/index.html)
- 4.测试(Post请求为例)
- 注意:
- 二、常用注解
- 1.常用注解汇总
- 2.常用注解示例
- @Tag
- @Operation
- @Parameter
- @Parameters
- @Schena
- @ApiRequest/@Content
- @ApiRequests
- @ResquestBody
- `结合使用`
- 扩展@ResponseStatus
- 三、分组
- 四、认证授权
一、集成SpringDoc
1.引入依赖
org.springdoc springdoc-openapi-ui 1.8.0
2.配置文档信息
后面会解释配置信息与文档的对应关系
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("标题---JsustPlay") .description("描述信息---JsustPlay API文档") .version("版本说明---1.0.0") .license(new License() .name("API文档的许可信息---这里模拟一下,转跳百度了") .url("http://www.baidu.com")) .contact(new Contact() .name("作者name---fengqing") .email("作者email--- 可以直接跳转邮箱发邮件,这里是假的") .extensions((Map) Maps.newHashMap().put("x-xxx-x","扩展字段,key必须以x开头")) .url("http://www.baidu.com"))) .externalDocs(new ExternalDocumentation() .description("外部文档描述---这里也转跳百度的") .url("http://www.baidu.com") ); } }
3.访问(ip:端口/swagger-ui/index.html)
以上即为配置信息与文档信息的对应关系,每个信息类的属性几乎都都涉及的,还有部分非常用属性信息为涉及,感兴趣的可以看下对应类的源码进行了解。
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: 风清 * @CreateTime: 2025-03-26 21:08 */ @Data public class StudentDto { private String name; private Integer age; }
注意:
默认情况下,Swagger3.0会根据请求类型来映射请求参数
我们将上述请求改为Get在进行测试
@GetMapping("/demo001_1") public StudentDto demo001_1(@RequestBody StudentDto studentDto){ return BeanUtil.toBean(studentDto,StudentDto.class); }
可以看到虽然填写请求体的时候仍然是Json格式,但是在发请求的时候数据被当做@RequestParam进行映射了
二、常用注解
1.常用注解汇总
注解 定位 @Tag 作用在Controller类上,用于描述API类信息。 @Operation 作用在Controller类的方法上,用于描述API方法信息,该注解可以包含一下全部注解。 @Parameter 作用在Controller类的方法上,用于描述 API 方法的参数信息。 @Parameters 作用在Controller类的方法上,用于描述API方法的多个参数。 @Schema 作用在实体类或者实体类属性上,用于描述实体类/实体类属性的信息,该实体类一般作为入参。或者结合在一些注解的schema属性中来描述参数信息(入参,返回值) @ApiResponse 作用在Controller类的方法上,用于描述API方法单个响应信息。 @ApiResponses 作用在Controller类的方法上,用于描述API方法多个响应信息。 @Hidden 隐藏某个类、方法或参数,不将其包含在生成的文档中。 @ResquestBody 作用在Controller类的方法上、用于描述请求体信息。 @Content 通常用于 @ApiResponse 或 @Parameter 注解中,用来定义 API 响应或参数的具体内容结构。 2.常用注解示例
@Tag
-
作用
为控制器或方法分组,便于组织和分类 API。
-
常用属性
name:标签名称。
description:标签描述信息。
-
示例
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: 风清 * @CreateTime: 2025-03-26 21:08 */ @Data public class StudentDto { private String name; private Integer age; }
- Swagger呈现结果
这里顺便说一Swagger的三大部分,如下图
@Operation
-
作用
为控制器或方法分组,便于组织和分类 API。
-
常用属性
summary:标签名称。
description:标签描述信息。
deprecated:标记方法是否已废弃。(默认为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: 风清 * @CreateTime: 2025-03-26 21:08 */ @Data public class StudentDto { private String name; private Integer age; }
- Swagger呈现结果
@Parameter
-
作用
描述方法参数的含义。
-
常用属性
name:参数名(使用时与参数一致)
description:参数描述信息。
in:参数位置。示例代码中进行说明。
schema:参数类型。
required:是否必填,默认为false。
example:示例值。
-
注意
该注解用于@RequestParam、@PathVariable参数,Sawgger通过@RequestBody注解来修饰@RequestBody类型参数。
-
示例
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:参数位置,ParameterIn.PATH表示参数在路径中, ParameterIn.QUERY表示参数在查询字符串中, ParameterIn.HEADER表示参数在请求头中, ParameterIn.COOKIE表示参数在cookie中。 */ @PostMapping("/{id}") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") public String demo001_1( @Parameter(name = "id", description = "学生id", in = ParameterIn.PATH, schema = @Schema(type = "integer"), required = true,example = "1") @PathVariable Integer id, @Parameter(name = "name", description = "学生姓名", in = ParameterIn.QUERY, schema = @Schema(type = "string"), required = true,example = "张三") @RequestParam String name ){ return name+":"+id; } //作用在类似修饰@RequestBody参数,上面说过,swagger有对应处理@RequestBody参数的注解@RequestBody,所以这里就不进行展示了,记住这种方式不要用即可 @PostMapping("/demo001_1") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") @Parameter(deprecated = true,description = "学生信息", 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呈现结果
@Parameters
-
作用
作用在实体类或者实体类属性上,用于描述实体类/实体类属性的信息,该实体类一般作为入参。或者结合在一些注解的schema属性中来描述参数信息(入参,返回值)
-
常用属性
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:参数位置,ParameterIn.PATH表示参数在路径中, ParameterIn.QUERY表示参数在查询字符串中, ParameterIn.HEADER表示参数在请求头中, ParameterIn.COOKIE表示参数在cookie中。 */ @PostMapping("/{id}") @Operation(summary = "Sdemo001_1",description = "Ddemo001_1") public String demo001_1( @Parameter(name = "id", description = "学生id", in = ParameterIn.PATH, schema = @Schema(type = "integer"), required = true,example = "1") @PathVariable Integer id, @Parameter(name = "name", description = "学生姓名", in = ParameterIn.QUERY, schema = @Schema(type = "string"), required = true,example = "张三") @RequestParam String name ){ return name+":"+id; }
- Swagger呈现结果
@Schena
-
作用
作用在实体类或者实体类属性上,用于描述实体类/实体类属性的信息,该实体类一般作为入参。或者结合在一些注解的schema属性中来描述参数信息(入参,返回值)
-
常用属性
- 作用于实体类/实体类属性上:
description:模型或属性的描述。
example:示例值。
required:必需属性。
hidden:是否隐藏属性。
- 结合其他注解使用上:
type: 指定@RequestParam、@PathVariable参数类型(用法与上方@Parameter中一致)
implementation:指定JSON(@RequestBody)参数类型(于下方@RequsetBody/@ApiRequest注解中演示)
-
注意
请求体或者响应体为json时,无论对应的Dto/Vo类无论是否被Schema注解都会被映射,Schema注解只是为响应/请求体添加了描述信息。
-
示例
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 风清 * @CreateTime: 2025-03-26 21:08 */ @Data //无论是否有Schema注解Swagger都会将请求参数映射到Swagger文档上,Schema注解只是给Swagger文档上添加一些描述信息和示例信息 @Schema(description = "学生信息", 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呈现结果
引入Swagger前(这里的schema会在用到的进行映射)
引入后:可以看到多了示例值,并且隐藏了age。
@ApiRequest/@Content
-
作用
作用在Controller类的方法上,用于描述API方法单个响应信息。
-
常用属性
responseCode:HTTP 状态码。
description:响应描述信息。
content:响应的内容类型(如 JSON、XML)。
- @Content常用属性
mediaType :响应格式。
schema :响应结果格式。
-
注意
不通过@ApiRequest的content属性去指定响应体时,Swagger会自动映射返回体,当响应值非200时一般不需要显示响应体内容(展示是无意义的),这个是时候就需要为content属性赋值一个空的@Content。
-
示例
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 风清 * @CreateTime: 2025-03-26 21:08 */ @Data //无论是否有Schema注解Swagger都会将请求参数映射到Swagger文档上,Schema注解只是给Swagger文档上添加一些描述信息和示例信息 @Schema(description = "学生信息", 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( //响应类型 mediaType = "application/json", //响应对象结果描述 schema = @Schema(implementation = StudentDto.class))} ) // 描述2 这里指定了一个空的@Content来实现swagger文档不展示响应体,否则会默认swagger会映射默认返回内容。 @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呈现结果
可以与上方默认的响应信息进行对比,可以看到响应200的描述信息由默认的ok改成了成功,类型有默认的*/*改成了application/json。
@ApiRequests
-
作用
作用在Controller类的方法上,用于描述API方法多个响应信息。
-
常用属性
value:ApiRequests集合。
-
示例
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** * @Description: StudentDto * @Author: 风清 * @CreateTime: 2025-03-26 21:08 */ @Data //无论是否有Schema注解Swagger都会将请求参数映射到Swagger文档上,Schema注解只是给Swagger文档上添加一些描述信息和示例信息 @Schema(description = "学生信息", 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( //响应类型 mediaType = "application/json", //响应对象结果描述 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呈现结果(与上述一致)
@ResquestBody
-
作用
作用在Controller类的方法上,用于描述请求体信息。
-
常用属性
description:请求体的描述。
required:是否必需。
content :请求的内容类型(与@ApiRequest一致)。
-
示例
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Data; /** * @Description: StudentDto * @Author: 风清 * @CreateTime: 2025-03-26 21:08 */ @Data @Builder @Schema(description = "学生信息", 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呈现结果
这里的mediaType 属性可以不进行描述默认就为application/json。
对了,这里在提下,在请求/响应体的旁边有个schema点击会展示对应的请求/响应体信息
结合使用
上面说过@Operation可以包含几乎全表Swagger3.0的注解,实际开发中这些注解通常也不会单独使用,而是包含在@Operation中。如下
package org.example.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Data; /** * @Description: StudentDto * @Author: 风清 * @CreateTime: 2025-03-26 21:08 */ @Data @Builder @Schema(description = "学生信息", 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呈现结果
扩展@ResponseStatus
上面我们通过@ApiResponse来设定响应信息,但实际上响应结果的种类是比较多的一个个设置很繁琐,而实际开发中通常会有统一的响应类以及全局异常处理器,我们通常通过Swagger的ResponseStatus注解结合全局异常处理器来实现响应信息的生成。
- 示例代码
package org.example.enums; /** * 文件名: AppHttpCodeEnum.java 响应枚举 * * @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,"密码错误"), // TOKEN50~100 TOKEN_INVALID(50,"无效的TOKEN"), TOKEN_EXPIRE(51,"TOKEN已过期"), TOKEN_REQUIRE(52,"TOKEN是必须的"), // SIGN验签 100~120 SIGN_INVALID(100,"无效的SIGN"), SIG_TIMEOUT(101,"SIGN已过期"), // 参数错误 500~1000 PARAM_REQUIRE(500,"缺少参数"), PARAM_INVALID(501,"无效参数"), PARAM_IMAGE_FORMAT_ERROR(502,"图片格式有误"), SERVER_ERROR(503,"服务器内部错误"), // 数据错误 1000~2000 DATA_EXIST(1000,"数据已经存在"), AP_USER_DATA_NOT_EXIST(1001,"ApUser数据不存在"), DATA_NOT_EXIST(1002,"数据不存在"), // 数据错误 3000~3500 NO_OPERATOR_AUTH(3000,"无权限操作"), NEED_ADMIND(3001,"需要管理员权限"); 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 //控制器增强类, 表示如果在controller.service中任何一个地方出现了异常之后,都会自动调用该捕获类 @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; /** * 通用的结果返回类 * @param */ public class ResponseResult 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; } }
- 展示结果
可以看到这里多了500和503,点开对应的schema可以看到正是我们的统一响应结果类信息。
三、分组
业界一般会更具不同服务模块或功能模块对接口进行分组,提高可观性和测试效率,实现起来很简单,只需要在配置类中注入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() //设置分组名称 .group("demo001") //设置匹配路径 .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; } }
- 结果展示
四、认证授权
这里浅谈一下认证授权,其实就是把登录的token放到请求中,这里我就不在举具体的列子了,仅展示一下怎么将认证信息放到请求中(基于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: 风清 * @CreateTime: 2025-04-14 21:13 */ @Configuration public class SpringDocSwaggerConfig { @Bean public OpenAPI testOpenAPI() { // 创建一个 OpenAPI 实例,并设置 API 的基本信息 OpenAPI openAPI = (new OpenAPI()).info((new Info()).title("Example API").version("1.0")); // 创建一个 Components 实例,用于管理 API 的组件,如安全方案等 Components components = new Components(); /*添加安全要求 为OpenAPI对象添加安全要求。SecurityRequirement表示一个安全要求,这里分别添加了 server-one、server-two、server-three、server-four和server-five这五个安全要求。 */ 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表示一个安全方案,这里定义了五个安全方案, 名称分别为server-one、server-two、server-three、server-four和server-five, 类型为APIKEY,即使用 API 密钥进行身份验证,并且密钥要放在请求头中。 */ 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 headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()){ String headName = headerNames.nextElement(); String headerValue = request.getHeader(headName); log.info(headName+":"+headerValue); } return id; } }
基于携带的请求信息我们就可以进行对应的验证,测试时,一般会将token放入请求头中。当然这里的安全方案不只有这一种,感兴趣可以进行了解。
- 在接口中打印下请求头信息
- 配置类
- 结果展示
- 示例
- 展示结果
- 示例代码
- Swagger呈现结果
- Swagger呈现结果
-
- Swagger呈现结果(与上述一致)
-
- Swagger呈现结果
- @Content常用属性
-
- Swagger呈现结果
- 作用于实体类/实体类属性上:
-
- Swagger呈现结果
-
- Swagger呈现结果
-
- Swagger呈现结果
-
- Swagger呈现结果
-