Spring的REST服务发现性,第5部分

这是有关使用Spring 3.1和Spring Security 3.1和基于Java的配置来建立安全的RESTful Web Service的系列文章的第五篇。 上一篇文章介绍了RESTful服务HATEOAS的可发现性的概念,然后介绍了一些由测试驱动的实际方案。 本文将重点介绍可发现性的实际实现以及使用Spring 3.1在REST服务中满足HATEOAS约束的情况。

通过事件使可发现性脱钩

可发现性作为Web层的一个单独方面或关注点 ,应与处理HTTP请求的控制器分离。 为此,Controller将触发所有需要对HTTP响应进行其他操作的操作的事件:

@RequestMapping( value = "admin/foo/{id}",method = RequestMethod.GET )
@ResponseBody
public Foo get( @PathVariable( "id" ) Long id, HttpServletRequest request, HttpServletResponse response ){Foo resourceById = RestPreconditions.checkNotNull( this.service.getById( id ) );this.eventPublisher.publishEvent( new SingleResourceRetrieved( this, request, response ) );return resourceById;
}
@RequestMapping( value = "admin/foo",method = RequestMethod.POST )
@ResponseStatus( HttpStatus.CREATED )
public void create( @RequestBody Foo resource, HttpServletRequest request, HttpServletResponse response ){RestPreconditions.checkNotNullFromRequest( resource );Long idOfCreatedResource = this.service.create( resource );this.eventPublisher.publishEvent( new ResourceCreated( this, request, response, idOfCreatedResource ) );
}

然后,可以通过任意数量的解耦侦听器来处理这些事件,每个侦听器都专注于其自身的特定情况,并且每个都在努力满足总体HATEOAS约束。

同样,侦听器应该是调用堆栈中的最后一个对象,并且不需要直接访问它们。 因此,它们不是公开的。

使新创建资源的URI可被发现

如前一篇文章所述,创建新资源的操作应在响应的Location HTTP标头中返回该资源的URI。 :

@Component
class ResourceCreatedDiscoverabilityListener implements ApplicationListener< ResourceCreated >{@Overridepublic void onApplicationEvent( ResourceCreated resourceCreatedEvent ){Preconditions.checkNotNull( resourceCreatedEvent );HttpServletRequest request = resourceCreatedEvent.getRequest();HttpServletResponse response = resourceCreatedEvent.getResponse();long idOfNewResource = resourceCreatedEvent.getIdOfNewResource();this.addLinkHeaderOnResourceCreation( request, response, idOfNewResource );}void addLinkHeaderOnResourceCreation( HttpServletRequest request, HttpServletResponse response, long idOfNewResource ){String requestUrl = request.getRequestURL().toString();URI uri = new UriTemplate( "{requestUrl}/{idOfNewResource}" ).expand( requestUrl, idOfNewResource );response.setHeader( HttpHeaders.LOCATION, uri.toASCIIString() );}
}

不幸的是,即使在Spring 3.1中,处理低级别的请求和响应对象也是不可避免的,因为仍在努力提供用于指定Location的一流支持。

获取单一资源

检索单个资源应允许客户端发现URI以获取该特定类型的所有资源:

@Component
class SingleResourceRetrievedDiscoverabilityListener implements ApplicationListener< SingleResourceRetrieved >{@Overridepublic void onApplicationEvent( SingleResourceRetrieved resourceRetrievedEvent ){Preconditions.checkNotNull( resourceRetrievedEvent );HttpServletRequest request = resourceRetrievedEvent.getRequest();HttpServletResponse response = resourceRetrievedEvent.getResponse();this.addLinkHeaderOnSingleResourceRetrieval( request, response );}void addLinkHeaderOnSingleResourceRetrieval( HttpServletRequest request, HttpServletResponse response ){StringBuffer requestURL = request.getRequestURL();int positionOfLastSlash = requestURL.lastIndexOf( "/" );String uriForResourceCreation = requestURL.substring( 0, positionOfLastSlash );String linkHeaderValue = RESTURLUtil.createLinkHeader( uriForResourceCreation, "collection" );response.addHeader( LINK_HEADER, linkHeaderValue );}
}

请注意,链接关系的语义使用了“ 集合 ”关系类型,该类型以多种微格式指定和使用,但尚未标准化。

出于可发现性的目的, Link头是最常用的HTTP头之一。 因此,需要一些简单的实用程序来简化在服务器上创建其值并避免引入第三方库的情况。

从根本上发现

根是RESTful Web服务中的入口点–它是客户端首次使用API​​时与之联系的对象。 如果要始终考虑并实施HATEOAS约束,那么这是一个起点。 到目前为止,必须从根目录中发现系统的大多数主要URI,这一事实不足为奇。

这是从根本上提供可发现性的示例控制器方法:

