亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

如何讓Jackson JSON生成的數據包含的中文以unicode方式編碼

2019-11-26 15:51:57
字體:
來源:轉載
供稿:網友

我們都知道,Jackson JSON以高速、方便和靈活著稱。之前的文章中介紹過使用注解的形式來規定如何將一個對象序列化成JSON的方法,以及如何將一個JSON數據反序列化到一個對象上。但是美中不足的一點就是對于中文的處理。當然我說的美中不足是在默認情況下,Jackson JSON不會將中文等非ASCII字符轉換為/uFFFF這樣的形式來顯示。也就是說默認情況下會顯示為{"name":"張三"}而不是{"name":"/u5F20/u4E09"}。那么為什么有這樣的需求呢?在HTTP協議中,我們可以指定數據頭部分的內容編碼。如:“GBK”、“UTF-8”等等。如果你設置正確了,那么OK,前者所表示的數據您可以正確處理。然而如果設置錯誤,對于中文字符將會產生亂碼。兩套應用系統對接,有可能兩邊使用的默認編碼不同,如果一方修改默認編碼將會對應用造成不可預知的后果。因此若能以長遠的眼光開發,那么無論您設置成什么編碼方式,都不會使數據產生亂碼。因為,這里用到了萬國編碼――Unicode。

好的,問題出來了,我們如何解決呢?使其通過實驗,Jackson JSON其實在默認設置下已經具備了對Unicode編碼的JSON數據進行解析。所欠缺的就是在序列化對象時缺少相應的步驟。好在Jackson JSON框架允許我們自定義序列化方法。那么我們就來寫一個序列化類:

復制代碼 代碼如下:

import java.io.IOException;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.impl.JsonWriteContext;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.util.CharTypes;

public class StringUnicodeSerializer extends JsonSerializer<String> {

 private final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
 private final int[] ESCAPE_CODES = CharTypes.get7BitOutputEscapes();

 private void writeUnicodeEscape(JsonGenerator gen, char c) throws IOException {
  gen.writeRaw('//');
  gen.writeRaw('u');
  gen.writeRaw(HEX_CHARS[(c >> 12) & 0xF]);
  gen.writeRaw(HEX_CHARS[(c >> 8) & 0xF]);
  gen.writeRaw(HEX_CHARS[(c >> 4) & 0xF]);
  gen.writeRaw(HEX_CHARS[c & 0xF]);
 }

 private void writeShortEscape(JsonGenerator gen, char c) throws IOException {
  gen.writeRaw('//');
  gen.writeRaw(c);
 }

 @Override
 public void serialize(String str, JsonGenerator gen,
   SerializerProvider provider) throws IOException,
   JsonProcessingException {
  int status = ((JsonWriteContext) gen.getOutputContext()).writeValue();
     switch (status) {
       case JsonWriteContext.STATUS_OK_AFTER_COLON:
         gen.writeRaw(':');
         break;
       case JsonWriteContext.STATUS_OK_AFTER_COMMA:
         gen.writeRaw(',');
         break;
       case JsonWriteContext.STATUS_EXPECT_NAME:
         throw new JsonGenerationException("Can not write string value here");
     }
     gen.writeRaw('"');//寫入JSON中字符串的開頭引號
     for (char c : str.toCharArray()) {
       if (c >= 0x80){
        writeUnicodeEscape(gen, c); // 為所有非ASCII字符生成轉義的unicode字符
       }else {
         // 為ASCII字符中前128個字符使用轉義的unicode字符
         int code = (c < ESCAPE_CODES.length ? ESCAPE_CODES[c] : 0);
         if (code == 0){
          gen.writeRaw(c); // 此處不用轉義
         }else if (code < 0){
          writeUnicodeEscape(gen, (char) (-code - 1)); // 通用轉義字符
         }else {
          writeShortEscape(gen, (char) code); // 短轉義字符 (/n /t ...)
         }
       }
     }
     gen.writeRaw('"');//寫入JSON中字符串的結束引號
 }

}


這個序列化類將要對應用中所有使用Jackson JSON的地方全都用一種方法來處理字符串類型。光有了方法還不行,還要對它進行注冊。讓Jackson JSON在序列化對象的時候使用剛剛定義好的方法:
復制代碼 代碼如下:

