超越JAX-RS规范:Apache CXF搜索扩展
在今天的帖子中,我們將超越JAX-RS 2.0規(guī)范,并探索Apache CXF (流行的JAX-RS 2.0實(shí)現(xiàn)之一)為REST服務(wù)和API開(kāi)發(fā)人員提供的有用擴(kuò)展。 特別是,我們將討論使用OData 2.0查詢(xún)過(guò)濾器子集的搜索擴(kuò)展。
簡(jiǎn)而言之,搜索擴(kuò)展僅將某種過(guò)濾器表達(dá)式映射到一組匹配的類(lèi)型化實(shí)體(Java類(lèi)的實(shí)例)。 OData 2.0查詢(xún)過(guò)濾器可能非常復(fù)雜,但是目前Apache CXF僅支持它們的子集:
| 當(dāng)量 | 等于 | 雷德蒙德市 |
| NE | 不相等 | 城市“倫敦” |
| gt | 比...更棒 | 價(jià)格gt 20 |
| ge | 大于或等于 | 價(jià)格GE 10 |
| lt | 少于 | 價(jià)格lt 20 |
| 樂(lè) | 小于或等于 | 價(jià)格100 |
| 和 | 邏輯與 | 價(jià)格le 200和價(jià)格gt 3.5 |
| 要么 | 邏輯或 | 價(jià)格le 3.5或價(jià)格gt 200 |
基本上,要配置和激活JAX-RS服務(wù)的搜索擴(kuò)展,只需定義兩個(gè)屬性search.query.parameter.name和search.parser ,再加上一個(gè)附加提供程序SearchContextProvider :
@Configuration public class AppConfig { @Bean( destroyMethod = "shutdown" )public SpringBus cxf() {return new SpringBus();}@Bean @DependsOn( "cxf" )public Server jaxRsServer() {final Map< String, Object > properties = new HashMap< String, Object >(); properties.put( "search.query.parameter.name", "$filter" );properties.put( "search.parser", new ODataParser< Person >( Person.class ) );final JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint( jaxRsApiApplication(), JAXRSServerFactoryBean.class );factory.setProvider( new SearchContextProvider() );factory.setProvider( new JacksonJsonProvider() );factory.setServiceBeans( Arrays.< Object >asList( peopleRestService() ) );factory.setAddress( factory.getAddress() ); factory.setProperties( properties );return factory.create();}@Bean public JaxRsApiApplication jaxRsApiApplication() {return new JaxRsApiApplication();}@Bean public PeopleRestService peopleRestService() {return new PeopleRestService();} }search.query.parameter.name定義用作過(guò)濾器的查詢(xún)字符串參數(shù)的名稱(chēng)(我們將其設(shè)置為$ filter ),而search.parser定義用于解析過(guò)濾器表達(dá)式的解析器(我們?cè)O(shè)置將其與Person類(lèi)一起參數(shù)化為ODataParser )。 ODataParser建立在出色的Apache Olingo項(xiàng)目之上, 該項(xiàng)目當(dāng)前實(shí)現(xiàn)了OData 2.0協(xié)議(正在支持OData 4.0 )。
配置完成后,任何JAX-RS 2.0服務(wù)都可以通過(guò)注入上下文參數(shù)SearchContext來(lái)受益于搜索功能。 讓我們通過(guò)定義REST服務(wù)來(lái)管理下面的Person類(lèi)所代表的人員,來(lái)了解實(shí)際情況 :
public class Person {private String firstName;private String lastName;private int age;// Setters and getters here }該P(yáng)eopleRestService將只允許使用來(lái)創(chuàng)建新的個(gè)人HTTP POST和使用進(jìn)行搜索HTTP GET,下/搜索端點(diǎn)所列:
package com.example.rs;import java.util.ArrayList; import java.util.Collection;import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo;import org.apache.cxf.jaxrs.ext.search.SearchCondition; import org.apache.cxf.jaxrs.ext.search.SearchContext;import com.example.model.Person;@Path( "/people" ) public class PeopleRestService {private final Collection< Person > people = new ArrayList<>();@Produces( { MediaType.APPLICATION_JSON } )@POSTpublic Response addPerson( @Context final UriInfo uriInfo,@FormParam( "firstName" ) final String firstName, @FormParam( "lastName" ) final String lastName,@FormParam( "age" ) final int age ) { final Person person = new Person( firstName, lastName, age );people.add( person );return Response.created( uriInfo.getRequestUriBuilder().path( "/search" ).queryParam( "$filter=firstName eq '{firstName}' and lastName eq '{lastName}' and age eq {age}" ).build( firstName, lastName, age ) ).entity( person ).build();}@GET@Path("/search")@Produces( { MediaType.APPLICATION_JSON } )public Collection< Person > findPeople( @Context SearchContext searchContext ) { final SearchCondition< Person > filter = searchContext.getCondition( Person.class );return filter.findAll( people );} }findPeople方法是我們正在尋找的方法。 由于Apache CXF所做的所有努力,該方法看起來(lái)非常簡(jiǎn)單:注入了SearchContext ,并從$ filter查詢(xún)字符串參數(shù)中自動(dòng)提取了過(guò)濾器表達(dá)式。 最后一部分是將過(guò)濾器應(yīng)用于數(shù)據(jù),在我們的例子中,它只是一個(gè)名為people的集合。 非常干凈和直接。
讓我們構(gòu)建項(xiàng)目并運(yùn)行它:
mvn clean package java -jar target/cxf-search-extension-0.0.1-SNAPSHOT.jar使用很棒的curl工具,讓我們發(fā)出幾個(gè)HTTP POST請(qǐng)求,以生成一些數(shù)據(jù)以針對(duì)以下條件運(yùn)行過(guò)濾器查詢(xún):
> curl http://localhost:8080/rest/api/people -X POST -d "firstName=Tom&lastName=Knocker&age=16" {"firstName": "Tom","lastName": "Knocker","age": 16 }> curl http://localhost:8080/rest/api/people -X POST -d "firstName=Bob&lastName=Bobber&age=23" {"firstName": "Bob","lastName": "Bobber","age": 23 }> curl http://localhost:8080/rest/api/people -X POST -d "firstName=Tim&lastName=Smith&age=50" {"firstName": "Tim","lastName": "Smith","age": 50 }有了示例數(shù)據(jù),讓我們繼續(xù)前進(jìn),提出幾個(gè)不同的搜索條件,這些條件足夠復(fù)雜,足以展示OData 2.0查詢(xún)過(guò)濾器的強(qiáng)大功能:
- 查找所有名字為Bob的人 ($ filter = “ firsteq eq'Bob'” )
- 查找所有姓氏為Bobber或姓氏 Smith且名字不是Bob的人 ($ filter = “ lastName eq'Bobber'或(lastName eq'Smith'and firstName ne'Bob')” ))
- 查找其名字開(kāi)始從字母T,誰(shuí)所有的人在16歲以上($ =過(guò)濾器“名字EQ‘T *’和年齡GE 16”)
注意 :如果在類(lèi)似Linux的環(huán)境中運(yùn)行此命令,則可能需要使用\ $轉(zhuǎn)義$符號(hào),例如:
curl -X GET -G http:// localhost:8080 / rest / api / people / search –data-urlencode \ $ filter =“ firstName eq'Bob'”
目前, Apache CXF僅提供OData 2.0查詢(xún)過(guò)濾器的基本支持,并保留了許多強(qiáng)大的表達(dá)式。 但是,一旦社區(qū)對(duì)使用此功能表示出足夠的興趣,就有承諾將其推進(jìn)。
值得一提的是, OData 2.0查詢(xún)過(guò)濾器不是唯一可用的選項(xiàng)。 搜索擴(kuò)展還支持FIQL (提要項(xiàng)查詢(xún)語(yǔ)言),而來(lái)自Apache CXF核心開(kāi)發(fā)人員之一的精彩文章也對(duì)其進(jìn)行了很好的介紹。
我認(rèn)為Apache CXF的這一非常有用的功能可以通過(guò)為JAX-RS 2.0服務(wù)提供簡(jiǎn)單(而不是那么簡(jiǎn)單)的搜索功能來(lái)節(jié)省大量時(shí)間和精力。 如果適合您的應(yīng)用程序需求,請(qǐng)嘗試一下。
- 完整的項(xiàng)目源代碼可在Github上獲得 。
翻譯自: https://www.javacodegeeks.com/2014/12/beyond-the-jax-rs-spec-apache-cxf-search-extension.html
總結(jié)
以上是生活随笔為你收集整理的超越JAX-RS规范:Apache CXF搜索扩展的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 笋叶子怎么做好吃 笋叶子如何做好吃
- 下一篇: 在命令行上操作JAR,WAR和EAR