解決辦法是 利用 com.alibaba.fastjson.serializer.ObjectSerializer 和 com.alibaba.fastjson.annotation.JSONField 。 ...
項目里 前後端頁面的http請求 及 dubbo服務間的RPC調用,返回值類型統一是一個Result<T>,其結構如下。
@Data public class Result<T> implements Serializable { private static final long serialVersionUID = 1L; /** * 返回處理消息 */ private String message = "操作成功!"; /** * 返回代碼 */ private Integer code = 0; /** * 返回數據對象 data */ @Getter private T data; }
項目的RPC使用的是dubbo。我們在項目中定義了一個公用的DubboTraceFilter。這個Filter會將介面方法返回值 Result<T>對象 列印到log文件里。序列化方式用的是 fastjson 的 JSON#toJSONString。
背景介紹完畢。接下來說我要解決的事情。
註意到Result<T>的data欄位。它是泛型T的實例,就是說,這個data會是任意類型的數據。
從log里看,當data里是集合數據,例如,分頁查詢的場景,列印出來的log會超長。
這導致日誌量很大,同時,這種無用的日誌刷屏,也不利於我們排查問題。
簡言之,看下麵兩段json串(為便於閱讀,進行了格式化),希望log里出現後者。
{ "message": "成功", "code": 200, "result": ["0memob92142f2-ad8a-4812-913e-002f8f9d1894", "1memo77d4ad82-078f-4f73-a26e-c5302a596042", "2memoa69185c2-670d-480b-b1d2-19fd1326ecd5", "3memoee5d13a7-83bd-4430-a4b0-198e65201dc7", "4memo519d9d69-a27f-4864-8dd4-889ada1790a3", "5memo85034936-564b-41d8-94f0-ff1ac7be8d92", "6memoa22d4b20-828a-4ac5-a3fe-461283fc4154", "7memo7b2b8880-80b2-41f8-93d9-553467287e13", "8memo55afe9f2-e6b5-481c-9978-773fb5ff0f14", "9memoa5a92ffd-4e72-42f1-8d81-7221d2f371a3"], "timestamp": 1666961782888 }
{ "code": 200, "message": "成功", "result": "[\"0memob92142f2-ad8a-4812-913e-002f8f9d1894\",\"1memo77d4ad82-078f-4f73-a26e-c5302a596042\",\"2memoa6...", "timestamp": 1666961782888 }
那麼,如何解決這個痛點?
我相信,找開發組裡的任何一位同學,他都能解決。改DubboTraceFilter里的代碼就行了,對序列化的json串進行相關截取。
而我想說什麼呢?
一勞永逸!
程式里有還有其他地方也存在通過 JSON#toJSONString(Result<T>) 列印log的代碼。 難道逐個改嗎?
所以,有沒有簡單的辦法,改一處就全改了。
世上無易事,用心求精進。只要不放棄,辦法就會有。
解決辦法是 利用 com.alibaba.fastjson.serializer.ObjectSerializer 和 com.alibaba.fastjson.annotation.JSONField 。
首先,通過實現ObjectSerializer介面來自定義一個序列化器: StringAbbreviatingSerializer
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.ObjectSerializer; import org.apache.commons.lang.StringUtils; import java.io.IOException; import java.lang.reflect.Type; public class StringAbbreviatingSerializer implements ObjectSerializer { /** * * @param serializer * @param object field的值 * @param fieldName field的name * @param fieldType field的類型,如java.lang.String * @param features * @throws IOException */ @Override public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { serializer.write( StringUtils.abbreviate(JSON.toJSONString(object),100)); } }View Code
然後,使用com.alibaba.fastjson.annotation.JSONField 註解。
@JSONField(serializeUsing = StringAbbreviatingSerializer.class) private T data;
完了嗎?我要補充——一併重寫Result<T>的toString方法。徹底一勞永逸。
@Data public class Result<T> implements Serializable { 。。。。 @Override public String toString() { return JSON.toJSONString(this); } }
要說明的是,加上這個註解後,對Result<T>的實際值並不會有影響(包括http請求和dubbo調用,親測)。所以,放心用,放心去序列化。媽媽再也不用擔心我的日誌爆屏了。
over!
附:
使用fastjson提供的介面實現自定義的編解碼器
在項目開發中經常會遇到一些業務需要對某些數據進行特殊的定製化處理,fastjson為我們提供了介面可以用於實現自定義的編解碼器來完成我們的業務要求。
ObjectSerializer和ObjectDeserializer分別是fastjson的編碼器和解碼器介面。
當看到一些不好的代碼時,會發現我還算優秀;當看到優秀的代碼時,也才意識到持續學習的重要!--buguge
本文來自博客園,轉載請註明原文鏈接:https://www.cnblogs.com/buguge/p/16837507.html