Java jersey 2:如何创建自定义HTTP参数绑定

Java jersey 2:如何创建自定义HTTP参数绑定,java,jersey-2.0,grizzly,Java,Jersey 2.0,Grizzly,我正在尝试为我的restful服务创建一个自定义http参数绑定。请参见下面的示例 @POST @Path("/user/{userId}/orders") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public MyResult foo(@PathParam("userId") String someString, @UserAuthHeaderParam String authStr

我正在尝试为我的restful服务创建一个自定义http参数绑定。请参见下面的示例

@POST
@Path("/user/{userId}/orders")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public MyResult foo(@PathParam("userId") String someString, @UserAuthHeaderParam String authString){

}
您可以看到函数签名中有一个UserAuthHeaderParam注释。我想做的是拥有一个自定义http参数绑定,而不是标准的javax.ws.rs.*param

我尝试实现org.glassfish.hk2.api.InjectionResolver,它基本上从http头中提取值:

public class ProtoInjectionResolver implements InjectionResolver<UserAuthHeaderParam>{
...
@Override
public Object resolve(Injectee injectee, ServiceHandle< ? > root)
{

    return "Hello World";
}
...

}
请帮忙。任何建议都将不胜感激。我确实在谷歌上做了很多搜索,但都没有成功。可能是类似的问题

--更新: 我使用AbstractBinder将解析程序绑定到UserAuthHeaderParam:

public class MyApplication extends ResourceConfig
{

public MyApplication()
{
    register(new AbstractBinder()
    {
        @Override
        protected void configure()
        {
            // bindFactory(UrlStringFactory.class).to(String.class);
            bind(UrlStringInjectResolver.class).to(new TypeLiteral<InjectionResolver<UrlInject>>()
            {
            }).in(Singleton.class);
        }
    });
    packages("rs");

}

}
公共类MyApplication扩展了ResourceConfig
{
公共应用程序()
{
注册(新的AbstractBinder()
{
@凌驾
受保护的void configure()
{
//bindFactory(UrlStringFactory.class).to(String.class);
绑定(UrlStringInjectResolver.class).to(new-TypeLiteral())
{
}).在(独生子女班);
}
});
包裹(“rs”);
}
}

谢谢大家!

我不知道如何解决您的异常。然而,我可以建议你用另一种方式来做同样的事情。我希望有帮助

我遇到了完全相同的问题:我需要http头中的额外参数(顺便说一句,也与身份验证相关)。此外,我需要在每次调用中发送它们,因为我希望在不维护会话的情况下执行“典型”rest实现

我使用的是Jersey 2.7,但我认为它应该在2.0中运行。我跟踪了他们的文档

这很清楚,但无论如何我复制粘贴我的实现下面。 它很好用。确实,还有其他一些方法可以保护rest服务,例如,这是一种很好的方法:

但它们取决于应用服务器实现和您使用的数据库。在我看来,过滤器更灵活,更容易实现

