我正在尝试为我的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";
}
...
}
当我调用restful服务时,服务器出现以下异常。表示框架无法解析函数签名中的param:
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
请帮帮忙。任何建议都是非常感谢的。我确实在谷歌上做了很多搜索,但都不能让它工作。Jersey 2.*. How to replace InjectableProvider and AbstractHttpContextInjectable of Jersey 1.*可能是类似的问题。
--更新:我使用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");
}
}
谢谢!
发布于 2014-05-01 04:06:14
如果您想要的只是将值直接从头部传递到方法,则不需要创建自定义注释。假设你有一个头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提供程序(这是您可以访问头参数的地方-请参阅我的注释):
@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<String>() {
@Override
protected String get(HttpContext httpContext) {
// you can get the header value here
return "testString";
}
};
}
}
现在声明一个注入解析器
public class UserAuthHeaderParamResolver extends ParamInjectionResolver<UserAuthHeaderParam> {
public UserAuthHeaderParamResolver() {
super(UserAuthHeaderParamValueFactoryProvider.class);
}
}
和用于您的配置的绑定器
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);
}
}
现在最后一件事,在你的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;
}
我希望这能帮到你。
发布于 2014-04-30 16:40:15
我不知道如何解决您的异常。然而,我可以向你推荐一种不同的方法来做同样的事情。我希望它能帮上忙。
我遇到过完全相同的问题:我需要在http头中添加额外的参数(顺便说一句,这也与身份验证有关)。此外,我需要在每个调用中发送它们,因为我想做一个“典型的”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
但它们取决于您使用的应用程序服务器实现和数据库。在我看来,过滤器更灵活,更容易实现。
复制-粘贴:我定义了一个用于身份验证的过滤器,它应用于每个调用,并在服务之前执行(感谢@PreMatching
)。
@PreMatching
public class AuthenticationRequestFilter implements ContainerRequestFilter {
@Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
final MultivaluedMap<String, String> 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
实现中包含此筛选器类,
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
// my init
// my packages
register(AuthenticationRequestFilter.class); // filtro de autenticación
// other register
}
}
希望它能帮上忙!
发布于 2014-05-02 16:23:35
如果您需要检索绑定到一个对象中的所有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);
}
}
https://stackoverflow.com/questions/23231511
复制相似问题