1. 程式人生 > >SpringBoot jackson傳入List引起的坑

SpringBoot jackson傳入List引起的坑

一、jackson無法解析value為[]的json

    當入參為{xxxx1:[1,2,3],xxxx2:[obj1,obj2,obj3]}時,springmvn controller接收入參寫為Long[] xxxx1,無法解析,報錯

    解決方案:

[email protected]只能使用一次

2.使用map接收,再用get獲取

二、如上,當陣列為POJO時,通過直接map.get然後強制轉換,不能成功,使用的時候還是LinkedHashMap

解決方案:

1.先將LinkedHashMap轉為json,再講json轉為物件,如下JsonUtils的convertObject方法,轉換List使用convertObjectList方法

package com.performancetest.common.utils;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class JsonUtils {

    /**
     * <p>
     * 物件轉JSON字串
     * </p>
     
*/ public static String object2Json(Object obj) { String result = null; try { ObjectMapper objectMapper = new ObjectMapper(); result = objectMapper.writeValueAsString(obj); } catch (IOException e) { e.printStackTrace(); }
return result; } public static Map object2Map(Object obj) { String object2Json = object2Json(obj); Map<?, ?> result = jsonToMap(object2Json); return result; } /** * <p> * JSON字串轉Map物件 * </p> */ public static Map<?, ?> jsonToMap(String json) { return json2Object(json, Map.class); } /** * <p> * JSON轉Object物件 * </p> * */ public static <T> T json2Object(String json, Class<T> cls) { T result = null; try { ObjectMapper objectMapper = new ObjectMapper(); result = objectMapper.readValue(json, cls); } catch (IOException e) { e.printStackTrace(); } return result; } public static <T> T convertObject(Object srcObject, Class<T> destObjectType) { String jsonContent = object2Json(srcObject); return json2Object(jsonContent, destObjectType); } public static <T> List convertObjectList(List<LinkedHashMap> list, Class<T> destObjectType){ List result =new ArrayList<>(); list.stream().forEach(x->{ result.add(convertObject(x,destObjectType)); }); return result; } }

三、如上轉換時,報出錯,jackson轉換DateFormat型別時,不支援yyyy-MM-DD HH-mm-ss格式的日期,報錯

解決方案:

方案1.在Date型別上加@JsonFormat( pattern="yyyy-MM-dd HH:mm:ss"),如下

(弊端:每個欄位都得加,麻煩,沒從根本上解決問題,不推薦,推薦方案2)

@JsonFormat( pattern="yyyy-MM-dd HH:mm:ss")
    private Date updateTime;

方案2.

1.重寫DateFormat子類,解析的實收優先用yyyy-MM-dd HH:mm:ss型別解析,不行再用父類

(這裡遇到一個坑,啟動時報calendar空指標異常,所以在建構函式里加了

this.calendar = dateFormat.getCalendar(); )
package com.performancetest.config;


import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyDateFormat extends DateFormat {

    private DateFormat dateFormat;

    private SimpleDateFormat format1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");

    public MyDateFormat(DateFormat dateFormat) {
        this.dateFormat = dateFormat;
        //要新增父類的calendar屬性,否則會報空指標異常
        this.calendar = dateFormat.getCalendar();
    }

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
        return dateFormat.format(date, toAppendTo, fieldPosition);
    }

    @Override
    public Date parse(String source, ParsePosition pos) {

        Date date = null;

        try {

            date = format1.parse(source, pos);
        } catch (Exception e) {

            date = dateFormat.parse(source, pos);
        }

        return date;
    }

    // 主要還是裝飾這個方法
    @Override
    public Date parse(String source) throws ParseException {

        Date date = null;

        try {

            // 先按我的規則來
            date = format1.parse(source);
        } catch (Exception e) {

            // 不行,那就按原先的規則吧
            date = dateFormat.parse(source);
        }

        return date;
    }

    // 這裡裝飾clone方法的原因是因為clone方法在jackson中也有用到
    @Override
    public Object clone() {
        Object format = dateFormat.clone();
        return new MyDateFormat((DateFormat) format);
    }
}
View Code

2.將新寫的子類關聯到WebConfig中的MappingJackson2HttpMessageConverter Bean,如下程式碼

package com.performancetest.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.text.DateFormat;

@Configuration
public class WebConfig {

    @Autowired
    private Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder;

    @Bean
    public MappingJackson2HttpMessageConverter MappingJsonpHttpMessageConverter() {

        ObjectMapper mapper = jackson2ObjectMapperBuilder.build();

        //MyDateFormate解決jackson反序列formdate不支援YYYY-MM-DD HH-mm-ss的格式
        // ObjectMapper為了保障執行緒安全性,裡面的配置類都是一個不可變的物件
        // 所以這裡的setDateFormat的內部原理其實是建立了一個新的配置類
        DateFormat dateFormat = mapper.getDateFormat();
        MyDateFormat myDateFormat = new MyDateFormat(dateFormat);
        mapper.setDateFormat(myDateFormat);

        MappingJackson2HttpMessageConverter mappingJsonpHttpMessageConverter = new MappingJackson2HttpMessageConverter(
                mapper);
        return mappingJsonpHttpMessageConverter;
    }
}
View Code