当前位置: 首页 > 工具软件 > Apache Olingo > 使用案例 >

超越JAX-RS规范:Apache CXF搜索扩展

逑何平
2023-12-01

在今天的帖子中,我们将超越JAX-RS 2.0规范,并探索Apache CXF (流行的JAX-RS 2.0实现之一)为REST服务和API开发人员提供的有用扩展。 特别是,我们将讨论使用OData 2.0查询过滤器子集的搜索扩展。

简而言之,搜索扩展仅将某种过滤器表达式映射到一组匹配的类型化实体(Java类的实例)。 OData 2.0查询过滤器可能非常复杂,但是目前Apache CXF仅支持它们的子集:

操作员 描述
当量 等于 雷德蒙德市
NE 不相等 城市“伦敦”
gt 比...更棒 价格gt 20
ge 大于或等于 价格GE 10
lt 少于 价格lt 20
小于或等于 价格100
逻辑与 价格le 200和价格gt 3.5
要么 逻辑或 价格le 3.5或价格gt 200

基本上,要配置和激活JAX-RS服务的搜索扩展,只需定义两个属性search.query.parameter.namesearch.parser ,再加上一个附加提供程序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定义用作过滤器的查询字符串参数的名称(我们将其设置为$ filter ),而search.parser定义用于解析过滤器表达式的解析器(我们设置将其与Person一起参数化为ODataParser )。 ODataParser建立在出色的Apache Olingo项目之上, 项目当前实现了OData 2.0协议(正在支持OData 4.0 )。

配置完成后,任何JAX-RS 2.0服务都可以通过注入上下文参数SearchContext来受益于搜索功能。 让我们通过定义REST服务来管理下面的Person类所代表的人员,来了解实际情况

public class Person {
    private String firstName;
    private String lastName;
    private int age;

    // Setters and getters here
}

PeopleRestService将只允许使用来创建新的个人HTTP POST和使用进行搜索HTTP GET,/搜索端点所列:

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  } )
    @POST
    public 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所做的所有努力,该方法看起来非常简单:注入了SearchContext ,并从$ filter查询字符串参数中自动提取了过滤器表达式。 最后一部分是将过滤器应用于数据,在我们的例子中,它只是一个名为people的集合。 非常干净和直接。

让我们构建项目并运行它:

mvn clean package
java -jar target/cxf-search-extension-0.0.1-SNAPSHOT.jar

使用很棒的curl工具,让我们发出几个HTTP POST请求,以生成一些数据以针对以下条件运行过滤器查询:

> 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
}

有了示例数据,让我们继续前进,提出几个不同的搜索条件,这些条件足够复杂,足以展示OData 2.0查询过滤器的强大功能:

    • 查找所有名字Bob的人 ($ filter = “ firsteq eq'Bob'”
> curl -G -X GET http://localhost:8080/rest/api/people/search --data-urlencode 
  $filter="firstName eq 'Bob'" 
[
    {
        "firstName": "Bob",
        "lastName": "Bobber",
        "age": 23
    }
]
    • 查找所有姓氏Bobber姓氏 Smith名字不是Bob的人 ($ filter = “ lastName eq'Bobber'或(lastName eq'Smith'and firstName ne'Bob')” ))
> curl -G -X GET http://localhost:8080/rest/api/people/search --data-urlencode 
  $filter="lastName eq 'Bobber' or (lastName eq 'Smith' and firstName ne 'Bob')" 
[
    {
        "firstName": "Bob",
        "lastName": "Bobber",
        "age": 23
    },
    {    
        "firstName": "Tim",
        "lastName": "Smith",
        "age": 50
    }
]
    • 查找其名字开始从字母T,谁所有的人在16岁以上($ =过滤器“名字EQ‘T *’和年龄GE 16”)
> curl -G -X GET http://localhost:8080/rest/api/people/search --data-urlencode 
  $filter="firstName eq 'T*' and age ge 16"
[
    {
        "firstName": "Tom",
        "lastName": "Knocker",
        "age": 16
    },
    {
        "firstName": "Tim",
        "lastName": "Smith",
        "age": 50
    }
]

注意 :如果在类似Linux的环境中运行此命令,则可能需要使用\ $转义$符号,例如:
curl -X GET -G http:// localhost:8080 / rest / api / people / search –data-urlencode \ $ filter =“ firstName eq'Bob'”

目前, Apache CXF仅提供OData 2.0查询过滤器的基本支持,并保留了许多强大的表达式。 但是,一旦社区对使用此功能表示出足够的兴趣,就有承诺将其推进。

值得一提的是, OData 2.0查询过滤器不是唯一可用的选项。 搜索扩展还支持FIQL (提要项查询语言),而来自Apache CXF核心开发人员之一的精彩文章也对其进行了很好的介绍。

我认为Apache CXF的这一非常有用的功能可以通过为JAX-RS 2.0服务提供简单(而不是那么简单)的搜索功能来节省大量时间和精力。 如果适合您的应用程序需求,请尝试一下。

翻译自: https://www.javacodegeeks.com/2014/12/beyond-the-jax-rs-spec-apache-cxf-search-extension.html

 类似资料: