其實,我一直想寫一個有關Util的系列。java
其中有四個緣由:apache
JsonUtil就是用來進行單個或複數個對象的序列化與反序列化操做。json
package top.jarry.learning.util; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.TypeReference; import java.io.IOException; import java.text.SimpleDateFormat; /** * @Description: * @Author: jarry */ @Slf4j public class JsonUtil { // 創建Jackson的ObjectMapper對象 private static ObjectMapper objectMapper = new ObjectMapper(); // 創建Json操做中的日期格式 private static final String JSON_STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss"; // DateTimeUtil.STANDARD_FORMAT = "yyyy-mm-dd HH:mm:ss"; // 日期格式若是設置爲這個,會出現月份出錯的問題(先是5月變3月,而後就不斷增長,甚至超過12月),具體緣由待查 static { //對象的全部字段所有列入 objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS); //取消默認轉換timestamps形式 objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); //忽略空Bean轉json的錯誤 objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false); //全部的日期格式都統一爲如下的樣式 objectMapper.setDateFormat(new SimpleDateFormat(JSON_STANDARD_FORMAT)); //反序列化 //忽略 在json字符串中存在,可是在java對象中不存在對應屬性的狀況。防止錯誤 objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); } /** * 完成對象序列化爲字符串 * @param obj 源對象 * @param <T> * @return */ public static <T> String obj2String(T obj) { if (obj == null) { return null; } try { return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj); } catch (Exception e) { log.warn("Parse Object to String error", e); return null; } } /** * 完成對象序列化爲字符串,可是字符串會保證必定的結構性(提升可讀性,增長字符串大小) * @param obj 源對象 * @param <T> * @return */ public static <T> String obj2StringPretty(T obj) { if (obj == null) { return null; } try { return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); } catch (Exception e) { log.warn("Parse Object to String error", e); return null; } } /** * 完成字符串反序列化爲對象 * @param str 源字符串 * @param clazz 目標對象的Class * @param <T> * @return */ public static <T> T string2Obj(String str, Class<T> clazz) { if (StringUtils.isEmpty(str) || clazz == null) { return null; } try { return (clazz == String.class) ? (T) str : objectMapper.readValue(str, clazz); } catch (IOException e) { log.warn("Parse String to Object error", e); return null; } } //jackson在反序列化時,若是傳入List,會自動反序列化爲LinkedHashMap的List //因此重載一下方法,解決以前String2Obj沒法解決的問題 /** * 進行復雜類型反序列化工做 (自定義類型的集合類型) * * @param str 源字符串 * @param typeReference 包含elementType與CollectionType的typeReference * @param <T> * @return */ public static <T> T string2Obj(String str, TypeReference<T> typeReference) { if (StringUtils.isEmpty(str) || typeReference == null) { return null; } try { return (T) ((typeReference.getType().equals(String.class)) ? str : objectMapper.readValue(str, typeReference.getClass())); } catch (IOException e) { log.warn("Parse String to Object error", e); return null; } } /** * 進行復雜類型反序列化工做(可變類型數量的) * * @param str 須要進行反序列化的字符串 * @param collectionClass 須要反序列化的集合類型 因爲這裏的類型未定,且爲了防止與返回值類型T衝突,故採用<?>表示泛型 * @param elementClasses 集合中的元素類型(可多個) 此處同上經過<?>...表示多個未知泛型 * @param <T> 返回值的泛型類型是由javatype獲取的 * @return */ public static <T> T string2Obj(String str, Class<?> collectionClass, Class<?>... elementClasses) { JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses); try { return objectMapper.readValue(str, javaType); } catch (IOException e) { log.warn("Parse String to Object error", e); return null; } } }
public void onInitializationInclinationMessage(String initializationInclinationStr, @Headers Map<String, Object> headers, Channel channel) throws IOException { log.info("InitializationInclinationConsumer/onInitializationInclinationMessage has received: {}", initializationInclinationStr); // 1.接收數據,並反序列化出對象 InitializationInclination initializationInclination = JsonUtil.string2Obj(initializationInclinationStr, InitializationInclination.class); // 2.數據校驗,判斷是否屬於該終端數據 if (initializationInclination == null) { Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG); channel.basicAck(deliveryTag, false); } if (!GuavaCache.getKey(TERMINAL_ID).equals(initializationInclination.getTerminalId())) { log.info("refuse target initializationInclination with terminalId({}).current_terminalId({})", initializationInclination.getTerminalId(), GuavaCache.getKey(TERMINAL_ID)); return; } // 3.將消息傳入業務服務,進行消費 ServerResponse response = iInitializationInclinationService.receiveInitializationInclinationFromMQ(initializationInclination); // 4.對成功消費的數據進行簽收 if (response.isSuccess()) { //因爲配置中寫的是手動簽收,因此這裏須要經過Headers來進行簽收 Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG); channel.basicAck(deliveryTag, false); }
public void onInclinationTotalMessage(String inclinationTotalListStr, @Headers Map<String, Object> headers, Channel channel) throws Exception { log.info("InclinationConsumer/onInclinationTotalMessage has received: {}", inclinationTotalListStr); // 1.對消息進行反序列化操做 List<InclinationTotal> inclinationTotalList = JsonUtil.string2Obj(inclinationTotalListStr, List.class, InclinationTotal.class); // 2.對數據進行校驗 if (CollectionUtils.isEmpty(inclinationTotalList)){ //因爲配置中寫的是手動簽收,因此這裏須要經過Headers來進行簽收 Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG); channel.basicAck(deliveryTag, false); } // 3.將消息傳入業務服務,進行消費 ServerResponse response = iInclinationService.insertTotalDataByList(inclinationTotalList); // 4.對成功消費的數據進行簽收 if (response.isSuccess()) { //因爲配置中寫的是手動簽收,因此這裏須要經過Headers來進行簽收 Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG); channel.basicAck(deliveryTag, false); } }
在使用這個JsonUtil的過程當中,遇到過一個問題,就是日期序列化,反序列化,出現問題。session
不過,通過一次次調試與追蹤後,發現只要修改了日期格式就能夠避免這個問題(其實當時真的沒有想到Util會出現這種問題,因此花了很多時間)。app
具體緣由,問了一圈,也沒有獲得答案。看來只能留待往後了。maven
Json序列化的Util固然不止這一種。還有不少方式,乃至不是基於Jackson的,如基於Gson的。
有機會往後會進行補充的。學習
若是你們對這個系列有什麼意見或者期待,能夠給我留言,謝謝。調試