Spring/SpringBoot中Controller的ResponseBody输出自动转JsonString(自定义的Object随意转JSONString)

2021-02-26 63点热度 0人点赞 0条评论

前言

再用Spring/SpringBoot做API输出的时候,最多用到的是Json格式的了。为了简单高效,我们并不希望每次在输出的时候,自己去拼接JSON,或者用JSON工具类去格式化转成Json的String输出,最好是直接返回一个对象,自动输出为String,我们还可能需要将Date类型的Object转成格式化过的日期例如:2021-02-26 09:02:01 或者将org.json.JSONObject org.json.JSONString等其他自定义的Object也转成JsonString

例如,我们定义这样一个对象:

public class JsonResult {
    private boolean result = false;
    private String message;

    @JsonIgnore
    private String ingored; // 如果有不需要输出的字段,用JsonIgnore
    private HashMap<String, Object> extra = new HashMap<String, Object>();

    public JsonResult(boolean result, String message) {
        this.result = result;
        this.message = message;
    }

    public JsonResult(boolean result) {
        this.result = result;
    }

    public JsonResult() {
    }

    public HashMap<String, Object> getExtra() {
        return extra;
    }

    public void setExtra(HashMap<String, Object> extra) {
        this.extra = extra;
    }

    public boolean isResult() {
        return result;
    }

    public void setResult(boolean result) {
        this.result = result;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void addExtra(String key, Object value) {
        this.extra.put(key, value);
    }
    
    /**
     * @return
     * @description 可以在这里用注解来让他特意生成时间格式,或者spring-servlet.xml中去配置ObjectMapper
     */
    @JsonSerialize(using = CustDateSerializer.class)
    public Date getTime() {
        return new Date();
    }

    public static JsonResult success(String message) {
        return new JsonResult(true, message);
    }

    public static JsonResult success() {
        return new JsonResult(true, "OK");
    }

    public static JsonResult fail(String message) {
        return new JsonResult(false, message);
    }

}

在Controller中,我们希望直接return JsonResult:

@RequestMapping("/ping")
public @ResponseBody JsonResult ping(HttpServletRequest request) {
    org.json.JSONObject pingResult = new org.json.JSONObject();

    pingResult.put("xxx", "xxx");

    JsonResult result = new JsonResult(true, "Ping Response OK");
    result.addExtra("stats", pingResult);
    return result;
}

客户端请求到的直接是JsonResult序列化成json的string

{"result":true,"message":"Ping Response OK","extra":{"stats":{"xxx":"xxx"}},"time":"2021-02-26 09:02:01"}

分别对Spring和SpringBoot进行配置(两者大同小异)

Spring的配置

这就需要用到 jackson

POM引入jackson相关类库:

<!-- json -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.12.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-joda</artifactId>
    <version>2.12.1</version>
</dependency>

<!-- org.json看你是否需要,按需要引入-->
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20200518</version>
</dependency>

修改spring-servlet.xml,增加自定义的message-converter,以及实现自定义的 CustomObjectMapper

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
            <bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper" ref="customObjectMapper" />
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    <bean id="customObjectMapper" class="com.terrynow.test.util.CustomObjectMapper"/>
    <!-- 把标记了@Controller注解的类转换为bean -->
    <context:component-scan base-package="com.terrynow.test.controller" />

    <!-- 其他配置省略 -->

</beans>

看下CustomObjectMapper.java 实现自定义的Object转成JsonString的规则,这里我让Date、JSONObject、JSONArray 转成JsonString

public class CustomObjectMapper extends ObjectMapper {
   
    private static final long serialVersionUID = -8859083943056178252L;

    public CustomObjectMapper() {
        this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        this.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        SimpleModule module = new SimpleModule("JSONModule", new Version(2, 0, 0, null, null, null));
        module.addSerializer(Date.class, new CustDateSerializer());
        module.addSerializer(JSONObject.class, new CustJsonSerializer());
        module.addSerializer(JSONArray.class, new CustJsonArraySerializer());
        // 按照上面的格式,增加其他Object转JsonString ...
        registerModule(module);
    }
}

看下CustDateSerializer.java CustJsonSerializer.java CustJsonArraySerializer 我把3个java写在一起了,如有需要复制,请写到3个不同的java文件里,其他自定义的,按照规律写。

public class CustDateSerializer extends JsonSerializer<Date> {

    @Override
    public void serialize(Date value, JsonGenerator jsonGenerator,
            SerializerProvider provider) throws IOException {
        // 按照这样的格式,输出String
        jsonGenerator.writeString(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value));
    }

}

public class CustJsonSerializer extends JsonSerializer<JSONObject> {
    @Override
    public void serialize(JSONObject json, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeObject(new ObjectMapper().readTree(json.toString()));
    }
}

public class CustJsonArraySerializer extends JsonSerializer<JSONArray> {
    @Override
    public void serialize(JSONArray json, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeObject(new ObjectMapper().readTree(json.toString()));
    }
}

SpringBoot的配置

SpringBoot 可以不用在pom.xml 引入jackson (默认已经引入,org.json看你需要,按需引入),自定义的HttpMessageConverter需要配置

新建MyConfiguration extends WebMvcConfigurerAdapter (如果已经有继承WebMvcConfigurerAdapter的文件,那就不需要新建,直接在已有的文件下配置)

@Configuration
public class MyConfiguration extends WebMvcConfigurerAdapter {

    @Bean(name = "jsonMapper")
    @Primary
    public ObjectMapper jsonMapper() {
        return new CustomObjectMapper();
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter(jsonMapper()));
        super.configureMessageConverters(converters);
    }

}

CustomObjectMapper.java 的内容,就和上面Spring里一样了,这里就不写了,有需要的,直接抄上面的。

admin

这个人很懒,什么都没留下

文章评论

*

code