是否可以使用JAX-RS设置ETag而无需使用Response对象?

在我发现的关于JAX-RS和缓存的少数问题(有答案)之一中 ,生成ETag(用于缓存)的答案是在Response对象上设置一些值。 如下所示:

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

问题是对我们不起作用,因为我们对SOAP和REST服务使用相同的方法,通过使用@WebMethod(SOAP),@ GET(以及我们可能需要公开服务的任何其他方法)来注释方法。 以前的服务对我们来说是这样的(不包括标题的创建):

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

有没有办法 – 通过一些额外的配置 – 设置这些标题? 这是我第一次发现使用Response对象实际上只比自动转换有一些好处…

我们正在使用Apache CXF。

是的,如果您可以在创建响应对象后生成E-tag,则可以使用拦截器来实现此目的。

 public class MyInterceptor extends AbstractPhaseInterceptor { public MyInterceptor () { super(Phase.MARSHAL); } public final void handleMessage(Message message) { MultivaluedMap headers = (MetadataMap) message.get(Message.PROTOCOL_HEADERS); if (headers == null) { headers = new MetadataMap(); } //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); } } 

如果这种方式不可行,我会使用您发布的原始解决方案,只需将您的Person实体添加到构建器:

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

或者它可以像发回“错误”代码一样简单……取决于你想要做什么。

 @Path("/{id}") @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public ProductSearchResultBean getProductById(@PathParam("id") Integer productId, @QueryParam("expand") List 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; } 

无论如何,我就是这样解决问题的。 祝你好运! (使用Spring MVC代替….有一个开箱即用的filter可以为你做一切……甚至可以做一个好的ETag :))

您可以考虑使用响应filter。 我开发了一个完全符合您要求的气味库: https : //github.com/tobilarscheid/jaxrs-etag-filter