亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

如何讓Jackson JSON生成的數(shù)據(jù)包含的中文以u(píng)nicode方式編碼

 更新時(shí)間:2013年12月05日 09:20:57   作者:  
這篇文章主要介紹了如何讓Jackson JSON生成的數(shù)據(jù)包含的中文以u(píng)nicode方式編碼。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助

我們都知道,Jackson JSON以高速、方便和靈活著稱。之前的文章中介紹過(guò)使用注解的形式來(lái)規(guī)定如何將一個(gè)對(duì)象序列化成JSON的方法,以及如何將一個(gè)JSON數(shù)據(jù)反序列化到一個(gè)對(duì)象上。但是美中不足的一點(diǎn)就是對(duì)于中文的處理。當(dāng)然我說(shuō)的美中不足是在默認(rèn)情況下,Jackson JSON不會(huì)將中文等非ASCII字符轉(zhuǎn)換為\uFFFF這樣的形式來(lái)顯示。也就是說(shuō)默認(rèn)情況下會(huì)顯示為{"name":"張三"}而不是{"name":"\u5F20\u4E09"}。那么為什么有這樣的需求呢?在HTTP協(xié)議中,我們可以指定數(shù)據(jù)頭部分的內(nèi)容編碼。如:“GBK”、“UTF-8”等等。如果你設(shè)置正確了,那么OK,前者所表示的數(shù)據(jù)您可以正確處理。然而如果設(shè)置錯(cuò)誤,對(duì)于中文字符將會(huì)產(chǎn)生亂碼。兩套應(yīng)用系統(tǒng)對(duì)接,有可能兩邊使用的默認(rèn)編碼不同,如果一方修改默認(rèn)編碼將會(huì)對(duì)應(yīng)用造成不可預(yù)知的后果。因此若能以長(zhǎng)遠(yuǎn)的眼光開發(fā),那么無(wú)論您設(shè)置成什么編碼方式,都不會(huì)使數(shù)據(jù)產(chǎn)生亂碼。因?yàn)椋@里用到了萬(wàn)國(guó)編碼——Unicode。

好的,問(wèn)題出來(lái)了,我們?nèi)绾谓鉀Q呢?使其通過(guò)實(shí)驗(yàn),Jackson JSON其實(shí)在默認(rèn)設(shè)置下已經(jīng)具備了對(duì)Unicode編碼的JSON數(shù)據(jù)進(jìn)行解析。所欠缺的就是在序列化對(duì)象時(shí)缺少相應(yīng)的步驟。好在Jackson JSON框架允許我們自定義序列化方法。那么我們就來(lái)寫一個(gè)序列化類:

復(fù)制代碼 代碼如下:

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中字符串的開頭引號(hào)
     for (char c : str.toCharArray()) {
       if (c >= 0x80){
        writeUnicodeEscape(gen, c); // 為所有非ASCII字符生成轉(zhuǎn)義的unicode字符
       }else {
         // 為ASCII字符中前128個(gè)字符使用轉(zhuǎn)義的unicode字符
         int code = (c < ESCAPE_CODES.length ? ESCAPE_CODES[c] : 0);
         if (code == 0){
          gen.writeRaw(c); // 此處不用轉(zhuǎn)義
         }else if (code < 0){
          writeUnicodeEscape(gen, (char) (-code - 1)); // 通用轉(zhuǎn)義字符
         }else {
          writeShortEscape(gen, (char) code); // 短轉(zhuǎn)義字符 (\n \t ...)
         }
       }
     }
     gen.writeRaw('"');//寫入JSON中字符串的結(jié)束引號(hào)
 }

}


這個(gè)序列化類將要對(duì)應(yīng)用中所有使用Jackson JSON的地方全都用一種方法來(lái)處理字符串類型。光有了方法還不行,還要對(duì)它進(jìn)行注冊(cè)。讓Jackson JSON在序列化對(duì)象的時(shí)候使用剛剛定義好的方法:
復(fù)制代碼 代碼如下:

if (objectMapper== null){
 objectMapper= new ObjectMapper();
 //當(dāng)找不到對(duì)應(yīng)的序列化器時(shí) 忽略此字段
 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);
 //支持結(jié)束
}

接下來(lái)我們來(lái)做一個(gè)測(cè)試用的對(duì)象,驗(yàn)證我們的代碼:
復(fù)制代碼 代碼如下:

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

}


從代碼上可以看出,我們并沒(méi)有對(duì)String類型的屬性強(qiáng)制指定用何種序列與反序列方法。然后我們來(lái)構(gòu)造測(cè)試用例:
復(fù)制代碼 代碼如下:

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("轉(zhuǎn)換為JSON后的數(shù)據(jù):%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("標(biāo)識(shí):%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())));
  }
 }

}


看一下輸出:
復(fù)制代碼 代碼如下:

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

我們看到,已經(jīng)成功將中文字符顯示成為了Unicode編碼的數(shù)據(jù)。同樣,我們之前構(gòu)造的Unicode編碼的數(shù)據(jù),在不經(jīng)過(guò)任何修改的情況下成功顯示出來(lái)了。

細(xì)心的朋友也許觀察到了,在測(cè)試用的對(duì)象定義代碼中,針對(duì)同樣Date類型的屬性“birthday”和“l(fā)ogTime”,我們指定了不同的序列化與反序列化方法。讓我們來(lái)看爛這兩個(gè)有什么不同:

復(fù)制代碼 代碼如下:

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);
 }

}


復(fù)制代碼 代碼如下:

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();
  }
 }
}


復(fù)制代碼 代碼如下:

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);
 }

}