复制粘贴:我定义了一个用于身份验证的过滤器,它适用于每个调用,并在服务之前执行(多亏了
@PreMatching


希望有帮助

如果您只想将值直接从标头传递到方法,则无需创建自定义注释。假设您有一个头
授权
,那么您可以通过如下方式声明您的方法轻松访问它:

@GET
public String authFromHeader(@HeaderParam("Authorization") String authorization) {
    return "Header Value: " + authorization + "\n";
}
@java.lang.annotation.Target(PARAMETER)
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Documented
public @interface UserAuthHeaderParam {
}
您可以通过调用
curl
来测试它,例如

$ curl --header "Authorization: 1234" http://localhost:8080/rest/resource
Header Value: 1234
鉴于您问题的答案,如何创建自定义绑定如下

首先,您必须像下面这样声明注释:

@GET
public String authFromHeader(@HeaderParam("Authorization") String authorization) {
    return "Header Value: " + authorization + "\n";
}
@java.lang.annotation.Target(PARAMETER)
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Documented
public @interface UserAuthHeaderParam {
}
声明注释后,必须定义如何解析注释。声明值工厂提供程序(在这里您可以访问标题参数-请参阅我的注释):

有鉴于此,您现在应该能够根据需要使用该值:

@GET
public String getResult(@UserAuthHeaderParam String param) {
    return "RESULT: " + param;
}

我希望这会有所帮助。

如果您需要检索绑定到一个对象中的所有http头,解决方案可能是使用
@Context
注释获取
javax.ws.rs.core.HttpHeaders
;其中包含所有请求头的列表

@POST
@Path("/user/{userId}/orders")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public MyResult foo(@PathParam("userId") String someString, @Context HttpHeaders headers){
 // You can list all available HTTP request headers via following code :
   for(String header : headers.getRequestHeaders().keySet()){
     System.out.println(header);
   }
}

下面是UserAuthHeaderParamValueFactoryProvider类的实际实现

import javax.inject.Inject;
import javax.inject.Singleton;

import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;

    import org.glassfish.jersey.server.model.Parameter;

    @Singleton
    public class UserAuthHeaderParamValueFactoryProvider extends AbstractValueFactoryProvider {

        @Inject
        protected UserAuthHeaderParamValueFactoryProvider(MultivaluedParameterExtractorProvider mpep, ServiceLocator locator) {
            super(mpep, locator, Parameter.Source.UNKNOWN);
        }

        @Override
        protected Factory<?> createValueFactory(Parameter parameter) {
            Class<?> classType = parameter.getRawType();

            if (classType == null || (!classType.equals(String.class))) {
                return null;
            }

            return new AbstractContainerRequestValueFactory<String>() {
                @Override
                public String provide() {
                    //you can use get any header value.
                    return getContainerRequest().getHeaderString("Authorization");
                }

            };
        }
import javax.inject.inject;
导入javax.inject.Singleton;
进口org.glassfish.hk2.api.Factory;
导入org.glassfish.hk2.api.ServiceLocator;
导入org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
导入org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
导入org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;
导入org.glassfish.jersey.server.model.Parameter;
@独生子女
公共类UserAuthHeaderParamValueFactoryProvider扩展了AbstractValueFactoryProvider{
@注入
受保护的用户AuthHeaderParamValueFactoryProvider(多值参数提取器提供程序mpep、服务定位器定位器){
超级(mpep,定位器,参数。源。未知);
}
@凌驾
受保护的工厂createValueFactory(参数){
Class classType=参数。getRawType();
if(classType==null | |(!classType.equals(String.class))){
返回null;
}
返回新的AbstractContainerRequestValueFactory(){
@凌驾
公共字符串提供(){
//可以使用“获取任何标题值”。
返回getContainerRequest().getHeaderString(“授权”);
}
};
}

Service在哪里?@MingtaoZhang我注册了一个AbstractBinder。编辑我的问题以添加此详细信息您正在使用哪个版本的jersey jar?您是否在任何应用服务器或grizzly上运行它?@DhanaKrishnasamy我正在使用jersey 2.0和grizzly。@yzandrew为什么要创建自定义Http参数?也许您可以使用
@头Param
并通过HTTP头将UserAuth值传递给REST API?当您在同一方法中与其他现有注释(如@PathParam)混合使用时,这是否起作用?@DhanaKrishnasamy显然,您不能在同一方法参数上有注释,但您可以使用类似于
@Path(“{id}”)的公共字符串getResult的方法(@UserAuthHeaderParam字符串用户,@PathParam(“id”)整数id)
,如果这是你想要的?@lpiepiora感谢你的解决方案!我实际上需要的是将所有HTTP头绑定到一个对象中。因此我必须创建一个自定义绑定。我很抱歉回复太晚。我正在处理多个项目,因此没有机会尝试你的解决方案。我将在验证后回复。这是非常重要的下周早些时候!再次感谢!@lpiepiora您的解决方案对我有效!这正是我需要的。谢谢,非常有用的帖子!只有一个问题,我在Jersey2.6上找不到
AbstractHttpContextValueFactory
。您知道我们可以使用什么吗?再次感谢!感谢您的解决方案!我
public class HeaderParamResolverBinder extends AbstractBinder {

    @Override
    protected void configure() {
        bind(UserAuthHeaderParamValueFactoryProvider.class)
                .to(ValueFactoryProvider.class)
                .in(Singleton.class);

        bind(UserAuthHeaderParamResolver.class)
                .to(new TypeLiteral<InjectionResolver<UserAuthHeaderParam>>() {})
                .in(Singleton.class);
    }
}
@ApplicationPath("rest")
public class MyApplication extends ResourceConfig {
    public MyApplication() {
        register(new HeaderParamResolverBinder());
        packages("your.packages");
    }
}
@GET
public String getResult(@UserAuthHeaderParam String param) {
    return "RESULT: " + param;
}
@POST
@Path("/user/{userId}/orders")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public MyResult foo(@PathParam("userId") String someString, @Context HttpHeaders headers){
 // You can list all available HTTP request headers via following code :
   for(String header : headers.getRequestHeaders().keySet()){
     System.out.println(header);
   }
}
import javax.inject.Inject;
import javax.inject.Singleton;

import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;

    import org.glassfish.jersey.server.model.Parameter;

    @Singleton
    public class UserAuthHeaderParamValueFactoryProvider extends AbstractValueFactoryProvider {

        @Inject
        protected UserAuthHeaderParamValueFactoryProvider(MultivaluedParameterExtractorProvider mpep, ServiceLocator locator) {
            super(mpep, locator, Parameter.Source.UNKNOWN);
        }

        @Override
        protected Factory<?> createValueFactory(Parameter parameter) {
            Class<?> classType = parameter.getRawType();

            if (classType == null || (!classType.equals(String.class))) {
                return null;
            }

            return new AbstractContainerRequestValueFactory<String>() {
                @Override
                public String provide() {
                    //you can use get any header value.
                    return getContainerRequest().getHeaderString("Authorization");
                }

            };
        }