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

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

@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 param绑定,而不是标准的javax.ws.rs。* Param。

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

 public class ProtoInjectionResolver implements InjectionResolver{ ... @Override public Object resolve(Injectee injectee, ServiceHandle root) { return "Hello World"; } ... } 

当我调用restful服务时,服务器会获得exception。 它表明框架无法解析函数签名中的参数:

 org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=MyResource,qualifiers={}),position=0,optional=false,self=false,unqualified=null,2136594195), java.lang.IllegalArgumentException: While attempting to resolve the dependencies of rs.server.MyResource errors were found 

请帮忙。 任何建议表示赞赏。 我在谷歌上做了很多搜索,但没能使它工作。 泽西岛2. *。 如何替换Jersey 1. *的InjectableProvider和AbstractHttpContextInjectable可能是类似的问题。

– 更新:我使用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>() { }).in(Singleton.class); } }); packages("rs"); } } 

谢谢!

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

 @GET public String authFromHeader(@HeaderParam("Authorization") String authorization) { return "Header Value: " + authorization + "\n"; } 

您可以通过调用curl来测试它,例如

 $ curl --header "Authorization: 1234" http://localhost:8080/rest/resource Header Value: 1234 

鉴于您的问题的答案,如何创建自定义绑定如下。

首先,您必须声明您的注释,如下所示:

 @java.lang.annotation.Target(PARAMETER) @java.lang.annotation.Retention(RUNTIME) @java.lang.annotation.Documented public @interface UserAuthHeaderParam { } 

声明注释后,您必须定义如何解析它。 声明Value Factory Provider(这是您可以访问标头参数的位置 – 请参阅我的评论):

 @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 AbstractHttpContextValueFactory() { @Override protected String get(HttpContext httpContext) { // you can get the header value here return "testString"; } }; } } 

现在声明一个注射旋转变压器

 public class UserAuthHeaderParamResolver extends ParamInjectionResolver { public UserAuthHeaderParamResolver() { super(UserAuthHeaderParamValueFactoryProvider.class); } } 

和一个Binder为您的配置

 public class HeaderParamResolverBinder extends AbstractBinder { @Override protected void configure() { bind(UserAuthHeaderParamValueFactoryProvider.class) .to(ValueFactoryProvider.class) .in(Singleton.class); bind(UserAuthHeaderParamResolver.class) .to(new TypeLiteral>() {}) .in(Singleton.class); } } 

现在最后一件事,在你的ResourceConfig添加register(new HeaderParamResolverBinder()) ,像这样

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

我希望这有帮助。

我不知道如何解决你的exception。 但是,我可以提出一个不同的方法来做同样的事情。 我希望它有所帮助。

我遇到了完全相同的问题:我需要http头中的额外参数(顺便说一句,也与身份validation有关)。 此外,我需要在每次调用时发送它们,因为我想做一个“典型”的rest实现,而不需要维护会话。

我正在使用Jersey 2.7 – 但我会说它应该在2.0中运行。 我按照他们的文档https://jersey.java.net/documentation/2.0/filters-and-interceptors.html

这里很清楚,但无论如何我复制粘贴我的实现如下。 它工作正常。 确实有一些其他方法来确保rest服务,例如这是一个很好的方法: http : //www.objecthunter.net/tinybo/blog/articles/89

但它们依赖于应用程序服务器实现和您使用的数据库。 在我看来,filter更灵活,更容易实现。

复制粘贴:我已经定义了一个用于身份validation的filter,它适用于每个调用,并在服务之前执行(感谢@PreMatching )。

 @PreMatching public class AuthenticationRequestFilter implements ContainerRequestFilter { @Override public void filter(final ContainerRequestContext requestContext) throws IOException { final MultivaluedMap headers = requestContext.getHeaders(); if (headers == null) { throw new... } // here I get parameters from the header, via headers.get("parameter_name") // In particular, I get the profile, which I plan to use as a Jersey role // then I authenticate // finally, I inform the Principal and the role in the SecurityContext object, so that I can use @RolesAllowed later requestContext.setSecurityContext(new SecurityContext() { @Override public boolean isUserInRole(final String arg0) { //... } @Override public boolean isSecure() { //... } @Override public Principal getUserPrincipal() { //... } @Override public String getAuthenticationScheme() { //... } }); } } 

您必须在ResourceConfig的实现中包含此filter类,

 public class MyResourceConfig extends ResourceConfig { public MyResourceConfig() { // my init // my packages register(AuthenticationRequestFilter.class); // filtro de autenticación // other register } } 

希望能帮助到你!

如果您需要检索绑定到一个对象的所有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() { @Override public String provide() { //you can use get any header value. return getContainerRequest().getHeaderString("Authorization"); } }; }