最新版 springdoc-openapi-starter-webmvc-ui 常用注解详解 + 实战示例

Spring Boot 3.x 引入springdoc-openapi (内置Swagger UI、webmvc-api) 给我的启发, 阅读详情
AI摘要

本文详细介绍了 Spring Boot 3 中 springdoc-openapi-starter-webmvc-ui 的常用注解,涵盖 API 文档分组、参数与请求体描述、安全认证配置及响应结构定义等内容,并结合实际代码示例展示如何生成清晰、可交互的 API 文档。适用于 Java 开发者提升前后端协作效率。

当然可以!在 Spring Boot 3 + SpringDoc OpenAPI(Swagger 3 替代方案)生态中,springdoc-openapi-starter-webmvc-ui 是目前官方推荐的集成方式。它提供了一套丰富的注解,用于精细化控制 API 文档的生成,提升前端、测试、产品等协作方的体验。


✅ 最新版 springdoc-openapi-starter-webmvc-ui 常用注解详解 + 实战示例

📌 当前最新稳定版本:springdoc-openapi 2.5+(2025年仍适用)
📌 所有注解位于包:io.swagger.v3.oas.annotations.*


🧩 一、核心注解概览

注解作用适用位置
@OpenAPIDefinition全局 API 信息配置(标题、版本、联系人等)@Configuration 类
@Tag标记 Controller 或方法所属的“标签/模块”类、方法
@Operation描述某个 API 操作(方法)的详细信息方法
@Parameter描述单个请求参数(路径、查询、Header)方法参数
@Parameters批量描述多个参数方法
@RequestBody描述请求体结构方法参数
@ApiResponse描述单个响应状态码及结构方法
@ApiResponses批量描述多个响应方法
@Schema描述 DTO 字段的含义、示例、格式等类、字段、方法参数
@Hidden隐藏某个 Controller 或方法,不生成文档类、方法、字段

🧱 二、详细注解说明 + 实战示例(带中文注释)


1️⃣ @Tag —— 模块分组标签

用于对 Controller 或方法进行分组,前端文档左侧菜单按 Tag 分组显示。

@Tag(name = "用户管理模块", description = "提供用户增删改查、状态管理等核心功能")
@RestController
@RequestMapping("/api/users")
public class UserController {
    // ...
}

✅ 作用:

  • 在 Swagger UI 左侧菜单中显示为“用户管理模块”。
  • 可用于模块化组织大型项目 API。

2️⃣ @Operation —— API 操作描述

描述某个接口的用途、注意事项、是否已废弃等。

@Operation(
    summary = "分页查询用户列表",
    description = "支持按用户名、年龄范围、状态筛选,返回分页数据。\n" +
                  "createTime 字段为 ISO 格式,如:2025-04-01T10:00:00",
    tags = {"用户管理模块"}, // 可覆盖类上的 Tag
    deprecated = false,      // 是否废弃
    security = @SecurityRequirement(name = "Bearer Token") // 安全要求(需配合 SecurityScheme)
)
@GetMapping
public Result<IPage<UserVO>> listUsers(
        @Parameter(description = "当前页码,从1开始", example = "1") @RequestParam(defaultValue = "1") Integer current,
        @Parameter(description = "每页大小,最大100", example = "10") @RequestParam(defaultValue = "10") Integer size,
        UserQueryDTO query) {
    // ...
}

✅ 作用:

  • summary:接口简短标题(必填,显示在接口列表)
  • description:详细说明,支持 Markdown
  • deprecated:标记为废弃接口(UI 会显示删除线)
  • security:声明该接口需要认证(需全局配置 SecurityScheme)

3️⃣ @Parameter —— 单个参数描述

用于描述 @RequestParam, @PathVariable, @RequestHeader 等参数。

