java - página - jersey 2: Cómo crear un enlace personalizado de parámetros HTTP
href html ejemplos (4)
Estoy tratando de crear un enlace personalizado de http param para mi servicio de descanso. Por favor, vea el ejemplo a continuación.
@POST
@Path("/user/{userId}/orders")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public MyResult foo(@PathParam("userId") String someString, @UserAuthHeaderParam String authString){
}
Puede ver que hay una anotación UserAuthHeaderParam en la firma de función. Lo que quiero hacer es tener un enlace de param http personalizado distinto del estándar javax.ws.rs. * Param.
He intentado implementar org.glassfish.hk2.api.InjectionResolver que básicamente extrae el valor del encabezado http:
public class ProtoInjectionResolver implements InjectionResolver<UserAuthHeaderParam>{
...
@Override
public Object resolve(Injectee injectee, ServiceHandle< ? > root)
{
return "Hello World";
}
...
}
Cuando llamo al servicio de descanso, el servidor recibe las siguientes excepciones. Indica que el marco no puede resolver el parámetro en la firma de función:
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
Por favor ayuda. Cualquier consejo es apreciado. Hago mucha búsqueda en google pero no puedo hacer que funcione. Jersey 2. *. Cómo reemplazar InjectableProvider y AbstractHttpContextInjectable of Jersey 1. * podría ser la pregunta similar.
- ACTUALIZACIONES: uso AbstractBinder para enlazar mi resolución a 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");
}
}
¡Gracias!
Aquí está mi implementación real de la clase 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");
}
};
}
No sé cómo resolver su excepción. Sin embargo, puedo proponerle una manera diferente de hacer lo mismo. Espero que ayude.
He enfrentado exactamente el mismo problema: necesito parámetros adicionales en el encabezado http (por cierto, también relacionado con la autenticación). Además, debo enviarlos en cada llamada, ya que quiero hacer una implementación de descanso "típica", sin mantener una sesión.
Estoy usando Jersey 2.7, pero diría que debería funcionar en 2.0. He seguido su documentación https://jersey.java.net/documentation/2.0/filters-and-interceptors.html
Está bastante claro allí, pero de todos modos copio y pego mi implementación a continuación. Funciona bien. Es cierto que hay otras formas de asegurar un servicio de descanso, por ejemplo, esta es una buena: http://www.objecthunter.net/tinybo/blog/articles/89
Pero dependen de la implementación del servidor de aplicaciones y de la base de datos que utilice. El filtro, en mi opinión, es más flexible y más fácil de implementar.
Copiar y pegar: he definido un filtro para la autenticación, que se aplica a cada llamada y se ejecuta antes del servicio (gracias a @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() {
//...
}
});
}
}
Debe incluir esta clase de filtro en su implementación de ResourceConfig
,
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
// my init
// my packages
register(AuthenticationRequestFilter.class); // filtro de autenticación
// other register
}
}
¡Espero eso ayude!
Si lo que necesita es recuperar todos los encabezados http vinculados en un objeto, una solución podría ser usar la anotación @Context
para obtener javax.ws.rs.core.HttpHeaders
; que contiene la lista de todos los encabezados de solicitud.
@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);
}
}
Si todo lo que desea es pasar el valor directamente del encabezado al método, no necesita crear anotaciones personalizadas. Supongamos que tiene una Authorization
encabezado, luego puede acceder a ella fácilmente declarando su método así:
@GET
public String authFromHeader(@HeaderParam("Authorization") String authorization) {
return "Header Value: " + authorization + "/n";
}
Puedes probarlo llamando a curl
, por ejemplo
$ curl --header "Authorization: 1234" http://localhost:8080/rest/resource
Header Value: 1234
Dado que la respuesta a su pregunta, cómo crear un enlace personalizado es la siguiente.
Primero tienes que declarar tu anotación así:
@java.lang.annotation.Target(PARAMETER)
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Documented
public @interface UserAuthHeaderParam {
}
Una vez declarada su anotación, debe definir cómo se resolverá. Declare el Value Factory Provider (aquí es donde tendrá acceso a los parámetros del encabezado, vea mi comentario):
@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";
}
};
}
}
Ahora declara un resolutor de inyección.
public class UserAuthHeaderParamResolver extends ParamInjectionResolver<UserAuthHeaderParam> {
public UserAuthHeaderParamResolver() {
super(UserAuthHeaderParamValueFactoryProvider.class);
}
}
y un cuaderno para su configuración.
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);
}
}
ahora lo último, en tu ResourceConfig agregar register(new HeaderParamResolverBinder())
, como este
@ApplicationPath("rest")
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new HeaderParamResolverBinder());
packages("your.packages");
}
}
Dado eso, ahora debería poder utilizar el valor como quisiera:
@GET
public String getResult(@UserAuthHeaderParam String param) {
return "RESULT: " + param;
}
Espero que esto ayude.