SpringBoot2(十三)HttpMessageConverter

HttpMessageConverter可以根据不同的数据类型(json,xml 等等),做不同的数据加工,一个项目可以设置多个不同的HttpMessageConverter;

HttpMessageConverter单独看,可能不理解它是什么,但是这个接口相关的开源框架,我们就非常熟悉了:Jackson、FastJSON。

 

注意:

本文的代码设计其实是失败的,仅供学习使用,实际生产中,不需要自己定义,因为已经有jackson、FastJSON,并不需要自己写一个更牛的

也不要轻易改动这些框架的源码,如果集成了其它公司的产品,我们的HttpMessageConverter有可能顺带地改掉他们的数据格式,会给维护带来额外负担。

 案例:

同样使用这个案例:对你的Controller返回值进行一个二次封装。
如下:code是结果码(1、成功,0、失败,2、未登录...),data为携带数据

{"code":"1","data":{"name":"xiaoming","age":"30"}}

 

GenericHttpMessageConverter

代码改编自com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter,此接口负责 Controller 的数据包装,并且最后写回到客户端。

 

为了满足上述需求,这是我最早提出的解决方案,直接改动 jar 包中的 writeInternal() 函数。

如果只是公司内部用,的确很开心,后来项目加入带前端界面的jar包,而HttpMessageConverter 是全局有效的,我们的 Converter 影响到了他们的功能。

HandlerMethodReturnValueHandler 和  ResponseBodyAdvice 两个接口,可以通过包名进行过滤,只对部分代码生效,更适合用于解决上述问题。

 

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());
        //FastJsonUtils代码未全部给出,参考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) {
      //Result做返回值二次封装的工具类,这里直接省略与之相关的代码,按照自己的需求封装即可 //如果是Integer 类型,我们当做数据库受影响行数处理,大于0直接返回“操作成功” text = Result.doUpdate((int) obj); } else if (obj instanceof String) { //如果是字符串类型,则直接原样返回 text = obj.toString(); } else { //如果是Java对象,通过工具类处理 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);
    }
}

 

posted on 2020-01-08 21:17  疯狂的妞妞  阅读(1540)  评论(0编辑  收藏  举报

导航