Jersey實現對方法進行過濾攔截
阿新 • • 發佈:2019-01-04
在web程式開發過程中,通常我們會需要對我們的介面進行訪問控制,例如控制使用者的訪問許可權、記錄使用者的訪問日誌等,在我們使用Jersey進行Restful服務開發中,同樣會有類似需求,下面我們介紹下,使用Jersey框架,實現介面訪問的三種方式。
一、使用註解名稱繫結過濾器 1.1 建立名稱繫結註解 使用@NameBinding註解,可以定義一個執行時的自定義註解,該註解可以用於定義類級別名稱和淚的方法。例如,我們定義一個使用者訪問的註解。
@UserLogger 就是我們自定義的名稱繫結註解
@Priority 是用於表示該過濾器的執行順序,其中引數為long型別,對於請求過濾器,該數值越小越先執行,響應過濾器則相反。
ContainerRequestFilter 為請求過濾器
ContainerResponseFilter 為響應過濾器
在請求和響應的過濾方法中,我們簡單的列印輸出。 需要注意的是,我們建立了過濾器之後需要在Jersey中進行宣告,我們在Jerysey的ResourceConfig 子類中,註冊該過濾器,註冊有兩種方式,一種是掃描包的形式,這時需要在過濾器上加上@Provider註解,另一種是直接註冊該過濾器。
1.3 註解繫結介面 上面我們建立好註解和過濾器之後,需要將在我們需要使用過濾器的介面方法上使用註解。
2.1 實現動態繫結特徵
我們需要在同樣我們需要註冊該動態特徵來
名稱繫結相比於動態繫結使用範圍更廣,因為我們使用註解的方式,可以對任意資源,任意方法進行控制。而使用動態繫結的形式,我們需要在動態特徵類進行對應的匹配,適用範圍較窄。 三、使用註解繫結攔截器 前面的兩種形式是通過過濾器的形式,對介面控制,一般我們做日誌訪問記錄等方式,採用該方式較好。而如果我們需要控制使用者對介面的訪問,例如登陸控制,許可權控制等,就需要使用方法攔截器。
由於Jersey中的AOP是基於HK2框架實現的,所以對應的攔截器的功能也是由HK2框架實現。
現在我們模擬實現一個登陸攔截器的功能。
3.1 登入器註解
3.3 方法攔截器的繫結 Jersey在呼叫方法攔截器的時候,需要InterceptionService的實現。
該介面中有三個方法,在執行對應的介面方法之前會呼叫getMethodInteceptors()方法,獲取對應的攔截器,並執行攔截器。
我們建立的攔截服務實現,需要與攔截服務進行繫結,這時需要AbstracctBinding物件的實現‘。
一、使用註解名稱繫結過濾器 1.1 建立名稱繫結註解 使用@NameBinding註解,可以定義一個執行時的自定義註解,該註解可以用於定義類級別名稱和淚的方法。例如,我們定義一個使用者訪問的註解。
@NameBinding //標識名稱繫結的註解
@Target({ElementType.TYPE,ElementType.METHOD}) //表示該註解可以使用在類和方法上。
@Retention(value =RetentionPolicy.RUNTIME)
public@interfaceUserLogger{
}
@Provider
@UserLogger
@Priority(Priorities.USER)
publicclassLoggerFilterimplementsContainerRequestFilter,ContainerResponseFilter{
@Override
publicvoid filter(ContainerRequestContext requestContext)throwsIOException{
System.out.println("訪問請求日誌過濾器執行了>>>>>>>>>>>>");
}
@Override
public
System.out.println("訪問響應日誌過濾器執行了>>>>>>>>>>>");
}
}
@UserLogger 就是我們自定義的名稱繫結註解
@Priority 是用於表示該過濾器的執行順序,其中引數為long型別,對於請求過濾器,該數值越小越先執行,響應過濾器則相反。
ContainerRequestFilter 為請求過濾器
ContainerResponseFilter 為響應過濾器
在請求和響應的過濾方法中,我們簡單的列印輸出。 需要注意的是,我們建立了過濾器之後需要在Jersey中進行宣告,我們在Jerysey的ResourceConfig 子類中,註冊該過濾器,註冊有兩種方式,一種是掃描包的形式,這時需要在過濾器上加上@Provider註解,另一種是直接註冊該過濾器。
packages
register(LoggerFilter.class); //直接註冊過濾器
1.3 註解繫結介面 上面我們建立好註解和過濾器之後,需要將在我們需要使用過濾器的介面方法上使用註解。
@Path("/test")
publicclassTestResource{
@GET
@Path("/1")
publicString test1(){
return"不帶過濾器";
}
@GET
@Path("/2")
@UserLogger
publicString test2(){
return"帶過濾器";
}
}
2.1 實現動態繫結特徵
publicclassLoggerDynaimcFeatureimplementsDynamicFeature{
@Override
publicvoid configure(ResourceInfo resourceInfo,FeatureContext context){
String name = resourceInfo.getResourceMethod().getName();
if("test2".equals(name)){
context.register(LoggerFilter.class);
}
}
}
我們需要在同樣我們需要註冊該動態特徵來
register(LoggerDynaimcFeature.class);
名稱繫結相比於動態繫結使用範圍更廣,因為我們使用註解的方式,可以對任意資源,任意方法進行控制。而使用動態繫結的形式,我們需要在動態特徵類進行對應的匹配,適用範圍較窄。 三、使用註解繫結攔截器 前面的兩種形式是通過過濾器的形式,對介面控制,一般我們做日誌訪問記錄等方式,採用該方式較好。而如果我們需要控制使用者對介面的訪問,例如登陸控制,許可權控制等,就需要使用方法攔截器。
由於Jersey中的AOP是基於HK2框架實現的,所以對應的攔截器的功能也是由HK2框架實現。
現在我們模擬實現一個登陸攔截器的功能。
3.1 登入器註解
@Documented
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public@interfaceLoginTest{
}
@LoginTest
publicclassLoginTestMethodInterceptorimplementsMethodInterceptor{
@Override
publicObject invoke(MethodInvocation methodInvocation)throwsThrowable{
return"沒有許可權訪問";
}
}
3.3 方法攔截器的繫結 Jersey在呼叫方法攔截器的時候,需要InterceptionService的實現。
該介面中有三個方法,在執行對應的介面方法之前會呼叫getMethodInteceptors()方法,獲取對應的攔截器,並執行攔截器。
publicclassJerseyInterceptorimplementsInterceptionService{
privatestaticMap<Annotation,MethodInterceptor> map =newHashMap<>();
static{
Annotation[] annotations =LoginTestMethodInterceptor.class.getAnnotations();
for(Annotation annotation : annotations){
map.put(annotation,newLoginTestMethodInterceptor());
}
}
@Override
publicFilter getDescriptorFilter(){
returnnewFilter(){
publicboolean matches(Descriptor descriptor){
returntrue;
}
};
}
@Override
publicList<MethodInterceptor> getMethodInterceptors(Method method){
Annotation[] annotations = method.getAnnotations();
List<MethodInterceptor> list =newArrayList<>();
for(Annotation annotation :annotations){
if(map.get(annotation)!=null){
list.add(map.get(annotation));
}
}
return list;
}
@Override
publicList<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> constructor){
returnnull;
}
}
我們建立的攔截服務實現,需要與攔截服務進行繫結,這時需要AbstracctBinding物件的實現‘。
publicclassJerseyBindingextendsAbstractBinder{
@Override
protectedvoid configure(){
this.bind(JerseyInterceptor.class).to(InterceptionService.class).in(Singleton.class);
}
}
publicclassJerseyFeatureimplementsFeature{
@Override
publicboolean configure(FeatureContext context){
context.register(newJerseyBinding());
returntrue;
}
}
-
register(JerseyFeature.class);
@Path("/test")
publicclassTestResource{
@Path("/1")
@GET
publicString test1(){
return"不帶攔截器";
}
@Path("/2")
@GET
@LoginTest
publicString test2(){
return"不帶攔截器";