码迷,mamicode.com
首页 > 编程语言 > 详细

SpringBoot2(十三)HttpMessageConverter

时间:2020-01-08 22:34:20      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:exception   rem   nec   优先级   因此   错误   integer   处理   char   

在介绍HttpMessageConverter之前,先看看平时常常写的一些代码

1、在JDBC的操作中,执行Update的时候,会返回受影响行数,你是如何处理的? 

  /**
     * 搞笑的写法
     */
    public MResult eg() {
        int rows = service.doUpdate();
        if(rows > 0){
            return new MResult(MResult.ERROR);
        } else {
            return new MResult(MResult.SUCCESS);
        }
    }

  /**
     * 稍作优化,但是还不够
     */
    public MResult eg() {
        int rows = service.doUpdate();
        return MResult.doUpdate(rows);
    }

  /**
     * 希望Controller也可以这样写,那该如何去处理切面?
     */
    public int eg() {
        return service.doUpdate();
    }

2、在做数据查询的时候,你是否希望直接返回数据,系统自动帮你打包数据?

  /**
     * 搞笑的写法
     */
    @ResponseBody
    @RequestMapping(value = "/find")
    public TAosPlaneChkEntity findById(String id){
        Object res = service.findById(id);
        return res == null?new MResult(MResult.ERROR):new MResult(MResult.SUCCESS, res);
    }

  /**
     * 因此,希望Controller这样写,数据自动装箱
     */
    @ResponseBody
    @RequestMapping(value = "/find")
    public TAosPlaneChkEntity findById(String id){
        return service.findById(id);
    }

如果有上述的这些需求,那你需要了解一下 HttpMessageConverter接口,和之前文章提到的 HandlerMethodReturnValueHandler 和  ResponseBodyAdvice 功能类似,这是第三个能处理返回值的接口了。相比于前面两个接口,前面两个都太底层了,HttpMessageConverter更像是框架留给用户的接口,它在系统中不是唯一存在的,用户可以指定多个HttpMessageConverter,并且设置不同的优先级。

 

回归上述的需求,需要给Controller立下规矩:

1、当返回值为int时,一律当成受影响行数处理,
  如果大于0,则返回{"code":"0","data":"操作成功!"}
  如果等于0,则返回{"code":"1","data":"操作失败!"}

2、当返回值为Object时,则对数据进行包装:
  变为{"code":"1","data":{"name":"xiaoming","age":"30"}}格式

3、当返回值为String时,则对数据进行原样返回

异常状态有专门切面可以处理,不纳入思考范围。

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());
        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 {
            //自定义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 + "\"}";
    }
}

 

SpringBoot2(十三)HttpMessageConverter

标签:exception   rem   nec   优先级   因此   错误   integer   处理   char   

原文地址:https://www.cnblogs.com/chenss15060100790/p/12168805.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!