Jersey 中是否有类似于 Spring 的 HandlerInterceptor 的拦截器

Ban*_*ore 5 spring filter interceptor servlet-filters jersey-2.0

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

类似于Spring 的HandlerInterceptor的东西。

要求:

  1. 需要在类上使用注释- 执行以下检查,仅当需要被 jersey 调用的相应方法未使用自定义注释进行注释时。
  2. 请求- 获取/设置属性并获取会话对象以验证用户。
  3. 响应- 重新定向调用,以防任何验证在调用相应的方法之前都失败。

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我找到了参考资料

  1. ReaderInterceptor - 这仅提供类的注释。无法访问请求/响应。
  2. ContainerRequestFilter - 提供请求对象但没有注释/响应。
  3. ContainerResponseFilter - 提供请求和响应。但是在调用 web-service/Method 之后。

有没有其他方法可以在不使用过滤器的情况下实现。因为我只需要在相应的 Web 服务存在时才进行此处理。另一方面,带有 /* 的过滤器将始终执行这些验证,即使未找到资源。

编辑: 感谢@peeskillet回答这就是我实现它的方式。

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

...
Run Code Online (Sandbox Code Playgroud)

// 发送 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);
...
Run Code Online (Sandbox Code Playgroud)

// 或发回 URL

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

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

Pau*_*tha 3

有没有其他方法可以在不使用过滤器的情况下实现这一目标。因为我需要仅当相应的网络服务存在时才进行此处理。另一方面,带有 /* 的过滤器将始终执行这些验证,即使未找到资源也是如此。

注册过滤器有多种方法。

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

  2. 通过注解注册,但名称绑定。这样,只有带注释的资源才会通过过滤器。(这就是想要的,唯一的问题是你需要注释每个类)

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

    @Provider
    public class MyFeature implements DynamicFeature {
        @Override
        public void configure(ResourceInfo ri, FeatureContext ctx) {
            ctx.register(YourFilter.class);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

也可以看看: