REST表示 Representational State Transfer(表示性状态转换).它是可以用来设计web services的框架,可以被不同的客户端调用。REST本身只是为分布式超媒体系统设计的一种架构风格,而不是标准。
核心思想是:使用简单的HTTP协议来实现调用,而不是CORBA, RPC 或者 SOAP等负责的机制。
在Rest 基础设计中,资源使用以下动词进行操作。
也意味着,你作为Rest 服务开发者或者客户,应该遵循以上的标准。
尽管没有限制必须返回的类型,但是一般基于Web services的Rest返回JSON或者XML作为响应。
客户端可以指定(使用HTTP Accept header)他们想要的资源类型吗,服务器返回需要的资源。
指明资源的Content-Type。
基于Rest的Controller(控制器)
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import com.cmcc.model.SysUser;
import com.cmcc.model.User;
import com.cmcc.service.SysUserService;
@RestController
public class HelloWorldRestController {
@Autowired
SysUserService userService; //Service which will do all data retrieval/manipulation work
//-------------------Retrieve All Users--------------------------------------------------------
@RequestMapping(value = "/user/", method = RequestMethod.GET)
public ResponseEntity> listAllUsers() {
List sysUser = userService.selectSysUserByCondition(new SysUser());
if(sysUser.isEmpty()){
return new ResponseEntity>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
}
return new ResponseEntity>(sysUser, HttpStatus.OK);
}
//-------------------Retrieve Single User--------------------------------------------------------
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity getUser(@PathVariable("id") String id) {
System.out.println("Fetching User with id " + id);
SysUser sysUser = new SysUser();
sysUser.setUserId(id);
List sysUsers = userService.selectSysUserByCondition(sysUser);
if (sysUsers.size() == 0) {
System.out.println("User with id " + id + " not found");
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
return new ResponseEntity(sysUsers.get(0), HttpStatus.OK);
}
//-------------------Create a User--------------------------------------------------------
@RequestMapping(value = "/user/", method = RequestMethod.POST)
public ResponseEntity createUser(@RequestBody SysUser user, UriComponentsBuilder ucBuilder) {
// System.out.println("Creating User " + user.getName());
if (userService.selectByLoginAccount(user.getUserAccount()) != null) {
System.out.println("A User with name " + user.getUserAccount() + " already exist");
return new ResponseEntity("A User with name " + user.getUserAccount() + " already exist" ,HttpStatus.CONFLICT);
}
userService.insertUser(user);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/user/{id}").buildAndExpand(user.getUserId()).toUri());
return new ResponseEntity(headers, HttpStatus.CREATED);
}
//------------------- Update a User --------------------------------------------------------
@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
public ResponseEntity updateUser(@PathVariable("id") String id, @RequestBody SysUser user) {
System.out.println("Updating User " + id);
SysUser sysUser = new SysUser();
sysUser.setUserId(id);
List sysUsers = userService.selectSysUserByCondition(sysUser);
sysUser = null;
if(sysUsers.size() != 0){
sysUser = sysUsers.get(0);
}
if (sysUser==null) {
System.out.println("User with id " + id + " not found");
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
sysUser.setUserName(user.getUserName());
sysUser.setUserAddress(user.getUserAddress());
userService.updateSysUser(sysUser);
return new ResponseEntity(sysUser, HttpStatus.OK);
}
//------------------- Delete a User --------------------------------------------------------
@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
public ResponseEntity deleteUser(@PathVariable("id") String id) {
System.out.println("Fetching & Deleting User with id " + id);
SysUser sysUser = new SysUser();
sysUser.setUserId(id);
SysUser user = (SysUser) userService.selectSysUserByCondition(sysUser);
if (user == null) {
System.out.println("Unable to delete. User with id " + id + " not found");
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
userService.deleteUserById(id);
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
//------------------- Delete All Users --------------------------------------------------------
@RequestMapping(value = "/user/", method = RequestMethod.DELETE)
public ResponseEntity deleteAllUsers() {
System.out.println("Deleting All Users");
// userService.deleteAllUsers();
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
}
一个良好的Rest架构的应用中,所有的异常都应该有对应的Http Status Code来表示具体的异常类型,这样可以客户端可以基于对应的Status Code做出最有利于自己的处理。
最近,一些新产品的开发甚至已经几乎完全抛弃了传统的类似 JSP 的技术, 转而大量使用 REST 风格的构架设计, 即在服务器端所有商业逻辑都以 REST API 的方式暴露给客户端, 所有浏览器用户界面使用 widget,Ajax,HTML5 等技术,用 HTTP 的方式与后台直接交互。
REST规范
客户-服务器
这种规范的提出,改善了用户接口跨多个平台的可移植性,并且通过简化服务器组件,改善了系统的可伸缩性。最为关键的是通过分离用户接口和数据存储这两个关注点,使得不同用户终端享受相同数据成为了可能。
无状态性
无状态性是在客户-服务器约束的基础上添加的又一层规范。他要求通信必须在本质上是无状态的,即从客户到服务器的每个request都必须包含理解该 request所必须的所有信息。这个规范改善了系统的可见性(无状态性使得客户端和服务器端不必保存对方的详细信息,服务器只需要处理当前request,而不必了解所有的request历史),可靠性(无状态性减少了服务器从局部错误中恢复的任务量),可伸缩性(无状态性使得服务器端可以 很容易的释放资源,因为服务器端不必在多个request中保存状态)。同时,这种规范的缺点也是显而易见得,由于不能将状态数据保存在服务器上的共享上 下文中,因此增加了在一系列request中发送重复数据的开销,严重的降低了效率。
缓存
为了改善无状态性带来的网络的低效性,我们填加了缓存约束。缓存约束允许隐式或显式地标记一个response中的数据,这样就赋予了客户端缓存 response数据的功能,这样就可以为以后的request共用缓存的数据,部分或全部的消除一部分交互,增加了网络的效率。但是用于客户端缓存了信 息,也就同时增加了客户端与服务器数据不一致的可能,从而降低了可靠性。
B/S架构的优点是其部署非常方便,但在用户体验方面却不是很理想。为了改善这种情况,我们引入了REST。
REST在原有的架构上增加了三个新规范:统一接口,分层系统和按需代码。
统一接口
REST 架构风格的核心特征就是强调组件之间有一个统一的接口,这表现在REST世界里,网络上所有的事物都被抽象为资源,而REST就是通过通用的链接器接口对 资源进行操作。这样设计的好处是保证系统提供的服务都是解耦的,极大的简化了系统,从而改善了系统的交互性和可重用性。并且REST针对Web的常见情况 做了优化,使得REST接口被设计为可以高效的转移大粒度的超媒体数据,这也就导致了REST接口对其它的架构并不是最优的。
分层系统
分层系统规则的加入提高了各种层次之间的独立性,为整个系统的复杂性设置了边界,通过封装遗留的服务,使新的服务器免受遗留客户端的影响,这也就提高了系统的可伸缩性。
按需代码
REST允许对客户端功能进行扩展。比如,通过下载并执行applet或脚本形式的代码,来扩展客户端功能。但这在改善系统可扩展性的同时,也降低了可见性。所以它只是REST的一个可选的约束。
REST提出了如下设计准则:
网络上的所有事物都被抽象为资源(resource);
每个资源对应一个唯一的资源标识符(resource identifier);
通过通用的连接器接口(generic connector interface)对资源进行操作;
对资源的各种操作不会改变资源标识符;
所有的操作都是无状态的(stateless)。
REST是基于Http协议的,任何对资源的操作行为都是通过Http协议来实现
REST新的思维方式是把所有用户需求抽象为资源,这在实际开发中是比较难做到的,因为并不是所有的用户需求都能被抽象为资源,这样也就是说不是整个系统的结构都能 通过REST的来表现。所以在开发中,我们需要根据以上2点来在REST和MVC中做出选择。我们认为比较好的办法是混用REST和MVC,因为这适合绝 大多数的Web应用开发,开发人员只需要对比较容易能够抽象为资源的用户需求采取REST的开发模式,而对其它需求采取MVC开发即可。