zoukankan      html  css  js  c++  java
  • SpringBoot2(十三)HttpMessageConverter

    在介绍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());
            //下列代码未给出,参考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 + ""}";
        }
    }
  • 相关阅读:
    unity中制作模拟第一人称视角下的指南针
    unity3D 中的C#脚本一个类调用另一类中简单方法
    unity中UI的屏幕自适应代码
    unity中导入插件时报错处理办法
    Unity3D在C#编程中的一些命名空间的引用及说明
    Unity中物体碰撞后去掉相互之间的反弹力
    unity3D打包发布Apk详细步骤
    unity3D开发的程序发布到Android平台上进行运行测试的详细步骤
    JAVA的环境变量配置(方式二)
    Java中的 JDK下载和环境配置(方式一)
  • 原文地址:https://www.cnblogs.com/chenss15060100790/p/12168805.html
Copyright © 2011-2022 走看看