活动公告

系统通知
05-18 21:22
系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

Swagger配置请求示例实战教程打造专业易读的API文档提升开发效率

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

<font color=白金月票" /> 发表于 2025-9-8 20:50:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

在当今快速发展的软件开发行业中,API(应用程序编程接口)已经成为连接不同系统和服务的桥梁。随着微服务架构的普及,API的数量和复杂性不断增加,如何有效地管理和文档化这些API成为开发团队面临的重要挑战。Swagger(现已更名为OpenAPI)作为一个强大的API文档工具,能够帮助开发者自动生成、描述、调用和可视化RESTful风格的Web服务,极大地提升了API开发和维护的效率。

本文将详细介绍如何配置Swagger并添加请求示例,帮助您打造专业、易读的API文档,从而提升整个开发团队的工作效率。我们将从基础概念入手,逐步深入到高级配置和实战案例,确保您能够全面掌握Swagger的使用技巧。

Swagger基础

什么是Swagger

Swagger是一套围绕OpenAPI规范构建的开源工具,可以帮助您设计、构建、记录和使用RESTful Web服务。它主要包括以下几个部分:

• Swagger Editor:基于浏览器的编辑器,可以在其中编写OpenAPI规范。
• Swagger UI:将OpenAPI规范呈现为交互式API文档。
• Swagger Codegen:根据OpenAPI规范生成服务器存根和客户端库。
• Swagger Core:与Java等编程语言集成的库,用于创建OpenAPI规范。

OpenAPI规范

OpenAPI规范(OAS)是Linux基金会下的一个项目,它定义了一个标准的、与语言无关的接口描述RESTful API。OpenAPI文档使团队能够在不查看实际源代码的情况下理解和调用API。

Swagger的优势

使用Swagger具有以下优势:

1. 自动化文档生成:减少手动编写和维护文档的工作量。
2. 交互式API探索:开发者可以直接在文档中测试API端点。
3. 客户端代码生成:可以自动生成多种编程语言的客户端代码。
4. API设计优先:可以在编码前设计API,促进团队协作。
5. 提高开发效率:减少前后端沟通成本,加速开发流程。

环境搭建

在Spring Boot项目中集成Swagger

对于Java开发者来说,将Swagger集成到Spring Boot项目中最常用的库是Springfox。以下是集成步骤:

首先,在您的pom.xml文件中添加Springfox依赖:
  1. <dependency>
  2.     <groupId>io.springfox</groupId>
  3.     <artifactId>springfox-swagger2</artifactId>
  4.     <version>3.0.0</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>io.springfox</groupId>
  8.     <artifactId>springfox-swagger-ui</artifactId>
  9.     <version>3.0.0</version>
  10. </dependency>
复制代码

如果您使用的是Spring Boot 2.6.x或更高版本,还需要添加以下配置以解决路径匹配问题:
  1. @Configuration
  2. public class WebConfig implements WebMvcConfigurer {
  3.     @Override
  4.     public void configurePathMatch(PathMatchConfigurer configurer) {
  5.         configurer.addPathPrefix("/api", Pattern.compile("/api"));
  6.     }
  7. }
复制代码

创建一个配置类来启用Swagger:
  1. @Configuration
  2. @EnableSwagger2
  3. public class SwaggerConfig {
  4.    
  5.     @Bean
  6.     public Docket api() {
  7.         return new Docket(DocumentationType.SWAGGER_2)
  8.                 .select()
  9.                 .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
  10.                 .paths(PathSelectors.any())
  11.                 .build();
  12.     }
  13. }
复制代码

启动应用程序后,您可以通过访问以下URL来查看Swagger UI:
  1. http://localhost:8080/swagger-ui.html
复制代码

在其他框架中的集成

在Node.js的Express框架中,您可以使用swagger-ui-express和swagger-jsdoc来集成Swagger:
  1. const express = require('express');
  2. const swaggerUi = require('swagger-ui-express');
  3. const swaggerJsdoc = require('swagger-jsdoc');
  4. const app = express();
  5. const options = {
  6.   definition: {
  7.     openapi: '3.0.0',
  8.     info: {
  9.       title: 'My API',
  10.       version: '1.0.0',
  11.     },
  12.   },
  13.   apis: ['./routes/*.js'], // 包含API注解的文件路径
  14. };
  15. const specs = swaggerJsdoc(options);
  16. app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));
  17. // ... 其他路由和中间件
  18. app.listen(3000, () => {
  19.   console.log('Server is running on port 3000');
  20. });
复制代码

在Python的Flask框架中,您可以使用flask-swagger-ui:
  1. from flask import Flask
  2. from flask_swagger_ui import get_swaggerui_blueprint
  3. app = Flask(__name__)
  4. SWAGGER_URL = '/api/docs'  # Swagger UI的URL
  5. API_URL = '/static/swagger.json'  # API文档文件的URL
  6. swaggerui_blueprint = get_swaggerui_blueprint(
  7.     SWAGGER_URL,
  8.     API_URL,
  9.     config={
  10.         'app_name': "My API"
  11.     }
  12. )
  13. app.register_blueprint(swaggerui_blueprint, url_prefix=SWAGGER_URL)
  14. if __name__ == '__main__':
  15.     app.run(debug=True)
复制代码

基础配置

Docket配置详解

在Spring Boot中,Docket是Swagger的核心配置类,它允许您自定义Swagger的行为。以下是一些常用的配置选项:
  1. @Configuration
  2. @EnableSwagger2
  3. public class SwaggerConfig {
  4.    
  5.     @Bean
  6.     public Docket api() {
  7.         return new Docket(DocumentationType.SWAGGER_2)
  8.                 .apiInfo(apiInfo()) // API基本信息
  9.                 .select()
  10.                 .apis(RequestHandlerSelectors.basePackage("com.example.controller")) // 控制器包路径
  11.                 .paths(PathSelectors.any()) // 所有路径
  12.                 .build()
  13.                 .produces(Collections.singleton("application/json")) // 生成的内容类型
  14.                 .consumes(Collections.singleton("application/json")) // 接受的内容类型
  15.                 .protocols(Collections.singleton("http")) // 支持的协议
  16.                 .securitySchemes(Collections.singletonList(apiKey())) // 安全方案
  17.                 .securityContexts(Collections.singletonList(securityContext())); // 安全上下文
  18.     }
  19.    
  20.     private ApiInfo apiInfo() {
  21.         return new ApiInfoBuilder()
  22.                 .title("示例API文档")
  23.                 .description("这是一个示例API的文档")
  24.                 .version("1.0.0")
  25.                 .contact(new Contact("开发者姓名", "https://example.com", "developer@example.com"))
  26.                 .license("Apache License Version 2.0")
  27.                 .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0")
  28.                 .build();
  29.     }
  30.    
  31.     private ApiKey apiKey() {
  32.         return new ApiKey("JWT", "Authorization", "header");
  33.     }
  34.    
  35.     private SecurityContext securityContext() {
  36.         return SecurityContext.builder()
  37.                 .securityReferences(defaultAuth())
  38.                 .forPaths(PathSelectors.regex("/api/.*"))
  39.                 .build();
  40.     }
  41.    
  42.     private List<SecurityReference> defaultAuth() {
  43.         AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
  44.         return Collections.singletonList(new SecurityReference("JWT", new AuthorizationScope[]{authorizationScope}));
  45.     }
  46. }
复制代码

全局参数配置

您可以为所有API请求添加全局参数,例如认证头:
  1. @Bean
  2. public Docket api() {
  3.     return new Docket(DocumentationType.SWAGGER_2)
  4.             .globalOperationParameters(
  5.                 Collections.singletonList(
  6.                     new ParameterBuilder()
  7.                         .name("Authorization")
  8.                         .description("认证令牌")
  9.                         .modelRef(new ModelRef("string"))
  10.                         .parameterType("header")
  11.                         .required(true)
  12.                         .build()
  13.                 )
  14.             )
  15.             // ... 其他配置
  16.             .build();
  17. }
复制代码

全局响应配置

您可以为所有API响应添加全局响应消息:
  1. @Bean
  2. public Docket api() {
  3.     return new Docket(DocumentationType.SWAGGER_2)
  4.             .globalResponseMessage(RequestMethod.GET,
  5.                 Collections.singletonList(
  6.                     new ResponseMessageBuilder()
  7.                         .code(500)
  8.                         .message("服务器错误")
  9.                         .responseModel(new ModelRef("Error"))
  10.                         .build()
  11.                 )
  12.             )
  13.             // ... 其他配置
  14.             .build();
  15. }
复制代码

注解详解

Swagger提供了一系列注解,帮助您丰富API文档的内容。下面详细介绍常用注解及其使用方法。

API级别注解

