要知道什么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 要求前端以一种预定义的语法格式发送请求,那么服务端就只需要定义一个统一的响应接口,不必像之前那样解析各色各式的请求。
对应的业务操作 | 对应的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请求,如果访问一次和访问十次获得的数据一样,那么就说这个请求具有幂等性。
# 获取用户信息
http://localhost:8080/user
http://localhost:8080/employees
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:删除某个用户
1、@RestController注释用于定义RESTful Web服务。它提供JSON,XML和自定义响应。其语法如下所示
@RestController
public class ResetfulApi {
}
2、@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。其有6个属性
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET,produces= MediaType.APPLICATION_PROBLEM_JSON_VALUE)
@RequestMapping("/teset")
public User test1(@RequestBody User user){
return user;
}
@RequestMapping("/teset")
public String test1(@RequestParam(value = "id",required = true) Long id,@RequestParam(value = "name",defaultValue = "hwj") String name){
return name;
}
# url:/url/1/hwj
@RequestMapping("/user/{id}/{name}")
public String test1(@PathVariable(name = "id")Long id ,@PathVariable(name = "name") String name){
return name;
}
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
新方法可以简化为:
@GetMapping("/get/{id}")
@RequestMapping(value = "/workflow",
produces = {"application/json"},
consumes = {"application/json"},
method = RequestMethod.POST)
新方法可以简化为:
@PostMapping(path = "/members", consumes = "application/json", produces = "application/json")
@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;
}
}
@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;
}
@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;
}
@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 resultDTO=new ResultDTO<>(true,200,userDTO,"success");
return resultDTO;
}
@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 resultDTO=new ResultDTO<>(true,200,userDTO,"success");
return resultDTO;
}
io.springfox
springfox-swagger2
2.8.0
io.swagger
swagger-models
io.springfox
springfox-swagger-ui
2.8.0
io.swagger
swagger-models
1.5.22
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 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","地址","[email protected]");
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