@GetMapping("/{id}")
@Operation(summary = "根据ID获取用户详情")
public Result<UserVO> getUserById(
        @Parameter(
            name = "id",
            description = "用户唯一标识,雪花ID",
            required = true,
            example = "123456789012345678",
            schema = @Schema(type = "integer", format = "int64")
        )
        @PathVariable Long id) {

    User user = userService.getById(id);
    if (user == null) {
        return Result.error(404, "用户不存在");
    }
    return Result.success(userStructMapper.toVO(user));
}

✅ 作用:

  • name:参数名(通常可省略,自动推断)
  • description:参数说明
  • required:是否必填
  • example:示例值(非常重要!前端可一键填充)
  • schema:指定数据类型和格式(如 int64、date-time、email 等)

4️⃣ @RequestBody —— 请求体描述

用于描述 @RequestBody 注解的 DTO 对象结构。

@PostMapping
@Operation(summary = "创建新用户")
public Result<String> createUser(
        @io.swagger.v3.oas.annotations.parameters.RequestBody(
            description = "用户创建请求体",
            required = true,
            content = @Content(
                mediaType = "application/json",
                schema = @Schema(implementation = UserCreateDTO.class),
                examples = {
                    @ExampleObject(
                        name = "创建普通用户",
                        value = """
                                {
                                  "name": "张三",
                                  "age": 25,
                                  "email": "zhangsan@example.com",
                                  "status": 1
                                }
                                """
                    ),
                    @ExampleObject(
                        name = "创建未成年用户",
                        value = """
                                {
                                  "name": "小明",
                                  "age": 16,
                                  "email": "xiaoming@example.com",
                                  "status": 0
                                }
                                """
                    )
                }
            )
        )
        @Valid @RequestBody UserCreateDTO createDTO) {
    boolean saved = userService.createUser(createDTO);
    return saved ? Result.success("用户创建成功") : Result.error("创建失败");
}

✅ 作用:

  • description:请求体说明
  • content.schema.implementation:指定 DTO 类,自动生成字段文档
  • examples:提供多个示例(前端可切换使用)
  • 支持 JSON/YAML 示例

💡 注意:不要与 org.springframework.web.bind.annotation.RequestBody 混淆,这里是 io.swagger.v3.oas.annotations.parameters.RequestBody


5️⃣ @Schema —— 字段/类级描述(最常用!)

用于描述 DTO/Entity 的字段含义、格式、示例、是否只读等。

@Data
@Schema(description = "用户创建请求参数")
public class UserCreateDTO {

    @Schema(
        description = "用户名,2-20位中文或英文",
        example = "张三",
        minLength = 2,
        maxLength = 20,
        requiredMode = Schema.RequiredMode.REQUIRED // 必填
    )
    @NotBlank(message = "用户名不能为空")
    private String name;

    @Schema(
        description = "年龄,0-150岁",
        example = "25",
        minimum = "0",
        maximum = "150",
        requiredMode = Schema.RequiredMode.REQUIRED
    )
    @NotNull(message = "年龄不能为空")
    @Min(value = 0, message = "年龄不能小于0")
    private Integer age;

    @Schema(
        description = "邮箱地址",
        example = "zhangsan@example.com",
        format = "email", // 格式校验提示
        requiredMode = Schema.RequiredMode.NOT_REQUIRED
    )
    @Email(message = "邮箱格式不正确")
    private String email;

    @Schema(
        description = "用户状态:0=禁用,1=启用",
        example = "1",
        allowableValues = {"0", "1"}, // 枚举值提示
        requiredMode = Schema.RequiredMode.REQUIRED
    )
    @NotNull(message = "状态不能为空")
    private Integer status;
}

✅ 作用:

  • 自动生成字段说明、示例、校验规则提示
  • format:支持 date, date-time, email, uuid, uri 等
  • allowableValues:枚举值提示(前端下拉可选)
  • accessMode:可设置 READ_ONLY(仅响应)或 WRITE_ONLY(仅请求,如密码字段)
  • implementation:用于嵌套对象或接口类型

6️⃣ @ApiResponse & @ApiResponses —— 响应结构描述

描述不同 HTTP 状态码对应的响应结构,特别是错误码。

@PutMapping
@Operation(summary = "更新用户信息")
@ApiResponses(value = {
    @ApiResponse(
        responseCode = "200",
        description = "更新成功",
        content = @Content(schema = @Schema(implementation = Result.class))
    ),
    @ApiResponse(
        responseCode = "400",
        description = "参数校验失败",
        content = @Content(schema = @Schema(implementation = Result.class))
    ),
    @ApiResponse(
        responseCode = "404",
        description = "用户不存在",
        content = @Content(schema = @Schema(implementation = Result.class))
    ),
    @ApiResponse(
        responseCode = "500",
        description = "系统内部错误",
        content = @Content(schema = @Schema(implementation = Result.class))
    )
})
public Result<String> updateUser(@Valid @RequestBody UserUpdateDTO updateDTO) {
    boolean updated = userService.updateUser(updateDTO);
    return updated ? Result.success("更新成功") : Result.error("更新失败");
}

✅ 作用:

  • 前端可预知不同状态码的响应结构
  • 配合全局异常处理器,可标准化错误返回
  • responseCode:HTTP 状态码
  • description:状态码含义
  • content.schema:指定响应体结构(通常为 Result<T>)

7️⃣ @Hidden —— 隐藏接口或字段

隐藏不想暴露给前端的接口或敏感字段。

@Hidden // 整个 Controller 不生成文档
@RestController
@RequestMapping("/api/internal")
public class InternalController {
    // ...
}

// 或隐藏某个字段(如密码、密钥)
@Data
public class UserVO {
    private Long id;
    private String name;

    @Hidden // 不在 Swagger 中显示
    private String internalCode;

    private String email;
}

✅ 作用:

  • 隐藏内部接口(如运维、回调、定时任务触发接口)
  • 隐藏敏感字段(如密码、密钥、审计字段)

8️⃣ @OpenAPIDefinition —— 全局 API 信息配置

通常放在启动类或独立配置类中,定义 API 全局元信息。

@OpenAPIDefinition(
    info = @Info(
        title = "企业用户管理系统 API 文档",
        version = "v1.2.0",
        description = "提供用户管理、权限控制、操作日志等核心功能",
        contact = @Contact(
            name = "API支持团队",
            email = "api-support@company.com",
            url = "https://www.company.com"
        ),
        license = @License(
            name = "Apache 2.0",
            url = "https://www.apache.org/licenses/LICENSE-2.0.html"
        )
    ),
    servers = {
        @Server(url = "http://localhost:8080", description = "本地开发环境"),
        @Server(url = "https://api.company.com", description = "生产环境")
    }
)
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

✅ 作用:

  • 定义 API 标题、版本、描述、联系人、许可证
  • 定义多环境服务器地址(前端可切换)
  • 显示在 Swagger UI 顶部

9️⃣ @SecurityScheme + @SecurityRequirement —— 安全认证配置

配置 JWT/Bearer Token 认证方式。

@SecurityScheme(
    name = "Bearer Token",
    type = SecuritySchemeType.HTTP,
    bearerFormat = "JWT",
    scheme = "bearer" // 小写 bearer
)
@Configuration
public class OpenApiConfig {
    // 可放在此类,或与 @OpenAPIDefinition 合并
}

然后在需要认证的接口上添加:

@Operation(
    summary = "删除用户",
    security = @SecurityRequirement(name = "Bearer Token") // 引用上面定义的 name
)
@DeleteMapping("/{id}")
public Result<String> deleteUser(@PathVariable Long id) {
    // ...
}

✅ 作用:

  • Swagger UI 顶部会出现 🔒 认证按钮
  • 前端可输入 Token,后续请求自动带 Authorization: Bearer xxx
  • 提升 API 安全性和测试便利性

🧪 三、完整 Controller 示例(整合所有注解)

package com.example.demo.controller;

import com.example.demo.entity.dto.*;
import com.example.demo.entity.vo.UserVO;
import com.example.demo.service.IUserService;
import com.example.demo.util.Result;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
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 io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

