SpringBoot2(十三)HttpMessageConverter


HttpMessageConverter可以根據不同的數據類型(MIME類型),做不同的數據加工,如果有各種格式的數據需要處理,可以設置多個不同的HttpMessageConverter;

HttpMessageConverter單獨看,可能不理解它是什么,但是它的實現類,我們就非常熟悉了:Jackson、FastJSON。

 

注意:

本文的代碼設計其實是失敗的,本意是為了減少代碼,但是,卻增加了很多維護升級工作;

HttpMessageConverter的配置對整個項目有效,如果集成了其它公司的產品,我們的HttpMessageConverter有可能順帶地改掉他們的數據格式;

Jackson、FastJSON這些都屬於大家都認可的產品,自定義之后,不見得很多人都能認可他。

 

我不推薦自定義HttpMessageConverte

HandlerMethodReturnValueHandler 和  ResponseBodyAdvice 兩個接口,可以通過包名進行過濾,可以只對部分代碼生效,更適合完成我下列提出的需求。

 

 案例:

如下,在做update的時候,返回受影響行數,結果大於0表示成功,否則表示失敗,這樣的代碼很常見;

其中ResultUtils.doUpdate(row)這一行代碼,是通用可以封裝的,下列展示如何通過HttpMessageConverter進行處理。

    public String  insert(){
        int row = service.doUpdate(sql); return ResultUtils.doUpdate(row); }

 

GenericHttpMessageConverter

代碼改編自com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter,此接口負責 Controller 的數據包裝和寫入。

