天天看點

JAX-RS與Jersey的Interceptor詳解

在JAX-RS标準中,過濾器Filter是JAX-RS API的組成部分,主要用于操作HTTP請求或響應的Headers, Methods和URI等參數。而攔截器Interceptor作為JAX-RS extension API的組成部分,主要操作HTTP請求或響應的Body中的Entity資料流,如對Entity資料流進行壓縮/解壓縮,JSON格式與Java對象之間的轉換等。可以說,在JAX-RS标準中,攔截器Interceptor是對過濾器Filter的補充,兩者各司其職。

關于的用法,詳見Jersey的過濾器詳解,本文聚焦在Jersey的攔截器。

1. 在JAX-RS extension API(也稱為SPI)提供了2個攔截器相關的接口

  • javax.ws.rs.ext.ReaderInterceptor,在讀取HTTP Body之前被攔截處理

在服務端操作HTTP請求的Entity,如對HTTP請求Body中的Entity進行處理。

在用戶端操作HTTP響應的Entity,如對HTTP響應Body中的Entity進行處理。

  • javax.ws.rs.ext.WriterInterceptor,在寫入HTTP Body之前被攔截處理

在服務端操作HTTP響應的Entity,然後将處理後的内容封裝到HTTP響應的Body中。

在用戶端操作HTTP請求的Entity,然後将處理後的内容封裝到HTTP請求的Body中。

2. 在Jersey應用中,使攔截器Interceptor實作類生效的方式與過濾器Filter完全一緻,請參考Jersey的過濾器詳解。

3. 攔截器實作類示例

1)讀取攔截器

@Provider
@Priority(Priorities.USER)
public class MyReader implements ReaderInterceptor {
    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
        final InputStream originalInputStream = context.getInputStream();
        context.setInputStream(new GZIPInputStream(originalInputStream));//解壓縮
        return context.proceed();
    }
}
           

2)寫入攔截器

@Provider
@Priority(Priorities.USER)
public class MyWriter implements WriterInterceptor {
    @Override
    public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
        final OutputStream outputStream = context.getOutputStream();
        context.setOutputStream(new GZIPOutputStream(outputStream));//壓縮
        context.proceed();
    }
}
           

4. Jersey的Entity資料流(即HTTP消息的Body)

HTTP消息的Entity資料流,可以是純文字、XML、JSON格式的資料。

對于收到的Entity資料流,其中的資料将作為輸入流傳遞給Jersey,Jersey的JAX-RS元件根據資料格式将其轉換為Java對象,供服務端資源方法後續解析處理。

對于要發出的資料,即服務端資源方法處理後傳回的Java對象,将被Jersey序列化為輸出流傳遞給Entity,然後作為HTTP消息的Body發送出去。

在JAX-RS标準的實作中,都應該提供各種格式的資料流與Java對象之間的預設轉換。但不是在JAX-RS API中,而是在JAX-RS extension API中。JAX-RS extension API(也稱為SPI)提供了2個操作Entity資料流相關的接口:

  •  javax.ws.rs.ext.MessageBodyReader<T>,負責将Entity資料流轉換為Java對象(T類型)
public boolean isReadable(Class<?> type, 
	Type genericType,
	Annotation[] annotations, MediaType mediaType) {
	return type == T.class;
}

public T readFrom(Class<T> type,
	Type genericType,
	Annotation[] annotations, MediaType mediaType,
	MultivaluedMap<String, String> httpHeaders,
	InputStream entityStream) throws IOException, WebApplicationException {
	//将entityStream讀入到T類型的對象并傳回
	...
}
           
  • javax.ws.rs.ext.MessageBodyWriter<T>,負責将Java對象(T類型)轉換為Entity資料流
public boolean isWriteable(Class<?> type, 
	Type genericType,
	Annotation[] annotations, 
	MediaType mediaType) {
	return type == T.class;
}
public void writeTo(T myBean,
	Class<?> type,
	Type genericType,
	Annotation[] annotations,
	MediaType mediaType,
	MultivaluedMap<String, Object> httpHeaders,
	OutputStream entityStream)
	throws IOException, WebApplicationException {
	//将myBean對象寫入到entityStream輸出流中
	...
}
           

參考連結:

https://jersey.github.io/documentation/latest/filters-and-interceptors.html

https://jersey.github.io/documentation/latest/message-body-workers.html

繼續閱讀