当前位置:   article > 正文

SpringBoot(17)接口架构风格—RESTful与Swagger_restful api和swagger是什么

restful api和swagger是什么

1.认识REST

1.1什么是REST

  REST是软件架构的规范体系结构,它将资源的状态以适合客户端的形式从服务器端发送到客户端(或相反方向)。在REST中,通过URL进行资源定位,用HTTP动作GET、POST、DELETE、PUSH等)描述操作,完成功能。

  道循RESTful风格,可以使开发的接口通用,以便调用者理解接口的作用。基于REST构建的 API 就是 RESTful ( REST 风格)API.

  各大机构提供的API基本都是RESTful风格的。这样可以统一规范,减少沟通、学习和开发 的成本。

1.2 REST的特征

  • 客户一服务器(client-server):提供服务的服务器和使用服务的客户端需要被隔离对待。
  • 无状态(stateless):服务器端不存储客户的请求中的信息,客户的每一个请求必须包含服务器处理该请求所需的所有信息,所有的资源都可以通过URI定位,而且这个定位与其他资源无关,也不会因为其他资源的变化而变化。

  Restful是典型的基于HTTP的协议。HTTP连接最显著的特点是:客户端发送的每次请求都需要服务器回送响应;在请求结束后,主动释放连接:

  从建立连接到关闭连接的过程称为“一次连接”,前后的请求没有必然的联系,所以是无状态的

  可缓存(cachable):服务器必须让客户知道请求是否可以被缓存。

  • 分层系统(layered System):服务器和客户之间的通信必须被标准化。
  • 统一接口 (uniform interface):客户和服务器之间通信的方法必须统一,REStful风格的 数据元操作 CRUD (create、read、update, delete)分别对应 HTTP 方法—— GET 用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源,这样就统一了数据操作的接口。
  • HTTP状态码:状态码在REST中都有特定的意义:200、201、202204、400、401、 403、500,比如,401表示用户身份认证失败;403表示验证身份通过了,但资源没有权限进行操作。
  • 支持按需代码(Code-On-Demand,可选):服务器可以提供一些代码或脚本,并在客户的运行环境中执行。

1.3 认识HTTP方法与CRUD动作映射

  RESTful风格使用同一个URL,通过约定不同的HTTP方法来实施不同的业务。 普通网页的CRUD和RESTful风格的CRUD的区别,见下表。

  

  可以看出,RESTful风格的CRUD比传统的CRUD简单明了,它通过HTTP方法来区分增加、修改、删除和查询。

1.4 实现RESTfuI风格的数据增加、删除、修改和查询

  在SpringBoot中,如果要返回JSON数据,则只需要在控制器中用@RestController注解。 如果提交HTTP方法,则只需要使用注解@RequestMapping来实现,它有以下两个属性。

  • Value:用来制定URI。
  • Method:用来制定HTTP请求方法。

  为了不重复编码,尽量在类上使用@RequestMapping("")来指定上一级URL

  使用RESTful风格操作数据的方法见以下代码。

  (1)获取列表采用的是GET方式,返回List,例如,下面代码返回User的List。

  1. @RequestMapping(value = "/",method = RequestMethod.GET)
  2. public List<User> getUserList(){
  3. List<User> userList = new ArrayList<User>(userRepository.findAll());
  4. return userList;
  5. }

  (2)增加内容(提交内容)采用的是POST方式,一般返回String类型或int类型的数据,见 以下代码:

  1. @RequestMapping(value = "/",method = RequestMethod.POST)
  2. public String add(User user){
  3. userRepository.save(user);
  4. return "success";
  5. }

  (3)删除内容,必须采用DEIETE方法。一般都是根据id主键进行删除的

  1. @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
  2. public String delete(@PathVariable("id")Long id){
  3. userRepository.deleteById(id);
  4. return "success";
  5. }

  (4)修改内容,则采用PUT方法。

  1. @RequestMapping(value = "/{id}",method = RequestMethod.PUT)
  2. public String update(User user){
  3. userRepository.save(user);
  4. return "success";
  5. }

  (5)查询内容,和上面获取列表的方法一样,也是采用GET方法。

  1. @RequestMapping(value = "/{id}",method = RequestMethod.GET)
  2. public User findUser(@PathVariable("id")Integer id){
  3. Optional<User> user = userRepository.findById(id.longValue());
  4. return user.get();
  5. }

  对于RESTful风格的增加、删除、修改和查询,可以编写测试单元,也可以用Postman测试, 分别用GET、POST、PUT、DELETE方法提交测试。虽然这样实现了 RESTful风格,但还有一 个问题——返回的数据并不统一,在实际生产环境中还需要进行改进,所以需要设计统一的RESTful 风格的数据接口。

2.设计统一的RESTful 风格的数据接口

  近年来,随着移动互联网的发展,各种类型的客户端层岀不穷。如果不统一数据接口,则会造成冗余编码,增加成本。RESTful风格的API正适合通过一套统一的接口为PC、手机APP等设备提供数据服务。

2.1 版本控制

  随着业务需求的变更、功能的迭代,API的更改是不可避免的。当一个API修改时,就会出现很多问题,比如,可能会在API中新增参数、修改返回的数据类型。这就要考虑根据原先版本API 编写的客户端如何保留或顺利过渡。所以,需要进行版本控制。

  REST不提供版本控制指南,常用的方法可以分为3种。

  (1)通过URL

  通过URL是最直接的方法,尽管它违背了 URI应该引用唯一资源的原则。当版本更新时,还可以保障客户端不会受到影响,如下面使用不同URL来确定不同版本。

  二级目录的方式:

  • API 版本 V1: http:// eg.com/api/v1
  • API 版本 V2: http://eg.com/api/v2

  二级域名的方式:

  • API 版本 V1: http://v1.eg.com
  • API 版本 V2: http://v2.eg.com

  还可以包括日期、项目名称或其他标识符。这些标识符对于开发API的团队来说足够有意义, 并旦随着版本的变化也足够灵活。

  (2)通过自定义请求头

  自定义头(例如,Accept-version)允许在版本之间保留URL。

  (3)通过Accept标头

  客户端在请求资源之前,必须要指定特定头,然后API接口负责确定要发送哪个版本的资源

2.2 过滤信息

  如果记录数量很务,则服务器不可能一次都将它们返回给用户。API应该提供参数,实现分页返回結果。下面是一些常用的参数

  • ?limit=10:指定返回记录的数量。
  • ?page=5&size=10:指定第几页,以及每页的记录数。
  • ?search_type=1:指定筛选条件。

2.3 确定HTTP的方法

在RESTful中,HTTP的方法有以下几种。

  • GET:代表请求资源。
  • POST:代表添加资源。
  • PUT:代表修改资源。PUT是进行全部的修改,大家在编写修改功能时可能会遇到这样的情况:只修改了一个字段,但提交之后导致其他字段为空。这是因为,其他字段的值没有一 起提交,数据库默认为空值。如果只修改一个或几个字段,则可以使用PATCH方法。
  • DELETE:代表删除资源。
  • HEAD:代表发送HTTP头消息,GET中其实也带了 HTTP头消息。
  • PATCH: PUT与PATCH方法比较相似,但它们的用法却完全不同,PUT用于替换资源, 而PATCH用于更新部分资源。
  • OPTIONS:用于获取URI所支持的方法。返回的响应消息会在HTTP头中包含"Allow” 的信息,其值是所支持的方法,如GET。

2.4 确定HTTP的返回状态

HTTP的返回状态一般有以下几种。

  • 200:成功。
  • 400:错误请求。
  • 404:没找到资源。
  • 403:禁止。
  • 406:不能使用请求内容特性来响应请求资源,比如请求的是HTML文件,但是消费者的 HTTP头包含了 JSON要求。
  • 500:服务器内部错误。

2.5定义统一返回的格式

为了保障前后端的数据交互的顺畅,建议规范数据的返回,并采用固定的数据格式封装。如,

异常信息:

  1. {
  2. "code":"10001",
  3. "msg":"异常信息",
  4. "data":null
  5. }
  1. {
  2. "code":200,
  3. "msg":"成功",
  4. "data":{
  5. "id":1,
  6. "name":"buretuzi",
  7. "age":2
  8. }
  9. }

2.6 为手机APP、PC、H5网页提供统一风格的API

  (1)实现响应的枚举类

  枚举是一种特殊的数据类型,它是一种"类类型",比类型多了一些特殊的约束。创建枚举类型要使用“enum”,表示所创建的类型都是java.lang.Enum(抽象类)的子类。见以下代码:

  1. package com.itheima.exception;
  2. public enum ExceptionMsg {
  3. SUCCESS("200","操作成功"),
  4. FAILED("999999","操作失败");
  5. private ExceptionMsg(String code,String msg){
  6. this.code = code;
  7. this.msg = msg;
  8. }
  9. private String code;
  10. private String msg;
  11. }

  (2)实现返回的对象实体

  实现返回的对象实体,返回Code和Message (信息),见以下代码:

  1. package com.itheima.domain;
  2. public class Response {
  3. private String rspCode="200";
  4. private String rspMsg="操作成功";
  5. }

  (3)封装返回结果

  这里把返回的结果逬行封装,以显示数据,见以下代码:

  1. package com.itheima.dao;
  2. import com.itheima.domain.Response;
  3. public class ReponseData extends Response {
  4. private Object data;
  5. public ReponseData(Object data) {
  6. this.data = data;
  7. }
  8. }

  (4)统一处理异常

查看代码

  1.  package com.itheima.handler;
  2. import com.itheima.exception.BusinessException;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.http.converter.HttpMessageNotReadableException;
  7. import org.springframework.validation.BindException;
  8. import org.springframework.validation.BindingResult;
  9. import org.springframework.validation.FieldError;
  10. import org.springframework.web.HttpMediaTypeNotSupportedException;
  11. import org.springframework.web.HttpRequestMethodNotSupportedException;
  12. import org.springframework.web.bind.MethodArgumentNotValidException;
  13. import org.springframework.web.bind.MissingServletRequestParameterException;
  14. import org.springframework.web.bind.annotation.ExceptionHandler;
  15. import org.springframework.web.bind.annotation.ResponseBody;
  16. import org.springframework.web.bind.annotation.ResponseStatus;
  17. import org.springframework.web.bind.annotation.RestControllerAdvice;
  18. import javax.validation.ConstraintViolation;
  19. import javax.validation.ConstraintViolationException;
  20. import javax.validation.ValidationException;
  21. import java.util.HashMap;
  22. import java.util.Map;
  23. import java.util.Set;
  24. @RestControllerAdvice
  25. public class GlobalExceptionHandler {
  26. private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
  27. @ResponseStatus(HttpStatus.BAD_REQUEST)
  28. @ExceptionHandler(MissingServletRequestParameterException.class)
  29. public Map<String, Object> handleMissingServletRequestParameterException(MissingServletRequestParameterException e){
  30. logger.error("缺少请求参数");
  31. Map<String, Object> map = new HashMap<String, Object>();
  32. map.put("code",400);
  33. map.put("message",e.getMessage());
  34. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  35. return map;
  36. }
  37. @ResponseStatus(HttpStatus.BAD_REQUEST)
  38. @ExceptionHandler(HttpMessageNotReadableException.class)
  39. public Map<String, Object> handleHttpMessageNotReadableException(HttpMessageNotReadableException e){
  40. logger.error("缺少请求参数");
  41. Map<String, Object> map = new HashMap<String, Object>();
  42. map.put("code",400);
  43. map.put("message",e.getMessage());
  44. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  45. return map;
  46. }
  47. @ResponseStatus(HttpStatus.BAD_REQUEST)
  48. @ExceptionHandler(MethodArgumentNotValidException.class)
  49. public Map<String, Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
  50. logger.error("参数验证失败",e);
  51. BindingResult result = e.getBindingResult();
  52. FieldError error = result.getFieldError();
  53. String field = error.getField();
  54. String code = error.getDefaultMessage();
  55. String message = String.format("%s: %s",field,code);
  56. Map<String, Object> map = new HashMap<String, Object>();
  57. map.put("code",code);
  58. map.put("message",message);
  59. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  60. return map;
  61. }
  62. @ResponseStatus(HttpStatus.BAD_REQUEST)
  63. @ExceptionHandler(BindException.class)
  64. public Map<String, Object> handleBindException(BindException e){
  65. logger.error("缺少请求参数",e);
  66. Map<String, Object> map = new HashMap<String, Object>();
  67. BindingResult result = e.getBindingResult();
  68. FieldError error = result.getFieldError();
  69. String field = error.getField();
  70. String code = error.getDefaultMessage();
  71. String message = String.format("%s: %s",field,code);
  72. map.put("code",code);
  73. map.put("message",message);
  74. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  75. return map;
  76. }
  77. @ResponseStatus(HttpStatus.BAD_REQUEST)
  78. @ExceptionHandler(ConstraintViolationException.class)
  79. public Map<String, Object> handleConstraintViolationException(ConstraintViolationException e){
  80. logger.error("缺少请求参数",e);
  81. Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
  82. ConstraintViolation<?> violation = violations.iterator().next();
  83. String message = violation.getMessage();
  84. Map<String, Object> map = new HashMap<String, Object>();
  85. map.put("code",400);
  86. map.put("message",message);
  87. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  88. return map;
  89. }
  90. @ResponseStatus(HttpStatus.BAD_REQUEST)
  91. @ExceptionHandler(ValidationException.class)
  92. public Map<String, Object> handleValidationException(ValidationException e){
  93. logger.error("参数验证失败",e);
  94. Map<String, Object> map = new HashMap<String, Object>();
  95. map.put("code",400);
  96. map.put("message",e.getMessage());
  97. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  98. return map;
  99. }
  100. @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
  101. @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
  102. public Map<String, Object> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e){
  103. logger.error("不支持当前请求方法",e);
  104. Map<String, Object> map = new HashMap<String, Object>();
  105. map.put("code",400);
  106. map.put("message",e.getMessage());
  107. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  108. return map;
  109. }
  110. @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
  111. @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
  112. public Map<String, Object> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e){
  113. logger.error("不支持当前媒体类型",e);
  114. Map<String, Object> map = new HashMap<String, Object>();
  115. map.put("code",415);
  116. map.put("message",e.getMessage());
  117. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  118. return map;
  119. }
  120. @ResponseBody
  121. @ExceptionHandler(BusinessException.class)
  122. public Map<String, Object> businessExceptionHandler(BusinessException e){
  123. logger.error("自定义业务失败",e);
  124. Map<String, Object> map = new HashMap<String, Object>();
  125. map.put("code",e.getCode());
  126. map.put("message",e.getMessage());
  127. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  128. return map;
  129. }
  130. @ExceptionHandler(value = Exception.class)
  131. public Map<String, Object> defaultErrorHandler(Exception e){
  132. logger.error("自定义业务失败",e);
  133. Map<String, Object> map = new HashMap<String, Object>();
  134. map.put("code",500);
  135. map.put("message",e.getMessage());
  136. //如果发生异常,则进行日志记录、写入数据库或其他处理,此处省略
  137. return map;
  138. }
  139. }

   (5)编写测试控制器

  1. package com.itheima.controller;
  2. import com.itheima.exception.BusinessException;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.RequestParam;
  5. import org.springframework.web.bind.annotation.RestController;
  6. @RestController
  7. public class TestController {
  8. @RequestMapping("BusinessException")
  9. public String testBusinessExceptionStatus(@RequestParam("i") int i){
  10. if (i == 0){
  11. throw new BusinessException(600,"这是自定义异常");
  12. }
  13. return "success";
  14. }
  15. }

  运行项目,访问http://localhost:8080/BusinessException?i=0,在网页中返回如下 JSON 格式的数据:

  

  (6)实现数据的增加、删除、修改和查询控制器

  1. package com.itheima.controller;
  2. import com.itheima.dao.ReponseData;
  3. import com.itheima.dao.UserRepository;
  4. import com.itheima.domain.Response;
  5. import com.itheima.domain.User;
  6. import com.itheima.exception.ExceptionMsg;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.web.bind.annotation.*;
  9. import java.util.*;
  10. @RestController
  11. @RequestMapping("/user")
  12. public class UserController {
  13. protected Response result(ExceptionMsg msg){
  14. return new Response();
  15. }
  16. protected Response result(){
  17. return new Response();
  18. }
  19. @Autowired
  20. private UserRepository userRepository;
  21. @RequestMapping(value = "",method = RequestMethod.GET)
  22. public ReponseData getUserList(){
  23. List<User> list = new ArrayList<>(userRepository.findAll());
  24. return new ReponseData(ExceptionMsg.SUCCESS,list);
  25. }
  26. @RequestMapping(value = "",method = RequestMethod.POST)
  27. public ReponseData add(User user) {
  28. userRepository.save(user);
  29. List<User> list = new ArrayList<>(userRepository.findAll());
  30. return new ReponseData(ExceptionMsg.SUCCESS,user);
  31. }
  32. @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
  33. public Response delete(@PathVariable("id") Long id) {
  34. userRepository.deleteById(id);
  35. return result(ExceptionMsg.SUCCESS);
  36. }
  37. @RequestMapping(value = "/{id}",method = RequestMethod.PUT)
  38. public ReponseData update(User user) {
  39. userRepository.save(user);
  40. return new ReponseData(ExceptionMsg.SUCCESS,user);
  41. }
  42. @RequestMapping(value = "/{id}",method = RequestMethod.GET)
  43. public ReponseData findUser(@PathVariable("id") int id) {
  44. Optional<User> user = userRepository.findById((long) id);
  45. if (user.get()!=null) {
  46. return new ReponseData(ExceptionMsg.SUCCESS,user);
  47. }
  48. return new ReponseData(ExceptionMsg.FAILED,user);
  49. }
  50. }

3. 用Swagger实现接口文档

    在项目开发中,一般都是前后端分离开发的,需要由前后端工程师共同定义接口:编写接口文档,之后大家都根据这个接口文档进行开发、维护。为了便于编写和维护稳定,可以使用Swagger来编写API接口文档,以提升团队的沟通效率。

  3.1 配置Swagger

  (1)添加Swagger依赖

  1. <dependency>
  2. <groupId>io.springfox</groupId>
  3. <artifactId>springfox-swagger2</artifactId>
  4. <version>2.7.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>io.springfox</groupId>
  8. <artifactId>springfox-swagger-ui</artifactId>
  9. <version>2.7.0</version>
  10. </dependency>

  (2)创建Swagger配置类

  1. package com.itheima.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import springfox.documentation.builders.ApiInfoBuilder;
  5. import springfox.documentation.builders.PathSelectors;
  6. import springfox.documentation.builders.RequestHandlerSelectors;
  7. import springfox.documentation.service.ApiInfo;
  8. import springfox.documentation.spi.DocumentationType;
  9. import springfox.documentation.spring.web.plugins.Docket;
  10. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  11. /**
  12. * Swagger配置类
  13. * 在与Spring Boot集成时,放在与Application.java同级的目录下
  14. * 通过注解@Configuration让Spring来加载该类配置
  15. * 再通过注解@EnableSwagger2来启用Swagger2
  16. */
  17. @Configuration
  18. @EnableSwagger2
  19. public class Swagger2 {
  20. /**
  21. * 创建API应用
  22. * apiInfo增加API相关信息
  23. * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现
  24. * 本例采用指定扫描的包路径来定义指定要建立API的目录
  25. */
  26. @Bean
  27. public Docket createRestApi(){
  28. return new Docket(DocumentationType.SWAGGER_2)
  29. .apiInfo(apiInfo())
  30. .select()
  31. .apis(RequestHandlerSelectors.basePackage(""))
  32. .paths(PathSelectors.any())
  33. .build();
  34. }
  35. /**
  36. * 创建该API的基本信息(这些基本信息会展现在文档页面中)
  37. * 访问地址:http:/项目实际地址/swagger-ui.html
  38. */
  39. private ApiInfo apiInfo(){
  40. return new ApiInfoBuilder()
  41. .title("RESTful APIs")
  42. .description("RESTful APIs")
  43. .termsOfServiceUrl("http://localhost:8080/")
  44. .contact("long")
  45. .version("1.0")
  46. .build();
  47. }
  48. }

  代码解释如下。

  • @Configuration:   让Spring来加载该类配置。
  • @EnableSwagger2:  启用 Swagger2.createRestApi 函数创建 Docket 的 Bean
  • apilnfo():用来展示该API的基本信息。
  • select():返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现。
  • apis(RequestHandlerSelectors.basePackage()):配置包扫描路径。Swagger 会扫描包下所有Controller定义的API,并产生文档内容。如果不想产生API,则使用注解 @Apilgnore

  (3)编写接口文档

  在完成上述配置后,即生成了文档,但是这样生成的文档主要针对请求本身,而描述自动根据方法等命名产生,对用户并不友好。所以,通常需要自己增加一些说明以丰富文档内容。可以通过以下注解来增加说明。

  • @Api:描述类/接口的主要用途。
  • @ApiOperation:描述方法用途,给API增加说明。
  • @ApilmplicitParam:   挡述方法的参数,给参数増加说距。
  • @ApilmplicitParams:   描述方法的参数(Multi-Params ),给参数增加说明。
  • @Apilgnore:忽略某类/方法/参数的义档。
  1. @ApiOperation(value = "删除用户",notes = "根据URL的id来指定删除对象")
  2. @ApiImplicitParam(name = "id",value = "文章ID",required = true,dataType = "Long")
  3. public String del(@PathVariable("id") Long id) {
  4. userRepository.deleteById(id);
  5. return "SUCCESS";
  6. }

  完成上述代码后,启动项目,访问http://localhost:8080/swagger-ui.html就能看到所展示的RESTful API的页面,可以通过单击具体的API测试请求,来查看代码中配置的信息,以及参数的描述信息。

  

  3.2 用RestTemplate发起请求

  (1)认识 RestTemplate

  在Java应用程序中访问RESTful服务,可以使用Apache的HttpClient来实现。不过此方法使用起来太烦琐。Spring提供了一种简单便捷的模板类一RestTemplate来进行操作。RestTemplate是Spring提供的用于访问REST服务的客户端,它提供了多种便捷访问远程HTTP 服务的方法,能够大大提高客户端的编写效率。

  RestTemplate用于同步Client端的核心类,简化与HTTP服务的通信。在默认情况下, RestTemplate默认依赖JDK的HTTP连接工具。也可以通过setRequestFactory属性切换到不同的 HTTP 源,比如 Apache HttpComponents, Netty 和 OkHttp。

  RestTemplate简化了提交表单数据的难度,并附帯自动转换为JSON格式数据的功能。该类的入口主要是根据HTTP的6种方法制定的,见下表。

  

  此外,exchange和excute也可以使用上述方法。

  RestTemplate 默认使用 HttpMessageConverter 将 HTTP 消息转换成 POJO,或从 POJO 转换成HTTP消息,默认情况下会注册MIME类型的转换器,但也可以通过setMessageConverters 注册其他类型的转换器。

  (2)用 RestTemplate 发送 GET 请求

  1.创建测试实体

  1. package com.intehel.domain;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. @Data
  5. @AllArgsConstructor
  6. @NoArgsConstructor
  7. public class User {
  8. private long id;
  9. private String name;
  10. }

  2.创建用于测试的API

  1. package com.intehel.controller;
  2. import com.intehel.domain.User;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.RequestMethod;
  5. import org.springframework.web.bind.annotation.RestController;
  6. @RestController
  7. public class TestController {
  8. @RequestMapping(value = "/getParameter", method = RequestMethod.GET)
  9. public User getParameter(User user){
  10. return user;
  11. }
  12. @RequestMapping(value = "/getuser1", method = RequestMethod.GET)
  13. public User user1(){
  14. return new User(1,"buretuzi");
  15. }
  16. @RequestMapping(value = "/postuser", method = RequestMethod.POST)
  17. public User postUser(User user){
  18. System.out.println("name:"+user.getName());
  19. System.out.println("id:"+user.getId());
  20. return user;
  21. }
  22. }

  3.使用getForEntity测试

  (1)返回String,不带参数,见以下代码:

  1. package com.intehel;
  2. import org.junit.Test;
  3. import org.springframework.boot.web.client.RestTemplateBuilder;
  4. import org.springframework.http.ResponseEntity;
  5. import org.springframework.web.client.RestTemplate;
  6. public class test {
  7. @Test
  8. public void nparameters(){
  9. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  10. RestTemplate client = restTemplateBuilder.build();
  11. ResponseEntity<String> responseEntity = client.getForEntity("http://localhost:8080/getuser1",String.class);
  12. System.out.println(responseEntity.getBody());
  13. }
  14. }

  控制台打印结果:

  11:01:35.973 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8080/getuser1
  11:01:35.991 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
  11:01:36.073 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
  11:01:36.073 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.lang.String] as "application/json"
  {"id":1,"name":"buretuzi"}

  (2)返回String,带参数的例子。

     在调用服务提供者提供的接口时,有时需要传递参数,有以下两种不同的方式。

    ①用一个数字做占位符。最后是一个可变长度的参数,用来替换前面的占位符。使用方法见以下代码:

  1. @Test
  2. public void withparameters(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. RestTemplate client = restTemplateBuilder.build();
  5. ResponseEntity<String> responseEntity = client.getForEntity("http://localhost:8080/getParameter?name={1}&id={2}",String.class,"buretuzi",2);
  6. System.out.println(responseEntity.getBody());
  7. }

  打印结果:

  11:06:20.893 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8080/getParameter?name=buretuzi&id=2
  11:06:20.893 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
  11:06:20.908 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
  11:06:20.908 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.lang.String] as "application/json"
  {"id":2,"name":"buretuzi"}

   ② 使用name={name}这种形式。最后一个参数是一个map, map的key即为前边占位符的名字,map的value为参数值。使用方法见以下代码:

  1. @Test
  2. public void withparameters2(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. RestTemplate client = restTemplateBuilder.build();
  5. Map<String,String> map = new HashMap<String,String>();
  6. map.put("name", "buretuzi");
  7. ResponseEntity<String> responseEntity = client.getForEntity("http://localhost:8080/getParameter?name={name}&id=3",String.class,map);
  8. System.out.println(responseEntity.getBody());
  9. }

  打印结果:

  11:19:28.842 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8080/getParameter?name=buretuzi&id=3
  11:19:28.848 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
  11:19:28.880 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
  11:19:28.880 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.lang.String] as "application/json"
  {"id":3,"name":"buretuzi"}  

  (3)返回对象,见以下代码:

  1. @Test
  2. public void restUser(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. RestTemplate client = restTemplateBuilder.build();
  5. ResponseEntity<User> responseEntity = client.getForEntity("http://localhost:8080/getuser1",User.class);
  6. System.out.println(responseEntity.getBody().getId());
  7. System.out.println(responseEntity.getBody().getName());
  8. }

  打印结果:

    1
    buretuzi

  4.使用 getForObject

  getForObject函数是对getForEntity函数的进一步封装。如果你只关注返回的消息体的内容, 对其他信息都不关注,则可以使用getForObject,见以下代码:

  1. @Test
  2. public void getForObject(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. RestTemplate client = restTemplateBuilder.build();
  5. User user = client.getForObject("http://localhost:8080/getuser1",User.class);
  6. System.out.println(user.getName());
  7. }

  (3)用 RestTemplate 发送 POST 请求

  在 RestTemplate 中,POST 请求可以通过 postForEntity、postForObject、postForLocation、exchange四种方法来发起。

  1.方法一:使用 postForEntity

  • postForEntity(String url,Object request,Class responseType,Object... urlVariables)
  • postForEntity(String url,Object request,Class responseType,Map urlVariables)
  • postForEntity(String url,Object request,Class responseType)

  2.方法二:使用 postForObject

  • postForObject(String url,Object request,Class responseType,Object... urlVariables)
  • postForObject(String url,Object request,Class responseType,Map urlVariables)
  • postForObject(String url,Object request,Class responseType)

  3.方法三:使用 postForLocation

  postForLocation也用于提交资源。在提交成功之后,会返回新资源的URI。它的参数和前面两种方法的参数基本一致,只不过该方法的返回值为URI,表示新资源的位置

  • postForLocation(String url,Object request,Object... urlVariables)
  • postForLocation(String url,Object request,Map urlVariables)
  • postForLocation(String url,Object request)

  4.方法四:使用exchange

  使用exchange方法可以指定调用方式,使用方法如下:

  ResponseEntity<String> response=tempIate.exchang(newUrl, HttpMethod.DELETE, request, String.class);

  5.实现发送POST请求

  (1)使用 postForEntity

  1. @Test
  2. public void postForEntity(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. RestTemplate client = restTemplateBuilder.build();
  5. MultiValueMap<String,Object> paramMap = new LinkedMultiValueMap<String,Object>();
  6. paramMap.add("name","buretuzi");
  7. paramMap.add("id",4);
  8. ResponseEntity<User> responseEntity = client.postForEntity("http://localhost:8080/postuser",paramMap,User.class);
  9. System.out.println(responseEntity.getBody().getName());
  10. }

  代码解释如下。

  • MultiValueMap:封装参数,千万不要替换为Map与HashMap,否则参数无法被传递
  • postForEntity("url", paramMap, User.class):参数分别表示要调用的服务的地址、上传的参数、返回的消息体的数据类型。

  运行测试单元,控制台输出如下结果:

  11:39:07.001 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP POST http://localhost:8080/postuser
  11:39:07.032 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json]
  11:39:07.032 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [{name=[buretuzi], id=[4]}] with           org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
  11:39:07.482 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
  11:39:07.482 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [com.intehel.domain.User]
  buretuzi 

  (2)使用 postForObject

  postForObject和getForObject相对应,只关注返回的消息体,见以下代码:

  1. @Test
  2. public void postForObject(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. RestTemplate client = restTemplateBuilder.build();
  5. MultiValueMap<String,Object> paramMap = new LinkedMultiValueMap<String,Object>();
  6. paramMap.add("name","buretuzi");
  7. paramMap.add("id",4);
  8. String response = client.postForObject("http://localhost:8080/postuser",paramMap,String.class);
  9. System.out.println(response);
  10. }

  运行测试单元,控制台输岀如下结果:

  11:44:46.470 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP POST http://localhost:8080/postuser
  11:44:46.470 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
  11:44:46.486 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [{name=[buretuzi], id=[4]}] with org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
  11:44:46.918 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
  11:44:46.918 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.lang.String] as "application/json"
  {"id":4,"name":"buretuzi"} 

  (3)使用postForexchange,见以下代码:

  1. @Test
  2. public void postForExchange(){
  3. MultiValueMap<String,Object> paramMap = new LinkedMultiValueMap<String,Object>();
  4. paramMap.add("name","buretuzi");
  5. paramMap.add("id",4);
  6. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  7. RestTemplate client = restTemplateBuilder.build();
  8. HttpHeaders headers = new HttpHeaders();
  9. HttpEntity<MultiValueMap<String,Object>> httpEntity = new HttpEntity<MultiValueMap<String,Object>>(paramMap,headers);
  10. ResponseEntity<String> response = client.exchange("http://localhost:8080/postuser", HttpMethod.POST, httpEntity,String.class,paramMap);
  11. System.out.println(response.getBody());
  12. }

  运行测试单元,控制台输岀如下结果:

  11:59:12.988 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP POST http://localhost:8080/postuser
  11:59:13.004 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
  11:59:13.004 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [{name=[buretuzi], id=[4]}] with org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
  11:59:13.436 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
  11:59:13.436 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.lang.String] as "application/json"
  {"id":4,"name":"buretuzi"}

  (4)使用 postForLocation

  它用于提交数据,并获取返回的URI。一般登录、注册都是POST请求,操作完成之后,跳转到某个页面,这种场景就可以使用postForLocation所以,先要添加处理登录的API,见以下代码:

  1. package com.intehel.controller;
  2. import com.intehel.domain.User;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.web.bind.annotation.*;
  5. import javax.servlet.http.HttpServletRequest;
  6. @Controller
  7. public class TestController {
  8. @RequestMapping(path = "success",method = RequestMethod.POST)
  9. @ResponseBody
  10. public String loginSuccess(String name){
  11. return "welcome"+name;
  12. }
  13. @RequestMapping(path = "post",method = RequestMethod.POST)
  14. public String post(HttpServletRequest request,
  15. @RequestParam(value = "name",required = false)String name,
  16. @RequestParam(value = "password",required = false)String password,
  17. @RequestParam(value = "id",required = false)Integer id){
  18. return "redirect:/success?name="+name+"&id="+id;
  19. }
  20. }

  然后使用postForLocation请求,用法见以下代码:

  1. @Test
  2. public void postForLocation(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. MultiValueMap<String,Object> paramMap = new LinkedMultiValueMap<String,Object>();
  5. paramMap.add("name","buretuzi");
  6. paramMap.add("id",4);
  7. RestTemplate client = restTemplateBuilder.build();
  8. URI response = client.postForLocation("http://localhost:8080/post",paramMap);
  9. System.out.println(response);
  10. }

  运行测试单元,控制台输出如下结果:

  13:59:06.415 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP POST http://localhost:8080/post
  13:59:06.415 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [{name=[buretuzi], id=[4]}] with   org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
  13:59:06.951 [main] DEBUG org.springframework.web.client.RestTemplate - Response 302 FOUND
  http://localhost:8080/success?name=buretuzi&id=4

  (4)用 RestTemplate 发送 PUT和DELETE 请求

  1.PUT请求

  在RestTemplate中,发送“修改”请求和前面介绍的postForEntity方法的参数基本一致, 只是修改请求没有返回值,用法如下:

  1. @Test
  2. public void put(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. RestTemplate client = restTemplateBuilder.build();
  5. User user = new User();
  6. user.setName("buretuzi");
  7. client.put("http://localhost:8080/{1}",user,4);
  8. }

  2.DELETE 请求

  删除请求,可以通过调用DELETE方法来实现,用法见以下代码:

  1. @Test
  2. public void delete(){
  3. RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
  4. RestTemplate client = restTemplateBuilder.build();
  5. client.delete("http://localhost:8080/{1}",4);
  6. }

  最后的“4”用来替換前面的占位符{1}。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/917436
推荐阅读
相关标签
  

闽ICP备14008679号