1. 简介

Representational State Transfer,简称为REST, 即表现层状态转化

  • 资源 Resources
    指的是网络上的某个数据, 如一个文件、一种服务等
  • 表现层 Representational
    资源的表现层,指的是资源的具体呈现形式,如HTML、JSON等
  • 状态转化 State Transfer
    指的是状态变化,通过HTTP方法来实现:

GET 获取资源

POST 新建资源

PUT 更新资源

DELETE 删除资源

简单来说,客户端通过HTTP方法对服务器的资源进行操作, 实现表现层状态转化

2. 设计原则

Restful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计

Restful API设计原则:

  • 尽量将API 部署在一个专用的域名下,如 http://api.itany.com
  • API的版本应该在URL中体现,如 http://api.itany.com/v2
  • URL中不要使用动词,应使用资源名词,且使用名词的复数形式,如

注:简单来说,可以使用同一个 URL ,通过约定不同的 HTTP 方法来实施不同的业务

  • 服务器响应时返回JSON对象,应包含HTTP状态码、消息、结果等,如{code:200,message:"success",result:{id:1001,name:"tom"}}
  • 最好在返回的结果中提供链接, 指向其他的API方法,使得用户不用查文档, 就能知道下一步该怎么做

3. 用法

cloud-common

提供基本传输对象,给多个服务之间传输提供基石

  • 依赖配置
<dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>
  • 公共响应体
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResponeResult {
    private int code;
    private String msg;
    private Object obj;

    public static ResponeResult createSuccessResult(Object obj){
        return new ResponeResult(200,"",obj);
    }
    public static ResponeResult createSuccessResult(){
        return new ResponeResult(200,"",null);
    }

    public static ResponeResult createErrorResult(String msg){
        return new ResponeResult(400,msg,null);
    }
    public static ResponeResult createErrorResult(){
        return new ResponeResult(400,"操作失败",null);
    }

    public static ResponeResult createServerErrorResult(){
        return new ResponeResult(500,"服务器异常",null);
    }
    public static ResponeResult createServerErrorResult(String msg){
        return new ResponeResult(500,msg,null);
    }
}
  • 业务数据对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String phone;
}

cloud-provider

构建Restful API服务

  • 服务依赖
<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>spring-cloud-provider</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-cloud-provider</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.example</groupId>
			<artifactId>spring-cloud-common</artifactId>
			<version>1.0-SNAPSHOT</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
  • 服务配置application.yml
server:
  port: 8001
  • 控制层接口
@RestController
@RequestMapping("/user")
public class UserController {
    static Map<Integer, User> userMap = new ConcurrentHashMap<>();
    static AtomicInteger nextId = new AtomicInteger();
    static {
        userMap.put(1,new User(1,"张三","18623232323"));
        userMap.put(2,new User(2,"李四","18623232323"));
        userMap.put(3,new User(3,"王五","18623232323"));
        userMap.put(4,new User(4,"赵六","19515785248"));
        nextId.set(5);
    }
    @GetMapping
    public ResponeResult userList(){
        return ResponeResult.createSuccessResult(userMap);
    }

    @GetMapping("/{id}")
    public ResponeResult user(@PathVariable("id")Integer id){
        return ResponeResult.createSuccessResult(userMap.get(id));
    }

	/**
	*
	*
	*/
    @PostMapping("/form")
    public ResponeResult addForm(User user){
        user.setId(nextId.getAndAdd(1));
        userMap.put(user.getId(),user);
        return ResponeResult.createSuccessResult(user);
    }

    @PostMapping("/json")
    public ResponeResult addJson(@RequestBody User user){
        user.setId(nextId.getAndAdd(1));
        userMap.put(user.getId(),user);
        return ResponeResult.createSuccessResult(user);
    }
    @DeleteMapping("/{id}")
    public ResponeResult delete(@PathVariable("id") Integer id){
        User user = userMap.get(id);
        if(Objects.isNull(user)){
            return ResponeResult.createErrorResult(String.format("没有id为%s的用户!",id));
        }
        userMap.remove(user.getId());
        return ResponeResult.createSuccessResult(user);
    }

    @PutMapping
    public ResponeResult update(@RequestBody User user){
        User oldUser = userMap.get(user.getId());
        if(Objects.isNull(oldUser)){
            return ResponeResult.createErrorResult(String.format("没有id为%s的用户!",user.getId()));
        }
        userMap.put(user.getId(),user);
        return ResponeResult.createSuccessResult(oldUser);
    }

}

cloud-consumer

  • 使用RestTemplate调用Rest服务
  • RestTemplate是Spring提供的用于访问Rest服务的客户端,提供了访问远程Http服务的方法
  • 服务依赖