@Tag(name = "用户管理模块", description = "提供用户增删改查、状态管理、批量操作等核心功能")
@Validated
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private IUserService userService;

    @Autowired
    private UserStructMapper userStructMapper;

    // ==================== 查询 ====================

    @Operation(
        summary = "分页查询用户列表",
        description = """
            支持多条件组合查询:
            - 按用户名模糊匹配
            - 按年龄范围筛选
            - 按状态精确匹配
            - 按创建时间区间筛选
            返回标准分页结构。
            """,
        security = @SecurityRequirement(name = "Bearer Token")
    )
    @Parameters({
        @Parameter(name = "current", description = "当前页码,从1开始", example = "1", required = true),
        @Parameter(name = "size", description = "每页大小,建议10~50", example = "10", required = true)
    })
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "查询成功", content = @Content(schema = @Schema(implementation = Result.class))),
        @ApiResponse(responseCode = "401", description = "未授权", content = @Content(schema = @Schema(implementation = Result.class)))
    })
    @GetMapping
    public Result<IPage<UserVO>> listUsers(
            @Min(1) @RequestParam(defaultValue = "1") Integer current,
            @Min(1) @RequestParam(defaultValue = "10") Integer size,
            UserQueryDTO query) {
        Page<User> page = new Page<>(current, size);
        IPage<User> userPage = userService.searchUsers(query, page);
        List<UserVO> voList = userStructMapper.toVOList(userPage.getRecords());
        IPage<UserVO> voPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
        voPage.setRecords(voList);
        return Result.success(voPage);
    }

    // ==================== 创建 ====================

    @Operation(
        summary = "创建新用户",
        description = "创建用户时会自动填充创建时间,状态默认启用"
    )
    @io.swagger.v3.oas.annotations.parameters.RequestBody(
        description = "用户创建请求体",
        required = true,
        content = @Content(
            mediaType = "application/json",
            schema = @Schema(implementation = UserCreateDTO.class),
            examples = {
                @ExampleObject(
                    name = "成人用户",
                    value = """
                            {
                              "name": "张三",
                              "age": 25,
                              "email": "zhangsan@example.com",
                              "status": 1
                            }
                            """
                ),
                @ExampleObject(
                    name = "未成年用户",
                    value = """
                            {
                              "name": "小明",
                              "age": 16,
                              "email": "xiaoming@example.com",
                              "status": 0
                            }
                            """
                )
            }
        )
    )
    @PostMapping
    public Result<String> createUser(@Valid @RequestBody UserCreateDTO createDTO) {
        boolean saved = userService.createUser(createDTO);
        return saved ? Result.success("用户创建成功") : Result.error("创建失败");
    }

    // ==================== 更新 ====================

    @Operation(summary = "更新用户信息")
    @PutMapping
    public Result<String> updateUser(@Valid @RequestBody UserUpdateDTO updateDTO) {
        boolean updated = userService.updateUser(updateDTO);
        return updated ? Result.success("更新成功") : Result.error("更新失败");
    }

    // ==================== 删除 ====================

    @Operation(
        summary = "删除用户(逻辑删除)",
        description = "不会物理删除数据,仅标记 deleted=1",
        security = @SecurityRequirement(name = "Bearer Token")
    )
    @Parameter(name = "id", description = "用户ID", required = true, example = "123456789012345678")
    @DeleteMapping("/{id}")
    public Result<String> deleteUser(@PathVariable @NotNull Long id) {
        boolean deleted = userService.removeById(id);
        return deleted ? Result.success("删除成功") : Result.error("用户不存在或已被删除");
    }
}

✅ 四、最佳实践建议

