Cómo crear un servicio de JAX-RS donde el Sub-Resource @path no tiene una barra directa -- java campo con path campo con jax-rs campo con mime-types camp Relacionados El problema

How to create a JAX-RS service where the sub-resource @Path doesn't have a leading slash


6
vote

problema

Español

He creado un servicio JAX-RS (MyService) que tiene una serie de sub recursos, cada uno de los cuales es una subclase de MySuResource. La clase de recursos secundaria que se está seleccionando se selecciona en función de los parámetros que se proporcionan en la ruta de MyService, por ejemplo:

  @Path("/") @Provides({"text/html", "text/xml"})  public class MyResource {   @Path("people/{id}") public MySubResource getPeople(@PathParam("id") String id) {     return new MyPeopleSubResource(id);   }   @Path("places/{id}") public MySubResource getPlaces(@PathParam("id") String id) {     return new MyPlacesSubResource(id);   } }   

Donde MyPlacessuResource y MyPeoplesuResUresource son ambas subclases de MySuResource.

MySuResource se define como:

  public abstract class MySubResource {   protected abstract Results getResults();    @GET public Results get() { return getResults(); }    @GET @Path("xml")    public Response getXml() {     return Response.ok(getResults(), MediaType.TEXT_XML_TYPE).build();     }    @GET @Path("html")    public Response getHtml() {     return Response.ok(getResults(), MediaType.TEXT_HTML_TYPE).build();     } }   

Los resultados se procesan mediante correspondientes mensajes de mensajes, dependiendo del tipo mimetype de la respuesta.

Si bien esto lo hace, se traduce en rutas, como / personas / bob / html o / html o / bob / xml, donde lo que realmente quiero es /people/bob.html o /people/bob.xml

¿Alguien sabe cómo lograr lo que quiero hacer?

Original en ingles

I've created a JAX-RS service (MyService) that has a number of sub resources, each of which is a subclass of MySubResource. The sub resource class being chosen is picked based on the parameters given in the MyService path, for example:

@Path("/") @Provides({"text/html", "text/xml"})  public class MyResource {   @Path("people/{id}") public MySubResource getPeople(@PathParam("id") String id) {     return new MyPeopleSubResource(id);   }   @Path("places/{id}") public MySubResource getPlaces(@PathParam("id") String id) {     return new MyPlacesSubResource(id);   } } 

where MyPlacesSubResource and MyPeopleSubResource are both sub-classes of MySubResource.

MySubResource is defined as:

public abstract class MySubResource {   protected abstract Results getResults();    @GET public Results get() { return getResults(); }    @GET @Path("xml")    public Response getXml() {     return Response.ok(getResults(), MediaType.TEXT_XML_TYPE).build();     }    @GET @Path("html")    public Response getHtml() {     return Response.ok(getResults(), MediaType.TEXT_HTML_TYPE).build();     } } 

Results is processed by corresponding MessageBodyWriters depending on the mimetype of the response.

While this works it results in paths like /people/Bob/html or /people/Bob/xml where what I really want is /people/Bob.html or /people/Bob.xml

Does anybody know how to accomplish what I want to do?

           

Lista de respuestas

7
 
vote
vote
La mejor respuesta
 

Tema viejo, pero esto es algo que resolví recientemente usando Jersey; Tal vez ayude a alguien más.

Jersey Soporta especificando el tipo de contenido aceptado como una extensión de archivo en la URI a través del uso de filtros de solicitud. Jersey suministra un UriConnegFilter (filtro de contenido de contenido de URI) Objeto que se extiende para traducir extensiones específicas a los tipos de contenido. Luego, incluye ese filtro como un parámetro inicial a la aplicación Jersey.

Dado que todos los sonidos son tan vagos, aquí hay un ejemplo concreto de mi proyecto:

Quería poder interpretar ".json" y ".xml" al final de la URL como lo que significa que el cliente quería el contenido de JSON formateado o formateado por XML, respectivamente. Para ese fin, extendí UriConnegFilter así:

  package my.filter.package;  import com.sun.jersey.api.container.filter.UriConnegFilter;  import java.util.HashMap; import java.util.Map;  import javax.ws.rs.core.MediaType;   public class MediaTypeFilter extends UriConnegFilter {   private static final Map<String, MediaType> mappedMediaTypes = new HashMap<String, MediaType>(2);    static {     mappedMediaTypes.put("json", MediaType.APPLICATION_JSON_TYPE);     mappedMediaTypes.put("xml", MediaType.APPLICATION_XML_TYPE);   }    public MediaTypeFilter() {     super(mappedMediaTypes);   } }   