@RequestMapping( value = "admin",method = RequestMethod.GET )
@ResponseStatus( value = HttpStatus.NO_CONTENT )
public void adminRoot( HttpServletRequest request, final response ){String rootUri = request.getRequestURL().toString();URI fooUri = new UriTemplate( "{rootUri}/{resource}" ).expand( rootUri, "foo" );String linkToFoo = RESTURIUtil.createLinkHeader( fooUri.toASCIIString(), REL_COLLECTION );response.addHeader( HttpConstants.LINK_HEADER, linkToFoo );
}

当然,这是该概念的说明,可以在该系列的概念证明RESTful服务的上下文中阅读。 在更复杂的系统中,会有更多的链接,每个链接都有自己的语义,这些语义由链接关系的类型定义。

可发现性与更改URI无关

与可发现性相关的最常见陷阱之一是一种误解,因为现在可以发现URI,因此它们可能会发生变化 。 但是,事实并非如此,这是有充分理由的:首先,这不是Web的工作方式–客户将URI加为书签,并希望它们将来能够正常工作。 其次,客户端不必浏览API就可以直接到达某个状态。

取而代之的是,RESTful Web服务的所有URI都应被视为即兴URI ,而URI 不变 。 相反,可以使用API​​的版本控制来解决URI重组的问题。

可发现性警告

正如前几篇文章中的某些讨论所指出的那样,可发现性的首要目标是最大限度地减少文档使用或不使用文档,并让客户通过获得的响应来学习和理解如何使用API​​。 实际上,这不应该被视为遥不可及的理想-这是我们如何使用每个新网页- 无需任何文档 。 因此,如果该概念在REST上下文中存在更多问题,那么它必须是技术实施的问题,而不是是否可能的问题。

话虽这么说,从技术上讲,我们离一个完整的解决方案还差得很远–规范和框架支持仍在不断发展,因此,可能必须做出一些折衷。 然而,这些都是妥协,应视为妥协。

结论

本文介绍了在具有Spring MVC的RESTful服务的上下文中实现可发现性的某些特征,并从根本上涉及了可发现性的概念。 在接下来的文章中,我将重点介绍自定义链接关系和Atom发布协议。 同时,检查github项目 。

参考: Baeldung博客上我们JCG合作伙伴 Eugen Paraschiv的第5部分 Spring的REST服务发现性 。

相关文章 :

  • 使用Spring 3.1和基于Java的配置引导Web应用程序,第1部分
  • 使用Spring 3.1和基于Java的配置构建RESTful Web服务,第2部分
  • 使用Spring Security 3.1保护RESTful Web服务,第3部分
  • RESTful Web服务可发现性,第4部分
  • 使用Spring Security 3.1的RESTful服务进行基本身份验证和摘要身份验证,第6部分
  • Spring&Quartz集成自定义注释
  • Spring MVC拦截器示例
  • 在运行时交换出Spring Bean配置

翻译自: https://www.javacodegeeks.com/2011/12/rest-service-discoverability-with.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

postman使用_postman如何使用集合断言?

在postman中&#xff0c;大家都使用过断言&#xff0c;但是我们使用的断言都是针对每一个接口或者是每一个用例添加的&#xff0c;那么是否有可以同时对多个用例或接口添加断言呢 &#xff1f; 答案是肯定有的。那么接下来我就带领大家认识下Postman中的批量断言&#xff0c;也…

纪念我的leetcode开门之旅

15.12.3在朋友的建议下开始了leetcode之旅&#xff0c;上面的题目先捡简单的刷吧。。。转载于:https://www.cnblogs.com/thewaytomakemiracle/p/5016825.html

NYOJ 16 矩形嵌套

矩形嵌套 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描述有n个矩形&#xff0c;每个矩形可以用a,b来描述&#xff0c;表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d&#xff08;相当于旋转X90度&…

沉思滥用:“强力使用,破坏滥用”

英国前首相本杰明迪斯雷利&#xff08;Benjamin Disraeli&#xff09;曾有一个古老的说法&#xff0c;说谎言分为三种&#xff1a;“谎言&#xff0c;该死的谎言和统计数据”。 这里的暗示是统计数据很容易弥补它们是不可靠的。 但是&#xff0c;统计学在经验科学中得到了广泛的…

centos和ubuntu下使用cron设置定时任务

1.启动cron工具[ps:使用root权限] centos启动cron两种方式 a) /etc/init.d/crond start b) service crond start ubuntu启动cron两种方式 a) /etc/init.d/cron start b) service cron start(推荐) 2.添加定时任务[每个整点执行ls命令] centos crontab -e命令打开文件 添加一行:…

算法与数据结构(一)

这里的许多资源&#xff0c;有时间可用多看看&#xff0c;写一下。 http://download.csdn.net/album/detail/3249/2 这个哥们的博客还不错&#xff1a;http://u.cxyblog.com/2/articles-3.html转载于:https://www.cnblogs.com/oxspirt/p/5805409.html

protected访问权限_权限修饰符 /重写