实践项说明
所有公开接口必须加 @Operation至少写 summary,让前端知道接口用途
DTO 字段必须加 @Schema描述 + 示例 + 校验规则,极大提升协作效率
关键参数加 @Parameter(example=...)前端可一键填充测试数据
提供多个 @ExampleObject覆盖正常、边界、异常场景
敏感接口加 @SecurityRequirement明确告知需要 Token
废弃接口加 deprecated = true前端可见,避免误用
内部接口用 @Hidden避免文档混乱
全局配置 @OpenAPIDefinition统一团队 API 文档风格

🌐 五、访问与调试

  • 文档地址:http://localhost:8080/swagger-ui/index.html
  • OpenAPI JSON:http://localhost:8080/v3/api-docs
  • 支持 Try it out → 在线调试 → 自动生成 Curl/Request

✅ 六、总结

通过合理使用 SpringDoc OpenAPI 注解,你可以:

✅ 生成专业级、可交互、可调试的 API 文档
✅ 减少前后端沟通成本,提升开发效率
✅ 标准化接口设计,避免“口口相传”
✅ 提升项目专业度和可维护性

💡 提示:注解虽好,但不要过度堆砌。保持简洁、实用、一致即可。大型项目建议制定《API 文档规范》,统一注解使用标准。


📌 官方文档参考:https://springdoc.org/


这份指南涵盖了企业开发中 95% 以上的 SpringDoc 注解使用场景,可直接用于生产项目!

SpringBoot 3.x集成SpringDoc OpenAPI:自动生成API文档实战指南 在RESTful API开发中,API文档是前后端协作和系统集成的关键。OpenAPI规范作为行业标准,定义了RESTful API的描述格式,而SpringDoc OpenAPI作为其实现工具,能够自动扫描Spring Boot项目中的控制器和注解,生成符合规范的交互式文档。其技术价值在于实现了“代码即文档”,通过注解驱动的方式,将文档维护成本降至最低,同时确保文档与代码的实时同步。在SpringBoot 3.x项目中,SpringDoc已成为默认的文档解决方案,广泛应用于微服务架构、对外API服务以及团 阅读详情

相关推荐

SpringDoc和Swagger使用

Swagger和Springdoc是两个常用的工具,用于生成和维护API文档,特别是针对基于REST的Web服务。它们有效地提升了API的可读性和可维护性,帮助开发者、产品经理和其他利益相关者更好地理解和使用所提供的API。注意:Swagger支持springboot2.0但不支持springboot3.0。

m0_66323401的博客 1546

java:springboot3集成swagger(springdoc-openapi-starter-webmvc-ui)

springboot3集成swagger报错Typejavax.servlet.http.HttpServletRequest not present,来使用springdoc-openapi-starter-webmvc-ui

分享前端开发工程师的一些日常生活、前端知识点、职业发展、对一些问题的看法、感悟等等 7680

使用 Spring Doc 为 Spring REST API 生成 OpenAPI 3.0 文档

文档是构建 REST API 的重要组成部分。在本教程中,我们将介绍 Spring Doc,它可简化 API 文档的生成和维护,这些文档基于 OpenAPI 3 规范,适用于 Spring Boot 3.x 应用程序。

福如意的博客 1万+

springboot集成springdoc-openapi(模拟前端请求)

springdoc-openapi使用`@io.swagger.v3.oas.annotations`包下的注解来定义API文档,它遵循OpenAPI规范,并提供了一些额外的注解来进行更细粒度的控制。springdoc-openapi-ui中间已经包含了swagger也就是说,使用springdoc-openapi-ui是可以替代的。- springdoc-openapi通常只需要引入`springdoc-openapi-ui`依赖,并且不需要太多的配置即可生成和展示OpenAPI文档。

比起日出,我更喜欢日落。我的意思是比起遇见你,我更喜欢与你终老 8849

随手记录第十四话 -- 在 Spring Boot 3.2.3 中使用 springdoc-openapi-starter-webmvc-ui