if (objectMapper== null){
 objectMapper= new ObjectMapper();
 //當找不到對應的序列化器時 忽略此字段
 objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
 //使Jackson JSON支持Unicode編碼非ASCII字符
 CustomSerializerFactory serializerFactory= new CustomSerializerFactory();
 serializerFactory.addSpecificMapping(String.class, new StringUnicodeSerializer());
 objectMapper.setSerializerFactory(serializerFactory);
 //支持結束
}

接下來我們來做一個測試用的對象,驗證我們的代碼:
復制代碼 代碼如下:

import java.util.Date;

import net.csdn.blog.chaijunkun.util.DateDeserializer;
import net.csdn.blog.chaijunkun.util.DateSerializer;
import net.csdn.blog.chaijunkun.util.DateTimeDeserializer;
import net.csdn.blog.chaijunkun.util.DateTimeSerializer;

import org.codehaus.jackson.annotate.JsonPropertyOrder;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;

@JsonPropertyOrder(alphabetic= false)
public class DemoObj {

 private Integer sid;

 private String stuName;

 private Boolean sex;

 @JsonSerialize(using= DateSerializer.class)
 @JsonDeserialize(using= DateDeserializer.class)
 private Date birthday;

 @JsonSerialize(using= DateTimeSerializer.class)
 @JsonDeserialize(using= DateTimeDeserializer.class)
 private Date logTime;

 //Getters and Setters

}


從代碼上可以看出,我們并沒有對String類型的屬性強制指定用何種序列與反序列方法。然后我們來構造測試用例:
復制代碼 代碼如下:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import net.csdn.blog.chaijunkun.json.DemoObj;
import net.csdn.blog.chaijunkun.util.JSONUtil;

import org.apache.log4j.Logger;

public class JSONTest {

 private static Logger logger= Logger.getLogger(JSONTest.class);

 private static String json= "{/"sid/":2,/"stuName/":/"/u6C5F/u5357Style/",/"sex/":true,/"birthday/":/"2012-07-15/",/"logTime/":/"2012-12-04 19:22:36/"}";

 public static void main(String[] args) {
  DemoObj objSrc= new DemoObj();
  objSrc.setSid(1);
  objSrc.setStuName("鳥叔");
  objSrc.setSex(true);
  Calendar calendar= Calendar.getInstance();
  calendar.set(1977, Calendar.DECEMBER, 31, 0, 0, 0);
  objSrc.setBirthday(calendar.getTime());
  objSrc.setLogTime(new Date());
  logger.info(String.format("轉換為JSON后的數據:%s", JSONUtil.toJSON(objSrc)));
  DemoObj objDes= JSONUtil.fromJSON(json, DemoObj.class);
  if(objDes==null){
   logger.info("反序列化失敗");
  }else{
   logger.info("反序列化成功");
   SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   logger.info(String.format("標識:%d", objDes.getSid()));
   logger.info(String.format("姓名:%s", objDes.getStuName()));
   logger.info(String.format("性別:%s", objDes.getSex()==true?"男":"女"));
   logger.info(String.format("生日:%s", sdf.format(objDes.getBirthday())));
   logger.info(String.format("登錄日期:%s", sdf.format(objDes.getLogTime())));
  }
 }

}


看一下輸出:
復制代碼 代碼如下:

轉換為JSON后的數據:{"sid":1,"stuName":"/u9E1F/u53D4","sex":true,"birthday":"1977-12-31","logTime":"2012-12-04 19:31:57"}
反序列化成功
標識:2
姓名:江南Style
性別:男
生日:2012-07-15 00:00:00
登錄日期:2012-12-04 19:22:36

我們看到,已經成功將中文字符顯示成為了Unicode編碼的數據。同樣,我們之前構造的Unicode編碼的數據,在不經過任何修改的情況下成功顯示出來了。

細心的朋友也許觀察到了,在測試用的對象定義代碼中,針對同樣Date類型的屬性“birthday”和“logTime”,我們指定了不同的序列化與反序列化方法。讓我們來看爛這兩個有什么不同:

復制代碼 代碼如下:

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;

public class DateTimeSerializer extends JsonSerializer<Date> {