import cn.seaboot.common.core.FastJsonUtils;
import cn.seaboot.plugin.util.Result; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.support.config.FastJsonConfig; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractHttpMessageConverter; import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Type; import java.nio.charset.Charset; /** * 改造FastJson,所有返回值進行二次封裝 * @author Mr.css * @date 2018年7月15日 上午12:11:14 v1 * 2019年10月16日 上午11:08 v2 */ public class FastJsonConverter extends AbstractHttpMessageConverter<Object> implements GenericHttpMessageConverter<Object> { private FastJsonConfig fastJsonConfig; public FastJsonConverter() { super(MediaType.ALL); this.fastJsonConfig = new FastJsonConfig(); this.fastJsonConfig.setCharset(Charset.defaultCharset()); //下列代碼未給出,參考FastJson配置 this.fastJsonConfig.setSerializeConfig(FastJsonUtils.serializeConfig); this.fastJsonConfig.setSerializerFeatures(FastJsonUtils.features); } @Override protected boolean supports(Class<?> clazz) { return true; } @Override protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { InputStream in = inputMessage.getBody(); return JSON.parseObject(in, this.fastJsonConfig.getCharset(), clazz, this.fastJsonConfig.getFeatures()); } /** * 重點改造這一函數 */ @Override protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { HttpHeaders headers = outputMessage.getHeaders(); ByteArrayOutputStream outnew = new ByteArrayOutputStream(); OutputStream out; String text; if (obj instanceof Integer) { //Integer 類型處理 text = Result.doUpdate((int) obj); } else if (obj instanceof String) { text = obj.toString(); } else { //自定義JSON格式 text = Result.succeed(obj); } out = outputMessage.getBody(); out.write(text.getBytes(this.fastJsonConfig.getCharset())); if(this.fastJsonConfig.isWriteContentLength()){ headers.setContentLength((long) text.length()); } outnew.close(); } @Override public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) { return super.canRead(contextClass, mediaType); } @Override public boolean canWrite(Type type, Class<?> contextClass, MediaType mediaType) { return super.canWrite(contextClass, mediaType); } @Override public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { InputStream in = inputMessage.getBody(); return JSON.parseObject(in, this.fastJsonConfig.getCharset(), type, this.fastJsonConfig.getFeatures()); } @Override public void write(Object t, Type type, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { HttpHeaders headers = outputMessage.getHeaders(); if (headers.getContentType() == null) { if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) { contentType = this.getDefaultContentType(t); } if (contentType != null) { headers.setContentType(contentType); } } if (headers.getContentLength() == -1L) { Long contentLength = this.getContentLength(t, headers.getContentType()); if (contentLength != null) { headers.setContentLength(contentLength.longValue()); } } this.writeInternal(t, outputMessage); outputMessage.getBody().flush(); } }

 

Spring中的使用

因為是代碼改造,配置與FastJSON的實現類完全相同

    <!-- 配置與FastJsonHttpMessageConverter完全相同 -->
    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="xxxxxxxxxxx.FastJsonConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

SpringBoot的使用

import cn.seaboot.common.core.Resource;
import cn.seaboot.plugin.config.ArgumentResolver; import cn.seaboot.plugin.config.FastJsonConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * * @author Created by 12614 on 2018/5/11. */ @Configuration public class ApplicationConfigurer implements WebMvcConfigurer { private Logger logger = LoggerFactory.getLogger(ApplicationConfigurer.class); /** * JSON解析 * @param converters - */ @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { //去除不需要的配置 String[] exclude = { "org.springframework.http.converter.xml" , "org.springframework.http.converter.json"}; Iterator<HttpMessageConverter<?>> ite = converters.iterator(); while (ite.hasNext()){ HttpMessageConverter<?> converter = ite.next(); String name = converter.getClass().getName(); for (String str: exclude) { if(name.startsWith(str)){ ite.remove(); break; } } } FastJsonConverter fastConverter = new FastJsonConverter(); // 處理中文亂碼問題 List<MediaType> fastMediaTypes = new ArrayList<>(); fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); fastConverter.setSupportedMediaTypes(fastMediaTypes); // 提高優先級,放到集合開頭 converters.set(0, fastConverter); } }

Result

對於Controller返回值的二次封裝工具,按照自己需求設計,此處僅供參考。

import cn.seaboot.common.core.FastJsonUtils;

import java.io.Serializable; import java.util.HashMap; import java.util.Map; /** * 返回值封裝 * @author ChenSS * @date 2018-10-12 17:19 提交 * 2019年10月15日 17:21 修訂 */ public class Result implements Serializable { public static final Map<String, Object> ERROR_MAP = new HashMap<>(); public static final String EMPTY_JSON = "{}"; private static final String SUCCEED = "{\"code\":\"0\",\"data\":\"操作成功\"}"; private static final String FAILED = "{\"code\":\"1\",\"data\":\"操作失敗\"}"; public static final String NOT_LOGIN = "{\"code\":\"5\",\"data\":\"用戶未登錄!\"}"; public static final String LACK_PERMISSION = "{\"code\":\"4\",\"data\":\"你缺少權限來執行此操作!\"}"; public static final String NAME_OR_PWD_WRONG = "{\"code\":\"6\",\"data\":\"用戶名或者密碼錯誤!\"}"; private String code; private Object data; static { ERROR_MAP.put("code", 1); ERROR_MAP.put("data", "未知的錯誤!請聯系管理員!"); } public Result(String code, Object data) { this.code = code; this.data = data; } public static String succeed(String data) { return "{\"code\":\"0\",\"data\":\"" + data + "\"}"; } public static String succeed(Object data) { return "{\"code\":\"0\",\"data\":" + FastJsonUtils.toJSONString(data) + "}"; } public static String failed(String data) { return "{\"code\":\"1\",\"data\":\"" + data + "\"}"; } public static String failed(Object data) { return "{\"code\":\"1\",\"data\":" + FastJsonUtils.toJSONString(data) + "}"; } public static String doUpdate(int row, String success, String fail) { return row > 0 ? Result.succeed(success) : Result.failed(fail); } public static String doUpdate(int row, String success) { return row > 0 ? Result.succeed(success) : Result.FAILED; } public static String doUpdate(int row) { return row > 0 ? Result.SUCCEED : Result.FAILED; } public static String succeed() { return SUCCEED; } public static String failed() { return FAILED; } public static Map<String, Object> build(String code, Object data) { Map<String, Object> map = new HashMap<>(); map.put("code", code); map.put("data", data); return map; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } @Override public String toString() { return "{\"code\":\"" + code + "\",\"data\":\"" + data + "\"}"; } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM