java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringDoc使用

从入门到精通一文搞定SpringDoc

作者:风清已存在

本文介绍Swagger3.0(OpenAPI3.0)在SpringBoot3中的集成,使用SpringDoc替代已停更的Springfox,涵盖依赖引入、配置、常用注解如@Tag、@Operation等,以及分组和认证授权的实现方法,感兴趣的朋友跟随小编一起看看吧

Swagger3.0—OpenAPI3.0

Sawgger3.0又叫OpenAPI3.0,对应的依赖包有两种,分别为Springfox以及SpringDoc,但是Springfox以及停止维护,无法支持SpringBoot3,以下围绕SpringDoc进行讲解。

一、集成SpringDoc

1.引入依赖

        <!--swagger-->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.8.0</version>
        </dependency>

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<String, Object>) 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

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的三大部分,如下图

@Operation

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;
}

@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 {
   /*
         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);
   }

@Parameters

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;
   }

@Schena

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前(这里的schema会在用到的进行映射)

引入后:可以看到多了示例值,并且隐藏了age。

@ApiRequest/@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();
    }
}

可以与上方默认的响应信息进行对比,可以看到响应200的描述信息由默认的ok改成了成功,类型有默认的*/*改成了application/json

@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();
    }
}

@ResquestBody

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;
    }
}

这里的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;
    }
}

扩展@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 <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;
    }
}

可以看到这里多了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<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String headName = headerNames.nextElement();
            String headerValue = request.getHeader(headName);
            log.info(headName+":"+headerValue);
        }
        return id;
    }
}

基于携带的请求信息我们就可以进行对应的验证,测试时,一般会将token放入请求头中。当然这里的安全方案不只有这一种,感兴趣可以进行了解。

到此这篇关于从入门到精通一文搞定SpringDoc的文章就介绍到这了,更多相关SpringDoc使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文