RESTful-web

spring guides里面有这样一段话:

传统 MVC 控制器与前面提到的 RESTful Web 服务控制器之间的一个关键区别在于 HTTP 响应体的创建方式。传统 MVC 控制器依赖view技术在服务器端将问候数据渲染成 HTML,而 RESTful Web 服务控制器则直接填充并返回一个Greeting对象。该对象的数据将以 JSON 格式直接写入 HTTP 响应。


之前写过 传统 MVC controller 处理HTTP请求的一小段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

@Controller
public class GreetingController{
//HTTP GET 请求映射
@GetMapping("/greeting")
public String greeting(
@RequestParam

//请求参数name的绑定
(name="name", required=false, defaultValue="World")
//name="name"是专门匹配?name=XXXX这个的,required=false表示这个name不是必要的,保证了这个值匹配不到时候不会报错

String name, Model model){
/**
* Model 是什么?
* Model是controller和View传递数据的中介
* 通过在model中写入KV对,我们可以用view引擎,拿model的内容参与html页面渲染,实现请求体参数数据在响应体页面的展示
* model.addAttribute("key",value)就是在做这个
*/
model.addAttribute("name", name);

return "greeting";
}

}

传统MVC控制器使用的是@Controller + Model的形式,数据传递的链路大致为:HTTP请求体 -> @RequestParam(解析url中参数,并绑定)-> (写入)Model ->返回view名称 -> 服务器使用view引擎,拿Model对html模板进行填充,形成完整html -> 服务端渲染html,呈现

这种架构的弊处是,前后端不分离,耦合性强,而且规定了http响应体返回的格式是html


而这里我们学到了新的架构——RESTful ,它使用的是@RestController(@COntroller+@ResponseBody的合体)

举同样的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();

//将HTTP GET请求映射到greeting()方法
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(defaultValue = "World") String name) {

//具体java对象的实例化 Greeting(id,content)
//responseBody是JackSON的形式返回给前端。由前端决定如何处理JSON文件
//此处返回的JSON文件格式如下:
//{
// "id": 1,
// "content": "Hello, User!"
//}
}
return new Greeting(counter.incrementAndGet(),
template.formatted(name));
}
}

RESTful 架构服务的对象不是发起http请求的浏览器,而变成了前端(Vue/React之类)以及移动端等等。所以响应体的内容不再是html,而是结构化的JSON数据,HTTP GET响应 大致的数据链路为:

HTTP请求体 ->
内嵌tomcat服务器 ->
dispatchedServlet ->
处理对应的getmapping的 RestController(处理数据,解析匹配参数)->
返回java对象 ->
(spring自动转成json格式) ->
交给前端处理JSON数据

RESTful架构实现了前后端的分离,因此一个后端可以服务于多个不同的前端架构,只需暴露JSON,后端开发也只需要注重业务逻辑处理于api设计而不用考虑html等如何写,使得分工明确,这也是现代开发更倾向于RESTful的原因。


和之前一样的思路,我们做一个前端发出POST,观察后端REST中数据是如何流动的
我们在Controller中加上PostMapping:

1
2
3
4
5
6
7
8
9
/**
* POST:创建客户
* 浏览器/前端发 JSON → @RequestBody 转成 Customer → save → 返回带 id 的对象(再变 JSON)
*/
//只处理/customers的POST请求
@PostMapping("/customers")
public Customer createCustomer(@RequestBody Customer customer) {
return repository.save(customer);
}

为了做自动测试,我们在/test中写一个REST端点测试,表示我们从前端post一个json文件给服务器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void TestPost(){
client.post()
.uri("/customers")
.contentType(MediaType.APPLICATION_JSON)
.body("""
{
"firstName": "Alice",
"lastName": "Smith"
}
""")
.exchangeSuccessfully()
.expectBody(Customer.class);
}

如果不用自动化测试文件,也可以用powershell中指令代替,效果也是一样的。

1
2
3
4
5
6

Invoke-RestMethod -Method Post `
-Uri http://localhost:8081/customers `
-ContentType "application/json" `
-Body '{"firstName":"Alice","lastName":"Smith"}'


于是,我们可以知道数据流动链路是这样:

测试文件发起POST ->
内嵌Tomcat服务器 ->
DispatchedServlet查找有@POSTMapping映射的controller ->
CustomerController ->
执行具体createCustomer(@RequestBody Customer customer)方法,从请求体中解析出lastname firstname ,生成id创建customer ->
jpa repository 的 save()写入h2数据库 ->
返回customer ->
spring转成json格式,写入http响应 ->
测试捕获结果,检验是否与expectBody格式匹配。

这样我们就从传统mvc思路出发,搭建了新的RESTful web!


Commentarii · 评论