標籤:api stream val figure oct convert 介面 註解 一個
今天上午技術群裡的一個人問” 如何在 Spring MVC 中統一對返回的 Json 進行加密?”。
大部分人的第一反應是通過 Spring 攔截器(Interceptor)中的postHandler
方法處理。實際這是行不通的,因為當程式運行到該方法,是在返回資料之後,渲染頁面之前,所以這時候 Response 中的輸出資料流已經關閉了,自然無法在對返回資料進行處理。
其實這個問題用幾行代碼就可以搞定,因為 Spring 提供了非常豐富的擴充支援,無論是之前提到的Interceptor
和MethodArgumentResolver
,還是接下來要提到的HttpMessageConverter
。
在 Spring MVC 的 Controller 層經常會用到@RequestBody
和@ResponseBody
,通過這兩個註解,可以在 Controller 中直接使用 Java 對象作為請求參數和返回內容,而完成這之間轉換作用的便是HttpMessageConverter
。
HttpMessageConverter
介面提供了 5 個方法:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
class CustomJsonHttpMessageConverter implements HttpMessageConverter { //Jackson 的 Json 映射類private ObjectMapper mapper = new ObjectMapper (); // 該轉換器的支援類型:application/jsonprivate List supportedMediaTypes = Arrays.asList (MediaType.APPLICATION_JSON); /*** 判斷轉換器是否可以將輸入內容轉換成 Java 類型* @param clazz 需要轉換的 Java 類型* @param mediaType 該請求的 MediaType* @return*/@Overridepublic boolean canRead (Class clazz, MediaType mediaType) {if (mediaType == null) {return true;}for (MediaType supportedMediaType : getSupportedMediaTypes ()) {if (supportedMediaType.includes (mediaType)) {return true;}}return false;} /*** 判斷轉換器是否可以將 Java 類型轉換成指定輸出內容* @param clazz 需要轉換的 Java 類型* @param mediaType 該請求的 MediaType* @return*/@Overridepublic boolean canWrite (Class clazz, MediaType mediaType) {if (mediaType == null || MediaType.ALL.equals (mediaType)) {return true;}for (MediaType supportedMediaType : getSupportedMediaTypes ()) {if (supportedMediaType.includes (mediaType)) {return true;}}return false;} /*** 獲得該轉換器支援的 MediaType* @return*/@Overridepublic List getSupportedMediaTypes () {return supportedMediaTypes;} /*** 讀取請求內容,將其中的 Json 轉換成 Java 對象* @param clazz 需要轉換的 Java 類型* @param inputMessage 請求對象* @return* @throws IOException* @throws HttpMessageNotReadableException*/@Overridepublic Object read (Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {return mapper.readValue (inputMessage.getBody (), clazz);} /*** 將 Java 對象轉換成 Json 返回內容* @param o 需要轉換的對象* @param contentType 傳回型別* @param outputMessage 回執對象* @throws IOException* @throws HttpMessageNotWritableException*/@Overridepublic void write (Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {mapper.writeValue (outputMessage.getBody (), o);}} |
當前 Spring 中已經預設提供了相當多的轉換器,分別有:
名稱 |
作用 |
讀支援 MediaType |
寫支援 MediaType |
ByteArrayHttpMessageConverter |
資料與位元組數組的相互轉換 |
\/\ |
application/octet-stream |
StringHttpMessageConverter |
資料與 String 類型的相互轉換 |
text/\* |
text/plain |
FormHttpMessageConverter |
表單與 MultiValueMap的相互轉換 |
application/x-www-form-urlencoded |
application/x-www-form-urlencoded |
SourceHttpMessageConverter |
資料與 javax.xml.transform.Source 的相互轉換 |
text/xml 和 application/xml |
text/xml 和 application/xml |
MarshallingHttpMessageConverter |
使用 Spring 的 Marshaller/Unmarshaller 轉換 XML 資料 |
text/xml 和 application/xml |
text/xml 和 application/xml |
MappingJackson2HttpMessageConverter |
使用 Jackson 的 ObjectMapper 轉換 Json 資料 |
application/json |
application/json |
MappingJackson2XmlHttpMessageConverter |
使用 Jackson 的 XmlMapper 轉換 XML 資料 |
application/xml |
application/xml |
BufferedImageHttpMessageConverter |
資料與 java.awt.image.BufferedImage 的相互轉換 |
Java I/O API 支援的所有類型 |
Java I/O API 支援的所有類型 |
回到最開始所提的需求,既然要對返回的 Json 內容進行加密,肯定是對MappingJackson2HttpMessageConverter
進行改造,並且只需要重寫write
方法。
從MappingJackson2HttpMessageConverter
的父類AbstractHttpMessageConverter
中的write
方法可以看出,該方法通過writeInternal
方法向返回結果的輸出資料流中寫入資料,所以只需要重寫該方法即可:
1234567891011121314151617181920 |
@Beanpublic MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter () {return new MappingJackson2HttpMessageConverter () {// 重寫 writeInternal 方法,在返回內容前首先進行加密@Overrideprotected void writeInternal (Object object,HttpOutputMessage outputMessage) throws IOException,HttpMessageNotWritableException {// 使用 Jackson 的 ObjectMapper 將 Java 對象轉換成 Json StringObjectMapper mapper = new ObjectMapper ();String json = mapper.writeValueAsString (object);LOGGER.error (json);// 加密String result = json + "加密了!";LOGGER.error (result);// 輸出outputMessage.getBody ().write (result.getBytes ());}};} |
在這之後還需要將這個自訂的轉換器配置到 Spring 中,這裡通過重寫WebMvcConfigurer
中的configureMessageConverters
方法添加自訂轉換器:
123456 |
// 添加自訂轉換器@Overridepublic void configureMessageConverters (List> converters) {converters.add (mappingJackson2HttpMessageConverter ());super.configureMessageConverters (converters);} |
測試一下:
如此便簡單的完成了對返回內容進行加密的功能。
(原文地址:http://www.scienjus.com/custom-http-message-converter/)
[轉]使用自訂HttpMessageConverter對返回內容進行加密