Entonces, ya que estoy usando Jersey como un servlet, agregué 9988777663 a mi web.xml:

  <servlet>   <servlet-name>My Jersey Servlet</servlet-name>   <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>   <init-param>     <param-name>com.sun.jersey.config.property.packages</param-name>     <param-value>my.resource.package</param-value>   </init-param>   <init-param>     <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>     <param-value>com.sun.jersey.api.container.filter.LoggingFilter;                  my.filter.package.MediaTypeFilter;                  com.sun.jersey.api.container.filter.PostReplaceFilter;                  com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>   </init-param>   <init-param>     <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>     <param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter;                  com.sun.jersey.api.container.filter.LoggingFilter</param-value>   </init-param>   <load-on-startup>1</load-on-startup> </servlet>   

Con eso en su lugar, Jersey traduce la extensión en el URI en el tipo de medios especificado, y elimina la extensión. Esto funciona para obtener recursos raíz y sub-recursos porque funciona en todo el URI. Para su ejemplo particular, /people/bob.xml se convertiría / personas / Bob y el encabezado 9988777665 en la solicitud "Aplicación / XML" (anulando cualquier Accept666666 código> encabezado).

hth,

-PETER

 

Old topic, but this is something I solved recently using Jersey; perhaps it'll help someone else.

Jersey supports specifying the accepted content type as a file extension in the URI through the use of request filters. Jersey supplies a UriConnegFilter (URI Content Negotiation Filter) object that you extend to translate specific extensions to content types. You then include that filter as an initial parameter to the Jersey application.

Since that all sounds so vague, here's a concrete example from my project:

I wanted to be able to interpret ".json" and ".xml" at the end of the URL as meaning that the client wanted JSON-formatted or XML-formatted content, respectively. To that end, I extended UriConnegFilter like so:

package my.filter.package;  import com.sun.jersey.api.container.filter.UriConnegFilter;  import java.util.HashMap; import java.util.Map;  import javax.ws.rs.core.MediaType;   public class MediaTypeFilter extends UriConnegFilter {   private static final Map<String, MediaType> mappedMediaTypes = new HashMap<String, MediaType>(2);    static {     mappedMediaTypes.put("json", MediaType.APPLICATION_JSON_TYPE);     mappedMediaTypes.put("xml", MediaType.APPLICATION_XML_TYPE);   }    public MediaTypeFilter() {     super(mappedMediaTypes);   } } 

Then, since I am using Jersey as a Servlet, I added MediaTypeFilter to my web.xml:

<servlet>   <servlet-name>My Jersey Servlet</servlet-name>   <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>   <init-param>     <param-name>com.sun.jersey.config.property.packages</param-name>     <param-value>my.resource.package</param-value>   </init-param>   <init-param>     <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>     <param-value>com.sun.jersey.api.container.filter.LoggingFilter;                  my.filter.package.MediaTypeFilter;                  com.sun.jersey.api.container.filter.PostReplaceFilter;                  com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>   </init-param>   <init-param>     <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>     <param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter;                  com.sun.jersey.api.container.filter.LoggingFilter</param-value>   </init-param>   <load-on-startup>1</load-on-startup> </servlet> 

With that in place, Jersey translates the extension on the URI into the specified media type, and removes the extension. This works for root resources and sub-resources because it operates on the whole URI. For your particular example, /people/Bob.xml would become /people/Bob and the Accept header in the request would be changed to "application/xml" (overriding any existing Accept header).

hth,

-Peter

 
 
 
 
1
 
vote

Posiblemente podría escribir un enrutamiento de servlet para resolverlo. Sin embargo, de manera realista, debe estar usando tipos de contenido para hacer esto.

  @GET @Path("/") @Produces(MediaType.APPLICATION_XML) public Response getXml() { ... }  @GET @Path("/") @Produces(MediaType.APPLICATION_HTML) public Response getHtml() { ... }   

