REST(Representational State Transfer),中文译为“表述性状态转移”,是由Roy Fielding博士在他的博士论文中提出的一种软件架构风格,特别适用于网络应用的设计。REST不是一个标准,而是一种设计原则和约束集,它基于HTTP协议,以资源为中心,通过统一的接口和标准的方法来访问和操作这些资源。以下是REST风格的几个核心概念和原则:
核心概念
- 资源(Resources):在REST中,网络上的所有内容都可以被视为资源。资源可以是文本、图片、视频、服务等任何可以命名的东西。每个资源都有一个唯一的标识符,即URI(Uniform Resource Identifier)
- 表现层(Representations):资源的表现形式,即资源的具体数据表现,如HTML、XML、JSON等。客户端通过HTTP请求获取资源时,服务器返回的是资源的一个表现层,而不是资源本身
- 状态转换(State Transfer):客户端和服务器之间通过HTTP协议进行交互,从而改变客户端的状态。这里的“状态转移”不是指服务器端的状态,而是指通过HTTP请求响应的方式,让客户端从一个状态转移到另一个状态
设计原则
- 客户端-服务器(Client-Server):保持客户端和服务器职责的分离,使得它们可以独立地进化。客户端负责展示,服务器负责数据的管理和业务逻辑
- 无状态(Stateless):服务器不保存客户端的会话信息。每次请求都必须包含理解该请求所必需的所有信息。这提高了系统的可伸缩性,因为服务器不需要为每个用户的会话维护状态
- 可缓存(Cacheable):利用HTTP协议的缓存机制,使得响应可以在客户端、代理服务器等多级进行缓存,减少网络请求,提高响应速度
- 分层系统(Layered System):系统可以设计成多层结构,每一层只与相邻层通信,这样可以简化复杂度,并且允许更容易地添加、修改或移除中间层,而不会影响整体架构
- 统一接口(Uniform Interface):所有资源都通过统一的接口进行访问,主要通过HTTP标准方法(GET, POST, PUT, DELETE等)来实现对资源的增删查改操作
- 按需代码(Code-On-Demand,可选):服务器可以提供可执行代码(如JavaScript),客户端可以选择执行这段代码来实现更丰富的功能。但这不是REST定义中的强制要求
REST风格的应用设计强调简单、灵活和高效,广泛应用于现代Web服务和API设计中,特别是对于需要跨平台、跨语言交互的场景,RESTful API因其规范性和易用性而成为首选。
最佳实践
RESTful风格则是遵循REST原则设计的Web服务。简单来说,当一个Web服务的设计完全符合REST的约束条件和原则时,我们称这个Web服务为RESTful,总体来说,REST是一种架构设计风格,而RESTful是这种风格的具体实践
RESTful API(Representational State Transferful Application Programming Interface)是一种遵循REST架构风格设计的Web服务API。它利用HTTP协议的特性,提供一套统一、简洁、无状态的接口设计模式,用于在客户端和服务器之间交换数据和管理资源。RESTful API的核心在于如何组织和访问网络上的资源,以及如何表述这些资源的状态。以下是RESTful API的一些关键特征和最佳实践:
关键特征
- 资源导向(Resource-Oriented):RESTful API围绕资源展开,每个资源通过唯一的URL(Uniform Resource Locator)来标识,资源的URL应该清晰、直观,反映资源的层次关系
- 标准HTTP方法(Standard HTTP Methods):利用HTTP协议预定义的方法来对资源进行操作,常见的有:
- GET:从服务器检索资源(应该是安全和幂等的)
- POST:向服务器提交数据,常用于创建新资源
- PUT:替换服务器上的现有资源或创建指定资源(如果不存在)
- PATCH:部分更新已有资源
- DELETE:删除指定资源
- 表述层多样性(Diverse Representations):支持多种数据格式(如JSON/XML/YAML等)来表示资源,客户端可以通过Accept头部指定期望的响应格式
- 无状态(Statelessness):服务器不存储关于客户端的上下文信息,每次请求都包含完成该请求所需的所有信息,这有利于扩展性和负载均衡
- 可缓存性(Cachability):利用HTTP的缓存机制,可以对响应进行缓存,减少网络请求,提高效率
最佳实践
- 版本控制:在API的URL中加入版本号,以便于不同版本间的兼容和迁移,如
/api/v1/users
- 使用复数名词:资源的URL推荐使用复数形式,如使用/users而非/user,以更好地表达资源集合的概念
- 过滤、排序和分页:提供查询参数来支持资源列表的过滤、排序和分页,如
/users?state=active&sort=name&limit=10
- 错误处理:使用合适的HTTP状态码来表示错误,如404表示资源未找到,同时返回易于理解的错误消息
- HATEOAS(Hypermedia as the Engine of Application State):虽然在实际应用中较少严格遵循,但理想上,响应中应包含链接,指示客户端下一步可能的动作或相关资源,促进API的自发现性
RESTful API的设计旨在简化客户端与服务端之间的交互,提高系统的可扩展性和可维护性。通过遵循上述原则和最佳实践,可以构建出既强大又易于使用的Web服务接口
一些简单的例子如下所示:
#获取角色信息,1是角色编号
GET /role/1#查询多个角色
GET /roles/{roleName}#新建角色
POST /role/{roleName}/{note}#修改角色
PUT /role/{id}/{roleName}/{note}#使用动词,在REST风格设计中URI不该存在动词
GET /role/get/{id}#按版本获取角色
#这里请注意,当无论何种版本都指向同一个角色时,不建议将版本参数{version}放在URI中
#因为在REST风格中,一个URI就代表一个资源,不同的URI不该指向同一个资源
#可以考虑放在请求头中,这样URI依旧是GET role/{id}, 在请求头中放入版本参数即可
GET /role/{version}/{id}#错误使用HTTP参数,这里问号加id参数是不符合REST风格的
PUT /role/{roleName}?id=1
#可以修改为
PUT role/{id}/{roleName}
@ResponseBody
之前文章的代码中,使用MappingJackson2JsonView
将结果转化为JSON视图,还有更简单的方法,就是使用注解@ResponseBody
,只是它的原理和视图不同,功能上主要用于标注控制器的映射方法,将方法返回的结果转变为JSON数据集展示,示例代码如下
package com.springrest.controller;import com.springrest.pojo.Role;
import com.springrest.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/*** RoleController类负责处理与角色相关的HTTP请求。* 它使用RoleService来执行具体的业务逻辑。*/
@Controller
@RequestMapping("/role")
public class RoleController {/*** 自动注入RoleService实例,用于处理角色相关的业务逻辑。*/@Autowiredprivate RoleService roleService = null;/*** 处理GET请求,根据角色ID获取角色信息。* @param id 角色的唯一标识符。* @return 对应于请求ID的角色对象。*/@GetMapping(value = "/info/{id}")@ResponseBodypublic Role getRole(@PathVariable("id") Long id) {return roleService.getRole(id);}
}
这样在请求/mvc/role/info/2
就可以看到如下的页面了
服务启动过程中经常会遇到的一个问题是无法创建连接,其中有一种原因是数据库的版本和连接驱动类的版本不匹配,如果使用的是MySQL8.0以下的版本,那在POM中添加的依赖应该是
<!-- 引入MySQL数据库连接驱动依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.29</version></dependency>
配置数据源的时候,driverClassName配置应该是props.setProperty("driverClassName", "com.mysql.jdbc.Driver");
而如果MySQL用的是8.0以上的版本,那么POM中应该添加的依赖是
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version> <!-- 使用实际的版本号 --></dependency>
配置数据源的时候,driverClassName配置应该是props.setProperty("driverClassName", "com.mysql.cj.jdbc.Driver");
但这是在Spring5基础上的,如果使用低版本的Spring MVC,需要自己创建MappingJackson2HttpMessageConverter
(如下代码所示),Spring5之后RequestMappingHandlerAdapter
再初始化过程中,会自动注册MappingJackson2HttpMessageConverter
对象,所以只需要依赖相关的JSON类库就可以了,自己创建的话代码如下所示;
/*** 初始化并配置RequestMappingHandlerAdapter,用于处理RESTful API的请求。* @return 配置好的RequestMappingHandlerAdapter实例。*/@Bean(name = "requestMappingHandlerAdapter")public HandlerAdapter initRequestMappingHandlerAdapter() {// 创建RequestMappingHandlerAdapter实例RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();// 创建MappingJackson2HttpMessageConverter实例,用于处理JSON格式的HTTP消息MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();// 定义支持的媒体类型为application/jsonMediaType mediaType = MediaType.APPLICATION_JSON;// 创建支持的媒体类型列表,并添加application/jsonList<MediaType> mediaTypes = new ArrayList<MediaType>();mediaTypes.add(mediaType);// 配置converter支持的媒体类型converter.setSupportedMediaTypes(mediaTypes);// 将converter添加到handler adapter的转换器列表中adapter.getMessageConverters().add(converter);// 返回配置好的handler adapterreturn adapter;}
也可以通过XML创建MappingJackson2HttpMessageConverter
<!-- 配置处理HTTP请求和响应的适配器 --><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><!-- 配置消息转换器,用于支持JSON格式的请求和响应 --><property name="messageConverters"><list><!-- 引用JSON消息转换器 bean --><ref bean = "converter"/></list></property></bean><!-- 配置JSON消息转换器 --><bean id="converter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"><!-- 配置支持的媒体类型,这里指定为UTF-8编码的JSON --><property name="supportedMediaTypes"><list><value>application/json;charset=UTF-8</value></list></property></bean>
SpringMVC的REST风格
为了更好地支持REST风格,Spring MVC4.3之后更新了对REST更多的支持,增加了更多的注解,例如@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
、@RestController
等等,大致可以将这些注解分为两类,其一是映射路由类,包括@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
等,其二是标注控制器类,就只有一个@RestController
,它将控制器映射方法的返回结果默认为JSON数据集
Rest风格的注解
REST风格映射路由,实际上是使用@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
等注解简化@RequestMapping
的编写,例如@GetMapping("/info/{id}")
就相当于@RequestMapping(value="/info/{id}",method=RequestMethod.GET)
,对应的其他几个也是类似的等效,但这些注解和@RequestMapping
的不同是,它们只能标注在方法上,不能标注在类上
package com.springrest.vo;/*** 结果消息类,用于封装操作结果的成功状态和相关消息。*/
public class ResultMessage {/*** 操作是否成功的标志。*/private Boolean success = false;/*** 操作结果的消息,用于描述操作的具体情况。*/private String message = null;/*** 构造函数,用于创建一个带有成功状态和消息的结果消息对象。** @param success 操作的成功状态。* @param message 操作的结果消息。*/public ResultMessage(Boolean success, String message) {this.success = success;this.message = message;}/*** 默认构造函数,用于创建一个成功状态为false,消息为空的结果消息对象。*/public ResultMessage() {}/*** 获取操作成功的标志。** @return 操作成功的布尔值。*/public Boolean getSuccess() {return success;}/*** 设置操作成功的标志。** @param success 操作的成功状态。*/public void setSuccess(Boolean success) {this.success = success;}/*** 获取操作结果的消息。** @return 操作结果的消息字符串。*/public String getMessage() {return message;}/*** 设置操作结果的消息。** @param message 操作结果的消息。*/public void setMessage(String message) {this.message = message;}}
package com.springrest.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;import com.springrest.pojo.Role;
import com.springrest.service.RoleService;
import com.springrest.vo.ResultMessage;@RestController
@RequestMapping("/role2")
public class RoleControllerII {@Autowiredprivate RoleService roleService = null;@GetMapping("/page")public ModelAndView page() {ModelAndView mv = new ModelAndView("restful");return mv;}@GetMapping("/info/{id}")public Role getRole(@PathVariable("id") Long id) {return roleService.getRole(id);}@PostMapping("/")public ResultMessage newRole(@RequestBody Role role) {Integer result = roleService.insertRole(role);if (result > 0) {return new ResultMessage(true, "新增角色成功,编号为:" + role.getId());}return new ResultMessage(false, "新增角色失败!");}@PutMapping("/")public ResultMessage updateRole(@RequestBody Role role) {Integer result = roleService.updateRole(role);if (result > 0) {return new ResultMessage(true, "修改角色成功,编号为:" + role.getId());}return new ResultMessage(false, "修改角色失败!");}@DeleteMapping("/{id}")public ResultMessage deleteRole(@PathVariable("id") Long id) {Integer result = roleService.deleteRole(id);if (result > 0) {return new ResultMessage(true, "删除角色成功,编号为:" + id);}return new ResultMessage(false, "新增角色失败!编号为" + id);}
}
在Controller类上标注了@RestController
,表示该控制器将采用REST风格,其他的URI都采用了REST风格设计,这里需要特别注意的是public ModelAndView page()
方法,它返回的是ModelAndView对象,而不是字符串,因为标注了@RestController
后,视图解析器就失去了解析字符串的能力,必须使用ModelAndView才能定位到视图,而page返回一个的是一个字符串"restful",它指向一个/WEB-INF/jsp/JSP
文件,源码如下
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>REST风格测试</title><script type="text/javascript"src="https://code.jquery.com/jquery-3.2.1.min.js"></script><script type="text/javascript"><!-- 此处加入对应的JavaScript脚本,进行测试 -->function post() {var role = {'roleName' : 'role_name_new','note' : "note_new"};$.post({url : "./",//此处需要告知传递参数类型为JSON,不能缺少contentType : "application/json",//将JSON转化为字符串传递data : JSON.stringify(role),//成功后的方法success : function(result) {if (result == null || result.success == false) {alert("插入失败");return;}alert(result.message);}});}post();function put() {var role = {'id' : 15,'roleName' : 'role_name_update','note' : "note_update"};$.ajax({url : "./", // 此处告知使用PUT请求type :'PUT', //此处需要告知传递参数类型为JSON,不能缺少contentType : "application/json",//将JSON转化为字符串传递data : JSON.stringify(role),success : function(result, status) {if (result == null) {alert("结果为空")} else {alert(JSON.stringify(result));}}});}put();function del() {var id = 17;$.ajax({url : "./" + id, // 告知请求类型为“DELETE”type :'DELETE', success : function(result) {if (result == null) {alert("后台出现异常。")} else {alert(result.message);}}});}del();</script></head><body></body>
</html>
JSP文件中加入了JQuery脚本,使用它来简化验证新建的控制器,例如使用了$.post(...)
对后端发送Ajax请求,它代表发送POST请求到后端,并组织了一个媒体类型为JSON的请求体发送到后端,这很显然就能匹配上控制器的newRole方法,其他的请求同理
以上是一些正常情况,但经常会出现后端不能正常返回的情况,比如尝试访问编号为1000的角色信息,但数据库中并没有这个角色,用如下代码模拟
function get() {var id = 1000;// 通过GET请求获取角色信息$.get("./info/" + id, function(role) { alert("role_name-> " + role.roleName); });}get();
如果角色不存在而返回一个空值,很显然不是友好的结果,比较好的处理是提示用户不存在,实际上使用HTTP请求会有响应码,比如200,比如POST请求创建资源的响应码201分别表示成功,使用响应码比较简单,Spring中提供了枚举类HttpStatus
定义各种HTTP响应码,同时提供了注解@ResponseStatus
, 修改一下控制器的newRole
方法
/*** 通过POST请求创建新角色。** @param role 包含新角色信息的请求体。* @return 如果角色创建成功,返回包含成功消息和角色ID的结果消息;如果创建失败,返回失败消息。*/@PostMapping("/")// 定义响应码为创建成功(201)@ResponseStatus(HttpStatus.CREATED)public ResultMessage newRole(@RequestBody Role role) {// 调用角色服务插入新角色Integer result = roleService.insertRole(role);// 根据插入结果判断角色创建是否成功if (result > 0) {// 如果插入成功,返回成功消息和角色IDreturn new ResultMessage(true, "新增角色成功,编号为:" + role.getId());}// 如果插入失败,返回失败消息return new ResultMessage(false, "新增角色失败!");}
然后执行到这个方法的时候会看到如下的信息
使用注解@ResponseStatus
,得到了状态码201,状态码比响应码更准确,可以通过状态码确定结果是否正确,这样客户端便可以通过状态码分析请求的结果,然而仅仅有状态码是不够的,有时候请求的失败是后端的限制造成的,比如请求编号为200的角色对象,事实上如果它根本不存在,这个时候应该把状态和原因插入响应头,这样请求者就能更明确地知道原因,并能更便利且直接的提示给用户,处理此类问题,SpringMVC提供了类ResponseEntity<T>
,这个类存在3个属性status
:HttpStatus类型,表示响应码,headers
:HTTP响应头,可以自定义消息,body
:响应体,HTTP请求响应的正文
/*** 执行删除操作的函数。* 该函数通过AJAX请求向服务器发送一个DELETE请求,以删除指定的资源。* 请求成功后,根据服务器返回的结果展示相应的提示信息。*/function del() {// 定义待删除资源的IDvar id = 17;// 发起AJAX请求$.ajax({// 构造请求的URL,基于当前路径和资源IDurl : "./" + id,// 告知请求类型为“DELETE”type :'DELETE',// 请求成功回调函数success : function(result) {// 判断服务器返回的结果是否为空if (result == null) {// 如果结果为空,提示“后台出现异常”alert("后台出现异常。")} else {// 如果结果不为空,显示服务器返回的提示信息alert(result.message);}},// 请求错误回调函数,当执行Ajax请求返回500时,则执行error属性对应的如下方法error:function (request, textStatus, errorThrown){// 显示请求错误的提示信息alert('访问后端失败'+ errorThrown)}});}
上边这段代码中,有个error对应的函数,如果请求错误就会回调该函数,就是当执行Ajax请求返回500时,则执行error属性对应的方法,然而同类的还有很多状态码1xx、2xx、3xx、4xx、5xx等如果每个都这么写代码就会相当复杂
通过status可以设置HTTP的响应码,而一般来说可以设置为200,即便产生错误请求也可以设置为200,这样有利于客户端的编写;Header属性可以设置一些值,作为服务器后端的返回信息,例如设置"success"属性表示该请求是否正常,如果不正常再通过属性"message"告诉服务器后端的问题是什么,这样更有利于客户端的编写,在Controller中新增方法,代码如下
@GetMapping("/info2/{id}")public ResponseEntity<Role> getRole2(@PathVariable("id") Long id) {// 响应体Role body = roleService.getRole(id);// 响应头HttpHeaders headers = new HttpHeaders();if (body != null) { // 获取角色成功headers.add("success", "true");headers.add("message", "ok!!");} else { // 获取角色失败headers.add("success", "false");headers.add("message", "no id=[" + id + "] role info!!");}// 创建ResponseEntityResponseEntity<Role> roleEntity = new ResponseEntity<>(body, headers, HttpStatus.OK);return roleEntity;}
然后用JQuery模拟请求,代码如下
function get2() {var id = 200;$.ajax({type: "get",url: './info2/' +id,success: function(role,status,xhr) {// 获取响应头var success = xhr.getResponseHeader("success");// 通过响应头判定获取失败if ("false" == success) { // 响应错误信息var message = xhr.getResponseHeader("message");alert(message);} else { // 获取结果成功alert(role.roleName)}}});}get2();
在执行到对应的控制器方法后,会的到如下信息
这样前端也可以更好的利用这些资源,但会增加一些代码量,如果有很好的开发规范,也不算什么大问题
RestTemplate
在当今的架构中,微服务已经是主流,而在微服务中,会将一个很大的系统拆分为多个子系统,REST风格请求是系统之间交互的基本方式,通常情况下各子系统或者各服务会以HTTP的REST风格暴露服务接口,各子系统或服务之间通过RestTemplate进行服务调用完成交互的目的,而SpringMVC提供的RestTemplate的作用是简化调用过程的,实例代码如下
package com.springrest.rest.client;import java.util.HashMap;
import java.util.Map;import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;import com.springrest.pojo.Role;
import com.springrest.vo.ResultMessage;public class RestTemplateDemo {// 创建RestTemplateprivate static RestTemplate restTemplate = new RestTemplate();// 基础HTTP请求路径private static String baseUrl = "http://localhost:8080/springrest_war/mvc";public static void main(String[] args) {
// testGet();
// testPost();
// testDelet();
// testPut();
// testEnity();exchange();}/*** 通过HTTP GET请求获取角色信息。* 此方法演示了如何使用RestTemplate从指定的URL获取特定角色的信息。* 它通过将URL模板与特定ID结合使用,构建一个请求URL,并期望返回一个Role对象。* @see Role 用于表示角色的数据类。* @see RestTemplate 用于执行RESTful请求的Spring框架类。*/private static void testGet() {// 构建请求URL,其中{id}是一个占位符,用于动态插入角色ID。String url = baseUrl + "/role2/info/{id}";// 使用RestTemplate的getForObject方法,从指定URL获取Role对象。// 1L是参数,代替URL中的{id}占位符Role role = restTemplate.getForObject(url, Role.class, 1L);// 输出角色名称。System.out.println(role.getRoleName());}/*** 使用RESTful API进行角色信息的创建测试。* 通过POST请求向指定URL发送角色信息,期望返回操作结果的消息。* 这个方法展示了如何使用Spring的RestTemplate类进行HTTP请求,以及如何处理响应。*/private static void testPost() {// 初始化HTTP请求头,指定请求内容类型为JSON。HttpHeaders headers = new HttpHeaders();// 设置请求内容为JSON类型headers.setContentType(MediaType.APPLICATION_JSON);// 创建一个新的角色实例,设置角色的名称和备注。Role role = new Role("tmpl_name", "tmpl_note");// 构建HTTP请求实体,包含角色信息和请求头,role作为请求体对象HttpEntity<Role> request = new HttpEntity<>(role, headers);// 拼接URL,指定请求的资源路径。String url = baseUrl + "/role2/";// 这里使用了RestTemplate的postForObject方法,该方法用于发送POST请求并解析响应,期望返回一个ResultMessage对象,其中包含操作结果的消息。ResultMessage resultMsg = restTemplate.postForObject(url, request, ResultMessage.class);// 输出操作结果的消息。System.out.println(resultMsg.getMessage());}/*** 测试删除操作。* 该方法通过发送一个DELETE请求到指定的URL来删除一个角色。* 删除操作的特定目标由URL中的{id}占位符和请求参数中的"id"值共同确定。* 使用REST模板的delete方法简化了HTTP删除请求的发送过程。*/private static void testDelete() {// 初始化请求参数映射,用于传递删除操作的特定ID。Map<String, Object> params = new HashMap<>();params.put("id", 20);// 构建请求的URL,其中包括基础URL和动态部分{id}。String url = baseUrl + "/role2/{id}";// 发送DELETE请求到指定URL,带上参数。restTemplate.delete(url, params);}/*** 测试使用REST模板更新角色信息的方法。* 该方法通过构造HTTP请求,包括请求头和请求体,来更新指定角色的信息。* 请求体中包含了角色的名称和备注信息,以及要更新的角色ID。* 使用REST模板的put方法发送PUT请求到指定的URL,完成角色信息的更新。*/private static void testPut() {// 初始化HTTP请求头,指定请求内容类型为JSONHttpHeaders headers = new HttpHeaders();// 设置请求内容为JSON类型headers.setContentType(MediaType.APPLICATION_JSON);// 创建一个新的角色对象,设置角色的名称、备注和IDRole role = new Role("u_tmpl_name", "u_tmpl_note");role.setId(19L);// 构造包含请求头和请求体的HTTP请求实体,role作为请求体对象HttpEntity<Role> request = new HttpEntity<>(role, headers);// 拼接角色信息更新的URLString url = baseUrl + "/role2/";// 使用REST模板发送PUT请求,更新角色信息restTemplate.put(url, request);}/*** 测试通过RESTful API获取实体对象。* 该方法通过发送HTTP GET请求到指定URL来获取一个Role实体。如果请求成功,它将打印出角色名称;* 如果请求失败,它将打印出错误消息。* 使用RestTemplate类来发送HTTP请求,并通过ResponseEntity来处理响应,包括响应体和响应头信息。*/private static void testEnity() {// 构建请求URL,其中{id}是一个占位符,用于动态插入角色ID。String url = baseUrl + "/role2/info2/{id}";// 指定要查询的角色ID。Long id = 1L;// 发送GET请求并获取响应实体。ResponseEntity<Role> roleEntity = restTemplate.getForEntity(url, Role.class, id);// 从响应头中获取"success"字段,判断请求是否成功。String success = roleEntity.getHeaders().get("success").get(0);// 将"success"字段的值转换为boolean类型。boolean flag = Boolean.parseBoolean(success);// 如果请求成功。if (flag) { // 获取成功// 提取响应体中的Role对象。Role role = roleEntity.getBody();// 打印角色名称。System.out.println(role.getRoleName());} else {// 如果请求失败,从响应头中获取"message"字段,获取后端响应头信息String message = roleEntity.getHeaders().get("message").get(0);System.out.print(message);}}/*** 调用API交换角色信息。* 该方法通过PUT请求更新指定角色的信息。它构造请求URL、请求头和请求体,然后发送请求。* 请求体是一个Role对象,包含要更新的角色名称和备注信息。* 方法打印出API响应中的消息部分。*/private static void exchange() {// 构造请求的URLString url = baseUrl + "/role2/";// 初始化HTTP请求头,指定请求内容类型为JSONHttpHeaders headers = new HttpHeaders();// 设置请求内容为JSON类型headers.setContentType(MediaType.APPLICATION_JSON);// 创建一个新的角色对象,设置角色的名称、备注和IDRole role = new Role("u_tmpl_name", "u_tmpl_note");role.setId(19L);// 将角色对象和请求头封装成一个HttpEntity对象,作为PUT请求的请求体HttpEntity<Role> request = new HttpEntity<>(role, headers);// 发送PUT请求,更新角色信息,并接收响应// 使用更为底层的exchange方法执行请求ResponseEntity<ResultMessage> result = restTemplate.exchange(url, HttpMethod.PUT, request, ResultMessage.class);// 打印响应体中的消息字段System.out.println(result.getBody().getMessage());}}
RestTemplate的PUT和DELETE请求都不返回结果,因此无法鉴别服务调用的成败,但大部分调用都需要鉴别请求结果,正如前边的代码将HTTP请求的结果返回ResponseEntity<T>
一样,对此RestTemplate也给予了支持,正如private static void testEnity()
方法中所写,此外RestTemplate还提供了一个底层的exchange方法,通过这个方法也可以获取PUT请求返回的ResponseEntity<T>
,正如代码中private static void exchange()
方法所写
exchange方法还支持
GET,HEAD,POST,PATCH,DELETE,OPTIONS,TRACE;
,具体情况可以直接看HttpMethod
的源码