通过使用 springdoc-openapi-starter-webmvc-ui ,我们可以在 Spring Boot 3.2.3 中继续方便地生成和展示 API 文档,帮助我们更好地理解和管理项目中的接口。在实际应用中,可以根据需要进行更深入的定制和优化。希望这篇文章对你顺利过渡到新的 API 文档工具提供帮助,让你在开发过程中能够更好地与 API 进行交互和文档化。随手记录第十三话 – 关于Python自动化部署神器fabric的应用与差异。

m0_74823933的博客 1771

【SpringBoot】98、SpringBoot中整合springdoc-openapi-ui接口文档

通常情况下,springdoc-openapi-ui 不需要额外的配置即可工作。Spring Boot 会自动扫描你的控制器并生成 OpenAPI 文档。

JACKAL 3万+

SpringBoot3整合swagger(springdoc-openapi)

SpringBoot3、swagger3、springdoc-openapi、jdk17

蓝影铁哥的博客 1万+

全球半导体设备氧化钇熔射服务行业规模预测:预计未来六年CAGR为7.8%

本文将对“半导体设备氧化钇熔射服务”行业进行深度分析,探讨市场趋势的演变、核心竞争者的战略布局、供应链结构的内外特点、研发创新的最新进展、法规政策环境的适应性调整以及投资机会与风险评估。这一稳健的增长趋势表明半导体设备氧化钇熔射服务在电子行业中的重要性逐渐增强。由于全球对于高效、高精度和可靠的电子解决方案的需求增加,对能够提供这些功能的半导体设备氧化钇熔射服务的需求日益增长。由于半导体设备氧化钇熔射服务主要为就地服务型,其“配送”主要依赖于专业团队和技术设备的及时调配,强调服务的时效性和高质量。

CC1239777的博客 570

Springdoc-openapi 注解及使用

摘要:springdoc-openapi-starter-webmvc-ui是一个基于OpenAPI 3.0规范的SpringBoot集成工具,用于自动生成RESTful API文档并支持Swagger UI交互界面。作为SpringFox的替代方案,它更轻量且完全兼容OpenAPI 3.0。工具支持自动扫描Spring MVC控制器和实体类,生成标准JSON文档,并适用于SpringBoot 2.x/3.x版本。通过简单配置和注解(如@Tag、@Operation等),开发者可以轻松定义API文档的元信息

gjjdtxz的博客 1664

解决此平台不支持虚拟化的 Intel VT-x/EPT故障问题

当我们在VMware Workstation虚拟机上【启用】虚拟系统(如:Windows10)所在的虚【拟机设置】【处理器】【虚拟化引擎】下面的【虚拟化 Intel VT-x/EPT 或AMD-V/RVI(V)】内容后,在启动虚拟系统时,虚拟系统无法启动,且弹出【此平台不支持虚拟化的 Intel VT-x/EPT。不使用虚拟化的 Intel VT-x/EPT,是否继续】窗口

提供C#相关开发 、云计算、运维测试、网络安全相关技术分享与服务,有意向可联系。 1万+

北斗导航 | ChatGPT之RTK、RTD、ARAIM算法原理及程序代码(ChatGPT看你怎么回答,附部分代码)

ChatGPT之RTK、RTD、ARAIM算法原理及程序代码

尘世冰封的专栏 3676

Springboot 3.x引入 SpringDoc OpenAPI Starter WebMvc UI 实现接口文档,解决 knife4j 文档请求异常:

苍穹外卖,knife4j 文档请求异常,SpringBoot, SpringDoc OpenAPI Starter WebMvc UI

H_Leonis的博客 961

SAP ABAP 获取采购订单未清数量/在途库存的 6 种方式

这篇文章我总结了获取采购订单未清数量/在途库存的 6 种方式,每种方式的优劣势和适用场景有所不同。读者请结合自身需要选择。

SAP李斌,本人承诺所有原创文章均不使用任何AI生成技术,请大家放心阅读。 2650
上一篇: 微服务电商项目基础结构
下一篇: 关于在 commons 模块中创建 commons-openapi 的深度分析与最佳实践
龙茶清欢
博客等级 码龄7年 3720粉丝 375原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙茶清欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值