 @Override
 public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
   throws IOException, JsonProcessingException {
  SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String formattedDate= sdf.format(date);
  gen.writeString(formattedDate);
 }

}


復制代碼 代碼如下:

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;

public class DateTimeDeserializer extends JsonDeserializer<Date> {

 @Override
 public Date deserialize(JsonParser parser, DeserializationContext context)
 throws IOException, JsonProcessingException {
  String dateFormat= "yyyy-MM-dd HH:mm:ss";
  SimpleDateFormat sdf= new SimpleDateFormat(dateFormat);
  try{
   String fieldData= parser.getText();
   return sdf.parse(fieldData);
  }catch (Exception e) {
   Calendar ca= Calendar.getInstance();
   ca.set(1970, Calendar.JANUARY, 1, 0, 0, 0);
   return ca.getTime();
  }
 }
}


復制代碼 代碼如下:

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;

public class DateSerializer extends JsonSerializer<Date> {

 @Override
 public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
   throws IOException, JsonProcessingException {
  SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
  String formattedDate= sdf.format(date);
  gen.writeString(formattedDate);
 }

}


復制代碼 代碼如下:

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;

public class DateDeserializer extends JsonDeserializer<Date> {

 @Override
 public Date deserialize(JsonParser parser, DeserializationContext context)
 throws IOException, JsonProcessingException {
  String dateFormat= "yyyy-MM-dd";
  SimpleDateFormat sdf= new SimpleDateFormat(dateFormat);
  try{
   String fieldData= parser.getText();
   return sdf.parse(fieldData);
  }catch (Exception e) {
   Calendar ca= Calendar.getInstance();
   ca.set(1970, Calendar.JANUARY, 1, 0, 0, 0);
   return ca.getTime();
  }
 }
}


從代碼我們可以看出,DateTimeSerializer和DateTimeDeserializer比DateSerializer和DateDeserializer細粒度更加高,加入了具體時間的屬性。這在應用開發中是很常見的,生日信息我們往往知道年月日就可以了,而登陸時間往往需要得比較詳細。從實例中我們可以知道,即便是同一類型,通過制定不同的序列與反序列方法,可以靈活地得到我們想要的數據形態。以上測試用例已經打包。點擊下載

補充:

