10

我正在尝试使用 Jersey 开发 RESTful API。我有 GET API 用于特定的获取操作,我的 GET 从同一个客户端花费相同的时间。是否可以缓存响应?任何指针表示赞赏。

谢谢

4

4 回答 4

10

您可以使用 CacheControl、eTag - 遵循以下示例代码

// In your jersey method
    final EntityTag eTag = new EntityTag(resource.getId() + "_" +
     resource.getLastModified().getTime());
    final CacheControl cacheControl = new CacheControl();
    cacheControl.setMaxAge(-1);

    ResponseBuilder builder = request.evaluatePreconditions(
         resource.getLastModified(), eTag);

    // the resoruce's information was modified, return it
    if (builder == null) {
         builder = Response.ok(resource);
    }

    // the resource's information was not modified, return a 304

    return builder.cacheControl(cacheControl).lastModified(
         resource.getLastModified()).tag(eTag).build();

替换resource为您的资源实例。

于 2013-02-26T11:32:01.810 回答
8

解决方案总结:

  1. 请求作为方法参数

    界面:

     @Path("myentity")
     public interface MyEntityResource
    
         @GET
         @Produces(MediaType.APPLICATION_JSON)
         public Response getMyEntity(@Context final Request request);
     }
    

    执行:

     public class MyEntityResourceImpl implements MyEntityResource
    
         @Override
         public Response getMyEntity(final Request request) {
    
             final MyEntity myEntity = ... // load entity
             final String eTagValue = ... // calclutate value of ETag
    
             final EntityTag eTag = new EntityTag(eTagValue);
    
             ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
             if (responseBuilder == null) {
                 return Response.ok(user).tag(eTag).build();
             }
    
             return responseBuilder.build();
         }
     }
    

    缺点:

    • 实施细节Request暴露

    • 返回类型Reponse是通用的

    • WADL 中缺少返回类型的语法

    • 带有不必要参数的客户端代理Request

  2. 请求作为实例变量

    界面:

     @Path("myentity")
     public interface MyEntityResource
    
         @GET
         @Produces(MediaType.APPLICATION_JSON)
         public Response getMyEntity();
     }
    

    执行:

     public class MyEntityResourceImpl implements MyEntityResource
    
         @Context
         private Request request
    
         @Override
         public Response getMyEntity() {
    
             final MyEntity myEntity = ... // load entity
             final String eTagValue = ... // calclutate value of ETag
    
             final EntityTag eTag = new EntityTag(eTagValue);
    
             ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
             if (responseBuilder == null) {
                 return Response.ok(user).tag(eTag).build();
             }
    
             return responseBuilder.build();
         }
     }
    

    缺点:

  3. ShallowEtagHeaderFilter作为网络过滤器

    网页.xml:

     <filter>
         <filter-name>etagFilter</filter-name>
         <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
     </filter>
     <filter-mapping>
         <filter-name>etagFilter</filter-name>
         <url-pattern>/api/*</url-pattern>
     </filter-mapping>
    

    界面:

     @Path("myentity")
     public interface MyEntityResource
    
         @GET
         @Produces(MediaType.APPLICATION_JSON)
         public MyEntity getMyEntity();
     }
    

    执行:

     public class MyEntityResourceImpl implements MyEntityResource
    
         @Override
         public MyEntity getMyEntity() {
    
             final MyEntity myEntity = ... // load entity
             return myEntity;
         }
     }
    

    缺点:

    • 服务器性能不佳,请参阅JavaDoc

    • 仅适用于未提交的响应

    • 不支持弱ETag

  4. 自定义WriterInterceptor作为JAX-RS 拦截器

    拦截器:

     public class CustomInterceptor implements WriterInterceptor {
    
         @Context
         private Request request;
    
         @Override
         public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
    
             OutputStream old = context.getOutputStream();
    
             ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    
             try {
    
                 context.setOutputStream(buffer);
                 context.proceed();
    
                 byte[] entity = buffer.toByteArray();
    
                 String etag = ... // calclutate value of ETag
                 context.getHeaders().putSingle(HttpHeaders.ETAG, etag);
    
                 ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
                 if (responseBuilder == null) {
                      throw new WebApplicationException(responseBuilder.status(Response.Status.NOT_MODIFIED).header(HttpHeaders.ETAG, etag).build());
                 }
    
                 old.write(entity);
    
             } finally {
                 context.setOutputStream(old);
             }
         }
     }
    

    另请参阅:ServerCacheInterceptor (Resteasy)

    界面:

     @Path("myentity")
     public interface MyEntityResource
    
         @GET
         @Produces(MediaType.APPLICATION_JSON)
         public MyEntity getMyEntity();
     }
    

    执行:

     public class MyEntityResourceImpl implements MyEntityResource
    
         @Override
         public MyEntity getMyEntity() {
    
             final MyEntity myEntity = ... // load entity
             return myEntity;
         }
     }
    

    缺点:

    • 没有可用的 Jersey 预定义拦截器

    • 服务器性能不佳

    • 不支持弱ETag

    • 丑陋的解决方法WebApplicationException

于 2016-01-06T14:14:59.270 回答
3

您可以将适用于标准 java 的任何缓存机制与 Jersey 一起使用,例如Ehcache

您只需要注意验证您在后端的数据没有更改。

这是一个简单的例子Ehcache

@GET
@Path("{id}")
public List<Data> getData(@PathParam("id") Long id) {
    Element element = CacheManager.getInstance().getCache("test").get(id);
    if(element == null) {
        Data value = fetchElementFromBackend(id);
        CacheManager.getInstance().getCache("test").put(new Element(id, value));
        return value;
    }

    return element.getObjectValue();
}
于 2013-02-26T11:31:51.500 回答
1

最近我一直在解决一个类似(如果不一样的话)的问题。作为它的附带结果,出现了以下库: https ://github.com/AndreyLebedenko/dropwizard-caching-filter

它的使用方式如下:

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/cached")
@ResponseCachedByFilter(10000)
public Object getCached() {
    return dao.get();
} 

希望能帮助到你。

于 2018-11-10T19:43:50.030 回答