Jersey中的Interceptor是否类似于Spring的HandlerInterceptor

时间:2016-03-01 15:57:05

标签: spring filter servlet-filters interceptor jersey-2.0

我需要Jersey 2.x中的一个拦截器,它提供对请求,响应和与Web服务路径匹配的方法的引用。

类似于Spring的 HandlerInterceptor

要求:

  1. 需要在类上使用的注释 - 执行以下检查,仅当需要通过jersey调用的相应方法未使用自定义注释进行注释时。
  2. 请求 - 获取/设置属性并获取会话对象以验证用户。
  3. 响应 - 如果在调用相应的Methos之前验证失败,则重新定向呼叫。
  4. Spring等效代码:

    public class WebServiceInterceptor implements HandlerInterceptor {
         @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            try {
                SkipWebServiceIntercept skipWebService = handler.getClass().getAnnotation(SkipWebServiceIntercept.class);
    
                if (skipWebService != null) {
                    return Boolean.TRUE;
                }
    
                ...
    
                if(securityFails)
                {
                    if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
                        response.setCharacterEncoding("utf-8");
                        response.setContentType("application/json");
                        PrintWriter out = response.getWriter();
                        String json;
                        ...
                        out.println(json);
                        return Boolean.FALSE;
                    }
                    else {
                        response.sendRedirect(redirectUrl);
                    }
                }
                else
                {
                    return Boolean.TRUE;
                }
            }catch (Exception e) {
                log.error("Exception in preHandle, redirecting to Login page", e);
                return LoginUtil.redirectToLogin(request, response);
            }
        }
    }
    

    我找到了

    的参考资料
    1. ReaderInterceptor - 这只提供了Class的注释。无法访问请求/响应。
    2. ContainerRequestFilter - 提供请求对象但没有注释/响应。
    3. ContainerResponseFilter - 提供请求&响应。但是在调用web-service / Method之后。
    4. 如果不使用过滤器,还有其他方法可以实现。因为只有相应的网络服务存在,才需要进行此处理。 另一方面,使用/ *过滤器即使在未找到资源时也始终执行这些验证。

      修改 感谢@peeskillet answer这就是我实现它的方式。

      @Provider
      public class ResourceInterceptor implements DynamicFeature {
      
          @Override
          public void configure(ResourceInfo resourceInfo, FeatureContext context) {
      
              System.out.println("Resource Interceptor called");
      
              if (resourceInfo.getResourceClass() != null
                      && resourceInfo.getResourceClass().getAnnotation(SkipWebServiceIntercept.class) != null)
                  return;
      
              context.register(LoginFilter.class);
          }
      
      }
      
      
      @Slf4j
      public class LoginFilter implements ContainerRequestFilter {
      
          @Context
          private HttpServletRequest      request;
      
          @Context
          private ServletContext          servletContext;
      
          @Override
          public void filter(ContainerRequestContext requestContext) throws IOException {
              try {
      
      
      WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
      
      CookieAuthenticator cookieAuthenticator = springContext.getBean(CookieAuthenticator.class);
      
      HttpSession session = request.getSession(true);
      
      ...
      
        

      //将JSON / Object作为响应发送回来

      ...
      String json = gson.toJson(resposeJson);
      
      Response response = new ResponseBuilderImpl().encoding(StandardCharsets.UTF_8.name())
                              .type(MediaType.APPLICATION_JSON).entity(json).build();
      requestContext.abortWith(response);
      ...
      
        

      //或发回网址

      ...
      URI uri = new URI(baseUrl + redirectUrl + "?refback=" + url);
      requestContext.abortWith(Response.temporaryRedirect(uri).build());
      ...
      

      这两种方法都很完美,类似于Spring的HandlerInterceptor。

1 个答案:

答案 0 :(得分:3)

  

如果不使用过滤器,还有其他方法可以实现。因为只有相应的网络服务存在,才需要进行此处理。另一方面,使用/ *进行过滤将始终执行这些验证,即使找不到资源也是如此。

注册过滤器有多种方法。

  1. 只需正常注册,结果是过滤器始终被调用。 (你不想要的)。

  2. 使用注释注册name binding。这样,只有注释的资源才会通过过滤器。 (这是有点你想要什么,只有问题是你需要注释每个类)

    @Target({TYPE, METHOD})
    @Retention(RetentionPolicy.RUNTIME);
    class @interface Filtered {}
    
    @Path("..")
    @Filtered
    public class YourResource {}
    
    @Filtered
    @Provider
    public class YourFilter implements ContainerRequestFilter {}
    
  3. Use a DynamicFeature以编程方式绑定资源,而不是以声明方式绑定资源。将为您的每个资源方法调用DynamicFeture,因此您只需为每次调用注册过滤器。这与使用名称绑定注释每个资源类(如上所述)具有相同的效果(这可能是您想要的)。

    @Provider
    public class MyFeature implements DynamicFeature {
        @Override
        public void configure(ResourceInfo ri, FeatureContext ctx) {
            ctx.register(YourFilter.class);
        }
    }
    
  4. 另见: