93.md 15.2 KB
Newer Older
W
wizardforcel 已提交
1 2 3 4 5 6
# Swagger – Spring REST 示例

> 原文: [https://howtodoinjava.com/swagger2/swagger-spring-mvc-rest-example/](https://howtodoinjava.com/swagger2/swagger-spring-mvc-rest-example/)

如今, [REST](http://restfulapi.net)[微服务](//howtodoinjava.com/microservices/microservices-definition-principles-benefits/)势头强劲。 同时,实际的 REST 规范并未建议任何标准方法来记录我们将要公开的 REST API(例如 WSDL for SOAP)。 结果,每个人都以自己的方式记录自己的 API,从而导致通用结构中的空白,所有这些都可以轻松地遵循,理解和使用。 我们需要一个通用的模式和工具。

W
wizardforcel 已提交
7
[Swagger](https://swagger.io/)(得到了 Google,IBM,Microsoft 等公司的支持)完成了相同工作,以填补常见文档样式的空白。 在本教程中,我们将学习**使用 Swagger 来使用 **swagger2 注释**来生成 REST API 文档**
W
wizardforcel 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21

```java
Table of Contents

What is Swagger
Project Structure and Technology Stack
Create REST APIs
Swagger2 Configuration
Swagger2 Annotations
Demo
```

## 昂首阔步

W
wizardforcel 已提交
22
Swagger(现为“Open API Initiative”)是一种规范和框架,用于使用所有人都可以理解的通用语言来描述 REST API。 还有其他一些流行的框架,例如 RAML,Summation 等。但是,考虑到它的功能和在开发者社区中的接受程度,Swagger 在这一点上最受欢迎。
W
wizardforcel 已提交
23 24 25 26 27 28 29 30 31

它提供了人类可读和机器可读的文档格式。 它同时提供 JSON 和 UI 支持。 JSON 可以用作机器可读格式,`Swagger-UI`用于可视化显示,人类只需浏览 api 文档即可轻松理解。

## 项目结构与技术栈

项目的文件夹结构为:

![Swagger2 Project Structure](img/e5fb83172c356c894cde300dfc0d9933.png)

W
wizardforcel 已提交
32
Swagger2 项目结构
W
wizardforcel 已提交
33 34 35 36 37 38 39



在本演示中,我们将使用以下技术。

1.  Eclipse 作为 IDE
2.  [Maven](//howtodoinjava.com/maven/) 作为构建工具
W
wizardforcel 已提交
40
3.  Spring Boot 作为应用框架
W
wizardforcel 已提交
41 42 43 44 45 46 47 48
4.  Spring Rest 作为 REST API 框架
5.  Swagger2 作为 REST 文档框架
6.  [Java 1.8](//howtodoinjava.com/java-8-tutorial/)

## 创建 REST API

我们将首先创建一些 REST API,这些 API 将用于展示 Swagger 文档功能。 我们将使用 Spring 引导样式公开剩余的 API,以缩短开发时间。

W
wizardforcel 已提交
49
1.  从具有 Web,Rest Repositories,Actuator 依赖项的 [Spring Boot 初始化器](https://start.spring.io/)门户创建一个 Spring Boot 项目。 给出其他 Maven GAV 坐标并下载项目。 该屏幕如下所示:
W
wizardforcel 已提交
50 51 52

    [![](img/dc6046216d8449cef133f2c6e41291ec.png)](//howtodoinjava.com/wp-content/uploads/2017/07/Project_Generation.jpg)

W
wizardforcel 已提交
53
    Spring Boot REST 项目生成
W
wizardforcel 已提交
54 55 56

    

W
wizardforcel 已提交
57
    将项目解压缩并将其作为现有的 maven 项目导入 Eclipse。 在此步骤中,将从 maven 仓库下载所有必需的依赖项。 在此步骤中执行全新的`mvn clean install`,以便正确下载所有与 Spring Boot相关的工件。
W
wizardforcel 已提交
58

W
wizardforcel 已提交
59
2.  打开`application.properties`并添加以下属性。 这将在`/swagger2-demo`上下文路径中启动应用。
W
wizardforcel 已提交
60 61 62 63 64

    ```java
    server.contextPath=/swagger2-demo
    ```

W
wizardforcel 已提交
65
3.  添加一个 REST 控制器“`Swagger2DemoRestController`”,该控制器将在“`Student`”实体上提供基于 REST 的基本功能。
W
wizardforcel 已提交
66

W
wizardforcel 已提交
67
    **`Swagger2DemoRestController.java`**
W
wizardforcel 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117

    ```java
    package com.example.springbootswagger2.controller;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.stream.Collectors;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import com.example.springbootswagger2.model.Student;

    @RestController
    public class Swagger2DemoRestController {

    	List<Student> students = new ArrayList<Student>();
    	{
    		students.add(new Student("Sajal", "IV", "India"));
    		students.add(new Student("Lokesh", "V", "India"));
    		students.add(new Student("Kajal", "III", "USA"));
    		students.add(new Student("Sukesh", "VI", "USA"));
    	}

    	@RequestMapping(value = "/getStudents")
    	public List<Student> getStudents() {
    		return students;
    	}

    	@RequestMapping(value = "/getStudent/{name}")
    	public Student getStudent(@PathVariable(value = "name") String name) {
    		return students.stream().filter(x -> x.getName().equalsIgnoreCase(name)).collect(Collectors.toList()).get(0);
    	}

    	@RequestMapping(value = "/getStudentByCountry/{country}")
    	public List<Student> getStudentByCountry(@PathVariable(value = "country") String country) {
    		System.out.println("Searching Student in country : " + country);
    		List<Student> studentsByCountry = students.stream().filter(x -> x.getCountry().equalsIgnoreCase(country))
    				.collect(Collectors.toList());
    		System.out.println(studentsByCountry);
    		return studentsByCountry;
    	}

    	@RequestMapping(value = "/getStudentByClass/{cls}")
    	public List<Student> getStudentByClass(@PathVariable(value = "cls") String cls) {
    		return students.stream().filter(x -> x.getCls().equalsIgnoreCase(cls)).collect(Collectors.toList());
    	}
    }

    ```

W
wizardforcel 已提交
118
    **`Student.java`**
W
wizardforcel 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

    ```java

    package com.example.springbootswagger2.model;

    public class Student {

    	private String name;
    	private String cls;
    	private String country;

    	public Student(String name, String cls, String country) {
    		super();
    		this.name = name;
    		this.cls = cls;
    		this.country = country;
    	}

    	public String getName() {
    		return name;
    	}

    	public String getCls() {
    		return cls;
    	}

    	public String getCountry() {
    		return country;
    	}

    	@Override
    	public String toString() {
    		return "Student [name=" + name + ", cls=" + cls + ", country=" + country + "]";
    	}
    }

    ```

W
wizardforcel 已提交
157 158 159 160 161
4.  作为 Spring Boot 应用启动该应用。 测试几个 REST 端点,以检查它们是否工作正常:
    *   `http://localhost:8080/swagger2-demo/getStudents`
    *   `http://localhost:8080/swagger2-demo/getStudent/sajal`
    *   `http://localhost:8080/swagger2-demo/getStudentByCountry/india`
    *   `http://localhost:8080/swagger2-demo/getStudentByClass/v`
W
wizardforcel 已提交
162 163 164

## Swagger2 配置

W
wizardforcel 已提交
165
我们的 REST API 已准备就绪。 现在将 swagger2 支持添加到`project.ff`
W
wizardforcel 已提交
166 167 168

#### 添加 Swagger2 Maven 依赖项

W
wizardforcel 已提交
169
打开`spring-boot-swagger2`项目的`pom.xml`文件,并在下面添加两个与 swagger 相关的依赖项,即`springfox-swagger2``springfox-swagger-ui`
W
wizardforcel 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

```java
     <dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.6.1</version>
		</dependency>

		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.6.1</version>
		</dependency>

```

W
wizardforcel 已提交
186
实际上,`swagger` API 具有多种变体,并且维护在不同的工件中。 今天,我们将使用`springfox`,因为该版本可以很好地适应任何基于 spring 的配置。 我们还可以轻松地尝试其他配置,并且应该提供相同的功能-无需更改/只需稍作更改即可。
W
wizardforcel 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

#### 添加 Swagger2 配置

在代码库中添加以下配置。 为了帮助您理解配置,我添加了嵌入式注释。

```java
package com.example.springbootswagger2.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.google.common.base.Predicates;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class Swagger2UiConfiguration extends WebMvcConfigurerAdapter 
{
	@Bean
	public Docket api() {
		// @formatter:off
		//Register the controllers to swagger
		//Also it is configuring the Swagger Docket
		return new Docket(DocumentationType.SWAGGER_2).select()
				// .apis(RequestHandlerSelectors.any())
				.apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.boot")))
				// .paths(PathSelectors.any())
				// .paths(PathSelectors.ant("/swagger2-demo"))
				.build();
		// @formatter:on
	}

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) 
	{
		//enabling swagger-ui part for visual documentation
		registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
	}
}

```

#### 验证 Swagger2 JSON 格式文档

W
wizardforcel 已提交
236
执行 maven 并启动服务器。 打开链接`http://localhost:8080/swagger2-demo/v2/api-docs`,它应该以`JSON`格式提供整个文档。 这并不是那么容易阅读和理解,实际上 Swagger 已经提供了将其用于其他系统中的功能,例如如今流行的 API 管理工具,它提供了 API 网关,API 缓存,API 文档等功能。
W
wizardforcel 已提交
237 238 239

[![](img/4e9fbf864b8b2663ee66dfc5c3fc5c8c.png)](//howtodoinjava.com/wp-content/uploads/2017/07/JSON_documenatation.jpg)

W
wizardforcel 已提交
240
JSON 文档
W
wizardforcel 已提交
241 242 243 244 245



#### 验证 Swagger2 UI 文档

W
wizardforcel 已提交
246
打开`http://localhost:8080/swagger2-demo/swagger-ui.html`在浏览器中查看 Swagger UI 文档。
W
wizardforcel 已提交
247 248 249 250 251 252 253 254 255

![Swagger2 UI Docs without Annotations](img/de00227979aa13b38e66dc6d767ad0be.png)

Swagger2 UI 文档(无注释)



## Swagger2 注释

W
wizardforcel 已提交
256
默认生成的 API 文档很好,但是缺少详细的 API 级别信息。 Swagger 提供了一些注释,可以将这些详细信息添加到 API。 例如:
W
wizardforcel 已提交
257

W
wizardforcel 已提交
258
1.  `@Api` – 我们可以将此注释添加到控制器,以添加有关控制器的基本信息。
W
wizardforcel 已提交
259 260 261 262 263 264 265 266 267

    ```java
    @Api(value = "Swagger2DemoRestController", description = "REST APIs related to Student Entity!!!!")
    @RestController
    public class Swagger2DemoRestController {
    	...
    }
    ```

W
wizardforcel 已提交
268
2.  `@ApiOperation``@ApiResponses` – 我们可以将这些注释添加到控制器中的任何 rest 方法,以添加与该方法有关的基本信息。 例如:
W
wizardforcel 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

    ```java
    @ApiOperation(value = "Get list of Students in the System ", response = Iterable.class, tags = "getStudents")
    @ApiResponses(value = { 
    			@ApiResponse(code = 200, message = "Success|OK"),
    			@ApiResponse(code = 401, message = "not authorized!"), 
    			@ApiResponse(code = 403, message = "forbidden!!!"),
    			@ApiResponse(code = 404, message = "not found!!!") })

    @RequestMapping(value = "/getStudents")
    public List<Student> getStudents() {
        return students;
    }

    ```

    在这里,我们可以将`tags`添加到方法中,以在`swagger-ui`中添加一些分组。

W
wizardforcel 已提交
287
3.  `@ApiModelProperty` – 在 Model 属性中使用此注释可为该 Model 属性的 Swagger 输出添加一些描述。 例如:
W
wizardforcel 已提交
288 289 290 291 292 293

    ```java
    @ApiModelProperty(notes = "Name of the Student",name="name",required=true,value="test name")
    private String name;
    ```

W
wizardforcel 已提交
294
添加 swagger2 注释后的控制器和模型类代码。
W
wizardforcel 已提交
295

W
wizardforcel 已提交
296
**`Swagger2DemoRestController.java`**
W
wizardforcel 已提交
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361

```java
package com.example.springbootswagger2.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.springbootswagger2.model.Student;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@Api(value = "Swagger2DemoRestController", description = "REST Apis related to Student Entity!!!!")
@RestController
public class Swagger2DemoRestController {

	List<Student> students = new ArrayList<Student>();
	{
		students.add(new Student("Sajal", "IV", "India"));
		students.add(new Student("Lokesh", "V", "India"));
		students.add(new Student("Kajal", "III", "USA"));
		students.add(new Student("Sukesh", "VI", "USA"));
	}

	@ApiOperation(value = "Get list of Students in the System ", response = Iterable.class, tags = "getStudents")
	@ApiResponses(value = { 
			@ApiResponse(code = 200, message = "Suceess|OK"),
			@ApiResponse(code = 401, message = "not authorized!"), 
			@ApiResponse(code = 403, message = "forbidden!!!"),
			@ApiResponse(code = 404, message = "not found!!!") })

	@RequestMapping(value = "/getStudents")
	public List<Student> getStudents() {
		return students;
	}

	@ApiOperation(value = "Get specific Student in the System ", response = Student.class, tags = "getStudent")
	@RequestMapping(value = "/getStudent/{name}")
	public Student getStudent(@PathVariable(value = "name") String name) {
		return students.stream().filter(x -> x.getName().equalsIgnoreCase(name)).collect(Collectors.toList()).get(0);
	}

	@ApiOperation(value = "Get specific Student By Country in the System ", response = Student.class, tags = "getStudentByCountry")
	@RequestMapping(value = "/getStudentByCountry/{country}")
	public List<Student> getStudentByCountry(@PathVariable(value = "country") String country) {
		System.out.println("Searching Student in country : " + country);
		List<Student> studentsByCountry = students.stream().filter(x -> x.getCountry().equalsIgnoreCase(country))
				.collect(Collectors.toList());
		System.out.println(studentsByCountry);
		return studentsByCountry;
	}

	// @ApiOperation(value = "Get specific Student By Class in the System ",response = Student.class,tags="getStudentByClass")
	@RequestMapping(value = "/getStudentByClass/{cls}")
	public List<Student> getStudentByClass(@PathVariable(value = "cls") String cls) {
		return students.stream().filter(x -> x.getCls().equalsIgnoreCase(cls)).collect(Collectors.toList());
	}
}

```

W
wizardforcel 已提交
362
**`Student.java`**
W
wizardforcel 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406

```java
package com.example.springbootswagger2.model;

import io.swagger.annotations.ApiModelProperty;

public class Student 
{
	@ApiModelProperty(notes = "Name of the Student",name="name",required=true,value="test name")
	private String name;

	@ApiModelProperty(notes = "Class of the Student",name="cls",required=true,value="test class")
	private String cls;

	@ApiModelProperty(notes = "Country of the Student",name="country",required=true,value="test country")
	private String country;

	public Student(String name, String cls, String country) {
		super();
		this.name = name;
		this.cls = cls;
		this.country = country;
	}

	public String getName() {
		return name;
	}

	public String getCls() {
		return cls;
	}

	public String getCountry() {
		return country;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", cls=" + cls + ", country=" + country + "]";
	}
}

```

W
wizardforcel 已提交
407
## 演示
W
wizardforcel 已提交
408

W
wizardforcel 已提交
409
现在,在正确注释我们的 REST API 之后,我们来看一下最终输出。 打开`http://localhost:8080/swagger2-demo/swagger-ui.html`在浏览器中查看 Swagger ui 文档。
W
wizardforcel 已提交
410 411 412

![Final Swagger2 REST API Output](img/1f62370e64802188fb3551506abb9860.png)

W
wizardforcel 已提交
413
Swagger2 REST API 最终输出
W
wizardforcel 已提交
414 415 416



W
wizardforcel 已提交
417
这一切都将通过 Spring Boot应用 swagger2 **创建 REST API 文档**。 将我的问题放在评论部分。
W
wizardforcel 已提交
418

W
wizardforcel 已提交
419
[下载源码](//howtodoinjava.com/wp-content/uploads/2017/07/spring-boot-swagger2.zip)
W
wizardforcel 已提交
420 421

学习愉快!