復(fù)制代碼 代碼如下:

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細(xì)粒度更加高,加入了具體時(shí)間的屬性。這在應(yīng)用開發(fā)中是很常見(jiàn)的,生日信息我們往往知道年月日就可以了,而登陸時(shí)間往往需要得比較詳細(xì)。從實(shí)例中我們可以知道,即便是同一類型,通過(guò)制定不同的序列與反序列方法,可以靈活地得到我們想要的數(shù)據(jù)形態(tài)。以上測(cè)試用例已經(jīng)打包。點(diǎn)擊下載

補(bǔ)充:

最近有一個(gè)需求,需要在序列化與反序列化對(duì)象的時(shí)候?qū)?shù)據(jù)進(jìn)行修改,當(dāng)發(fā)現(xiàn)數(shù)據(jù)源值為空時(shí)需要讓生成的JSON顯示改字段為“游客”??墒俏覠o(wú)論如何指定序列化器與反序列化器都無(wú)效。程序根本走不到指定的代碼中去。后來(lái)我得出結(jié)論,Jackson JSON在反序列化對(duì)象的時(shí)候,若JSON數(shù)據(jù)中對(duì)應(yīng)屬性為null,則不會(huì)走自定義的反序列化器;同樣地,當(dāng)你設(shè)置對(duì)象的某個(gè)屬性值為null時(shí),在將其序列化成JSON時(shí),也不會(huì)走自定義的序列化器。因此若有類似的需求,請(qǐng)?jiān)谛蛄谢c反序列化之前通過(guò)硬代碼形式判斷和修改,千萬(wàn)不要什么事都指望著序列化器與反序列化器。

相關(guān)文章

  • SpringBoot通過(guò)請(qǐng)求對(duì)象獲取輸入流無(wú)數(shù)據(jù)

    SpringBoot通過(guò)請(qǐng)求對(duì)象獲取輸入流無(wú)數(shù)據(jù)

    這篇文章主要介紹了使用SpringBoot通過(guò)請(qǐng)求對(duì)象獲取輸入流無(wú)數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Spring Cloud Alibaba使用Sentinel實(shí)現(xiàn)接口限流

    Spring Cloud Alibaba使用Sentinel實(shí)現(xiàn)接口限流

    這篇文章主要介紹了Spring Cloud Alibaba使用Sentinel實(shí)現(xiàn)接口限流,本文詳細(xì)的介紹了Sentinel組件的用法以及接口限流,感興趣的可以了解一下
    2019-04-04
  • Java doGet, doPost方法和文件上傳實(shí)例代碼

    Java doGet, doPost方法和文件上傳實(shí)例代碼

    這篇文章主要介紹了Java doGet, doPost方法和文件上傳實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2016-11-11
  • 基于Redisson實(shí)現(xiàn)注解式分布式鎖的示例代碼

    基于Redisson實(shí)現(xiàn)注解式分布式鎖的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何基于Redisson實(shí)現(xiàn)注解式分布式鎖,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,需要的可以了解一下
    2023-07-07
  • SpringBoot源碼 PropertySource解析

    SpringBoot源碼 PropertySource解析

    PropertySource是spring中對(duì)于鍵值屬性的一種抽象,主要是name和sourcePropertyResolver是對(duì)PropertySource提供對(duì)外的統(tǒng)一數(shù)據(jù)處理,對(duì)于占位符的處理委托于PropertyPlaceholderHelper,對(duì)Springboot?源碼 PropertySource相關(guān)知識(shí)感興趣的朋友一起看看吧
    2023-01-01
  • MyBatis Plus 將查詢結(jié)果封裝到指定實(shí)體的方法步驟

    MyBatis Plus 將查詢結(jié)果封裝到指定實(shí)體的方法步驟

    這篇文章主要介紹了MyBatis Plus 將查詢結(jié)果封裝到指定實(shí)體的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 詳解Java如何跨平臺(tái)獲取MAC地址

    詳解Java如何跨平臺(tái)獲取MAC地址

    有時(shí)我們因?yàn)檐浖跈?quán)或者其它需要獲取主機(jī)唯一標(biāo)識(shí)而需要獲取用戶主機(jī)的MAC地址,而本文則將介紹如何通過(guò)Java來(lái)實(shí)現(xiàn)跨平臺(tái)獲取MAC地址的兩種方法,需要的朋友可以參考下
    2021-06-06
  • springboot集成flyway自動(dòng)創(chuàng)表的詳細(xì)配置

    springboot集成flyway自動(dòng)創(chuàng)表的詳細(xì)配置

    Flayway是一款數(shù)據(jù)庫(kù)版本控制管理工具,支持?jǐn)?shù)據(jù)庫(kù)版本自動(dòng)升級(jí),Migrations可以寫成sql腳本,也可以寫在java代碼里;本文通過(guò)實(shí)例代碼給大家介紹springboot集成flyway自動(dòng)創(chuàng)表的詳細(xì)過(guò)程,感興趣的朋友一起看看吧
    2021-06-06
  • mybatis-plus讀取JSON類型的方法實(shí)現(xiàn)

    mybatis-plus讀取JSON類型的方法實(shí)現(xiàn)

    這篇文章主要介紹了mybatis-plus讀取JSON類型的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • rabbitmq學(xué)習(xí)系列教程之消息應(yīng)答(autoAck)、隊(duì)列持久化(durable)及消息持久化

    rabbitmq學(xué)習(xí)系列教程之消息應(yīng)答(autoAck)、隊(duì)列持久化(durable)及消息持久化

    這篇文章主要介紹了rabbitmq學(xué)習(xí)系列教程之消息應(yīng)答(autoAck)、隊(duì)列持久化(durable)及消息持久化,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03

最新評(píng)論