用于标记Controller类作为Swagger文档的资源。
  1. @Api(tags = "用户管理", description = "提供用户的增删改查功能")
  2. @RestController
  3. @RequestMapping("/api/users")
  4. public class UserController {
  5.     // ...
  6. }
复制代码

用于对API进行排序,这在有多个Controller时特别有用。
  1. @ApiSort(1)
  2. @Api(tags = "用户管理")
  3. @RestController
  4. @RequestMapping("/api/users")
  5. public class UserController {
  6.     // ...
  7. }
复制代码

方法级别注解

用于描述一个方法或API操作。
  1. @ApiOperation(
  2.     value = "获取用户列表",
  3.     notes = "获取系统中所有用户的列表,支持分页",
  4.     response = User.class,
  5.     responseContainer = "List",
  6.     tags = {"用户管理"}
  7. )
  8. @GetMapping
  9. public ResponseEntity<List<User>> getAllUsers() {
  10.     // ...
  11. }
复制代码

用于描述方法的参数。
  1. @ApiImplicitParams({
  2.     @ApiImplicitParam(
  3.         name = "page",
  4.         value = "页码",
  5.         required = true,
  6.         dataType = "int",
  7.         paramType = "query",
  8.         defaultValue = "1"
  9.     ),
  10.     @ApiImplicitParam(
  11.         name = "size",
  12.         value = "每页大小",
  13.         required = true,
  14.         dataType = "int",
  15.         paramType = "query",
  16.         defaultValue = "10"
  17.     )
  18. })
  19. @GetMapping
  20. public ResponseEntity<List<User>> getUsersByPage(@RequestParam int page, @RequestParam int size) {
  21.     // ...
  22. }
复制代码

用于描述方法可能的响应。
  1. @ApiResponses(value = {
  2.     @ApiResponse(code = 200, message = "成功获取用户", response = User.class),
  3.     @ApiResponse(code = 401, message = "未授权"),
  4.     @ApiResponse(code = 403, message = "禁止访问"),
  5.     @ApiResponse(code = 404, message = "用户不存在"),
  6.     @ApiResponse(code = 500, message = "服务器错误")
  7. })
  8. @GetMapping("/{id}")
  9. public ResponseEntity<User> getUserById(@PathVariable Long id) {
  10.     // ...
  11. }
复制代码

模型注解

用于描述模型(通常是实体类)。
  1. @ApiModel(description = "用户详细信息")
  2. public class User {
  3.     // ...
  4. }
复制代码

用于描述模型属性。
  1. public class User {
  2.     @ApiModelProperty(value = "用户ID", example = "1", required = true)
  3.     private Long id;
  4.    
  5.     @ApiModelProperty(value = "用户名", example = "john_doe", required = true)
  6.     private String username;
  7.    
  8.     @ApiModelProperty(value = "电子邮箱", example = "john@example.com", required = true)
  9.     private String email;
  10.    
  11.     @ApiModelProperty(value = "密码", example = "password123", required = true, accessMode = ApiModelProperty.AccessMode.WRITE_ONLY)
  12.     private String password;
  13.    
  14.     @ApiModelProperty(value = "创建时间", example = "2023-01-01T00:00:00Z", readOnly = true)
  15.     private Date createdAt;
  16.    
  17.     // getters and setters
  18. }
复制代码

请求和响应注解

当使用@RequestBody时,可以结合@ApiParam提供更详细的描述。
  1. @ApiOperation(value = "创建新用户")
  2. @PostMapping
  3. public ResponseEntity<User> createUser(
  4.     @ApiParam(value = "用户对象", required = true) @Valid @RequestBody UserDto userDto) {
  5.     // ...
  6. }
复制代码

用于忽略某个方法或参数,使其不出现在API文档中。
  1. @ApiIgnore
  2. @GetMapping("/internal")
  3. public String internalMethod() {
  4.     return "This is an internal method";
  5. }
复制代码

请求示例配置

请求示例是API文档中非常重要的一部分,它可以帮助开发者快速了解如何正确地调用API。下面介绍如何在Swagger中配置请求示例。

使用@ApiModelProperty添加示例值

最简单的方式是在@ApiModelProperty注解中直接提供example属性:
  1. public class UserDto {
  2.     @ApiModelProperty(value = "用户名", example = "john_doe", required = true)
  3.     private String username;
  4.    
  5.     @ApiModelProperty(value = "电子邮箱", example = "john@example.com", required = true)
  6.     private String email;
  7.    
  8.     @ApiModelProperty(value = "年龄", example = "30")
  9.     private Integer age;
  10.    
  11.     // getters and setters
  12. }
复制代码

使用@Example和@ExampleProperty

对于更复杂的示例,可以使用@Example和@ExampleProperty注解:
  1. @ApiOperation(value = "创建用户", notes = "创建一个新用户")
  2. @ApiResponses(value = {
  3.     @ApiResponse(code = 201, message = "用户创建成功",
  4.         examples = @Example(value = {
  5.             @ExampleProperty(mediaType = "application/json", value = "{"id": 1, "username": "john_doe", "email": "john@example.com"}")
  6.         })
  7.     )
  8. })
  9. @PostMapping
  10. public ResponseEntity<User> createUser(@Valid @RequestBody UserDto userDto) {
  11.     // ...
  12. }
复制代码

在@ApiOperation中添加示例

您可以在@ApiOperation注解中直接添加示例:
  1. @ApiOperation(
  2.     value = "更新用户",
  3.     notes = "更新指定ID的用户信息",
  4.     examples = @Example(value = {
  5.         @ExampleProperty(mediaType = "application/json", value = "{"username": "new_username", "email": "new_email@example.com"}")
  6.     })
  7. )
  8. @PutMapping("/{id}")
  9. public ResponseEntity<User> updateUser(
  10.     @ApiParam(value = "用户ID", example = "1") @PathVariable Long id,
  11.     @Valid @RequestBody UserDto userDto) {
  12.     // ...
  13. }
复制代码

使用@RequestPart和@ExampleProperty处理文件上传

对于文件上传接口,可以使用@RequestPart和@ExampleProperty:
  1. @ApiOperation(value = "上传用户头像")
  2. @ApiResponses(value = {
  3.     @ApiResponse(code = 200, message = "上传成功",
  4.         examples = @Example(value = {
  5.             @ExampleProperty(mediaType = "application/json", value = "{"url": "https://example.com/avatar.jpg"}")
  6.         })
  7.     )
  8. })
  9. @PostMapping("/{id}/avatar")
  10. public ResponseEntity<Map<String, String>> uploadAvatar(
  11.     @ApiParam(value = "用户ID", example = "1") @PathVariable Long id,
  12.     @ApiParam(value = "头像文件", required = true) @RequestPart("file") MultipartFile file) {
  13.     // ...
  14. }
复制代码

使用Swagger配置类添加全局示例

您可以在Swagger配置类中添加全局示例:
  1. @Bean
  2. public Docket api() {
  3.     return new Docket(DocumentationType.SWAGGER_2)
  4.             .globalRequestParameters(Collections.singletonList(
  5.                 new ParameterBuilder()
  6.                     .name("Authorization")
  7.                     .description("认证令牌")
  8.                     .modelRef(new ModelRef("string"))
  9.                     .parameterType("header")
  10.                     .required(true)
  11.                     .example("Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
  12.                     .build()
  13.             ))
  14.             // ... 其他配置
  15.             .build();
  16. }
复制代码

使用@Operation和@RequestBody(OpenAPI 3.0)

如果您使用的是OpenAPI 3.0,可以使用@Operation和@RequestBody注解:
  1. @Operation(
  2.     summary = "创建用户",
  3.     description = "创建一个新用户",
  4.     requestBody = @RequestBody(
  5.         description = "用户对象",
  6.         required = true,
  7.         content = @Content(
  8.             mediaType = "application/json",
  9.             schema = @Schema(implementation = UserDto.class),
  10.             examples = {
  11.                 @ExampleObject(
  12.                     name = "示例1",
  13.                     description = "一个普通的用户示例",
  14.                     value = "{"username": "john_doe", "email": "john@example.com", "age": 30}"
  15.                 ),
  16.                 @ExampleObject(
  17.                     name = "示例2",
  18.                     description = "一个包含所有字段的用户示例",
  19.                     value = "{"username": "jane_doe", "email": "jane@example.com", "age": 25, "phone": "1234567890"}"
  20.                 )
  21.             }
  22.         )
  23.     )
  24. )
  25. @PostMapping
  26. public ResponseEntity<User> createUser(@Valid @RequestBody UserDto userDto) {
  27.     // ...
  28. }
复制代码

动态生成请求示例

有时您可能需要根据不同的条件动态生成请求示例。这时,您可以创建一个自定义的示例提供器:
  1. public class UserExampleProvider {
  2.    
  3.     public static User getExampleUser() {
  4.         User user = new User();
  5.         user.setId(1L);
  6.         user.setUsername("john_doe");
  7.         user.setEmail("john@example.com");
  8.         user.setAge(30);
  9.         user.setCreatedAt(new Date());
  10.         return user;
  11.     }
  12.    
  13.     public static List<User> getExampleUserList() {
  14.         List<User> users = new ArrayList<>();
  15.         users.add(getExampleUser());
  16.         
  17.         User user2 = new User();
  18.         user2.setId(2L);
  19.         user2.setUsername("jane_doe");
  20.         user2.setEmail("jane@example.com");
  21.         user2.setAge(25);
  22.         user2.setCreatedAt(new Date());
  23.         users.add(user2);
  24.         
  25.         return users;
  26.     }
  27. }
复制代码

然后在控制器中使用这些示例:
  1. @ApiOperation(
  2.     value = "获取用户列表",
  3.     notes = "获取系统中所有用户的列表",
  4.     response = User.class,
  5.     responseContainer = "List"
  6. )
  7. @GetMapping
  8. public ResponseEntity<List<User>> getAllUsers() {
  9.     // 实际实现...
  10.     // 这里只是一个示例,展示如何使用示例提供器
  11.     return ResponseEntity.ok(UserExampleProvider.getExampleUserList());
  12. }
复制代码

高级功能

API分组

在大型项目中,您可能需要将API文档分组,以便更好地组织和管理。Swagger提供了分组功能,允许您根据不同的标准(如模块、版本等)对API进行分组。
  1. @Configuration
  2. @EnableSwagger2
  3. public class SwaggerConfig {
  4.    
  5.     @Bean
  6.     public Docket publicApi() {
  7.         return new Docket(DocumentationType.SWAGGER_2)
  8.                 .groupName("public-api")
  9.                 .select()
  10.                 .apis(RequestHandlerSelectors.basePackage("com.example.controller.public"))
  11.                 .paths(PathSelectors.any())
  12.                 .build()
  13.                 .apiInfo(publicApiInfo());
  14.     }
  15.    
  16.     @Bean
  17.     public Docket adminApi() {
  18.         return new Docket(DocumentationType.SWAGGER_2)
  19.                 .groupName("admin-api")
  20.                 .select()
  21.                 .apis(RequestHandlerSelectors.basePackage("com.example.controller.admin"))
  22.                 .paths(PathSelectors.any())
  23.                 .build()
  24.                 .apiInfo(adminApiInfo())
  25.                 .securitySchemes(Collections.singletonList(apiKey()))
  26.                 .securityContexts(Collections.singletonList(securityContext()));
  27.     }
  28.    
  29.     private ApiInfo publicApiInfo() {
  30.         return new ApiInfoBuilder()
  31.                 .title("公共API文档")
  32.                 .description "系统公共接口文档")
  33.                 .version("1.0.0")
  34.                 .build();
  35.     }
  36.    
  37.     private ApiInfo adminApiInfo() {
  38.         return new ApiInfoBuilder()
  39.                 .title("管理API文档")
  40.                 .description("系统管理接口文档")
  41.                 .version("1.0.0")
  42.                 .build();
  43.     }
  44.    
  45.     // 其他方法...
  46. }
复制代码

自定义Swagger UI

您可以通过自定义配置来改变Swagger UI的外观和行为。创建一个WebMvcConfigurer来添加自定义资源:
  1. @Configuration
  2. public class WebMvcConfig implements WebMvcConfigurer {
  3.    
  4.     @Override
  5.     public void addResourceHandlers(ResourceHandlerRegistry registry) {
  6.         registry.addResourceHandler("swagger-ui.html")
  7.                 .addResourceLocations("classpath:/META-INF/resources/");
  8.         
  9.         registry.addResourceHandler("/webjars/**")
  10.                 .addResourceLocations("classpath:/META-INF/resources/webjars/");
  11.     }
  12. }
复制代码

然后,您可以创建一个自定义的Swagger UI页面:
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>自定义Swagger UI</title>
  6.     <link rel="stylesheet" type="text/css" href="./webjars/swagger-ui/dist/swagger-ui.css" />
  7.     <link rel="stylesheet" type="text/css" href="./css/custom-swagger.css" />
  8.     <style>
  9.         html {
  10.             box-sizing: border-box;
  11.             overflow: -moz-scrollbars-vertical;
  12.             overflow-y: scroll;
  13.         }
  14.         *, *:before, *:after {
  15.             box-sizing: inherit;
  16.         }
  17.         body {
  18.             margin: 0;
  19.             background: #fafafa;
  20.         }
  21.     </style>
  22. </head>
  23. <body>
  24.     <div id="swagger-ui"></div>
  25.     <script src="./webjars/swagger-ui/dist/swagger-ui-bundle.js"></script>
  26.     <script src="./webjars/swagger-ui/dist/swagger-ui-standalone-preset.js"></script>
  27.     <script>
  28.         window.onload = function() {
  29.             const ui = SwaggerUIBundle({
  30.                 url: "/v2/api-docs",
  31.                 dom_id: '#swagger-ui',
  32.                 deepLinking: true,
  33.                 presets: [
  34.                     SwaggerUIBundle.presets.apis,
  35.                     SwaggerUIStandalonePreset
  36.                 ],
  37.                 plugins: [
  38.                     SwaggerUIBundle.plugins.DownloadUrl
  39.                 ],
  40.                 layout: "StandaloneLayout",
  41.                 validatorUrl: null,
  42.                 supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
  43.                 docExpansion: "none",
  44.                 defaultModelsExpandDepth: -1,
  45.                 displayRequestDuration: true,
  46.                 filter: true,
  47.                 persistAuthorization: true
  48.             });
  49.         };
  50.     </script>
  51. </body>
  52. </html>
复制代码

集成Spring Security

如果您的应用使用了Spring Security,您需要配置Swagger UI可以访问的端点:
  1. @Configuration
  2. @EnableWebSecurity
  3. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  4.    
  5.     @Override
  6.     protected void configure(HttpSecurity http) throws Exception {
  7.         http
  8.             .authorizeRequests()
  9.                 .antMatchers("/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**").permitAll()
  10.                 .anyRequest().authenticated()
  11.             .and()
  12.             .csrf().disable();
  13.     }
  14. }
复制代码

多环境配置

您可能希望在不同的环境中使用不同的Swagger配置。可以通过Spring Profile实现:
  1. @Configuration
  2. @Profile({"dev", "test"})
  3. @EnableSwagger2
  4. public class SwaggerConfig {
  5.    
  6.     @Bean
  7.     public Docket api() {
  8.         return new Docket(DocumentationType.SWAGGER_2)
  9.                 .select()
  10.                 .apis(RequestHandlerSelectors.any())
  11.                 .paths(PathSelectors.any())
  12.                 .build();
  13.     }
  14. }
复制代码

然后在application.properties中指定活动Profile:
  1. spring.profiles.active=dev
复制代码

API版本控制

随着API的演进,您可能需要支持多个版本的API。Swagger可以帮助您实现这一点:
  1. @Configuration
  2. @EnableSwagger2
  3. public class SwaggerConfig {
  4.    
  5.     @Bean
  6.     public Docket apiV1() {
  7.         return new Docket(DocumentationType.SWAGGER_2)
  8.                 .groupName("v1")
  9.                 .select()
  10.                 .apis(RequestHandlerSelectors.withMethodAnnotation(ApiV1.class))
  11.                 .build()
  12.                 .apiInfo(apiV1Info());
  13.     }
  14.    
  15.     @Bean
  16.     public Docket apiV2() {
  17.         return new Docket(DocumentationType.SWAGGER_2)
  18.                 .groupName("v2")
  19.                 .select()
  20.                 .apis(RequestHandlerSelectors.withMethodAnnotation(ApiV2.class))
  21.                 .build()
  22.                 .apiInfo(apiV2Info());
  23.     }
  24.    
  25.     private ApiInfo apiV1Info() {
  26.         return new ApiInfoBuilder()
  27.                 .title("API V1文档")
  28.                 .version("1.0.0")
  29.                 .build();
  30.     }
  31.    
  32.     private ApiInfo apiV2Info() {
  33.         return new ApiInfoBuilder()
  34.                 .title("API V2文档")
  35.                 .version("2.0.0")
  36.                 .build();
  37.     }
  38. }
复制代码

然后创建自定义注解来标记不同版本的API:
  1. @Target({ElementType.METHOD, ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface ApiV1 {
  4. }
  5. @Target({ElementType.METHOD, ElementType.TYPE})
  6. @Retention(RetentionPolicy.RUNTIME)
  7. public @interface ApiV2 {
  8. }
复制代码

在控制器中使用这些注解:
  1. @ApiV1
  2. @GetMapping("/v1/users")
  3. public ResponseEntity<List<User>> getUsersV1() {
  4.     // V1实现
  5. }
  6. @ApiV2
  7. @GetMapping("/v2/users")
  8. public ResponseEntity<List<UserDto>> getUsersV2() {
  9.     // V2实现
  10. }
复制代码

最佳实践

1. 保持文档与代码同步

Swagger最大的优势之一是能够保持文档与代码同步。为了充分利用这一点:

• 使用注解来描述API,而不是单独维护文档文件。
• 在API变更时,同时更新相关的Swagger注解。
• 将API文档检查纳入CI/CD流程,确保文档始终是最新的。

2. 提供清晰且有意义的描述

为API、参数和模型提供清晰且有意义的描述:
  1. @ApiOperation(
  2.     value = "创建新用户",
  3.     notes = "创建一个新用户账户。用户名必须是唯一的,电子邮件地址必须是有效的格式。密码必须至少包含8个字符,包括至少一个大写字母、一个小写字母和一个数字。"
  4. )
  5. @PostMapping
  6. public ResponseEntity<User> createUser(@Valid @RequestBody UserDto userDto) {
  7.     // ...
  8. }
复制代码

3. 使用适当的HTTP状态码

使用标准HTTP状态码来表示操作结果:
  1. @ApiResponses(value = {
  2.     @ApiResponse(code = 201, message = "用户创建成功", response = User.class),
  3.     @ApiResponse(code = 400, message = "无效的输入数据"),
  4.     @ApiResponse(code = 409, message = "用户名或电子邮件已存在"),
  5.     @ApiResponse(code = 500, message = "服务器错误")
  6. })
  7. @PostMapping
  8. public ResponseEntity<User> createUser(@Valid @RequestBody UserDto userDto) {
  9.     // ...
  10. }
复制代码

4. 提供真实且有意义的示例

提供真实且有意义的请求和响应示例,而不是无意义的占位符:
  1. public class UserDto {
  2.     @ApiModelProperty(
  3.         value = "用户名",
  4.         example = "john_doe",
  5.         required = true,
  6.         notes = "用户名必须是唯一的,只能包含字母、数字和下划线,长度在3到20个字符之间。"
  7.     )
  8.     private String username;
  9.    
  10.     @ApiModelProperty(
  11.         value = "电子邮箱",
  12.         example = "john@example.com",
  13.         required = true,
  14.         notes = "必须是有效的电子邮件地址格式。"
  15.     )
  16.     private String email;
  17.    
  18.     // ...
  19. }
复制代码

5. 使用DTO而不是实体类

在API中使用DTO(数据传输对象)而不是直接使用实体类,这样可以:

• 隐藏不想暴露的字段(如密码哈希)。
• 提供更适合API需求的字段结构。
• 避免因实体类变更而影响API兼容性。
  1. @ApiModel(description = "用户数据传输对象")
  2. public class UserDto {
  3.     @ApiModelProperty(value = "用户ID", example = "1", readOnly = true)
  4.     private Long id;
  5.    
  6.     @ApiModelProperty(value = "用户名", example = "john_doe", required = true)
  7.     private String username;
  8.    
  9.     @ApiModelProperty(value = "电子邮箱", example = "john@example.com", required = true)
  10.     private String email;
  11.    
  12.     // 不包含密码等敏感字段
  13.    
  14.     // getters and setters
  15. }
复制代码

6. 合理使用分组和标签

对于大型项目,使用分组和标签来组织API文档:
  1. @Api(tags = {"用户管理", "核心功能"})
  2. @RestController
  3. @RequestMapping("/api/users")
  4. public class UserController {
  5.     // ...
  6. }
复制代码

7. 添加认证信息

如果API需要认证,确保在文档中明确说明:
  1. @Bean
  2. public Docket api() {
  3.     return new Docket(DocumentationType.SWAGGER_2)
  4.             .securitySchemes(Collections.singletonList(apiKey()))
  5.             .securityContexts(Collections.singletonList(securityContext()))
  6.             // ... 其他配置
  7.             .build();
  8. }
  9. private ApiKey apiKey() {
  10.     return new ApiKey("JWT", "Authorization", "header");
  11. }
  12. private SecurityContext securityContext() {
  13.     return SecurityContext.builder()
  14.             .securityReferences(defaultAuth())
  15.             .forPaths(PathSelectors.regex("/api/.*"))
  16.             .build();
  17. }
  18. private List<SecurityReference> defaultAuth() {
  19.     AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
  20.     return Collections.singletonList(new SecurityReference("JWT", new AuthorizationScope[]{authorizationScope}));
  21. }
复制代码

8. 在生产环境中禁用Swagger

出于安全考虑,应该在生产环境中禁用Swagger:
  1. @Configuration
  2. @Profile({"dev", "test"})
  3. @EnableSwagger2
  4. public class SwaggerConfig {
  5.     // ...
  6. }
复制代码

或者使用条件配置:
  1. @Bean
  2. @ConditionalOnProperty(name = "swagger.enabled", havingValue = "true")
  3. public Docket api() {
  4.     return new Docket(DocumentationType.SWAGGER_2)
  5.             // ...
  6.             .build();
  7. }
复制代码

然后在application.properties中:
  1. # 开发和测试环境
  2. swagger.enabled=true
  3. # 生产环境
  4. # swagger.enabled=false
复制代码

9. 使用外部化配置

对于复杂的Swagger配置,考虑使用外部化配置:
  1. @Configuration
  2. @EnableSwagger2
  3. @ConfigurationProperties(prefix = "swagger")
  4. public class SwaggerConfig {
  5.     private String title;
  6.     private String description;
  7.     private String version;
  8.     private Contact contact;
  9.    
  10.     @Bean
  11.     public Docket api() {
  12.         return new Docket(DocumentationType.SWAGGER_2)
  13.                 .apiInfo(new ApiInfoBuilder()
  14.                         .title(title)
  15.                         .description(description)
  16.                         .version(version)
  17.                         .contact(contact)
  18.                         .build())
  19.                 // ... 其他配置
  20.                 .build();
  21.     }
  22.    
  23.     // getters and setters
  24. }
复制代码

然后在application.yml中:
  1. swagger:
  2.   title: "我的API文档"
  3.   description: "这是一个示例API的文档"
  4.   version: "1.0.0"
  5.   contact:
  6.     name: "开发者姓名"
  7.     email: "developer@example.com"
  8.     url: "https://example.com"
复制代码

10. 定期审查和更新文档

定期审查和更新API文档,确保其准确性和完整性:

• 将文档审查纳入开发流程。
• 在API变更时,评估是否需要更新文档。
• 收集用户反馈,持续改进文档质量。

实战案例

让我们通过一个完整的示例来展示如何使用Swagger创建专业、易读的API文档。我们将创建一个简单的博客系统API,包括用户管理、文章管理和评论管理功能。

项目结构
  1. src/main/java/com/example/blog/
  2. ├── config/
  3. │   └── SwaggerConfig.java
  4. ├── controller/
  5. │   ├── AuthController.java
  6. │   ├── PostController.java
  7. │   ├── CommentController.java
  8. │   └── UserController.java
  9. ├── dto/
  10. │   ├── request/
  11. │   │   ├── CreateUserRequest.java
  12. │   │   ├── CreatePostRequest.java
  13. │   │   ├── CreateCommentRequest.java
  14. │   │   └── LoginRequest.java
  15. │   └── response/
  16. │       ├── UserResponse.java
  17. │       ├── PostResponse.java
  18. │       └── CommentResponse.java
  19. ├── model/
  20. │   ├── User.java
  21. │   ├── Post.java
  22. │   └── Comment.java
  23. ├── repository/
  24. │   ├── UserRepository.java
  25. │   ├── PostRepository.java
  26. │   └── CommentRepository.java
  27. ├── security/
  28. │   ├── JwtTokenProvider.java
  29. │   └── JwtAuthenticationFilter.java
  30. └── BlogApplication.java
复制代码

依赖配置

首先,在pom.xml中添加必要的依赖:
  1. <dependencies>
  2.     <!-- Spring Boot Starter Web -->
  3.     <dependency>
  4.         <groupId>org.springframework.boot</groupId>
  5.         <artifactId>spring-boot-starter-web</artifactId>
  6.     </dependency>
  7.    
  8.     <!-- Spring Boot Starter Data JPA -->
  9.     <dependency>
  10.         <groupId>org.springframework.boot</groupId>
  11.         <artifactId>spring-boot-starter-data-jpa</artifactId>
  12.     </dependency>
  13.    
  14.     <!-- Spring Boot Starter Security -->
  15.     <dependency>
  16.         <groupId>org.springframework.boot</groupId>
  17.         <artifactId>spring-boot-starter-security</artifactId>
  18.     </dependency>
  19.    
  20.     <!-- Spring Boot Starter Validation -->
  21.     <dependency>
  22.         <groupId>org.springframework.boot</groupId>
  23.         <artifactId>spring-boot-starter-validation</artifactId>
  24.     </dependency>
  25.    
  26.     <!-- H2 Database -->
  27.     <dependency>
  28.         <groupId>com.h2database</groupId>
  29.         <artifactId>h2</artifactId>
  30.         <scope>runtime</scope>
  31.     </dependency>
  32.    
  33.     <!-- JWT -->
  34.     <dependency>
  35.         <groupId>io.jsonwebtoken</groupId>
  36.         <artifactId>jjwt-api</artifactId>
  37.         <version>0.11.5</version>
  38.     </dependency>
  39.     <dependency>
  40.         <groupId>io.jsonwebtoken</groupId>
  41.         <artifactId>jjwt-impl</artifactId>
  42.         <version>0.11.5</version>
  43.         <scope>runtime</scope>
  44.     </dependency>
  45.     <dependency>
  46.         <groupId>io.jsonwebtoken</groupId>
  47.         <artifactId>jjwt-jackson</artifactId>
  48.         <version>0.11.5</version>
  49.         <scope>runtime</scope>
  50.     </dependency>
  51.    
  52.     <!-- Swagger -->
  53.     <dependency>
  54.         <groupId>io.springfox</groupId>
  55.         <artifactId>springfox-swagger2</artifactId>
  56.         <version>3.0.0</version>
  57.     </dependency>
  58.     <dependency>
  59.         <groupId>io.springfox</groupId>
  60.         <artifactId>springfox-swagger-ui</artifactId>
  61.         <version>3.0.0</version>
  62.     </dependency>
  63.    
  64.     <!-- Lombok -->
  65.     <dependency>
  66.         <groupId>org.projectlombok</groupId>
  67.         <artifactId>lombok</artifactId>
  68.         <optional>true</optional>
  69.     </dependency>
  70. </dependencies>
复制代码

Swagger配置

创建Swagger配置类:
  1. package com.example.blog.config;
  2. import com.example.blog.security.JwtTokenProvider;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import springfox.documentation.builders.ApiInfoBuilder;
  6. import springfox.documentation.builders.PathSelectors;
  7. import springfox.documentation.builders.RequestHandlerSelectors;
  8. import springfox.documentation.service.*;
  9. import springfox.documentation.spi.DocumentationType;
  10. import springfox.documentation.spi.service.contexts.SecurityContext;
  11. import springfox.documentation.spring.web.plugins.Docket;
  12. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  13. import java.util.Arrays;
  14. import java.util.Collections;
  15. import java.util.List;
  16. @Configuration
  17. @EnableSwagger2
  18. public class SwaggerConfig {
  19.     @Bean
  20.     public Docket api() {
  21.         return new Docket(DocumentationType.SWAGGER_2)
  22.                 .select()
  23.                 .apis(RequestHandlerSelectors.basePackage("com.example.blog.controller"))
  24.                 .paths(PathSelectors.any())
  25.                 .build()
  26.                 .apiInfo(apiInfo())
  27.                 .securityContexts(Collections.singletonList(securityContext()))
  28.                 .securitySchemes(Collections.singletonList(apiKey()))
  29.                 .produces(Collections.singleton("application/json"))
  30.                 .consumes(Collections.singleton("application/json"));
  31.     }
  32.     private ApiInfo apiInfo() {
  33.         return new ApiInfoBuilder()
  34.                 .title("博客系统API文档")
  35.                 .description("这是一个博客系统的RESTful API文档,提供了用户管理、文章管理和评论管理等功能。")
  36.                 .version("1.0.0")
  37.                 .contact(new Contact("博客开发团队", "https://blog.example.com", "dev@blog.example.com"))
  38.                 .license("MIT License")
  39.                 .licenseUrl("https://opensource.org/licenses/MIT")
  40.                 .build();
  41.     }
  42.     private ApiKey apiKey() {
  43.         return new ApiKey("JWT", "Authorization", "header");
  44.     }
  45.     private SecurityContext securityContext() {
  46.         return SecurityContext.builder()
  47.                 .securityReferences(defaultAuth())
  48.                 .forPaths(PathSelectors.regex("/api/.*"))
  49.                 .build();
  50.     }
  51.     private List<SecurityReference> defaultAuth() {
  52.         AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
  53.         return Collections.singletonList(new SecurityReference("JWT", new AuthorizationScope[]{authorizationScope}));
  54.     }
  55. }
复制代码

模型类

定义用户模型:
  1. package com.example.blog.model;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import javax.persistence.*;
  6. import javax.validation.constraints.Email;
  7. import javax.validation.constraints.NotBlank;
  8. import javax.validation.constraints.Size;
  9. import java.time.LocalDateTime;
  10. import java.util.HashSet;
  11. import java.util.Set;
  12. @Entity
  13. @Table(name = "users")
  14. @Data
  15. @NoArgsConstructor
  16. @AllArgsConstructor
  17. public class User {
  18.     @Id
  19.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  20.     private Long id;
  21.     @NotBlank
  22.     @Size(min = 3, max = 20)
  23.     @Column(unique = true)
  24.     private String username;
  25.     @NotBlank
  26.     @Size(max = 50)
  27.     @Email
  28.     @Column(unique = true)
  29.     private String email;
  30.     @NotBlank
  31.     @Size(min = 6, max = 100)
  32.     private String password;
  33.     @Column(name = "created_at")
  34.     private LocalDateTime createdAt;
  35.     @Column(name = "updated_at")
  36.     private LocalDateTime updatedAt;
  37.     @ElementCollection(fetch = FetchType.EAGER)
  38.     @Enumerated(EnumType.STRING)
  39.     private Set<Role> roles = new HashSet<>();
  40.     public User(String username, String email, String password) {
  41.         this.username = username;
  42.         this.email = email;
  43.         this.password = password;
  44.         this.createdAt = LocalDateTime.now();
  45.         this.updatedAt = LocalDateTime.now();
  46.         this.roles.add(Role.ROLE_USER);
  47.     }
  48.     public enum Role {
  49.         ROLE_USER,
  50.         ROLE_ADMIN
  51.     }
  52. }
复制代码

定义文章模型:
  1. package com.example.blog.model;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import javax.persistence.*;
  6. import javax.validation.constraints.NotBlank;
  7. import javax.validation.constraints.Size;
  8. import java.time.LocalDateTime;
  9. import java.util.HashSet;
  10. import java.util.Set;
  11. @Entity
  12. @Table(name = "posts")
  13. @Data
  14. @NoArgsConstructor
  15. @AllArgsConstructor
  16. public class Post {
  17.     @Id
  18.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  19.     private Long id;
  20.     @NotBlank
  21.     @Size(min = 1, max = 100)
  22.     private String title;
  23.     @NotBlank
  24.     @Size(min = 1, max = 5000)
  25.     private String content;
  26.     @Column(name = "created_at")
  27.     private LocalDateTime createdAt;
  28.     @Column(name = "updated_at")
  29.     private LocalDateTime updatedAt;
  30.     @ManyToOne(fetch = FetchType.LAZY)
  31.     @JoinColumn(name = "author_id")
  32.     private User author;
  33.     @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
  34.     private Set<Comment> comments = new HashSet<>();
  35.     public Post(String title, String content, User author) {
  36.         this.title = title;
  37.         this.content = content;
  38.         this.author = author;
  39.         this.createdAt = LocalDateTime.now();
  40.         this.updatedAt = LocalDateTime.now();
  41.     }
  42. }
复制代码

定义评论模型:
  1. package com.example.blog.model;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import javax.persistence.*;
  6. import javax.validation.constraints.NotBlank;
  7. import javax.validation.constraints.Size;
  8. import java.time.LocalDateTime;
  9. @Entity
  10. @Table(name = "comments")
  11. @Data
  12. @NoArgsConstructor
  13. @AllArgsConstructor
  14. public class Comment {
  15.     @Id
  16.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  17.     private Long id;
  18.     @NotBlank
  19.     @Size(min = 1, max = 1000)
  20.     private String text;
  21.     @Column(name = "created_at")
  22.     private LocalDateTime createdAt;
  23.     @Column(name = "updated_at")
  24.     private LocalDateTime updatedAt;
  25.     @ManyToOne(fetch = FetchType.LAZY)
  26.     @JoinColumn(name = "post_id")
  27.     private Post post;
  28.     @ManyToOne(fetch = FetchType.LAZY)
  29.     @JoinColumn(name = "author_id")
  30.     private User author;
  31.     public Comment(String text, Post post, User author) {
  32.         this.text = text;
  33.         this.post = post;
  34.         this.author = author;
  35.         this.createdAt = LocalDateTime.now();
  36.         this.updatedAt = LocalDateTime.now();
  37.     }
  38. }
复制代码

DTO类

定义用户相关的DTO:
  1. package com.example.blog.dto.request;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import javax.validation.constraints.Email;
  6. import javax.validation.constraints.NotBlank;
  7. import javax.validation.constraints.Size;
  8. @ApiModel(description = "创建用户请求")
  9. @Data
  10. public class CreateUserRequest {
  11.     @ApiModelProperty(value = "用户名", example = "john_doe", required = true, notes = "用户名必须是唯一的,只能包含字母、数字和下划线,长度在3到20个字符之间。")
  12.     @NotBlank
  13.     @Size(min = 3, max = 20)
  14.     private String username;
  15.     @ApiModelProperty(value = "电子邮箱", example = "john@example.com", required = true, notes = "必须是有效的电子邮件地址格式。")
  16.     @NotBlank
  17.     @Size(max = 50)
  18.     @Email
  19.     private String email;
  20.     @ApiModelProperty(value = "密码", example = "password123", required = true, notes = "密码必须至少包含6个字符。")
  21.     @NotBlank
  22.     @Size(min = 6, max = 100)
  23.     private String password;
  24. }
复制代码
  1. package com.example.blog.dto.response;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import java.time.LocalDateTime;
  6. import java.util.Set;
  7. @ApiModel(description = "用户响应")
  8. @Data
  9. public class UserResponse {
  10.     @ApiModelProperty(value = "用户ID", example = "1", readOnly = true)
  11.     private Long id;
  12.     @ApiModelProperty(value = "用户名", example = "john_doe")
  13.     private String username;
  14.     @ApiModelProperty(value = "电子邮箱", example = "john@example.com")
  15.     private String email;
  16.     @ApiModelProperty(value = "创建时间", example = "2023-01-01T00:00:00", readOnly = true)
  17.     private LocalDateTime createdAt;
  18.     @ApiModelProperty(value = "更新时间", example = "2023-01-01T00:00:00", readOnly = true)
  19.     private LocalDateTime updatedAt;
  20.     @ApiModelProperty(value = "用户角色", example = "["ROLE_USER"]")
  21.     private Set<String> roles;
  22. }
复制代码

定义文章相关的DTO:
  1. package com.example.blog.dto.request;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import javax.validation.constraints.NotBlank;
  6. import javax.validation.constraints.Size;
  7. @ApiModel(description = "创建文章请求")
  8. @Data
  9. public class CreatePostRequest {
  10.     @ApiModelProperty(value = "文章标题", example = "如何使用Swagger创建API文档", required = true, notes = "标题长度在1到100个字符之间。")
  11.     @NotBlank
  12.     @Size(min = 1, max = 100)
  13.     private String title;
  14.     @ApiModelProperty(value = "文章内容", example = "Swagger是一个强大的API文档工具...", required = true, notes = "内容长度在1到5000个字符之间。")
  15.     @NotBlank
  16.     @Size(min = 1, max = 5000)
  17.     private String content;
  18. }
复制代码
  1. package com.example.blog.dto.response;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import java.time.LocalDateTime;
  6. @ApiModel(description = "文章响应")
  7. @Data
  8. public class PostResponse {
  9.     @ApiModelProperty(value = "文章ID", example = "1", readOnly = true)
  10.     private Long id;
  11.     @ApiModelProperty(value = "文章标题", example = "如何使用Swagger创建API文档")
  12.     private String title;
  13.     @ApiModelProperty(value = "文章内容", example = "Swagger是一个强大的API文档工具...")
  14.     private String content;
  15.     @ApiModelProperty(value = "创建时间", example = "2023-01-01T00:00:00", readOnly = true)
  16.     private LocalDateTime createdAt;
  17.     @ApiModelProperty(value = "更新时间", example = "2023-01-01T00:00:00", readOnly = true)
  18.     private LocalDateTime updatedAt;
  19.     @ApiModelProperty(value = "作者信息", readOnly = true)
  20.     private UserResponse author;
  21. }
复制代码

定义评论相关的DTO:
  1. package com.example.blog.dto.request;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import javax.validation.constraints.NotBlank;
  6. import javax.validation.constraints.Size;
  7. @ApiModel(description = "创建评论请求")
  8. @Data
  9. public class CreateCommentRequest {
  10.     @ApiModelProperty(value = "评论内容", example = "这篇文章写得很好!", required = true, notes = "评论内容长度在1到1000个字符之间。")
  11.     @NotBlank
  12.     @Size(min = 1, max = 1000)
  13.     private String text;
  14. }
复制代码
  1. package com.example.blog.dto.response;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import java.time.LocalDateTime;
  6. @ApiModel(description = "评论响应")
  7. @Data
  8. public class CommentResponse {
  9.     @ApiModelProperty(value = "评论ID", example = "1", readOnly = true)
  10.     private Long id;
  11.     @ApiModelProperty(value = "评论内容", example = "这篇文章写得很好!")
  12.     private String text;
  13.     @ApiModelProperty(value = "创建时间", example = "2023-01-01T00:00:00", readOnly = true)
  14.     private LocalDateTime createdAt;
  15.     @ApiModelProperty(value = "更新时间", example = "2023-01-01T00:00:00", readOnly = true)
  16.     private LocalDateTime updatedAt;
  17.     @ApiModelProperty(value = "作者信息", readOnly = true)
  18.     private UserResponse author;
  19. }
复制代码

定义登录请求DTO:
  1. package com.example.blog.dto.request;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import javax.validation.constraints.NotBlank;
  6. @ApiModel(description = "登录请求")
  7. @Data
  8. public class LoginRequest {
  9.     @ApiModelProperty(value = "用户名或邮箱", example = "john_doe", required = true)
  10.     @NotBlank
  11.     private String usernameOrEmail;
  12.     @ApiModelProperty(value = "密码", example = "password123", required = true)
  13.     @NotBlank
  14.     private String password;
  15. }
复制代码

控制器类

定义认证控制器:
  1. package com.example.blog.controller;
  2. import com.example.blog.dto.request.LoginRequest;
  3. import com.example.blog.security.JwtAuthenticationResponse;
  4. import com.example.blog.security.JwtTokenProvider;
  5. import io.swagger.annotations.Api;
  6. import io.swagger.annotations.ApiOperation;
  7. import io.swagger.annotations.ApiResponse;
  8. import io.swagger.annotations.ApiResponses;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.http.ResponseEntity;
  11. import org.springframework.security.authentication.AuthenticationManager;
  12. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  13. import org.springframework.security.core.Authentication;
  14. import org.springframework.security.core.context.SecurityContextHolder;
  15. import org.springframework.web.bind.annotation.PostMapping;
  16. import org.springframework.web.bind.annotation.RequestBody;
  17. import org.springframework.web.bind.annotation.RequestMapping;
  18. import org.springframework.web.bind.annotation.RestController;
  19. import javax.validation.Valid;
  20. @Api(tags = "认证管理")
  21. @RestController
  22. @RequestMapping("/api/auth")
  23. public class AuthController {
  24.     @Autowired
  25.     private AuthenticationManager authenticationManager;
  26.     @Autowired
  27.     private JwtTokenProvider tokenProvider;
  28.     @ApiOperation(value = "用户登录", notes = "使用用户名/邮箱和密码进行登录,成功后返回JWT令牌。")
  29.     @ApiResponses(value = {
  30.             @ApiResponse(code = 200, message = "登录成功", response = JwtAuthenticationResponse.class),
  31.             @ApiResponse(code = 400, message = "无效的输入数据"),
  32.             @ApiResponse(code = 401, message = "认证失败")
  33.     })
  34.     @PostMapping("/signin")
  35.     public ResponseEntity<JwtAuthenticationResponse> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
  36.         Authentication authentication = authenticationManager.authenticate(
  37.                 new UsernamePasswordAuthenticationToken(
  38.                         loginRequest.getUsernameOrEmail(),
  39.                         loginRequest.getPassword()
  40.                 )
  41.         );
  42.         SecurityContextHolder.getContext().setAuthentication(authentication);
  43.         String jwt = tokenProvider.generateToken(authentication);
  44.         return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
  45.     }
  46. }
复制代码

定义用户控制器:
  1. package com.example.blog.controller;
  2. import com.example.blog.dto.request.CreateUserRequest;
  3. import com.example.blog.dto.response.UserResponse;
  4. import com.example.blog.model.User;
  5. import com.example.blog.service.UserService;
  6. import io.swagger.annotations.Api;
  7. import io.swagger.annotations.ApiOperation;
  8. import io.swagger.annotations.ApiParam;
  9. import io.swagger.annotations.ApiResponse;
  10. import io.swagger.annotations.ApiResponses;
  11. import org.modelmapper.ModelMapper;
  12. import org.springframework.beans.factory.annotation.Autowired;
  13. import org.springframework.http.HttpStatus;
  14. import org.springframework.http.ResponseEntity;
  15. import org.springframework.security.access.prepost.PreAuthorize;
  16. import org.springframework.web.bind.annotation.*;
  17. import javax.validation.Valid;
  18. import java.util.List;
  19. import java.util.stream.Collectors;
  20. @Api(tags = "用户管理")
  21. @RestController
  22. @RequestMapping("/api/users")
  23. public class UserController {
  24.     @Autowired
  25.     private UserService userService;
  26.     @Autowired
  27.     private ModelMapper modelMapper;
  28.     @ApiOperation(value = "创建新用户", notes = "创建一个新的用户账户。")
  29.     @ApiResponses(value = {
  30.             @ApiResponse(code = 201, message = "用户创建成功", response = UserResponse.class),
  31.             @ApiResponse(code = 400, message = "无效的输入数据"),
  32.             @ApiResponse(code = 409, message = "用户名或邮箱已存在")
  33.     })
  34.     @PostMapping
  35.     public ResponseEntity<UserResponse> createUser(@Valid @RequestBody CreateUserRequest createUserRequest) {
  36.         User user = modelMapper.map(createUserRequest, User.class);
  37.         User createdUser = userService.createUser(user);
  38.         UserResponse userResponse = modelMapper.map(createdUser, UserResponse.class);
  39.         return new ResponseEntity<>(userResponse, HttpStatus.CREATED);
  40.     }
  41.     @ApiOperation(value = "获取所有用户", notes = "获取系统中所有用户的列表。需要管理员权限。")
  42.     @ApiResponses(value = {
  43.             @ApiResponse(code = 200, message = "成功获取用户列表", response = UserResponse.class, responseContainer = "List"),
  44.             @ApiResponse(code = 403, message = "没有权限访问")
  45.     })
  46.     @PreAuthorize("hasRole('ADMIN')")
  47.     @GetMapping
  48.     public ResponseEntity<List<UserResponse>> getAllUsers() {
  49.         List<User> users = userService.getAllUsers();
  50.         List<UserResponse> userResponses = users.stream()
  51.                 .map(user -> modelMapper.map(user, UserResponse.class))
  52.                 .collect(Collectors.toList());
  53.         return ResponseEntity.ok(userResponses);
  54.     }
  55.     @ApiOperation(value = "根据ID获取用户", notes = "根据用户ID获取用户信息。")
  56.     @ApiResponses(value = {
  57.             @ApiResponse(code = 200, message = "成功获取用户", response = UserResponse.class),
  58.             @ApiResponse(code = 404, message = "用户不存在")
  59.     })
  60.     @GetMapping("/{id}")
  61.     public ResponseEntity<UserResponse> getUserById(
  62.             @ApiParam(value = "用户ID", example = "1", required = true) @PathVariable Long id) {
  63.         User user = userService.getUserById(id);
  64.         UserResponse userResponse = modelMapper.map(user, UserResponse.class);
  65.         return ResponseEntity.ok(userResponse);
  66.     }
  67. }
复制代码

定义文章控制器:
  1. package com.example.blog.controller;
  2. import com.example.blog.dto.request.CreatePostRequest;
  3. import com.example.blog.dto.response.PostResponse;
  4. import com.example.blog.model.Post;
  5. import com.example.blog.model.User;
  6. import com.example.blog.service.PostService;
  7. import com.example.blog.service.UserService;
  8. import io.swagger.annotations.Api;
  9. import io.swagger.annotations.ApiOperation;
  10. import io.swagger.annotations.ApiParam;
  11. import io.swagger.annotations.ApiResponse;
  12. import io.swagger.annotations.ApiResponses;
  13. import org.modelmapper.ModelMapper;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.data.domain.Page;
  16. import org.springframework.data.domain.Pageable;
  17. import org.springframework.http.HttpStatus;
  18. import org.springframework.http.ResponseEntity;
  19. import org.springframework.security.core.Authentication;
  20. import org.springframework.web.bind.annotation.*;
  21. import javax.validation.Valid;
  22. import java.util.List;
  23. import java.util.stream.Collectors;
  24. @Api(tags = "文章管理")
  25. @RestController
  26. @RequestMapping("/api/posts")
  27. public class PostController {
  28.     @Autowired
  29.     private PostService postService;
  30.     @Autowired
  31.     private UserService userService;
  32.     @Autowired
  33.     private ModelMapper modelMapper;
  34.     @ApiOperation(value = "创建新文章", notes = "创建一篇新的文章。需要用户登录。")
  35.     @ApiResponses(value = {
  36.             @ApiResponse(code = 201, message = "文章创建成功", response = PostResponse.class),
  37.             @ApiResponse(code = 400, message = "无效的输入数据"),
  38.             @ApiResponse(code = 401, message = "未登录")
  39.     })
  40.     @PostMapping
  41.     public ResponseEntity<PostResponse> createPost(
  42.             @Valid @RequestBody CreatePostRequest createPostRequest,
  43.             Authentication authentication) {
  44.         User author = userService.getUserByUsername(authentication.getName());
  45.         Post post = modelMapper.map(createPostRequest, Post.class);
  46.         post.setAuthor(author);
  47.         Post createdPost = postService.createPost(post);
  48.         PostResponse postResponse = modelMapper.map(createdPost, PostResponse.class);
  49.         return new ResponseEntity<>(postResponse, HttpStatus.CREATED);
  50.     }
  51.     @ApiOperation(value = "获取所有文章", notes = "获取系统中所有文章的列表,支持分页。")
  52.     @ApiResponses(value = {
  53.             @ApiResponse(code = 200, message = "成功获取文章列表", response = PostResponse.class, responseContainer = "Page")
  54.     })
  55.     @GetMapping
  56.     public ResponseEntity<Page<PostResponse>> getAllPosts(Pageable pageable) {
  57.         Page<Post> posts = postService.getAllPosts(pageable);
  58.         Page<PostResponse> postResponses = posts.map(post -> modelMapper.map(post, PostResponse.class));
  59.         return ResponseEntity.ok(postResponses);
  60.     }
  61.     @ApiOperation(value = "根据ID获取文章", notes = "根据文章ID获取文章信息。")
  62.     @ApiResponses(value = {
  63.             @ApiResponse(code = 200, message = "成功获取文章", response = PostResponse.class),
  64.             @ApiResponse(code = 404, message = "文章不存在")
  65.     })
  66.     @GetMapping("/{id}")
  67.     public ResponseEntity<PostResponse> getPostById(
  68.             @ApiParam(value = "文章ID", example = "1", required = true) @PathVariable Long id) {
  69.         Post post = postService.getPostById(id);
  70.         PostResponse postResponse = modelMapper.map(post, PostResponse.class);
  71.         return ResponseEntity.ok(postResponse);
  72.     }
  73.     @ApiOperation(value = "更新文章", notes = "更新指定的文章。只有文章作者或管理员可以更新文章。")
  74.     @ApiResponses(value = {
  75.             @ApiResponse(code = 200, message = "文章更新成功", response = PostResponse.class),
  76.             @ApiResponse(code = 400, message = "无效的输入数据"),
  77.             @ApiResponse(code = 401, message = "未登录"),
  78.             @ApiResponse(code = 403, message = "没有权限更新此文章"),
  79.             @ApiResponse(code = 404, message = "文章不存在")
  80.     })
  81.     @PutMapping("/{id}")
  82.     public ResponseEntity<PostResponse> updatePost(
  83.             @ApiParam(value = "文章ID", example = "1", required = true) @PathVariable Long id,
  84.             @Valid @RequestBody CreatePostRequest createPostRequest,
  85.             Authentication authentication) {
  86.         User currentUser = userService.getUserByUsername(authentication.getName());
  87.         Post existingPost = postService.getPostById(id);
  88.         
  89.         // 检查用户是否有权限更新文章
  90.         if (!existingPost.getAuthor().getId().equals(currentUser.getId()) &&
  91.             !currentUser.getRoles().contains(User.Role.ROLE_ADMIN)) {
  92.             return new ResponseEntity<>(HttpStatus.FORBIDDEN);
  93.         }
  94.         
  95.         Post post = modelMapper.map(createPostRequest, Post.class);
  96.         post.setId(id);
  97.         post.setAuthor(existingPost.getAuthor());
  98.         post.setCreatedAt(existingPost.getCreatedAt());
  99.         Post updatedPost = postService.updatePost(post);
  100.         PostResponse postResponse = modelMapper.map(updatedPost, PostResponse.class);
  101.         return ResponseEntity.ok(postResponse);
  102.     }
  103.     @ApiOperation(value = "删除文章", notes = "删除指定的文章。只有文章作者或管理员可以删除文章。")
  104.     @ApiResponses(value = {
  105.             @ApiResponse(code = 204, message = "文章删除成功"),
  106.             @ApiResponse(code = 401, message = "未登录"),
  107.             @ApiResponse(code = 403, message = "没有权限删除此文章"),
  108.             @ApiResponse(code = 404, message = "文章不存在")
  109.     })
  110.     @DeleteMapping("/{id}")
  111.     public ResponseEntity<Void> deletePost(
  112.             @ApiParam(value = "文章ID", example = "1", required = true) @PathVariable Long id,
  113.             Authentication authentication) {
  114.         User currentUser = userService.getUserByUsername(authentication.getName());
  115.         Post post = postService.getPostById(id);
  116.         
  117.         // 检查用户是否有权限删除文章
  118.         if (!post.getAuthor().getId().equals(currentUser.getId()) &&
  119.             !currentUser.getRoles().contains(User.Role.ROLE_ADMIN)) {
  120.             return new ResponseEntity<>(HttpStatus.FORBIDDEN);
  121.         }
  122.         
  123.         postService.deletePost(id);
  124.         return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  125.     }
  126. }
复制代码

定义评论控制器:
  1. package com.example.blog.controller;
  2. import com.example.blog.dto.request.CreateCommentRequest;
  3. import com.example.blog.dto.response.CommentResponse;
  4. import com.example.blog.model.Comment;
  5. import com.example.blog.model.Post;
  6. import com.example.blog.model.User;
  7. import com.example.blog.service.CommentService;
  8. import com.example.blog.service.PostService;
  9. import com.example.blog.service.UserService;
  10. import io.swagger.annotations.Api;
  11. import io.swagger.annotations.ApiOperation;
  12. import io.swagger.annotations.ApiParam;
  13. import io.swagger.annotations.ApiResponse;
  14. import io.swagger.annotations.ApiResponses;
  15. import org.modelmapper.ModelMapper;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.http.HttpStatus;
  18. import org.springframework.http.ResponseEntity;
  19. import org.springframework.security.core.Authentication;
  20. import org.springframework.web.bind.annotation.*;
  21. import javax.validation.Valid;
  22. import java.util.List;
  23. import java.util.stream.Collectors;
  24. @Api(tags = "评论管理")
  25. @RestController
  26. @RequestMapping("/api/posts/{postId}/comments")
  27. public class CommentController {
  28.     @Autowired
  29.     private CommentService commentService;
  30.     @Autowired
  31.     private PostService postService;
  32.     @Autowired
  33.     private UserService userService;
  34.     @Autowired
  35.     private ModelMapper modelMapper;
  36.     @ApiOperation(value = "创建新评论", notes = "为指定文章创建一条新评论。需要用户登录。")
  37.     @ApiResponses(value = {
  38.             @ApiResponse(code = 201, message = "评论创建成功", response = CommentResponse.class),
  39.             @ApiResponse(code = 400, message = "无效的输入数据"),
  40.             @ApiResponse(code = 401, message = "未登录"),
  41.             @ApiResponse(code = 404, message = "文章不存在")
  42.     })
  43.     @PostMapping
  44.     public ResponseEntity<CommentResponse> createComment(
  45.             @ApiParam(value = "文章ID", example = "1", required = true) @PathVariable Long postId,
  46.             @Valid @RequestBody CreateCommentRequest createCommentRequest,
  47.             Authentication authentication) {
  48.         Post post = postService.getPostById(postId);
  49.         User author = userService.getUserByUsername(authentication.getName());
  50.         Comment comment = modelMapper.map(createCommentRequest, Comment.class);
  51.         comment.setPost(post);
  52.         comment.setAuthor(author);
  53.         Comment createdComment = commentService.createComment(comment);
  54.         CommentResponse commentResponse = modelMapper.map(createdComment, CommentResponse.class);
  55.         return new ResponseEntity<>(commentResponse, HttpStatus.CREATED);
  56.     }
  57.     @ApiOperation(value = "获取文章的所有评论", notes = "获取指定文章的所有评论列表。")
  58.     @ApiResponses(value = {
  59.             @ApiResponse(code = 200, message = "成功获取评论列表", response = CommentResponse.class, responseContainer = "List"),
  60.             @ApiResponse(code = 404, message = "文章不存在")
  61.     })
  62.     @GetMapping
  63.     public ResponseEntity<List<CommentResponse>> getCommentsByPostId(
  64.             @ApiParam(value = "文章ID", example = "1", required = true) @PathVariable Long postId) {
  65.         Post post = postService.getPostById(postId);
  66.         List<Comment> comments = commentService.getCommentsByPostId(postId);
  67.         List<CommentResponse> commentResponses = comments.stream()
  68.                 .map(comment -> modelMapper.map(comment, CommentResponse.class))
  69.                 .collect(Collectors.toList());
  70.         return ResponseEntity.ok(commentResponses);
  71.     }
  72.     @ApiOperation(value = "删除评论", notes = "删除指定的评论。只有评论作者、文章作者或管理员可以删除评论。")
  73.     @ApiResponses(value = {
  74.             @ApiResponse(code = 204, message = "评论删除成功"),
  75.             @ApiResponse(code = 401, message = "未登录"),
  76.             @ApiResponse(code = 403, message = "没有权限删除此评论"),
  77.             @ApiResponse(code = 404, message = "评论不存在")
  78.     })
  79.     @DeleteMapping("/{commentId}")
  80.     public ResponseEntity<Void> deleteComment(
  81.             @ApiParam(value = "文章ID", example = "1", required = true) @PathVariable Long postId,
  82.             @ApiParam(value = "评论ID", example = "1", required = true) @PathVariable Long commentId,
  83.             Authentication authentication) {
  84.         User currentUser = userService.getUserByUsername(authentication.getName());
  85.         Comment comment = commentService.getCommentById(commentId);
  86.         
  87.         // 检查用户是否有权限删除评论
  88.         if (!comment.getAuthor().getId().equals(currentUser.getId()) &&
  89.             !comment.getPost().getAuthor().getId().equals(currentUser.getId()) &&
  90.             !currentUser.getRoles().contains(User.Role.ROLE_ADMIN)) {
  91.             return new ResponseEntity<>(HttpStatus.FORBIDDEN);
  92.         }
  93.         
  94.         commentService.deleteComment(commentId);
  95.         return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  96.     }
  97. }
复制代码

运行和测试

启动应用程序后,访问以下URL查看Swagger UI:
  1. http://localhost:8080/swagger-ui.html
复制代码

您将看到一个专业、易读的API文档,包括:

1. 认证管理
2. 用户管理
3. 文章管理
4. 评论管理

每个API都有详细的描述、参数说明、请求示例和响应示例。您可以直接在Swagger UI中测试API,只需点击”Try it out”按钮,填入参数,然后点击”Execute”。

效果展示

通过以上配置,我们实现了一个功能完整、文档完善的博客系统API。Swagger UI将显示:

1. 清晰的API分组:按照功能模块将API分为认证管理、用户管理、文章管理和评论管理四个部分。
2. 详细的API描述:每个API都有清晰的功能描述和使用说明。
3. 完整的参数说明:包括参数类型、是否必需、示例值等。
4. 丰富的请求示例:为每个API提供了符合规范的请求示例。
5. 详细的响应说明:包括不同HTTP状态码的含义和对应的响应结构。
6. 认证集成:支持JWT认证,可以在Swagger UI中直接输入令牌进行测试。

这样的API文档不仅对前端开发者友好,也便于后端开发者进行测试和维护,大大提高了开发效率。

总结

本文详细介绍了如何使用Swagger配置请求示例,打造专业、易读的API文档,从而提升开发效率。我们从Swagger的基础概念入手,逐步深入到环境搭建、基础配置、注解详解、请求示例配置、高级功能、最佳实践和实战案例,全面覆盖了Swagger的使用技巧。

通过本文的学习,您应该能够:

1. 在项目中集成Swagger并配置基本参数。
2. 使用Swagger注解丰富API文档的内容。
3. 添加请求和响应示例,提高API文档的实用性。
4. 利用Swagger的高级功能,如API分组、自定义UI等。
5. 遵循最佳实践,创建高质量的API文档。
6. 通过实战案例,掌握Swagger在实际项目中的应用。

Swagger作为一款强大的API文档工具,不仅能够自动生成文档,还能提供交互式的API测试功能,大大简化了API开发和测试的流程。通过合理使用Swagger,您可以创建专业、易读的API文档,提高团队协作效率,加速项目开发进程。

随着API经济的不断发展,API文档的重要性将日益凸显。掌握Swagger等API文档工具,将成为现代软件开发者的必备技能。希望本文能够帮助您更好地使用Swagger,打造出高质量的API文档,提升开发效率和用户体验。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则