Jersey中是不是有类似于Spring的HandlerInterceptor的Interceptor

Posted

技术标签:

【中文标题】Jersey中是不是有类似于Spring的HandlerInterceptor的Interceptor【英文标题】:Is there an Interceptor in Jersey similar to that of Spring's HandlerInterceptorJersey中是否有类似于Spring的HandlerInterceptor的Interceptor 【发布时间】:2016-06-14 03:24:03 【问题描述】:

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

类似于 Spring 的 HandlerInterceptor 的东西。

要求:

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

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

我找到了

的参考资料
    ReaderInterceptor - 这仅提供类的注释。无权访问请求/响应。 ContainerRequestFilter - 提供请求对象但不提供注释/响应。 ContainerResponseFilter - 提供请求和响应。但是在调用 web-service/Method 之后。

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

编辑: 感谢@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。

【问题讨论】:

感谢您返回并使用有效的解决方案进行更新。我一切正常,但我不明白 SkipWebServiceIntercept 是什么。这是如何创建的? 没关系,我刚刚创建了一个自定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface SkipWebServiceIntercept String value() default ""; 【参考方案1】:

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

有多种注册过滤器的方法。

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

    注册了一个注释,虽然name binding。这样,只有带注释的资源才会通过过滤器。 (这是你想要的,唯一的问题是你需要注释每个类)

    @Target(TYPE, METHOD)
    @Retention(RetentionPolicy.RUNTIME);
    class @interface Filtered 
    
    @Path("..")
    @Filtered
    public class YourResource 
    
    @Filtered
    @Provider
    public class YourFilter implements ContainerRequestFilter 
    

    Use a DynamicFeature 以编程方式而非声明方式绑定资源。 DynamicFeture 将为您的每个资源方法 调用,因此您只需为每个 调用注册过滤器。这与使用名称绑定注释每个资源类(如上所述)具有相同的效果(这可能是您想要的)。

    @Provider
    public class MyFeature implements DynamicFeature 
        @Override
        public void configure(ResourceInfo ri, FeatureContext ctx) 
            ctx.register(YourFilter.class);
        
    
    

另请参阅:

Chapter 10. Filters and Interceptors

【讨论】:

使用ContainerRequestFilter 的问题是我没有响应对象。我可以访问 ResourceInfo 来检查注释,但如果验证失败,那么我将不得不从过滤器本身重定向而不调用资源。使用 Servlet Filter 我可以使用 response.sendRedirect() 来实现这一点。如何使用 ContainerRequestFilter 来执行此操作?我探索了 ContainerRequestContext 的所有 API,但找不到响应。那么有没有办法从 ContainerRequestFilter 重定向到另一个 URL 呢? 您可以使用requestContext.abortWith(Response)...(Response.seeOther(...) 用于重定向) 或者您可以抛出异常并在ExceptionMapper中处理重定向 谢谢。我会尝试这些方法并更新。另外如何在球衣 web.xml 中注册 DynamicFeature?我写了一个 DynamicFeature 但配置方法没有被调用。 如果您按包扫描资源,即您有 init-param jersey.config.server.provider.packages,您可以使用多个包,只需用逗号分隔即可。包扫描获取@Provider 注释。或者您可以使用 init-param jersey.config.server.provider.classnames 显式注册该类

以上是关于Jersey中是不是有类似于Spring的HandlerInterceptor的Interceptor的主要内容,如果未能解决你的问题,请参考以下文章

JPA/Spring/Hibernate/etc 中是不是有类似于 JPA 的 @PrePersist 允许更改相关实体的功能?

列出所有已部署的 REST 端点(spring-boot、jersey)

有没有人在嵌入模式下使用Jersey(不是servlet env而是独立的Grizzly实例)成功使用模板引擎?

Jersey和Springboot应用程序抛出java.lang.StackOverflowError

spring boot - 迫使我在运行时使用jersey client 1.19

Spring boot、jwt、jersey、spring security和CORS问题