第11章 为Spring添加REST功能
来源:互联网 发布:mirror.centos.org 编辑:程序博客网 时间:2024/06/05 16:56
第11章 为Spring添加REST功能
数据为王。
为信息为中心的表述性状态转移(Representational State Trannfer,REST)已成为替换传统SOAP Web服务的流行方案。
11.1 了解REST
11.1.1 REST的基本原理
REST与RPC几乎没有任何关系。RPC是面向服务的,并关注与行为和动作;而REST是面向资源的,强调描述应用程序的事务和名词。
*表述性(Representational)——REST资源实际上可以用各种形式来进行表述,包括XML,JSON,甚至HTML——最适合资源使用者的任意形式。
*状态(State)——当使用REST的时候,我们更关注资源的状态而不是对资源采取的行为。
*转移(Transfer)——REST涉及转移资源数据,它以某一种表述性形式从一个应用转移到了一个应用。
11.1.2 Spring是如何支持REST的
11.2 编写面向资源的控制器
不符合RESTful资源的控制器就是RESTless。
11.2.1 剖析RESTless的控制器
<span style="font-size:18px;">@Controller@RequestMapping("/displaySpittle.htm") //<co id="co_restlessRequestMapping"/> public class DisplaySpittleController { private final SpitterService spitterService; @Inject public DisplaySpittleController(SpitterService spitterService) { this.spitterService = spitterService; } @RequestMapping(method=RequestMethod.GET) public String showSpittle(@RequestParam("id") long id, Model model) { model.addAttribute(spitterService.getSpittleById(id)); return "spittles/view"; }}</span>DisplaySpittleController的编写方式并没有严重的错误。但是,它并不是一个RESTful的控制器。它是面向行为的并关注于一个特殊的用例:以HTML的形式展现一个Spittle对象的详细信息。
11.2.2 处理RESTful URL
URL是统一资源定位符的缩写,本意是用于定为资源的。此外,所有的URL同时也都是URI或统一资源标识符。
在URL中嵌入参数
<span style="font-size:18px;">@Controller@RequestMapping("/spittles") //<co id="co_spittlesRequestMapping"/> public class SpittleController { private SpitterService spitterService; @Inject public SpittleController(SpitterService spitterService) { this.spitterService = spitterService; } @RequestMapping(value="/{id}", method=RequestMethod.GET) //<co id="co_requestMapping_getSpittleMethod"/> public String getSpittle(@PathVariable("id") long id, Model model) { model.addAttribute(spitterService.getSpittleById(id)); return "spittles/view"; }}</span>"spittles/{id}"这种URL格式的GET请求,{id}是一个占位符,通过它会将变量数据传递给方法。它对应了方法参数id的@PathVariable注解。
11.2.3 执行REST动作
GET请求将资源的状态从服务器转移到客户端 ,而PUT将资源的状态从客户端转移到服务器上。
使用PUT更新资源
<span style="font-size:18px;"> @RequestMapping(value="/{id}", method=RequestMethod.PUT) @ResponseStatus(HttpStatus.NO_CONTENT) public void putSpittle(@PathVariable("id") long id, @Valid Spittle spittle) { spitterService.saveSpittle(spittle); }</span>
<p><span style="font-size:18px;">@ResponseStatus注解定义了HTTP状态,这个状态要设置在发往客户端的响应中。HttpStatus.NO_CONTENT说明响应状态要设置为HTTP状态码204。这个状态码意味着请求被成功处理了,但是在响应体重不包括任何返回信息。</span></p>处理DELETE请求
<span style="font-size:18px;"> @RequestMapping(value="/{id}", method=RequestMethod.DELETE) @ResponseStatus(HttpStatus.NO_CONTENT) public void deleteSpittle(@PathVariable("id") long id) { spitterService.deleteSpittle(id); }</span>使用POST创建资源
<span style="font-size:18px;"> @RequestMapping(method=RequestMethod.POST) //<co id="co_handlePOST"/> @ResponseStatus(HttpStatus.CREATED) // <co id="co_createdResponse" /> public @ResponseBody Spittle createSpittle(@Valid Spittle spittle, BindingResult result, HttpServletResponse response) throws BindException { if(result.hasErrors()) { throw new BindException(result); } spitterService.saveSpittle(spittle); response.setHeader("Location", "/spittles/" + spittle.getId()); //<co id="co_setLocationHeader"/> return spittle; //<co id="co_returnSpittle"/> }</span>
11.3 表述资源
表述是REST中很重要的一个方面。它是关于客户端与服务器端针对某一资源是如何通信的。任何给定的资源都几乎可以用任意的形式来进行表述。
控制器以Java对象的方式来处理资源。控制器完成了它的工作之后,资源才会被转化成最适合客户端的形式。
Spring提供了两种方法将资源的Java表述形式转化为发送给客户端的表述形式:
*基于试图渲染进行协商
*HTTP消息转化器
11.3.1 协商资源表述
如果方法不直接返回逻辑试图名(例如方法返回void),那么逻辑试图名会来源于请求的URL。
Spring的ContentNegotiatingViewResolver是一个特殊的视图解析器,它考虑到了客户端所需要的内容类型。
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="mediaTypes"> <map> <entry key="json" value="application/json" /> <entry key="xml" value="text/xml" /> <entry key="htm" value="text/html" /> </map> </property> <property name="defaultContentType" value="text/html" /> </bean>要理解ContentNegotiatingViewResolver是如何工作的,要涉及内容协商的两个步骤:
1 确定请求的媒体类型
2 找到适合请求媒体类型的最佳视图
确定请求的媒体类型
影响如何选择媒体类型
查找视图
11.3.2 使用HTTP信息转化器
在响应体中返回资源状态
@RequestMapping(value="/(username)",method=RequestMethod.GET,headers = {*Accept = text/xml, application/json*})
public @ResponseBody Spitter getSpitter(@PathVariable String username){
return spitterService.getSpitter(username);
}
@ResponseBody注解会告知Spring,将返回的对象作为资源发送给客户端,并将其转换为客户端可接受的表述形式。
在请求中接收资源状态
@ResponseBody注解能够将发送给客户端的数据进行转换一样,@RequestBody也能够对客户端发过来的对象做相同的事情。
@RequestMapping(value = */{username}*, method = RequestMethod.PUT, headers = *Content-Type = application/json*}
@ResponseStatus(HttpStatus.NO_CONTENT)
public void updateSpitter(@PathVariable String username,@RequestBody Spitter spitter) {
spitterService.saveSpitter(spitter);
}
JSON信息转换为Spitter对象,条件:
*请求的Content-Type头信息必须是application/json;
*Jackson JSON库必须包含在应用程序的类路径下。
11.4 编写REST客户端
public Spittle[] retrieveSpittlesForSpitter(String username) { try { HttpClient httpClient = new DefaultHttpClient();//<co id="co_createHttpClient"/> String spittleUrl = "http://localhost:8080/Spitter/spitters/" + username + "/spittles";//<co id="co_constructUrl"/> HttpGet getRequest = new HttpGet(spittleUrl);//<co id="co_createRequest"/> getRequest.setHeader( new BasicHeader("Accept", "application/json")); HttpResponse response = httpClient.execute(getRequest);//<co id="co_executeRequest"/> HttpEntity entity = response.getEntity();//<co id="co_parseResult"/> ObjectMapper mapper = new ObjectMapper(); return mapper.readValue(entity.getContent(), Spittle[].class); } catch (IOException e) { throw new SpitterClientException("Unable to retrieve Spittles", e); } }在资源使用上有如此之多的样板代码,你可能会觉得最好的方式是封装通过代码并参数化可变的地方。这正是Spring的RestTemplate所做的事情。
- 第11章 为Spring添加REST功能
- 《Spring实战:为Spring添加REST功能(第11章) 》 笔记
- 为Spring Security添加IP限制功能
- 为Spring配置文件添加提示功能
- LuceneInAction(第2版)学习笔记——第三章 为应用程序添加搜索功能
- 第16章 使用Spring MVC创建 REST API
- 如何为Spring Web程序添加log4j功能
- Beginning Spring学习笔记——第11章 使用Spring开发REST风格的Web服务
- 第4章、REST
- 为REST添加服务发现能力
- 为REST添加服务发现能力
- 为REST添加服务发现能力
- 为REST添加服务发现能力
- 第二章 为博客添加高级功能
- 为应用程序添加插件功能
- 为DataList添加分页功能
- 为SQL添加 intellisense功能
- 为benchmark添加gzip功能
- 3dmax雪景插件(SnowFlow) For Max2012/2014
- 使用Git命令实现代码上传与同步
- 【实际项目】微信相关api调用例子【以分享为例】
- Android线程模型(Painless Threading)
- 关于iOS提交审核的IDFA-2
- 第11章 为Spring添加REST功能
- Abstract Class And Interface
- java-spring的JdbcTempldate对oracle 的CLob字段进行读和写
- java中应该尽量使用notifyall而不是notify(容易发生死锁)
- Rails表单帮助方法使用之(select)
- ld.so.conf的错误
- Forest Pack Pro(3DMax森林制作插件) v4.3.6
- oracle函数wm_concat行转列
- Hibernate搭建教程以及基础信息介绍