在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