一 权限修饰符 private内容不能被继承类:只有public / default 可以修饰 ,且default 默认出现protected访问权限1.同包下的类2.不同包的子类,只能通过子父类关系访问,只有子类中才可以使用.权限修饰符只能修饰成员,成员修饰符(成员变量|成员方法)二 重写重写和重载的区别:(都指…

NYOJ 26 孪生素数问题

孪生素数问题 时间限制&#xff1a;3000ms | 内存限制&#xff1a;65535KB难度&#xff1a;3描述写一个程序&#xff0c;找出给出素数范围内的所有孪生素数的组数。一般来说&#xff0c;孪生素数就是指两个素数距离为2&#xff0c;近的不能再近的相邻素数。有些童鞋一看到题就…

python importlib_importlib --- import 的实现 — Python 3.10.0a2 文档

3.7 新版功能.这个模块使得Python的导入系统提供了访问*包*内的*资源*的功能。如果能够导入一个包&#xff0c;那么就能够访问那个包里面的资源。资源可以以二进制或文本模式方式被打开或读取。资源非常类似于目录内部的文件&#xff0c;要牢记的是这仅仅是一个比喻。资源和包不…

原生js使用forEach()与jquery使用each遍历数组,return false 的区别

原生js使用forEach()与jquery使用each()遍历数组&#xff0c;return false 的区别&#xff1a; 1、使用each()遍历数组a,如下&#xff1a; var a[20,21,22,23,24];$.each(a, function(index,val) {console.log(indexindex);if(index2){return false;}console.log(valval);}); …

配置Java EE应用程序或“将Bien付诸实践”

过去&#xff0c;有关应用程序配置的讨论很多。 我不知道谁拉开了辩论的序幕&#xff0c;但是最基础的阅读&#xff08;着眼于未来的Java EE 7及更高版本&#xff09;是Antonio Goncalves的帖子[辩论] – Java EE 7中的配置如何 &#xff1f; 事实是&#xff0c;使用香草Java E…

HTML5 Canvas入门

HTML5的canvas&#xff08;画布&#xff09;元素使用JavaScript在网页上绘制图像。下面以一个简单例子及其效果图&#xff08;图1&#xff09;开始&#xff1a; <!DOCTYPE HTML> <html><head><style type"text/css"> canvas{border:dashed 2…

NYOJ 27 大数阶乘

大数阶乘 时间限制&#xff1a;3000ms | 内存限制&#xff1a;65535KB难度&#xff1a;3描述我们都知道如何计算一个数的阶乘&#xff0c;可是&#xff0c;如果这个数很大呢&#xff0c;我们该如何去计算它并输出它&#xff1f; 输入输入一个整数m(0<m<5000)输出输出m的…

泄漏:Oracle WebLogic Server 12g

JavaOne已经比我们落后了将近一个星期&#xff0c;我仍在撰写有关它的详细博客文章 。 我真的很惊讶的事实是&#xff0c;我没有看到任何提及我最喜欢的应用程序服务器更新的事实。 是的&#xff0c;我喜欢WebLogic产品。 从一开始。 自从收购BEA以来&#xff0c;甲骨文一直对我…

画家问题

【题目描述】 有一个正方形的墙&#xff0c;由N*N个正方形的砖组成&#xff0c;其中一些砖是白色的&#xff0c;另外一些砖是黄色的。Bob是个画家&#xff0c;想把全部的砖都涂成黄色。但他的画笔不好使。当他用画笔涂画第(i,j)个位置的砖时&#xff0c;位置(i-1,j)、(i1,j)、(…

8-IO总结

3、 4、 5、 转载于:https://www.cnblogs.com/fubaizhaizhuren/p/5026207.html

NYOJ 36 最长公共子序列

最长公共子序列 时间限制&#xff1a;3000ms | 内存限制&#xff1a;65535KB难度&#xff1a;3描述咱们就不拐弯抹角了&#xff0c;如题&#xff0c;需要你做的就是写一个程序&#xff0c;得出最长公共子序列。tip&#xff1a;最长公共子序列也称作最长公共子串(不要求连续)&…

python 发邮件_python发邮件

smtplibPython提供smtplib模块&#xff0c;该模块定义了一个SMTP客户端会话对象&#xff0c;可用于使用SMTP或ESMTP侦听器守护程序向任何互联网机器发送邮件。这是一个简单的语法&#xff0c;用来创建一个SMTP对象&#xff0c;稍后将演示如何用它来发送电子邮件 import smtplib…

Java SE 7、8、9 –推进Java

今天&#xff08;注&#xff1a;2011年10月4日&#xff09;是主题演讲日。 JavaOne Keynote将于今早从上午8:30到10:30进行&#xff0c;而我的新闻通行证又一次让我很早就开始了。 因此&#xff0c;我有时间在所有关键球员准备就绪并可能感到紧张的同时为其拍摄一些非常个性化的…

Ferguson游戏

考虑一个简单的游戏&#xff1a; 有两个盒子&#xff0c;其中一个装有m颗糖、另一个装有n颗糖&#xff0c;将这样的状态记为(m,n)。每次的移动是将其中一个盒子清空&#xff0c;把另一个盒子的一些糖拿到被清空的盒子里使得两个盒子至少各有一颗糖。两个操作者轮流进行操作&…