<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>spring-cloud-customer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-cloud-customer</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.example</groupId>
			<artifactId>spring-cloud-common</artifactId>
			<version>1.0-SNAPSHOT</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
  • 配置文件
server:
  port: 8080
  • Spring服务配置类
@Configuration
public class SpringConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
  • 访问端
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    RestTemplate restTemplate;
    static final String BASEURL = "http://localhost:8001/user";
    @GetMapping
    public ResponeResult userList(){
        return restTemplate.getForObject(BASEURL,ResponeResult.class);
    }

    @GetMapping("/{id}")
    public ResponeResult user(@PathVariable("id")Integer id){
        return restTemplate.getForObject(BASEURL+"/{id}",ResponeResult.class,id);
    }

    /**
     * 发送对方使用x-www-form-urlencode方式接收数据
     * @param user
     * @return
     */
    @PostMapping("/form")
    public ResponeResult addForm(User user){
        MultiValueMap params = new LinkedMultiValueMap();
        params.add("name",user.getName());
        params.add("phone",user.getPhone());
        return restTemplate.postForObject(BASEURL+"/form",params,ResponeResult.class);
    }

    /**
     * 发送对方使用application/json接受数据方式
     * @param user
     * @return
     */
    @PostMapping("/json")
    public ResponeResult addJson(@RequestBody User user){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Accept",MediaType.APPLICATION_JSON.toString());
        HttpEntity entity = new HttpEntity<User>(user,headers);
        return restTemplate.postForObject(BASEURL+"/json",entity,ResponeResult.class);
    }
    @DeleteMapping("/{id}")
    public ResponeResult delete(@PathVariable("id") Integer id){

        ResponseEntity<ResponeResult> entity= restTemplate.exchange(BASEURL+"/{id}",
                HttpMethod.DELETE,null,ResponeResult.class,id);
        return entity.getBody();
    }

    @PutMapping
    public ResponeResult update(@RequestBody User user){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Accept",MediaType.APPLICATION_JSON.toString());
        HttpEntity entity = new HttpEntity<User>(user,headers);
        ResponseEntity<ResponeResult> responseEntity= restTemplate.exchange(BASEURL,
                HttpMethod.PUT,entity,ResponeResult.class);
        return responseEntity.getBody();
    }
}

消费者的访问接口与生产者的访问接口相同,只是 消费者的数据依赖生产者的数据。

4. 使用postman

Postman是一款非常优秀的调试工具,可以用来模拟发送各类HTTP请求,进行接口测试。

rest post接口接收两个body示例_restful

5. 使用Swagger2

通常情况下,我们会创建一份Restful API文档来记录所有的接口细节,供其他开发人员使用提供的接口服务,但会存在以下的问题:

  • 接口众多,并且细节复杂
  • 需要根据接口的变化,不断修改API文档,非常麻烦,费时费力

Swagger2的出现就是为了解决上述的这些问题,减少创建API文档的工作量

  • 后端人员在代码里添加接口的说明内容,就能够生成可预览的API文档,无须再维护Word文档
  • 让维护文档和修改代码整合为一体,在修改代码逻辑的同时方便的修改文档说明
  • 提供了强大的页面测试功能,便于对接口进行测试

使用步骤:

  1. 添加Swagger2依赖
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-annotations</artifactId>
    <version>1.5.21</version>
</dependency>
<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-models</artifactId>
    <version>1.5.21</version>
</dependency>
  1. 创建Swagger2配置类
@Configuration
@EnableSwagger2  // 启用Swagger2
public class Swagger2Config {

    /**
     * 创建Restful API文档内容
     */
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // 指定要暴露给Swagger来展示的接口所在的包
                .apis(RequestHandlerSelectors.basePackage("com.itany.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 创建API的基本信息,这些信息会展现在文档页面中
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                // 标题
                .title("使用Swagger2构建Restful API文档")
                // 描述
                .description("欢迎访问后端API接口文档")
                // 联系人
                .contact(new Contact("tangxiaoyang","https://github.com/tangyang8942","1049901079@qq.com"))
                // 版本号
                .version("1.0")
                .build();
    }

}
  1. 添加文档内容
    使用Swagger2提供的注解对接口进行说明,常用注解:
  • @Api 标注在类上,对类进行说明
  • @ApiOperation 标注在方法上,对方法进行说明
  • @ApiImplicitParams 标注在方法上,对方法的多个参数进行说明
  • @ApiImplicitParam 标注在方法上,对方法的一个参数进行说明
  • @ApiModel 标注在模型Model上,对模型进行说明
  • @ApiModelProperty 标注在属性上,对模型的属性进行说明
  • @ApiIgnore 标注在类或方法上,表示忽略这个类或方法
  1. 查看Restful API的页面,并测试接口
    启动SpringBoot程序,访问http://localhost:端口/swagger-ui.html