Можно ли установить ETags с помощью JAX-RS, не прибегая к объектам ответа?
В одном из немногих вопросов (с ответами), которые я нашел на SO относительно JAX-RS и кэширования, ответ на генерацию ETags (для кэширования) заключается в установке некоторых значений на объект ответа. Как в следующем:
@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);
}
Существует ли какой - либо способ - через некоторую дополнительную конфигурацию-установки этих заголовков? Это первый раз, когда я обнаружил, что использование объектов ответа на самом деле имеет некоторое преимущество перед просто автоматическим преобразованием ...
Мы используем Apache CXF.
3 ответа:
Да, вы могли бы использовать перехватчики для достижения этой цели, если бы вы могли генерировать электронный тег после создания объекта ответа.
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); } }
Если этот способ не жизнеспособен, я бы использовал оригинальное решение, которое вы опубликовали, и просто добавил бы вашу личность в конструктор:
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<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; }
Именно так я в любом случае взялся за issure. Удачи вам! (Вместо этого используйте Spring MVC.... есть фильтр из коробки, который делает все за вас... даже делая хороший ETag :))
Для этого можно использовать фильтр ответов. Я разработал библиотеку запахов, делая именно то, что вы ищете: https://github.com/tobilarscheid/jaxrs-etag-filter