SpringBoot(七)——Restful风格
前言
Restful风格是一种前端页面请求后端接口资源的一种书写形式,该书写形式中包含很多规则以及细节,本篇笔记会尽量说明一下相关的知识点。
本篇笔记属于偷懒的产品,因为该部分知识点十分简单。临近年关,我也不想写太多文字(要大扫除呀~大扫除),直接上干货。
概述
Restful风格与传统的有一些不同,传统的资源请求中只有Get以及Post两种方式来传递参数,而Restful风格将资源请求按照增删改查这基本的数据操作分成了四个基本传递方式。
其中:
- 查询为Get请求;
- 更新为Put(全部字段)或Patch(部分字段);
- 新建为Post;
- 删除为Delete
Restful风格认为只有Get和Post请求十分不合理,应该针对CRUD四种方式分出四种相关的申请方式。其中,Put 和Delete是从Post中分离出来的,可以浅显的理解为Post的子集。具体使用如下:
<script>
function testput(){
var request = new XMLHttpRequest();
request.onreadystatechange = function(){
if (request.status== 200 && request.readyState== 4){
console.log(request.responseText);
document.getElementById("msg").innerText="返回结果:"+request.responseText;
}
}
/*open 方法中的第一个参数就是请求的方式*/
request.open("PUT","http://localhost:8081/springboot-restful/demo");
request.send();
}
</script>
@PutMapping("demo")
public ResponseEntity demoPut(){
// 该方法中的得ResponseEntity后续会说明,暂时大家把它理解为响应给页面的参数的方式
return new ResponseEntity("demoPut is OK!",HttpStatus.OK);
}
// 如果前端页面把提交请求的方式设定为其他方式就得将Controller注解改为对应方法的注解(注解中的资源路径可以相同,理论上同一个资源路径中可以针对四个方法)
@GetMapping("demo")
@PostMapping("demo")
@DeleteMapping("demo")
如果需要在请求资源的时候传递参数的话,我们应该在请求的路径后加入路径作为参数,具体如下:
// 浏览器中请求的资源路径为
http://localhost:8081/springboot-restful/test3/1001
// 控制器写法
@GetMapping("/test3/{id}")
public void test3(@PathVariable("id") String id){
log.debug("成功请求控制器——3");
log.debug("传入的参数:{}",id);
}
如果直接运行上述控制器很可能会出现问题,这个时候,我们需要新增一个注解@ResponseBody
,使用这个注解将返回的资源数据制成JSON格式响应给客户端。
会出错的具体原因我们会在下文后进行说明。
响应数据
控制器中响应给前端客户端的数据在传统Web开发中,我们最早使用的是Session、response等Servlet域对象来可以将想要显示到页面的数据加入到浏览器的数据域中;后来在我们使用SpringMVC的时候,SpringMVC中为我们提供了Model(模型)的概念,我们可以使用该模型将数据 加入到对象域中;再后来,SpringMVC为我们提供了模型和视图的概念(ModelAndView),这个时候我们发现,SpringMVC的视图转换器的局限性,控制器中的返回状态在日益提升的业务需求中为我们提升了更加便捷的返回数据格式。
ResponseEntity,一个可以将返回的数据和状态码一起响应给前端页面的数据格式。他又五个构造方法,在此我们不做过多赘述,简单说明使用方法:
- 我们可以将想要相应的数据放入该数据对象中,响应给客户端:
private static final Logger log = LoggerFactory.getLogger(super.class);
@GetController("test")
public ResponseEntity test(){
log.debug("进入test控制器中");
return new ResponseEntity("控制器执行成功",HttpStatus.OK);
}
其实我们不单单可以将自己手写的数据放入到对应的参数位置,源码中的构造方法如下:
// 参数列表第一个参数是一个泛型,所以我们可以将我们自定义的类型放入这个位置
public ResponseEntity(@Nullable T body, HttpStatus status) {
this(body, null, status);
}
**【注】:**在这种情况下,我们发现该类型是一个很方便的工具类,但是它从很大维度上对业务逻辑进行了总结,而对于我们个人来说,无论学习还是工作中的业务方面并不会覆盖很广阔的方向上。所以我们可以按照ResponseEntity中的逻辑定义属于自己的响应类,下面简单做一个相应的类做个例子:
import org.springframework.http.HttpStatus;
public class ResultEntity {
// 响应给页面的数据对象
private Object result;
// 相应给客户端时的Http状态值
private HttpStatus status;
// 响应给客户端页面时的必要说明
private String msg;
public ResultEntity() {
}
public ResultEntity(Object result, HttpStatus status, String msg) {
this.result = result;
this.status = status;
this.msg = msg;
}
public ResultEntity(Object result, HttpStatus status) {
this.result = result;
this.status = status;
}
public ResultEntity(HttpStatus status, String msg) {
this.status = status;
this.msg = msg;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
public HttpStatus getStatus() {
return status;
}
public void setStatus(HttpStatus status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
这个类在使用的时候,可以按照使用RepsonseEntity类一样,将需要相应给客户端页面的数据按照定义好的规则放入这个类实例的对象中。
public ResultEntity test(){
// 实例化一个自定义类
TestEntity testEntity = new TestEntity();
testEntity.setMsg = "这是一个测试对象";
return new ResultEntity(testEntity,HttpStatus.OK,"test控制器执行成功");
}
状态码
上一个标题中我们说明了ResponseEntity和按照逻辑自定义的ResultEntity,在这两个类中我们都提到过Http响应状态码,这个状态码就是我们Http请求和响应的时候客户端和服务器中的状态信息,它标注着各种问题和错误:404和500是我们经常见到的状态码。Http常见状态码如下所示:
- 200: 一切正常;
- 201:新的资源已经创建完成;
- 204:资源已经成功删除;
- 304:客户端使用缓存数据;
- 400:请求无效,需增加细节解释;
- 401:请求需要用户验证;
- 403:服务器已经理解了请求,但是拒绝服务或这种请求访问是不允许的;
- 404:没有发现资源;
- 422:只有服务器不能处理时提示使用,比如图像不能被格式化,或者重要字段丢失;
- 500:代码错误、逻辑错误等,API开发者应该避免的问题。
总结
现在的项目多数都是前后端分离的项目,曾经的视图转换器在单体项目中大放异彩,甚至后来的分布式项目都有一席之地,知道前后端分离和微服务体系的完善,视图转换器就稍微有一些鸡肋,毕竟前后端分离和微服务这两种架构之间最核心的连接就是各个服务之间的数据连接,所以我们指定了各种语言、服务、技术都可以支持的数据格式,并定义了数据传输的基本信息。
所以个人建议不要在单体项目上浪费太多的时间,单体项目并一定需要很多开发经验,但是要对依旧还在使用的相关技术进行深度的学习和理解。