2012-07-03 6 views
12

En one of the few questions (with answers) he encontrado en SO con respecto a JAX-RS y el almacenamiento en caché, la respuesta a la generación de ETags (para el almacenamiento en caché) es mediante la configuración de algunos valores en el objeto de respuesta. Como en el siguiente:¿Es posible establecer ETags usando JAX-RS sin recurrir a objetos de respuesta?

@GET 
@Path("/person/{id}") 
public Response getPerson(@PathParam("id") String name, @Context Request request){ 
    Person person = _dao.getPerson(name); 

    if (person == null) { 
    return Response.noContent().build(); 
    } 

    EntityTag eTag = new EntityTag(person.getUUID() + "-" + person.getVersion()); 

    CacheControl cc = new CacheControl(); 
    cc.setMaxAge(600); 

    ResponseBuilder builder = request.evaluatePreconditions(person.getUpdated(), eTag); 

    if (builder == null) { 
    builder = Response.ok(person); 
    } 

    return builder.cacheControl(cc).lastModified(person.getUpdated()).build(); 
} 

El problema es que no va a funcionar para nosotros, ya que utilizamos los mismos métodos para SOAP y REST servicios, anotando los métodos con @WebMethod (SOAP), @GET (y cualquier otra cosa que necesitemos para exponer el servicio). El servicio anterior se parecería a esto a nosotros (con exclusión de la creación de cabeceras):

@WebMethod 
@GET 
@Path("/person/{id}") 
public Person getPerson(@WebParam(name="id") @PathParam("id") String name){ 
    return _dao.getPerson(name); 
} 

¿Hay alguna manera - a través de alguna configuración adicional - de establecer esas cabeceras? Esta es la primera vez que encuentro que el uso de objetos Response en realidad tiene algún beneficio sobre la auto conversión ...

Estamos usando Apache CXF.

+0

¿Podría posiblemente usar algún tipo de Interceptor? http://stackoverflow.com/questions/3165647/apache-cxf-how-to-add-custom-http-header-to-jax-rs-response?rq=1 – oligofren

Respuesta

7

Sí, es posible que pueda utilizar interceptores para lograr esto si pudiera generar la etiqueta E DESPUÉS de crear su objeto de respuesta.

public class MyInterceptor extends AbstractPhaseInterceptor<Message> { 

    public MyInterceptor() { 
     super(Phase.MARSHAL); 
    } 

    public final void handleMessage(Message message) { 
     MultivaluedMap<String, Object> headers = (MetadataMap<String, Object>) message.get(Message.PROTOCOL_HEADERS); 

     if (headers == null) { 
      headers = new MetadataMap<String, Object>(); 
     }    

     //generate E-tag here 
     String etag = getEtag(); 
     // 
     String cc = 600; 

     headers.add("E-Tag", etag); 
     headers.add("Cache-Control", cc); 
     message.put(Message.PROTOCOL_HEADERS, headers); 
    } 
} 

Si de esa manera no es viable, usaría la solución original que usted envió, y acaba de añadir su entidad Persona al constructor:

Person p = _dao.getPerson(name); 
return builder.entity(p).cacheControl(cc).lastModified(person.getUpdated()).build(); 
1

o puede ser tan simple como enviar respalda un código de "error" ... dependiendo de lo que quieras hacer.

@Path("/{id}") 
@GET 
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) 
public ProductSearchResultBean getProductById(@PathParam("id") Integer productId, @QueryParam("expand") List<String> expand, @Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { 

    ProductSearchResultBean productDetail = loadProductDetail(productId, expand); 

    EntityTag etag = new EntityTag(((Integer)(productDetail.toString().hashCode())).toString()); 
    String otherEtag = request.getHeader("ETag"); 
    if(etag.getValue().equals(otherEtag)){ 
     response.sendError(304, "not Modified"); 
    } 

    response.addHeader("ETag", etag.getValue()); 

    return productDetail; 
} 

Así es como me enfrenté a la situación de todos modos. ¡Buena suerte! (Use Spring MVC en su lugar ... hay un filtro listo para usar que hace TODO por usted ... incluso haciendo una buena ETag :))

Cuestiones relacionadas