文章目录
一、Rrestful API介绍
(一) 什么是RESTful API?
要知道什么RESTful API,首先要知道REST是什么?
REST,表示性状态转移(representation state transfer)。简单来说,就是用URI表示资源,用HTTP方法(GET, POST, PUT, DELETE)表征对这些资源的操作。
Resource: 资源,即数据,存在互联网上的可被访问的实体,可以是文本、图片、音频、视频。资源总是以一定的格式来表现自己。文本用txt、html;图片用JPG、JPEG等等。而JSON是RESTful API中最常用的资源表现格式。
Representation: 数据的某种表现形式,如HTML, JSON。 State
Transfer:状态变化,HTTP方法实现
RESTful API 就是REST风格的API。现在终端平台多样,移动、平板、PC等许多媒介向服务端发送请求后,如果不使用RESTful API,需要为每个平台的数据请求定义相应的返回格式,以适应前端显示。但是RESTful API 要求前端以一种预定义的语法格式发送请求,那么服务端就只需要定义一个统一的响应接口,不必像之前那样解析各色各式的请求。
(二) RESTful 是典型的基于HTTP的协议。哪些设计原则和规范呢?
- JSON格式返回
- 统一接口,对于业务数据的增删改查,RESTful 用HTTP方法与之对应。
对应的业务操作 | 对应的HTTP Method | 优点 | 代码表示 |
---|---|---|---|
Read/SELECT | GET | 安全且幂等、获取表示、变更时获取表示(缓存) | 200(OK) - 表示已在响应中发出、204(无内容) - 资源有空表示、301(Moved Permanently) - 资源的URI已被更新、303(See Other) - 其他(如,负载均衡)、304(not modified)- 资源未更改(缓存)、400 (bad request)- 指代坏请求(如,参数错误)、404 (not found)- 资源不存在、406 (not acceptable)- 服务端不支持所需表示、500 (internal server error)- 通用错误响应、503 (Service Unavailable)- 服务端当前无法处理请求 |
Create | POST | 不安全且不幂等、使用服务端管理的(自动产生)的实例号创建资源、创建子资源、部分更新资源、如果没有被修改,则不过更新资源(乐观锁) | 200(OK)- 如果现有资源已被更改、201(created)- 如果新资源被创建、202(accepted)- 已接受处理请求但尚未完成(异步处理)、301(Moved Permanently)- 资源的URI被更新、303(See Other)- 其他(如,负载均衡)、400(bad request)- 指代坏请求、404 (not found)- 资源不存在、406 (not acceptable)- 服务端不支持所需表示、409 (conflict)- 通用冲突、412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)、415 (unsupported media type)- 接受到的表示不受支持、500 (internal server error)- 通用错误响应、503 (Service Unavailable)- 服务当前无法处理请求 |
Update | PUT | 在服务器更新资源(客户端提供改变后的完整资源)不安全但幂等、用客户端管理的实例号创建一个资源、通过替换的方式更新资源、如果未被修改,则更新资源(乐观锁) | 200 (OK)- 如果已存在资源被更改、201 (created)- 如果新资源被创建、301(Moved Permanently)- 资源的URI已更改、303 (See Other)- 其他(如,负载均衡)、400 (bad request)- 指代坏请求、404 (not found)- 资源不存在、406 (not acceptable)- 服务端不支持所需表示、409 (conflict)- 通用冲突、412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)、415 (unsupported media type)- 接受到的表示不受支持、500 (internal server error)- 通用错误响应、503 (Service Unavailable)- 服务当前无法处理请求 |
Update | PATCH | 在服务器更新资源(客户端提供改变的属性) | 与PUT一致 |
Delete | DELETE | 不安全但幂等、删除资源 | 200 (OK)- 资源已被删除、301 (Moved Permanently)- 资源的URI已更改、303 (See Other)- 其他,如负载均衡、400 (bad request)- 指代坏请求、404 (not found)- 资源不存在、409 (conflict)- 通用冲突、500 (internal server error)- 通用错误响应、503 (Service Unavailable)- 服务端当前无法处理请求 |
ps:幂等性就是无论一个操作被执行一次还是多次,执行后的效果都相同。比如对某资源发送GET请求,如果访问一次和访问十次获得的数据一样,那么就说这个请求具有幂等性。
(三) RESTful API的规范
- url中使用的是名词,不使用动词。
# 获取用户信息
http://localhost:8080/user
http://localhost:8080/employees
- 尽量把API放在专用域名下
- 版本号可以放在url中,也可以放在HTTP头信息中(推荐)
http://www.hwj.com/api/1.0/user
http://www.hwj.com/api/1.1/user
http://www.hwj.com/app/2.0/user
因为不同的版本,可以理解成同一种资源的不同表现形式,所以应该采用同一个URI。版本号可以在HTTP请求头信息的Accept字段中进行区分
Accept: vnd.example-com.foo+json; version=1.0
Accept: vnd.example-com.foo+json; version=1.1
Accept: vnd.example-com.foo+json; version=2.0
举例
GET /user:列出所有用户信息
GET /user/Id:获取某个指定用户的信息
POST /user:新建一个用户
PUT /user/ID:更新某个指定用户的信息(提供该动物园的全部信息)
PATCH /user/ID:更新某个指定用户的信息(提供该动物园的部分信息)
DELETE /user/ID:删除某个用户
二、springboot中使用RESTful API
(一) 注解解析
1、@RestController注释用于定义RESTful Web服务。它提供JSON,XML和自定义响应。其语法如下所示
@RestController
public class ResetfulApi {
}
2、@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。其有6个属性
- value: 指定请求的实际地址;
- method: 指定请求的method类型, GET、POST、PUT、DELETE等;
- consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
- produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
- params: 指定request中必须包含某些参数值是,才让该方法处理。
- headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET,produces= MediaType.APPLICATION_PROBLEM_JSON_VALUE)
- @RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)
其有特殊要求前端必须是用POST请求,而且一个请求,只有一个RequestBody
@RequestMapping("/teset")
public User test1(@RequestBody User user){
return user;
}
- @RequestParam是将请求参数绑定到你控制器的方法参数上
- value:参数名,url请求的参数名必须与其一致
- required:是否包含该参数,默认为true,表示该请求路径中必须包含该参数,如果不包含就报错。
- defaultValue:默认参数值,如果设置了该值,required=true将失效,自动为false,如果没有传该参数,就使用默认值
@RequestMapping("/teset")
public String test1(@RequestParam(value = "id",required = true) Long id,@RequestParam(value = "name",defaultValue = "hwj") String name){
return name;
}
- @PathVariable用于定义自定义或动态请求URI。 将URL中占位符参数{xxx}绑定到处理器类的方法形参中@PathVariable(“xxx“)
# url:/url/1/hwj
@RequestMapping("/user/{id}/{name}")
public String test1(@PathVariable(name = "id")Long id ,@PathVariable(name = "name") String name){
return name;
}
- @GetMapping就是一个GET的请求映射
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
新方法可以简化为:
@GetMapping("/get/{id}")
- @PostMapping就是一个POST的请求映射
@RequestMapping(value = "/workflow",
produces = {"application/json"},
consumes = {"application/json"},
method = RequestMethod.POST)
新方法可以简化为:
@PostMapping(path = "/members", consumes = "application/json", produces = "application/json")
- @PutMapping就是一个PUT的请求映射
- @DeleteMapping就是一个DELETE的请求映射
- @PatchMapping就是一个PATCH的请求映射
(二) swagger注解
- @Api 表示标识这个类是swagger的资源,用于controller类上
- tags表示说明 ,如果有多个值,会生产多个list
- value–也是说明,可以使用tags替代
- description --对该接口的一个描述
@RestController
@RequestMapping("/user")
@Api(tags = {"用户处理接口"})
public class ResetfulApi {
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET,produces= MediaType.APPLICATION_PROBLEM_JSON_VALUE)
public User test(@PathVariable Long id){
User user1=new User(1L,"admin","123456");
if (user1.getId().equals(id)) {
}
return user1;
}
}
- @ApiOperation 作用在方法上,表示一个http请求的操作
- value - 字段说明
- notes - 注释说明
- httpMethod - 说明这个方法被请求的方式
- response - 方法的返回值的类型
@RequestMapping(value = "/user/{id}")
@ApiOperation(value = "获取指定用户信息",notes = "用于获取指定的用户信息",httpMethod = "GET")
public User test(@PathVariable Long id){
User user1=new User(1L,"admin","123456");
if (user1.getId().equals(id)) {
}
return user1;
}
- @ApiParam() 用于方法,参数,字段说明;表示对参数的添加元数据(说明或是否必填等)
- name–参数名
- value–参数说明
- required–是否必填
@GetMapping(value = "/user/{id}/{name}")
@ApiOperation(value = "获取指定用户信息",notes = "用于获取指定的用户信息",httpMethod = "GET")
public User test(@ApiParam(name="id",value="用户id",required=true) @PathVariable Long id,@ApiParam(name="name",value="用户名") @PathVariable String name){
User user1=new User(1L,"admin","123456");
if (user1.getId().equals(id)) {
}
return user1;
}
- @ApiImplicitParam()用于方法,参数,字段说明;表示对参数的添加元数据(说明或是否必填等),一个参数说明
- name–参数名
- value–参数说明
- required–是否必填
- example 举例
@GetMapping("/{id}")
//参数描述
@ApiOperation(value = "获取指定用户信息",notes = "用于获取指定的用户信息",httpMethod = "GET")
@ApiImplicitParam(name = "id",value = "用户ID",required = true,example = "123")
public ResultDTO getUser(@PathVariable(name = "id")Long id){
UserDTO userDTO=new UserDTO(1L,"hwj","25");
ResultDTO<UserDTO> resultDTO=new ResultDTO<>(true,200,userDTO,"success");
return resultDTO;
}
- @ApiImplicitParams() 用于方法,参数,字段说明;表示对参数的添加元数据(说明或是否必填等),一个参数说明,多个参数
@GetMapping("/{id}")
//参数描述
@ApiOperation(value = "获取指定用户信息",notes = "用于获取指定的用户信息",httpMethod = "GET")
@ApiImplicitParams({
@ApiImplicitParam(name = "id",value = "用户ID",required = true,example = "123"),
@ApiImplicitParam(name = "username",value = "用户名",required = true,example = "hwj")
})
public ResultDTO getUser(@PathVariable(name = "id")Long id){
UserDTO userDTO=new UserDTO(1L,"hwj","25");
ResultDTO<UserDTO> resultDTO=new ResultDTO<>(true,200,userDTO,"success");
return resultDTO;
}
- @ApiModel()用于类 ;表示对类进行说明,用于参数用实体类接收
value–表示对象名
description–描述
都可省略
@ApiModelProperty()用于方法,字段; 表示对model属性的说明或者数据操作更改
value–字段说明
name–重写属性名字
dataType–重写属性类型
required–是否必填
example–举例说明
hidden–隐藏
三、springboot 整合Swagger2自动生成API文档
(一)、添加依赖
<!--springboot 整合swagger2自动生成result API接口文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.22</version>
</dependency>
(二)、配置
package com.jiead.swagger2Demo.config;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
/**
* @author hwj
* @date 2020/5/3 15:38
* @Description Swagger2 配置文件类
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
/**注入环境变量*/
@Autowired
Environment environment;
/**
* @creator hwj
* @date 2020/5/3 15:44
* @parameter
* @description 构造一个bean
*/
@Bean
public Docket restApi() {
/**设置哪些环境变量可以访问*/
Profiles profiles=Profiles.of("dev");
boolean isEnale=environment.acceptsProfiles(profiles);
/** 配置swagger的全局变量
* 举例:每一个接口都带上token
* */
Parameter token=new ParameterBuilder().name("tocken")
.description("用户令牌")
//请求头
// .parameterType("header")
//请求参数
.parameterType("query")
.modelRef(new ModelRef("String"))
.required(true)
.build();
List<Parameter> parameters=new ArrayList<>();
parameters.add(token);
return new Docket(DocumentationType.SWAGGER_2)
//配置swagger的全局变量
.globalOperationParameters(parameters)
//是否启用swagger ,true 能访问,false 不能访问
.enable(isEnale)
//忽略参数,使其不展示
.ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
//调用apiInfo方法,创建一个ApiInfo实例,里面是展示在文档页面信息内容
.apiInfo(apiInfo())
/* 控制暴露出去的路径下的实例,如果某个接口不想暴露,可以使用以下注解 @ApiIgnore 这样,该接口就不会暴露在 swagger2 的页面下*/
.select()
// 设置basePackage会将包下的所有类的所有方法作为api暴露出给swagger
// .apis(RequestHandlerSelectors.basePackage("com.jiead.swagger2Demo.controller"))
//类,使用@RestController注解的类下的接口才会暴露出给swagger
// .apis(RequestHandlerSelectors.withClassAnnotation(@RestController.class))
// 方法,只有使用@ApiOperation的方法才会暴露出给swagger
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
/**
* @creator hwj
* @date 2020/5/3 15:45
* @parameter
* @description 构建 api文档的详细信
*/
private ApiInfo apiInfo() {
//文档负责人信息
Contact contact=new Contact("hwj","地址","1457581030@qq.com");
return new ApiInfoBuilder()
//页面标题
.title("Spring Boot Swagger2 整合Swagger2自动生成RESTful API接口文档")
// 项目地址
.termsOfServiceUrl("http://localhost:8080/")
// 文档负责人信息
.contact(contact)
//版本号
.version("1.0")
//描述
.description("Spring Boot Swagger2 整合Swagger2自动生成RESTful API接口文档一个demo")
.build();
}
/**
* @creator hwj
* @date 2020/5/3 17:22
* @parameter
* @description 分组
*
*/
/* @Bean
public Docket restApiUser() {
*//**设置哪些环境变量可以访问*//*
Profiles profiles=Profiles.of("dev");
boolean isEnale=environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.enable(isEnale)
.groupName("用户")
.ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.ant("/user"))
.build();
}
@Bean
public Docket restApiFoodr() {
*//**设置哪些环境变量可以访问*//*
Profiles profiles=Profiles.of("dev");
boolean isEnale=environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.enable(isEnale)
.groupName("food")
.ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.ant("/food"))
.build();
}
*/
}
(三) 访问接口文档
http://IP:post//swagger-ui.html
举例:
http://localhost:8080/swagger-ui.html