美文网首页
优雅编程 - HttpMessageConverter

优雅编程 - HttpMessageConverter

作者: 林昀熙 | 来源:发表于2019-12-19 11:12 被阅读0次

    消息转换器

    在Spring中org.springframework.http.converter.HttpMessageConverter规范中定义了Http请求和响应的消息转换规范, 我们知道SpringMvc可以接收不同的消息形式,也可以将不同的消息形式响应回去(最常见的是json);这些消息所蕴含的"有效信息"是一致的,那么各种不同的消息转换器,都会生成同样的转换结果. 至于各种消息间解析细节的不同,就被屏蔽在不同的HttpMessageConverter实现类中.

    SpringMVC中使用FastJson作为转换器

    通过SpringMvc中message-converts配置FastJson作为转换器

    <!-- 默认的注解映射的支持,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -->
    <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
       <mvc:message-converters register-defaults="true">
          <!-- 将Jackson2HttpMessageConverter的默认格式化输出为true -->
          <!-- 配置Fastjson支持 -->
          <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
             <property name="supportedMediaTypes">
                <list>
                   <value>text/html;charset=UTF-8</value>
                   <value>application/json</value>
                </list>
             </property>
             <property name="features">
                <list>
                   <!-- 输出key时是否使用双引号 -->
                   <value>QuoteFieldNames</value>
                   <!-- 是否输出值为null的字段 -->
                   <!-- <value>WriteMapNullValue</value> -->
                   <!-- 数值字段如果为null,输出为0,而非null -->
                   <value>WriteNullNumberAsZero</value>
                   <!-- List字段如果为null,输出为[],而非null -->
                   <value>WriteNullListAsEmpty</value>
                   <!-- 字符类型字段如果为null,输出为"",而非null -->
                   <value>WriteNullStringAsEmpty</value>
                   <!-- Boolean字段如果为null,输出为false,而非null -->
                   <value>WriteNullBooleanAsFalse</value>
                   <!-- null String不输出  -->
                   <value>WriteNullStringAsEmpty</value>
                   <!-- null String也要输出  -->
                   <!-- <value>WriteMapNullValue</value> -->
               
                   <!-- Date的日期转换器 -->
                   <value>WriteDateUseDateFormat</value>
                </list>
             </property>
          </bean>
       </mvc:message-converters>
    </mvc:annotation-driven>
    
    <!-- REST中根据URL后缀自动判定Content-Type及相应的View -->
    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
       <property name="mediaTypes" >
          <map>
             <entry key="json" value="application/json"/>
          </map>
       </property>
       <!-- 这里是否忽略掉accept header,默认就是false -->
       <property name="ignoreAcceptHeader" value="true"/>
       <property name="favorPathExtension" value="true"/>
    </bean>
    

    Fastjson轻量级属性转换

    定义示例对象模型

    做fastjson轻量注解配置, 更多配置参考https://github.com/alibaba/fastjson/wiki/JSONField

    public class ModelTest implements Serializable{
    
        // 使用ordinal指定字段
        @JSONField(ordinal = 1)
        private Long id;
    
        @JSONField(ordinal = 2)
        private String name;
    
        @JSONField(ordinal = 3)
        private Integer age;
    
        // 使用serialize/deserialize指定字段不序列化
        @JSONField(deserialize = false, serialize = false)
        private String remark;
    
        // 配置date序列化和反序列使用yyyyMMdd日期格式
        @JSONField(format="yyyy-MM-dd HH:mm:ss")
        private Date crateTime;
    
        // 配置属性序列化使用的名称
        @JSONField(name = "updateTime", format="yyyy-MM-dd HH:mm:ss")
        private Date modifyTime;
    
        @JSONField(ordinal = 0)
        private DeleteEnum deleteEnum;
    
        public enum DeleteEnum {
    
            DISABLE(1, "禁用"),
            ENABLE(2, "启用");
    
            private int value;
            private String depict;
    
            DeleteEnum(int value, String depict) {
                this.value = value;
                this.depict = depict;
            }
    
            public static DeleteEnum findByValue(int value) {
                switch (value) {
                    case 1:
                        return DISABLE;
                    case 2:
                        return ENABLE;
                    default:
                        return null;
                }
            }
        }
    
    // getter and setter
    }
    
    

    定义示例Controller

    示例完成序列化数据到前端和提交JSON数据转换成对象模型

    @Controller
    @RequestMapping(value = "/test")
    public class TestWebController {
    
        private static final Logger LOG = LoggerFactory.getLogger(TestWebController.class);
        
          // 序列化对象到视图
        @ResponseBody
        @RequestMapping(value = {"/bean/data"}, method = {RequestMethod.GET, RequestMethod.POST})
        public Object toBody(){
    
            ModelTest modelTest = new ModelTest();
            modelTest.setAge(11);
            modelTest.setCrateTime(new Date());
            modelTest.setModifyTime(new Date());
            modelTest.setId(1L);
            modelTest.setName("测试Fastjson");
            modelTest.setRemark("备注");
            modelTest.setDeleteEnum(ModelTest.DeleteEnum.ENABLE);
    
            return ImmutableMap.<String, String>builder()
                    .put("code", "0")
                    .put("data", JSON.toJSONString(modelTest)).build();
        }
    
        // 解析JSON对象到实体模型
        @ResponseBody
        @RequestMapping(value = {"/bean/put"}, method = {RequestMethod.GET, RequestMethod.POST})
        public Object getBody(@RequestBody ModelTest modelTest){
            System.out.println(JSON.toJSONString(modelTest));
            return ImmutableMap.<String, String>builder()
                    .put("code", "0")
                    .put("data", "ok").build();
        }
    }
    

    测试对象序列化到前端展示

    @Test
        public void fastJSONTest01() throws Exception {
            MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.post("/test/bean/data")
                    .cookie(new Cookie("token", "F3AF5F1D14F534F677XF3A00E352C"))   // 登录授权
                    .accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
                    .andExpect(handler().handlerType(TestWebController.class))      // 验证执行的控制器类型
                    .andExpect(status().isOk())                                     // 验证执行状态
                    .andDo(print())                                                 // 打印交互信息
                    .andReturn();
            System.out.println(mvcResult.getResponse().getContentAsString());
        }
    

    执行结果:

    {
      "code": "0",
      "data": "{"crateTime":"2016-12-2808: 02: 50","deleteEnum":"ENABLE","updateTime":"2016-12-2808: 02: 50","id":1,"name":"测试Fastjson","age":11}"
    }
    

    测试提交数据转换成模型

    @Test
        public void fastJSONTest02() throws Exception {
    
            ModelTest modelTest = new ModelTest();
            modelTest.setAge(11);
            modelTest.setCrateTime(new Date());
            modelTest.setModifyTime(new Date());
            modelTest.setId(1L);
            modelTest.setName("测试Fastjson");
            modelTest.setRemark("备注");
            modelTest.setDeleteEnum(ModelTest.DeleteEnum.ENABLE);
        
            MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.post("/test/bean/put")
                    .content(JSON.toJSONString(modelTest))
                    .contentType(MediaType.APPLICATION_JSON)
                    .cookie(new Cookie("token", "F3AF5F1D14F534F677XF3A00E352C"))   // 登录授权
                    .accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
                    .andExpect(handler().handlerType(TestWebController.class))      // 验证执行的控制器类型
                    .andExpect(status().isOk())                                     // 验证执行状态
                    .andDo(print())                                                 // 打印交互信息
                    .andReturn();
            System.out.println(mvcResult.getResponse().getContentAsString());
        }
    

    执行后台打印:

    {"crateTime":"2016-12-28 08:04:33","deleteEnum":"ENABLE","updateTime":"2016-12-28 08:04:33","id":1,"name":"测试Fastjson","age":11}
    
    

    枚举绑定处理

    示例中我们看到序列化的枚举为枚举的name(). 如果我们想用枚举的寓意值进行传输过程中的映射时,可以这样做, 透传一个数值, 该数值和枚举在getter()和setter()方法上绑定即可.

    修改示例的对象模型

    public class ModelTest implements Serializable{
    
        // 使用ordinal指定字段
        @JSONField(ordinal = 1)
        private Long id;
    
        @JSONField(ordinal = 2)
        private String name;
    
        @JSONField(ordinal = 3)
        private Integer age;
    
        // 使用serialize/deserialize指定字段不序列化
        @JSONField(deserialize = false, serialize = false)
        private String remark;
    
        // 配置date序列化和反序列使用yyyyMMdd日期格式
        @JSONField(format="yyyy-MM-dd HH:mm:ss")
        private Date crateTime;
    
        // 配置属性序列化使用的名称
        @JSONField(name = "updateTime", format="yyyy-MM-dd HH:mm:ss")
        private Date modifyTime;
    
        @JSONField(ordinal = 0)
        private DeleteEnum deleteEnum;
    
        private int enable;
    
        public enum DeleteEnum {
    
            DISABLE(1, "禁用"),
            ENABLE(2, "启用");
    
            private int value;
            private String depict;
    
            DeleteEnum(int value, String depict) {
                this.value = value;
                this.depict = depict;
            }
    
            public static DeleteEnum findByValue(int value) {
                switch (value) {
                    case 1:
                        return DISABLE;
                    case 2:
                        return ENABLE;
                    default:
                        return null;
                }
            }
        }
        
         // 数值绑定枚举
        public int getEnable() {
            this.deleteEnum = DeleteEnum.findByValue(enable);
            return enable;
        }
         
         // 数值绑定枚举
        public void setEnable(int enable) {
            this.enable = enable;
            this.deleteEnum = DeleteEnum.findByValue(enable);
        }
    
         // 枚举映射数值
        public DeleteEnum getDeleteEnum() {
            this.enable = this.deleteEnum.value;
            return deleteEnum;
        }
        
         // 枚举映射数值
        public void setDeleteEnum(DeleteEnum deleteEnum) {
            this.deleteEnum = deleteEnum;
            this.enable = this.deleteEnum.value;
        }
    }
    
    

    我们保持示例中Controller类和测试用例的代码不变,执行用例.

    • 测试对象序列化到前端展示执行结果
    {
      "code": "0",
      "data": "{"crateTime":"2016-12-2808: 12: 52","deleteEnum":"ENABLE","enable":2,"updateTime":"2016-12-2808: 12: 52","id":1,"name":"测试Fastjson","age":11}"
    }
    
    • 测试提交数据转换成模型 执行后台打印
    {"crateTime":"2016-12-28 08:20:17","deleteEnum":"ENABLE","enable":2,"updateTime":"2016-12-28 08:20:17","id":1,"name":"测试Fastjson","age":11}
    
    

    修改用例模拟的实体对象, 测试数值到枚举的映射.

    ModelTest modelTest = new ModelTest();
    modelTest.setAge(11);
    modelTest.setCrateTime(new Date());
    modelTest.setModifyTime(new Date());
    modelTest.setId(1L);
    modelTest.setName("测试Fastjson");
    modelTest.setRemark("备注");
    modelTest.setEnable(1);
    

    后台打印输出:

    {"crateTime":"2016-12-28 08:21:48","deleteEnum":"DISABLE","enable":1,"updateTime":"2016-12-28 08:21:48","id":1,"name":"测试Fastjson","age":11}
    

    可以看到enable的值自动和枚举类型映射上.

    使用FastJson做对象和JSON之间的转换

    对象转换成JSON

    @Test
        public void fastJSONTest03() {
            ModelTest modelTest = new ModelTest();
            modelTest.setAge(11);
            modelTest.setCrateTime(new Date());
            modelTest.setModifyTime(new Date());
            modelTest.setId(1L);
            modelTest.setName("测试Fastjson");
            modelTest.setRemark("备注");
            modelTest.setEnable(1);
            System.out.println(JSON.toJSONString(modelTest));
        }
    

    执行结果:

    {"crateTime":"2016-12-28 08:30:42","deleteEnum":"DISABLE","enable":1,"updateTime":"2016-12-28 08:30:42","id":1,"name":"测试Fastjson","age":11}
    

    JSON转换成对象

    @Test
    public void fastJSONTest04() {
       String json = "{\n" +
               "  \"id\": 1,\n" +
               "  \"deleteEnum\": \"DISABLE\",\n" +
               "  \"updateTime\": 1482884802549,\n" +
               "  \"crateTime\": 1482884802549,\n" +
               "  \"age\": 11,\n" +
               "  \"name\": \"测试Fastjson\",\n" +
               "  \"enable\": 1\n" +
               "}";
       ModelTest modelTest = JSONObject.parseObject(json, ModelTest.class);
       System.out.println(modelTest);
       System.out.println(modelTest.getName());
    }
    

    执行结果:

    ModelTest{id=1, name='测试Fastjson', age=11, remark='null', crateTime=Wed Dec 28 08:26:42 CST 2016, modifyTime=Wed Dec 28 08:26:42 CST 2016, deleteEnum=DISABLE, enable=1}
    测试Fastjson
    

    示例中直接打印输出对象,是因为复写了toString()方法.

    相关文章

      网友评论

          本文标题:优雅编程 - HttpMessageConverter

          本文链接:https://www.haomeiwen.com/subject/xmlmnctx.html