javascript
Spring的REST服务发现性,第5部分
通過(guò)事件使可發(fā)現(xiàn)性脫鉤
可發(fā)現(xiàn)性作為Web層的一個(gè)單獨(dú)方面或關(guān)注點(diǎn) ,應(yīng)與處理HTTP請(qǐng)求的控制器分離。 為此,Controller將觸發(fā)所有需要對(duì)HTTP響應(yīng)進(jìn)行其他操作的操作的事件:
@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 ) ); }然后,可以通過(guò)任意數(shù)量的解耦偵聽器來(lái)處理這些事件,每個(gè)偵聽器都專注于其自身的特定情況,并且每個(gè)都在努力滿足總體HATEOAS約束。
同樣,偵聽器應(yīng)該是調(diào)用堆棧中的最后一個(gè)對(duì)象,并且不需要直接訪問(wèn)它們。 因此,它們不是公開的。
使新創(chuàng)建資源的URI可被發(fā)現(xiàn)
如前一篇文章所述,創(chuàng)建新資源的操作應(yīng)在響應(yīng)的Location HTTP標(biāo)頭中返回該資源的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中,處理低級(jí)別的請(qǐng)求和響應(yīng)對(duì)象也是不可避免的,因?yàn)槿栽谂μ峁┯糜谥付↙ocation的一流支持。
獲取單一資源
檢索單個(gè)資源應(yīng)允許客戶端發(fā)現(xiàn)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 );} }請(qǐng)注意,鏈接關(guān)系的語(yǔ)義使用了“ 集合 ”關(guān)系類型,該類型以多種微格式指定和使用,但尚未標(biāo)準(zhǔn)化。
出于可發(fā)現(xiàn)性的目的, Link頭是最常用的HTTP頭之一。 因此,需要一些簡(jiǎn)單的實(shí)用程序來(lái)簡(jiǎn)化在服務(wù)器上創(chuàng)建其值并避免引入第三方庫(kù)的情況。
從根本上發(fā)現(xiàn)
根是RESTful Web服務(wù)中的入口點(diǎn)–它是客戶端首次使用API??時(shí)與之聯(lián)系的對(duì)象。 如果要始終考慮并實(shí)施HATEOAS約束,那么這是一個(gè)起點(diǎn)。 到目前為止,必須從根目錄中發(fā)現(xiàn)系統(tǒng)的大多數(shù)主要URI,這一事實(shí)不足為奇。
這是從根本上提供可發(fā)現(xiàn)性的示例控制器方法:
@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 ); }當(dāng)然,這是該概念的說(shuō)明,可以在該系列的概念證明RESTful服務(wù)的上下文中閱讀。 在更復(fù)雜的系統(tǒng)中,會(huì)有更多的鏈接,每個(gè)鏈接都有自己的語(yǔ)義,這些語(yǔ)義由鏈接關(guān)系的類型定義。
可發(fā)現(xiàn)性與更改URI無(wú)關(guān)
與可發(fā)現(xiàn)性相關(guān)的最常見陷阱之一是一種誤解,因?yàn)楝F(xiàn)在可以發(fā)現(xiàn)URI,因此它們可能會(huì)發(fā)生變化 。 但是,事實(shí)并非如此,這是有充分理由的:首先,這不是Web的工作方式–客戶將URI加為書簽,并希望它們將來(lái)能夠正常工作。 其次,客戶端不必瀏覽API就可以直接到達(dá)某個(gè)狀態(tài)。
取而代之的是,RESTful Web服務(wù)的所有URI都應(yīng)被視為即興URI ,而URI 不變 。 相反,可以使用API??的版本控制來(lái)解決URI重組的問(wèn)題。
可發(fā)現(xiàn)性警告
正如前幾篇文章中的某些討論所指出的那樣,可發(fā)現(xiàn)性的首要目標(biāo)是最大限度地減少文檔使用或不使用文檔,并讓客戶通過(guò)獲得的響應(yīng)來(lái)學(xué)習(xí)和理解如何使用API??。 實(shí)際上,這不應(yīng)該被視為遙不可及的理想-這是我們?nèi)绾问褂妹總€(gè)新網(wǎng)頁(yè)- 無(wú)需任何文檔 。 因此,如果該概念在REST上下文中存在更多問(wèn)題,那么它必須是技術(shù)實(shí)施的問(wèn)題,而不是是否可能的問(wèn)題。
話雖這么說(shuō),從技術(shù)上講,我們離一個(gè)完整的解決方案還差得很遠(yuǎn)–規(guī)范和框架支持仍在不斷發(fā)展,因此,可能必須做出一些折衷。 然而,這些都是妥協(xié),應(yīng)視為妥協(xié)。
結(jié)論
本文介紹了在具有Spring MVC的RESTful服務(wù)的上下文中實(shí)現(xiàn)可發(fā)現(xiàn)性的某些特征,并從根本上涉及了可發(fā)現(xiàn)性的概念。 在接下來(lái)的文章中,我將重點(diǎn)介紹自定義鏈接關(guān)系和Atom發(fā)布協(xié)議。 同時(shí),檢查github項(xiàng)目 。
參考: Baeldung博客上我們JCG合作伙伴 Eugen Paraschiv的第5部分 : Spring的REST服務(wù)發(fā)現(xiàn)性 。
相關(guān)文章 :
- 使用Spring 3.1和基于Java的配置引導(dǎo)Web應(yīng)用程序,第1部分
- 使用Spring 3.1和基于Java的配置構(gòu)建RESTful Web服務(wù),第2部分
- 使用Spring Security 3.1保護(hù)RESTful Web服務(wù),第3部分
- RESTful Web服務(wù)可發(fā)現(xiàn)性,第4部分
- 使用Spring Security 3.1的RESTful服務(wù)進(jìn)行基本身份驗(yàn)證和摘要身份驗(yàn)證,第6部分
- Spring&Quartz集成自定義注釋
- Spring MVC攔截器示例
- 在運(yùn)行時(shí)交換出Spring Bean配置
翻譯自: https://www.javacodegeeks.com/2011/12/rest-service-discoverability-with.html
總結(jié)
以上是生活随笔為你收集整理的Spring的REST服务发现性,第5部分的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: Oracle JRockit Missi
- 下一篇: 同舱改期是什么意思 同舱改期含义
