簡體   English   中英

從Jersey過濾器或攔截器內部訪問資源方法參數。 或者使用AOP和資源方法

[英]Access resource method arguments from inside a Jersey filter or interceptor. Or use AOP with resource method

我正在嘗試使用用戶的ID在每個請求上豐富SLF4J MDC。 問題是ID可以以多種方式傳遞,有時作為路徑參數傳遞,有時在體內,有時由首先解密它的自定義ValueFactoryProvider注入。

如果我可以以某種方式訪問​​所有注入(即已經反序列化 )的參數值,我可以輕松處理所有這些情況。

例如

對於以下資源:

@GET
//@Encrypted params are injected by a custom ValueFactoryProvider
public Something getSomething(@Encrypted("userId") String userId) {
    return ...;
}

@POST
public Something getSomething(@RequestBody RequestWithUserId requestWithUserId) {
    return ...;
}

我可以有一個過濾器,如:

public class MdcFilter implements ContainerRequestFilter, ContainerResponseFilter {

    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        Method theMethod = resourceInfo.getResourceMethod();
        for (Parameter parameter : theMethod.getParameters()) {
            //Deal with the @Encrypted case
            if (parameter.isAnnotationPresent(Encrypted.class) && parameter.getAnnotation(Encrypted.class).value().equals("userId")) {
                MDC.put("userId", somehowGetTheValue());
            }
            //Deal with the @RequestBody case
            if (parameter.isAnnotationPresent(RequestBody.class) && parameter.getType().equals(RequestWithUserId.class)) {
                MDC.put("userId", ((RequestWithUserId)somehowGetTheValue()).getUserId());
            }
            ... //other possibilities
        }
    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        MDC.clear();
    }
}

但我沒有看到從ContainerRequestFilter攔截器或其他任何東西實現somehowGetTheValue的方法......

澤西使用引擎蓋下的HK2進行依賴注入。 HK2有AOP支持 您的用例的一個選項是使用此AOP支持。 您需要做的就是實現一個MethodInterceptor和一個InterceptionService MethodInterceptor ,您可以從MethodInvocation獲取所有參數,並且可以從Method獲取參數注釋

class MyMethodInteceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        Object[] args = invocation.getArguments();

        // do your logging or whatever with the args.

        // invoke method and get return value.
        Object returnValue = invocation.proceed();
        // if you want to do something with the return
        // value before returning it, you can.

        return returnValue;
    }
}

要使用攔截器,請配置InterceptionService

public class MyInterceptionService implements InterceptionService {

    private final static MethodInterceptor METHOD_INTERCEPTOR 
            = new MyMethodInterceptor();
    private final static List<MethodInterceptor> METHOD_LIST
            = Collections.singletonList(METHOD_INTERCEPTOR);

    @Override
    public Filter getDescriptorFilter() {
        return BuilderHelper.allFilter();
    }

    @Override
    public List<MethodInterceptor> getMethodInterceptors(Method method) {
        // you implement shouldIntercept
        if (shouldIntercept(method)) {
            return METHOD_LIST;
        }
        return null;
    }

    @Override
    public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> constructor) {
        return null;
    }
}

您可以確定在getMethodInterceptors()方法中應截取哪個方法。 如果該方法應該被截獲,則返回一個攔截器列表,否則返回null。 處理此問題的常用方法是創建自定義注釋並僅注釋該方法。 在上面的方法中,只需檢查

if (method.isAnnotationPresent(YourAnno.class)) {
    return METHOD_LIST;
}

要使一切正常,您只需要使用HK2注冊InteceptionService 您可以在AbstractBinder執行此操作,這是Jersey應用程序中用於配置DI的內容。

ResourceConfig config = new ResourceConfig();
config.register(new AbstractBinder() {
    @Override
    protected void configure() {
        bind(MyInterceptionService.class)
                .to(InterceptionService.class)
                .in(Singleton.class);
    }
});

你可以在這個GitHub倉庫中看到一個完整的例子。 在HK2網站上也有一個官方的例子。 只需在帖子頂部看到“AOP支持”鏈接即可。

你可以這樣得到它

StringWriter stringWriter = new StringWriter();
IOUtils.copy(new InputStreamReader(requestContext.getEntityStream()), stringWriter);
System.out.println(stringWriter.toString());// String representation of the payload
requestContext.setEntityInputStream(new ByteArrayInputStream(requestEntity));

基本上,我們的想法是復制流並進行任何處理,然后重新設置流。 因為如果你不這樣做,那么在你的控制器方法中你會得到null,因為已經讀取了流。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM