通过message-converters自定义json序列化

通过message-converters自定义json序列化

问题描述

最近写项目遇到了一个问题,由于这个服务之前是对接线下mis,所以返回json的时候,之前同事复写了消息转换器,使全局的json都从驼峰自动转成了下划线。
现在由于需要拆分服务,根据业务部分接口需要对接web,则需要过滤掉一部分的url,使返回的requestBody中的json不需要驼峰转下划线。

修改前代码

spring-context.xml

<mvc:annotation-driven>
	<mvc:message-converters>
			
			<bean class="com.razera.sp.component.jackson.DefaultMappingJacksonConverter">
			<property name="supportedMediaTypes"> 
				<list>
					<value>application/json;charset=UTF-8value>
				list>
			property>
		bean>
	mvc:message-converters>
mvc:annotation-driven>

DefaultMappingJacksonConverter

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

/**
 * @Author razera
 * @Description json序列化驼峰转下划线配置
 */
public class DefaultMappingJacksonConverter extends MappingJackson2HttpMessageConverter {

    public DefaultMappingJacksonConverter() {

        ObjectMapper mapper = this.getObjectMapper();
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
        //设置输出时包含属性的风格
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //禁止使用int代表Enum的order()來反序列化Enum,非常危險
        mapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
    }
}

解决问题

解决json序列化考虑到了两种方式

  1. 重写writeInternal方法
  2. 通过FilterProvider自定义过滤注解

因为FilterProvider是基于实体类的,项目中通过new JsonDate方式向前端返回值,如果要使用这种方式,需要自定义一个新的JsonDate类,有点麻烦。
这里我们选择重写DefaultMappingJacksonConverter类的writeInternal方法来实现这个功能

步骤

  1. 通过静态代码块来初始化ObjectMapper
  2. 定义静态集合,来存放需要过滤的url
  3. 复写writeInternal方法,整体和父类的writeInternal方法差不多。本质上就是将新的ObjectMapper进行初始化,避开了之前的驼峰转下划线设置

修改后的代码

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

/**
 * @Author razera
 * @Description json序列化驼峰转下划线配置
 */
public class DefaultMappingJacksonConverter extends MappingJackson2HttpMessageConverter {

    //需要过滤的url集合
    private static List<String> FILTER_URLS = Arrays.asList(
            "/privates/spPayMethod/query",
            "/privates/spPayMethod/download"
    );

    //新的自定义ObjectMapper
    private final static ObjectMapper mapper = new ObjectMapper();

    //通过静态代码块进行初始化
    static {
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //禁止使用int代表Enum的order()來反序列化Enum,非常危險
        mapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
    }

    public DefaultMappingJacksonConverter() {

        ObjectMapper mapper = this.getObjectMapper();
		//设置驼峰转下划线
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
        //设置输出时包含属性的风格
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //禁止使用int代表Enum的order()來反序列化Enum,非常危險
        mapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
    }

    //复写writeInternal方法
    @Override
    protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        if (FILTER_URLS.contains(StringUtils.remove(request.getRequestURI(),request.getContextPath()))) {
            MediaType contentType = outputMessage.getHeaders().getContentType();
            JsonEncoding encoding = getJsonEncoding(contentType);
            ObjectWriter objectWriter = mapper.writer();
            JsonGenerator generator = mapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
            objectWriter.writeValue(generator, object);
            generator.flush();
            return;
        }
        super.writeInternal(object, type, outputMessage);
    }
}

注意:这里使用复写writeInternal方法而不是在初始化的时候判断,是因为时机问题,writeInternal,是在response的body的序列化才起作用

你可能感兴趣的:(遇到的问题)