最近有一個需求,需要在序列化與反序列化對象的時候對數據進行修改,當發現數據源值為空時需要讓生成的JSON顯示改字段為“游客”。可是我無論如何指定序列化器與反序列化器都無效。程序根本走不到指定的代碼中去。后來我得出結論,Jackson JSON在反序列化對象的時候,若JSON數據中對應屬性為null,則不會走自定義的反序列化器;同樣地,當你設置對象的某個屬性值為null時,在將其序列化成JSON時,也不會走自定義的序列化器。因此若有類似的需求,請在序列化與反序列化之前通過硬代碼形式判斷和修改,千萬不要什么事都指望著序列化器與反序列化器。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲国产精彩中文乱码av| 国产亚洲精品一区二区| 国产激情999| 欧美另类极品videosbest最新版本| 一夜七次郎国产精品亚洲| 在线午夜精品自拍| 欧美性videos高清精品| 国产一区二区香蕉| 97久久国产精品| 欧美激情va永久在线播放| 亚洲美女性生活视频| 国产精品一区二区久久精品| 成人午夜激情免费视频| 亚洲国产精品成人一区二区| 久久成年人视频| 国产精品久久久久91| 丝袜亚洲欧美日韩综合| 欧美成人激情图片网| 国产午夜精品麻豆| 免费91麻豆精品国产自产在线观看| 亚洲欧美一区二区三区情侣bbw| 神马国产精品影院av| 日韩欧美在线免费观看| 欧美成人合集magnet| 欧美激情手机在线视频| 2019最新中文字幕| 精品自在线视频| 久久久国产在线视频| 97视频在线观看网址| 日韩精品免费一线在线观看| 欧美天天综合色影久久精品| 日韩av一卡二卡| 久久精品久久久久| 亚洲精品动漫100p| 国产精品精品视频一区二区三区| 91精品中文在线| 91精品国产自产91精品| 色妞久久福利网| 亚洲午夜久久久影院| 国产欧美日韩综合精品| 欧美黑人狂野猛交老妇| 性色av一区二区三区在线观看| 萌白酱国产一区二区| 亚洲国产成人精品久久| 国产精品久久久久久久久久久新郎| 国产精品欧美一区二区三区奶水| 亚洲偷欧美偷国内偷| 精品久久香蕉国产线看观看gif| 夜夜嗨av一区二区三区四区| 国产精品都在这里| 欧洲日本亚洲国产区| 自拍偷拍亚洲一区| 国产精品久久久久久久久免费| 久久精品亚洲一区| 777午夜精品福利在线观看| 久久视频在线视频| 日韩电影大全免费观看2023年上| 精品久久久久久电影| 日韩av最新在线| 精品中文字幕在线观看| 亚洲女人初尝黑人巨大| 亚洲精品第一国产综合精品| 综合欧美国产视频二区| 91美女福利视频高清| 国产精品91久久| 中文字幕精品久久久久| 亚洲精品91美女久久久久久久| 亚洲影院在线看| 国产一区二区日韩精品欧美精品| 国产成人一区二区| 欧美日韩国产色| 国产精品免费电影| 91精品免费久久久久久久久| 少妇高潮久久久久久潘金莲| 日韩精品极品毛片系列视频| 国产精品自拍偷拍| 日韩精品极品毛片系列视频| 亚洲欧美999| 中文字幕亚洲第一| 日韩在线播放av| 亚洲另类xxxx| 黑人巨大精品欧美一区二区免费| 欧美极品在线视频| 日韩av综合网| 日韩精品免费在线视频观看| 尤物99国产成人精品视频| 亚洲午夜精品久久久久久久久久久久| 欧美色播在线播放| 久久久久久亚洲精品中文字幕| 国产精品一区二区av影院萌芽| 久久精品视频免费播放| 久久国产精品久久久久久久久久| 狠狠色狠色综合曰曰| 欧美激情xxxxx| 欧美在线亚洲一区| 久久久国产视频| 日本免费一区二区三区视频观看| 热久久免费视频精品| 欧美午夜美女看片| 色婷婷综合久久久久中文字幕1| 亚洲人成在线观| 成人精品久久久| 蜜月aⅴ免费一区二区三区| 亚洲欧洲日产国码av系列天堂| 日韩欧美黄色动漫| 欧美性猛交视频| 亚洲国产精品va在线看黑人动漫| 亚洲精品国产精品久久清纯直播| 欧美一级淫片aaaaaaa视频| 国产一区二区三区18| 精品国产91乱高清在线观看| 这里只有精品视频在线| 一区二区三区国产视频| 国内外成人免费激情在线视频| 啊v视频在线一区二区三区| 亚洲第一页在线| 欧美性xxxx18| 欧美另类精品xxxx孕妇| 欧美一区视频在线| 国产婷婷97碰碰久久人人蜜臀| 亚洲人成网7777777国产| 日韩高清中文字幕| 大胆人体色综合| 国产91精品高潮白浆喷水| 成人网在线观看| 国产日韩精品一区二区| 欧美高清videos高潮hd| 欧美最猛性xxxxx(亚洲精品)| 亚洲国产女人aaa毛片在线| 精品福利樱桃av导航| 国产福利视频一区| 北条麻妃一区二区三区中文字幕| 亚洲视频777| 福利二区91精品bt7086| 国产精品电影网站| 欧美激情videos| 亚洲第一免费播放区| 亚洲精品欧美一区二区三区| 欧美日韩亚洲视频一区| 国产精品视频网站| 综合国产在线视频| 亚洲japanese制服美女| 日韩av在线天堂网| 国产在线精品自拍| 欧美成年人网站| 中文字幕一区二区精品| 国产精品青青在线观看爽香蕉| 韩日精品中文字幕| 精品偷拍一区二区三区在线看| 91久久夜色精品国产网站| 久久精品一区中文字幕| 久久久久久伊人| 亚洲精品一区中文| 国产精品久久激情| 国产91精品青草社区| 欧美激情综合色综合啪啪五月| 久久精品小视频| 久久久久久久久久久久av| 亚洲日本中文字幕免费在线不卡| 97国产真实伦对白精彩视频8| 欧美激情视频一区二区三区不卡| 国产91精品久久久久久| 91中文字幕在线| 97视频在线观看网址|