El proveedor JAX-RS resolverá qué llamará en función de la solicitud del cliente. ¡Aún mejor, podríamos hacerlo Jaxb y RESTEASY para hacerlo todo por ti!

  @GET @Produces(MediaType.APPLICATION_XML) @Path("/{id}") public MyObject getXml(@PathParam("typeDocument") String id) {  myObjectService.get(id); }   @XmlRootElement(name="myObject") public class MyObject { // Some properties }   

Consulte http://java.dzone.com/articles/Resteasy-Spring Para un buen ejemplo con la primavera.

 

You could possibly write some servlet routing to work it out. Realistically though, you should be using Content Types to do this.

@GET @Path("/") @Produces(MediaType.APPLICATION_XML) public Response getXml() { ... }  @GET @Path("/") @Produces(MediaType.APPLICATION_HTML) public Response getHtml() { ... } 

The JAX-RS provider will then work out what to call based on the client's request. Even better, you could us JAXB and RestEASY to do it all for you!

@GET @Produces(MediaType.APPLICATION_XML) @Path("/{id}") public MyObject getXml(@PathParam("typeDocument") String id) {  myObjectService.get(id); }   @XmlRootElement(name="myObject") public class MyObject { // Some properties } 

See http://java.dzone.com/articles/resteasy-spring for a good example with Spring.

 
 
 
 
1
 
vote

Este es un antiguo tema y estoy seguro de que usted descubrió esto, pero para aquellos que llegan a esta página, RESTEASY tiene una manera fácil de lograr lo que necesita. Se llama negociación de contenido basada en URL.

ver detalles aquí: http: //docs.jboss.org/reseasy/docs/2.0.0ga/userguide/html_single/index.html#media_mappings

Básicamente, debe agregar un parámetro de contexto en su archivo web.xml que le dirá a Retasony para asignar el sufijo de su URL a un tipo de contenido específico:

  <context-param>     <param-name>resteasy.media.type.mappings</param-name>     <param-value>html : text/html, json : application/json, xml : application/xml</param-value> </context-param>   

Con esto, acceder a /people/bob.xml es lo mismo que Aessing / People / Bob y especificando una codificación de aceptación: Aplicación / XML.

 

This is an old topic and I'm sure you figured this out, but for those getting to this page, Resteasy has an easy way to achieve what you needed. It's called URL-based content negotiation.

See details here: http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html_single/index.html#media_mappings

Basically, you need to add a context parameter in your web.xml file that will tell Resteasy to map the suffix of your URL to a specific content-type:

<context-param>     <param-name>resteasy.media.type.mappings</param-name>     <param-value>html : text/html, json : application/json, xml : application/xml</param-value> </context-param> 

With this, accessing /people/Bob.xml is the same as acessing /people/Bob and specifying an Accept-Encoding: application/xml.

 
 
1
 
vote

Una forma de resolver esto es que probablemente puede usar una captura de expresión regular en su @ javax.ws.rs.Path.

  UriConnegFilter0  

luego en su sub-recurso:

  UriConnegFilter111  

Ten cuidado con las expresiones regulares. Di un ejemplo, pero es posible que desee apretar la expresión para asegurarse de que nada se desliza a través.

Otra forma de resolver Esto es cambiar dónde se está capturando su {ID} y use la expresión regular allí. En lugar de tener UriConnegFilter2 capture la identificación, elimine la captura de ID de GetPeople () y cambie MySuResource, así:

  UriConnegFilter3  

Hay concesiones en cualquier caso, dependiendo de cómo se organizan sus estructuras de datos y cuando necesite conocer el parámetro "ID". No soy particularmente aficionado a las expresiones regulares, ya que son muy difíciles de tener en la derecha, pero es una posibilidad en este caso.

 

One way to solve this is you can probably use a regular expression capture in your @javax.ws.rs.Path.

@Path("people/{id:[^/]+?}{format:(\\.[^/]*?)?}") @GET public MySubResource getPeople(@PathParam("id") String id, @PathParam("format") String format) {     // remove the "." from the start of "format" if it is not null     return new MySubResource(id, format); } 

Then in your sub-resource:

public abstract class MySubResource {     final protected String format;      protected MySubResource(String id, String format) {         this.format = format;     }      protected abstract Results getResults();      @GET     public Response get() {        return Response.ok(getResults(), this.format).build();       } } 

Be careful with the regular expressions. I gave an example but you may want to tighten the expression to make sure that nothing slips through.

Another way to solve this is to change where your {id} is being captured and use the regular expression there. Instead of having @Path("id") MySubResource public getPeople(@PathParam("id") String id) capture the id, remove the id capture from getPeople() and change MySubResource like so:

 @Path("people")  public MySubResource getPeople() {     return new MyPeopleSubResource();  }  public abstract class MySubResource {   protected abstract Results getResults();    @GET   @Path("{id}")   public Results get() { return getResults(); }    @GET   @Path("{id}.xml")    public Response getXml() {     return Response.ok(getResults(), MediaType.TEXT_XML_TYPE).build();     }    @GET   @Path("{id}.html")    public Response getHtml() {     return Response.ok(getResults(), MediaType.TEXT_HTML_TYPE).build();     } } 

There are tradeoffs in either case depending on how your data structures are organized and when you need to know the "id" parameter. I'm not particular fond of regular expressions since they're really hard to get right but it's a possibility in this case.

 
 
 
 

Relacionados problema

1  Detección de tipo MIME incorrecto en Mac / Ubuntu  ( Wrong mime type detection in mac ubuntu ) 
Estoy ejecutando Mac 10.10.3. Supongamos some_file.xlsx es un archivo de MS Excel adecuado. Cuando escribo file -b --mime some_file.xlsx , obtengo appli...

2  Rails + Filepicker GEM: ¿Cómo permitir cargar solo imágenes?  ( Rails filepicker gem how to allow to upload only images ) 
Estoy usando la gema oficial de Filepicker para las aplicaciones de rieles y hasta ahora, si quiero especificar los mimetypes como todas las imágenes, lo esto...

57  Cambiar el tipo de salida MIME en PHP  ( Change mime type of output in php ) 
Tengo un script PHP. La mayoría de las veces que el script devuelve HTML, que está funcionando bien, pero en una ocasión (parámetro? Formato = XML) El script ...

0  ¿Hay algún método para deducir el tipo de contenido desde el archivo [duplicado]  ( Is there any method to deduct content type from file ) 
Esta pregunta ya tiene respuestas aquí : Cerrado 9 años . posible duplicado: obtener el ti...

13  Tipo MIME SPOOFING  ( Mime type spoofing ) 
Comprobación del tipo MIME en PHP es bastante fácil, pero por lo que sé, MIME puede ser falsificado. El atacante puede cargar un script PHP con por ejemplo, J...

4  Usando la biblioteca PHP GD para cambiar el tamaño y guardar imágenes es el infierno  ( Using the php gd library to resize and save images is hell ) 
Estoy escribiendo un script que cargará un archivo de la entrada del usuario, cambiarlo de tamaño a una miniatura y agregar los dos nuevos nombres de archivo ...

3  Nodo JS: ¿Cómo obtener encabezados de firma de archivos en lugar de tipo MIME?  ( Node js how to get file signature headers instead of mime type ) 
He descargado este módulo para mi proyecto de nodo js, ​​y parece funcionar bien hasta cierto punto. Si usted console.log(mime.lookup(pathToFile)); devuel...

10  manejar la solicitud de JSON en PHP  ( Handle json request in php ) 
Al realizar una llamada AJAX, cuando CONTENTTYPE está configurado en Aplicación / JSON en lugar del lado predeterminado, el lado del servidor (en PHP), no pue...

0  ¿Cómo pasar datos ocultos en la línea de asunto PHP Correo electrónico?  ( How to pass hidden data in php email subject line ) 
Como quiero manejar la falla por correo electrónico y, en ese caso, cuando envía correo a otro y, si se incita a la razón no válida para correo electrónico o ...

2  ¿Por qué se solicitan páginas en My Rails Aplicación con un tipo MIME TXT? [cerrado]  ( Why are pages in my rails app being requested with a txt mime type ) 
cerrado. Esta pregunta es off-topic . Actualmente no está aceptando respuestas. ¿Quieres ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos