REST定位为“分布式超媒体应用(Distributed Hypermedia System)”的架构风格。REST是“REpresentational State Transfer”的缩写,可以翻译成“表现状态转换”,但是在绝大多数场合中我们只说REST或者RESTful。
REST,即Representational State Transfer的缩写。RESTful架构,是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制,所以正得到越来越多网站的采用。如果一个架构符合REST原则,就称它为RESTful架构。
Web 应用程序最重要的 REST 原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。
- 资源(resource):网络上的一个实体或者说是一个具体信息,可以是一段文本、一张图片、一首歌曲、一种服务。
- 统一资源定位符(URI,Universal Resource Identifier):一个资源的识别符或者说是一个地址,通过URI你可以定位到特定的资源。要获取这个资源,需要访问它的URI,因此,URI就成了每一个资源的地址或独一无二的识别符。
- 状态转换(State Transfer): 所有资源都共享统一的接口,以便在客户端和服务器之间传输状态。客户端与服务器互动的过程,通常涉及到服务器端数据和状态的变化过程,比如文件被修改,访问数量增加等。
REST的使用场景是Machine-to-machine的系统集成,目标是让服务发布者和消费者在最小约束下自由演化。这个约束是指服务契约,简单讲就是服务输入输出的语义。消费者只需知道服务的根资源的URI,就可以由根资源引导到所需的资源。换句话说,消费者和发布者的耦合只在于根资源的URI以及各资源及其操作的语义。
rest服务的优势:
1.服务自解释
2.降低服务的版本粒度
3.降低消费者对服务内部实现细节的耦合
4.数据描述简单,一般以xml,json做数据交换。
以前我们可能需要纠结于依赖底层系统的接口对象版本,接口的设计需要充分且谨慎考虑依赖版本的兼容性问题并进行审慎评估,而版本的升级又带来客户端系统的再次发布问题。现在rest服务则彻底释放了,客户端不需要在被服务端系统绑架进行所谓依赖版本的升级,关注度可以更加聚焦与客户端系统的实际业务处理。
下面开始构建一个rest服务:
1、生成maven工程,执行以下命令
mvn archetype:generate -DgroupId=com.myteay -DartifactId=rest-common-persist -Dversion=1.0.0 -Dpackage=com.myteay -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeGroupId=org.apache.maven.archetypes -DinteractiveMode=false
2、编辑pom文件
4.0.0 com.myteay rest-common-persist 1.0.0 jar rest-common-persist http://maven.apache.org UTF-8 org.springframework.boot spring-boot-starter-parent 1.3.5.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test com.jayway.jsonpath json-path test org.springframework.boot spring-boot-maven-plugin spring-releases https://repo.spring.io/libs-release spring-releases https://repo.spring.io/libs-release
3、生成eclipse导入工程,执行: mvn eclipse:eclipse
4、编写rest服务的controller
/** * Danlley Wei (mailto://[email protected]) * Copyright (c) 2005-2017 All Rights Reserved. */ package com.myteay.restful.service.impl; import java.util.Random; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * * @author danlley([email protected]) * @version $Id: RestfulController.java, v 0.1 2017年4月13日 下午11:05:43 danlley([email protected]) Exp $ */ @RestController public class RestfulController { @RequestMapping("/greetting") public ObjectModel greeting(@RequestParam(value = "name", defaultValue = "World") String name) { System.out.println("-------------------------------->" + name); return new ObjectModel(new Random(100).nextInt(), name); } }
5、编写实体类
/** * Danlley Wei (mailto://[email protected]) * Copyright (c) 2005-2017 All Rights Reserved. */ package com.myteay.restful.service.impl; /** * @author danlley([email protected]) * @version $Id: ObjectModel.java, v 0.1 2017年4月13日 下午11:09:21 danlley([email protected]) Exp $ */ public class ObjectModel { private long id; private String content; public ObjectModel(long id, String content) { this.id = id; this.content = content; } public long getId() { return id; } public String getContent() { return content; } }
6、编写springboot启动程序
/** * Danlley Wei (mailto://[email protected]) * Copyright (c) 2005-2017 All Rights Reserved. */ package com.myteay.restful.service.impl; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @author danlley([email protected]) * @version $Id: Application.java, v 0.1 2017年4月13日 下午11:11:15 danlley([email protected]) Exp $ */ @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
7、启动服务,用postman推送数据进行测试,地址:http://localhost:8080/greetting
{ "id": -1193959466, "content": "danlley" }
8、用postman测试复杂入参对象的rest服务,定义一个稍微复杂点的嵌套对象
/** * Danlley Wei (mailto://[email protected]) * Copyright (c) 2005-2017 All Rights Reserved. */ package com.myteay.restful.service.impl; import java.io.Serializable; /** * @author danlley([email protected]) * @version $Id: ObjectModel.java, v 0.1 2017年4月13日 下午11:09:21 danlley([email protected]) Exp $ */ public class ObjectModel implements Serializable { /** */ private static final long serialVersionUID = -7268281773027468885L; private String id; private String content; public ObjectModel() { } /** * Setter method for property id. * * @param id value to be assigned to property id */ public void setId(String id) { this.id = id; } /** * Setter method for property content. * * @param content value to be assigned to property content */ public void setContent(String content) { this.content = content; } public ObjectModel(String id, String content) { this.id = id; this.content = content; } public String getId() { return id; } public String getContent() { return content; } }
注:这里如果有其他构造方法,需要指明默认的构造方法,否则在服务端接收到传过来的json数据格式时,无法进行对象重建过程。
/** * Danlley Wei (mailto://[email protected]) * Copyright (c) 2005-2017 All Rights Reserved. */ package com.myteay.restful.service.impl; import java.io.Serializable; /** * * @author danlley([email protected]) * @version $Id: ApplicationModel.java, v 0.1 2017年4月16日 下午9:46:23 danlley([email protected]) Exp $ */ public class ApplicationModel implements Serializable { /** */ private static final long serialVersionUID = -9078227456354860981L; /** */ private ObjectModel keyModel; /** */ private String key; /** */ private String value; /** * Getter method for property keyModel. * * @return property value of keyModel */ public ObjectModel getKeyModel() { return keyModel; } /** * Setter method for property keyModel. * * @param keyModel value to be assigned to property keyModel */ public void setKeyModel(ObjectModel keyModel) { this.keyModel = keyModel; } /** * Getter method for property key. * * @return property value of key */ public String getKey() { return key; } /** * Setter method for property key. * * @param key value to be assigned to property key */ public void setKey(String key) { this.key = key; } /** * Getter method for property value. * * @return property value of value */ public String getValue() { return value; } /** * Setter method for property value. * * @param value value to be assigned to property value */ public void setValue(String value) { this.value = value; } }
9、在RestfulController类中增加一个greet服务,明确指明是post方式,同时将参数指定为ApplicationModel类型
/** * Danlley Wei (mailto://[email protected]) * Copyright (c) 2005-2017 All Rights Reserved. */ package com.myteay.restful.service.impl; import java.util.Random; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; 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.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * * @author danlley([email protected]) * @version $Id: RestfulController.java, v 0.1 2017年4月13日 下午11:05:43 danlley([email protected]) Exp $ */ @RestController public class RestfulController { /** */ private static final Logger logger = Logger.getLogger(RestfulController.class); @RequestMapping("/greetting") public ObjectModel greeting(@RequestParam(value = "name", defaultValue = "World") String name) { System.out.println("-------------------------------->" + name); return new ObjectModel(new Random(100).nextInt() + "", name); } @RequestMapping(value = "/greet", method = { RequestMethod.POST }) public ApplicationModel greeting(@RequestBody ApplicationModel model, HttpServletRequest request, HttpServletResponse response) { logger.warn("-------------------->model=" + model); return model; } }
10、设置postman的header如下:
key=Content-Type value=application/json;charset=UTF-8
11、在postman中指明row格式的Body信息如下:
{ "keyModel": { "id": "test", "content": "danlley-----------" }, "key":"my", "value":"alipay" }
12、通过postman发送请求,得到返回结果如下:
{ "keyModel": { "id": "test", "content": "danlley-----------" }, "key": "my", "value": "alipay" }