RESTful不是一种协议,也不是一种文件格式,更不是一种开发框架。它是一系列设计约束的集合:无状态、将超媒体作为应用状态的引擎等。
以RESTful的风格访问web服务:客户端向标识资源的URL发起一系列HTTP请求,然后服务器在响应中向客户端发送表述。随着时间的推移,客户端通过这些表述建立起了一个资源状态的全景图。最后,客户端发起一个意义重大的PUT、POST或者PATCH请求,将一个表述发送回服务器从而更改资源的状态。
读完这句话你肯定有以下几点疑问:
下面我们一一解答各个术语的含义:
1.资源
资源一般是可以保存到计算机里面的事物。比如网页,电子文档,数据库的一条记录。在Web中,我们使用URL来为每个资源提供一个全球唯一的地址。将一个事物赋以URL,它就会成为一个资源。
2.资源状态
资源状态指的是服务器中资源的状态。例如,服务器中有一个拥有三个邮件的邮件列表,那么邮件列表的状态就是拥有三个邮件的邮件列表。如果用户又发送了一条邮件,那么邮件列表的状态就变为拥有四个邮件的邮件列表。
3.表述
当客户端对一个资源发起一个GET请求的时候,服务器会以一种有效的方式提供一个采集了资源信息的文档作为回应。这就是表述——一种以机器可读的方式对资源当前状态的说明。对于数据库中的一条记录,服务器可以用XML文档、JSON对象、逗号分隔的数值或者用来生成它的SQL INSERT语句来描述它。
4.状态的转换
我们通常都认为表述是服务器发送给客户端的东西,这是由于在我们上网的时候,发送的大部分的请求都是GET请求,我们一直都在请求获取表述。但是实际上,在POST、PUT或者PATCH请求中,客户端也会向服务器端发送表述,服务器随后的工作就是改变资源状态,这种情况下的表述反映的是将来的表述。
尽管任何事物都可以成为一个资源,但是客户端并不能随心所欲地对资源进行任意的操作。所能进行的操作是有规定的。在一个RESTful系统里,客户端和服务器端只能通过相互发送遵循预定义协议的消息来进行交互。
6种不同类型的消息:
响应协议的结构:
从上图可以看出HTTP响应由三部分构成:
根据RESTful的特点,我们可以得到RESTful的风格,并分析出SpringMVC是如何支持RESTful风格的。
我们的 REST API :
package com.xuecheng.restful.controller;
import com.xuecheng.restful.api.UserControllerApi;
import com.xuecheng.restful.model.domain.ucenter.User;
import com.xuecheng.restful.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(value = "/user/")
public class UserController implements UserControllerApi {
@Autowired
UserService userService;
@RequestMapping(value = "/list", method = RequestMethod.GET)
public List findAllUsers() {
return userService.findAllUser();
}
@RequestMapping(value = "/id", method = RequestMethod.GET)
public ResponseEntity findById(@PathVariable("id") String id) {
User user = userService.findById(id);
if (user == null) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
return new ResponseEntity(user,HttpStatus.OK);
}
@RequestMapping(value = "/save", method = RequestMethod.POST)
public ResponseEntity saveUser(@RequestBody User user) {
if(userService.isUserExist(user)){
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
userService.saveUser(user);
return new ResponseEntity<>(HttpStatus.OK);
}
@RequestMapping(value = "/update", method = RequestMethod.PUT)
public ResponseEntity updateUser(@RequestBody User user) {
User user1 = userService.findById(user.getId());
if(user1 == null){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
BeanUtils.copyProperties(user,user1);
userService.updateUser(user);
return new ResponseEntity<>(HttpStatus.OK);
}
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public ResponseEntity deleteUserById(@PathVariable("id") String id) {
User user = userService.findById(id);
if(user == null){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
userService.deleteUserById(id);
return new ResponseEntity<>(HttpStatus.OK);
}
public ResponseEntity deleteAllUsers() {
userService.deleteAllUsers();
return new ResponseEntity<>(HttpStatus.OK);
}
public boolean isUserExist(@RequestBody User user) {
return false;
}
}
springmvc注解详解
@RestController :首先我们使用的是Spring 4的新注解 @RestController注解.
此注解避免了每个方法都要加上@ResponseBody注解。也就是说@RestController 自己戴上了 @ResponseBody注解,看以看作是
@RequestBody : 如果方法参数被 @RequestBody注解,Spring将绑定HTTP请求体到那个参数上。如果那样做,Spring将根据请求中的ACCEPT或者 Content-Type header(私下)使用 HTTP Message converters 来将http请求体转化为domain对象。
@ResponseBody : 如果方法加上了@ResponseBody注解,Spring返回值到响应体。如果这样做的话,Spring将根据请求中的 Content-Type header(私下)使用 HTTP Message converters 来将domain对象转换为响应体。
@ResponseEntity: 是一个真实数据.它代表了整个 HTTP 响应(response). 它的好处是你可以控制任何对象放到它内部。
你可以指定状态码、头信息和响应体。它包含你想要构建HTTP Response 的信息。
@PathVariable: 此注解意味着一个方法参数应该绑定到一个url模板变量[在’{}’里的一个]中
一般来说你,要实现REST API in Spring 4 需要了解@RestController , @RequestBody, ResponseEntity 和 @PathVariable 这些注解 .另外, spring 也提供了一些支持类帮助你实现一些可定制化的东西。
就以查询所有用户为例进行测试
Spring的 RestTemplate随之出现。RestTemplate 提供了高级方法,来响应者6种主要的HTTP方法。
HTTP 方法和对应的 RestTemplate方法:
定义 Rest client , 定义REST services
package com.xuecheng.restful;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestSpringMVCRest {
public static final String REST_SERVICE_URI = "http://localhost:31001/user/";
@Autowired
RestTemplate restTemplate;
/* GET */
@Test
public void listAllUsers() {
ResponseEntity users = restTemplate.getForEntity(REST_SERVICE_URI + "list", List.class);
if (users != null) {
System.out.println(users.getBody());
} else {
System.out.println("No user exist----------");
}
}
}
4.0.0
xc-framework-parent
com.xuecheng
1.0-SNAPSHOT
../xc-framework-parent/pom.xml
com.xuecheng
test-restful
1.0-SNAPSHOT
io.springfox
springfox-swagger2
io.springfox
springfox-swagger-ui
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-freemarker
org.springframework.boot
spring-boot-starter-test
org.projectlombok
lombok
org.hibernate
hibernate-core
5.0.12.Final
com.squareup.okhttp3
okhttp
package com.xuecheng.restful.service;
import com.xuecheng.restful.model.domain.ucenter.User;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
@Service
public class UserService {
private static List users;
static {
users = populateDummyUsers();
}
private static List populateDummyUsers() {
List users = new ArrayList();
users.add(new User(UUID.randomUUID().toString(), "Sam", 30, 70000));
users.add(new User(UUID.randomUUID().toString(), "Tom", 40, 50000));
users.add(new User(UUID.randomUUID().toString(), "Jerome", 45, 30000));
users.add(new User(UUID.randomUUID().toString(), "Silvia", 50, 40000));
return users;
}
public List findAllUser() {
return users;
}
public User findById(String id) {
for (User user : users) {
if (user.getId().equals(id)) {
return user;
}
}
return null;
}
public User findByName(String name) {
for (User user : users) {
if (user.getName().equals(name)) {
return user;
}
}
return null;
}
public void saveUser(User user) {
user.setId(UUID.randomUUID().toString());
users.add(user);
}
public void updateUser(User user) {
int index = users.indexOf(user);
users.set(index, user);
}
public void deleteUserById(String id) {
Iterator iterable = users.iterator();
while (iterable.hasNext()){
if(iterable.next().getId().equals(id)){
users.remove(iterable.next());
}
}
}
public void deleteAllUsers() {
users.clear();
}
public boolean isUserExist(User user) {
return findByName(user.getName())!=null;
}
}
package com.xuecheng.restful.model.domain.ucenter;
import lombok.Data;
import lombok.ToString;
import javax.persistence.Entity;
@Data
@ToString
@Entity
public class User {
private String id;
private String name;
private int age;
private double salary;
public User(String id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
}
server:
port: ${PORT:31001}
spring:
application:
name: test-restful
package com.xuecheng.restful;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;
/**
* @author Administrator
* @version 1.0
* @create 2018-09-12 17:13
**/
@SpringBootApplication
@ComponentScan(basePackages = {"com.xuecheng.restful"})//扫描本项目下的所有类
public class ManageCmsApplication {
public static void main(String[] args) {
SpringApplication.run(ManageCmsApplication.class, args);
}
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
https://download.csdn.net/download/A1342772/12275260