如何让Jackson JSON生成的数据包含的中文以unicode方式编码

我们都知道,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时,也不会走自定义的序列化器。因此若有类似的需求,请在序列化与反序列化之前通过硬代码形式判断和修改,千万不要什么事都指望着序列化器与反序列化器。

时间: 2013-12-02

JS 文字符串转换unicode编码函数

复制代码 代码如下: function uniencode(text) { text = escape(text.toString()).replace(/\+/g, "%2B"); var matches = text.match(/(%([0-9A-F]{2}))/gi); if (matches) { for (var matchid = 0; matchid < matches.length; matchid++) { var code = matches[matchid

javascript unicode与GBK2312(中文)编码转换方法

复制代码 代码如下: var GB2312UnicodeConverter = {    ToUnicode: function (str) {        return escape(str).toLocaleLowerCase().replace(/%u/gi, '\\u');    }    , ToGB2312: function (str) {        return unescape(str.replace(/\\u/gi, '%u'));    }}; var str = '

javascript下汉字和Unicode编码互转代码

var classObj= { ToUnicode:function(str) { return escape(str).replace(/%/g,"\\").toLowerCase(); }, UnUnicode:function(str) { return unescape(str.replace(/\\/g, "%")); }, copyingTxt:function(str) { document.getElementById(str).select();

javascript实现unicode与ASCII相互转换的方法

本文实例讲述了javascript实现unicode与ASCII相互转换的方法.分享给大家供大家参考,具体如下: <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>Unicode.ASCII相互转换</title> <script type="text/javascript"&g

JavaScript字符串对象fromCharCode方法入门实例(用于把Unicode值转换为字符串)

JavaScript fromCharCode 方法 fromCharCode 方法用于把一个或多个 Unicode 值转换为(大写)字符串,并返回该字符串.其语法如下: 复制代码 代码如下: String.fromCharCode( num1, num2, ... ) 参数说明: 参数 说明 num1/num2 必需.Unicode 编码值 提示:该方法是 String 的静态方法,它的语法应该是 String.fromCharCode(),而不适用于您自己创建的 String 对象. fro

python 转换 Javascript %u 字符串为python unicode的代码

web采集的数据为 %u6B63%u5F0F%u4EBA%u5458,需要读取并转换为python对象,想了下不调用Javascript去eval,只能自己翻译了. 核心代码: import re import codecs pattern = re.compile('%u[0-9A-Z]{4}') n = codecs.open('d:\\new.txt', 'w', 'utf-8') with open('d:\\p', 'r') as f: for l in f: for i in pat

JS实现汉字与Unicode码相互转换的方法详解

本文实例讲述了JS实现汉字与Unicode码相互转换的方法.分享给大家供大家参考,具体如下: js文件中,有些变量的值可能会含有汉字,画面引入js以后,有可能会因为字符集的原因,把里面的汉字都变成乱码.后来发现网上的一些js里会把变量中的汉字都表示成"\u"开头的16进制编码,这样应该可以解决上面的问题. 最近有时间在网上查找了一下实现方式,一种比较大众化的: function tounicode(data) { if(data == '') return '请输入汉字'; var s

js 中文汉字转Unicode、Unicode转中文汉字、ASCII转换Unicode、Unicode转换ASCII、中文转换&#XXX函数代码

最近看不少在线工具里面都有一些编码转换的代码,很多情况下我们都用得到,这里我们小编就跟大家分享一下这些资料 Unicode介绍 Unicode(统一码.万国码.单一码)是一种在计算机上使用的字符编码. Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言.跨平台进行文本转换.处理的要求. Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案.Unicode用数字0-0x10FFFF来映射这些字符,最多

javascript实现unicode和字符的互相转换

<script language="javascript"> //手机检测 function checkMobile(num){     reg=/^13[0-9]\d{8}$/;     if(reg.test(num)){         return true;     }else{         reg=/^15[8-9]\d{8}$/;         if(reg.test(num)){             return true;         }el

JS实现的Unicode编码转换操作示例

本文实例讲述了JS实现的Unicode编码转换操作.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Unicode编码转换</title> </head> <body> <script> /* *js Unicode编码转换 */ va

JavaScript中字符串与Unicode编码互相转换的实现方法

本文实例讲述了JavaScript中字符串与Unicode编码互相转换的实现方法.分享给大家供大家参考,具体如下: 这段代码演示了JavaScript中字符串与Unicode编码的转换: // 为了控制台的演示方便, 变量没有添加 var 定义 // 实际编程中请避免 // 字符串 str = "中文"; // 获取字符 char0 = str.charAt(0); // "中" // 数字编码值 code = str.charCodeAt(0); // 20013

js unicode 编码解析关于数据转换为中文的两种方法

复制代码 代码如下: var str = "\\u6211\\u662Funicode\\u7F16\\u7801"; 关于这样的数据转换为中文问题,常用的两种方法. 1. eval 解析 复制代码 代码如下: str = eval("'" + str + "'"); // "我是unicode编码" 2. unescape 解析 复制代码 代码如下: str = unescape(str.replace(/\\u/g, &q

Json_encode防止汉字转义成unicode的方法

大家都知道,json_encode通常会把json中的汉字转义成unicode,但是这并不一定是我们想要的.有时候,我们需要获得汉字形式的json字符串,比如需要获得gbk编码的json字符串(只要把汉字形式的字符串转码就可以得到了).有什么好办法么? php官方听到了这个需求,并提供了一种可靠的解决方案:JSON_UNESCAPED_UNICODE.这个参数可以保证json_encode不再将汉字转为unicode. 似乎这样就解决了?当我们高高兴兴的用这个参数的时候,发现并没有什么卵用.仔细

python实现将汉字保存成文本的方法

如果汉字不多的话,建议采取下列方式 首先,在python文件中添加 #coding=utf-8 或者 # -*- coding:utf-8 -*- 然后用一个for循环开始处理汉字: with open('str.txt','w') as f: for s in str: s = s.encode('utf-8') f.write(s) 其中str是一个汉字的列表,如:str = ('制造业').decode('utf-8') ,或者从其他地方得到的包含汉字的一个变量,这个变量也需要改成str

PHP中让json_encode不自动转义斜杠“/”的方法

前言 最近将使用爬虫爬取的链接保存到 mysql 数据库中时,发现我将链接使用 json_encode 保存时候,在数据库中却显示了转义字符,我并不需要这转义的,看起来不清晰而且占用存储空间. 后来发现在默认的情况之下使用 json_encode 对数组进行 json 格式的转换时候会自动的将数据中含有斜杠的字符串进行转义,但是我们往往有的时候不需要药对它们进行转义的,本文说说如何使用 json_encode 不自动转义斜杠. 对于如下数组 $a,现有两种办法解决: $a = array( 'h

PHP使用json_encode函数时不转义中文的解决方法

本文实例讲述了PHP使用json_encode函数时不转义中文的解决方法.分享给大家供大家参考.具体方法如下: json_encode函数对于gbk中的中文字符是不会转换的或直接转换成空格了,本文就来给各位整理一个关于json不转义中文问题处理技巧,相信对大家有所帮助. 如果你调用 PHP 自带的 json_encode() 函数, 碰到中文时, 中文会被转义掉. 例如: 复制代码 代码如下: echo json_encode(array('你好')); // 输出: ["\u4f60\u597

C#实现将汉字转化为2位大写的16进制Unicode的方法

本文实例讲述了C#实现将汉字转化为2位大写的16进制Unicode的方法.分享给大家供大家参考.具体实现方法如下: 说明: str.ToString("x") : 转为1位16进制小写 str.ToString("X") : 转为1位16进制大写 str.ToString("X2"):转为2位16进制大写 具体代码如下: 复制代码 代码如下: publicstaticstring StringToUnicode16(string text, st

在PHP语言中使用JSON和将json还原成数组的方法

在之前我写过php返回json数据简单实例,刚刚上网,突然发现一篇文章,也是介绍json的,还挺详细,值得参考.内容如下 从5.2版本开始,PHP原生提供json_encode()和json_decode()函数,前者用于编码,后者用于解码. 一.json_encode() <?php $arr = array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5); echo json_encode($arr); ?> 输出 {"a&

python获取一组汉字拼音首字母的方法

本文实例讲述了python获取一组汉字拼音首字母的方法.分享给大家供大家参考.具体实现方法如下: #!/usr/bin/env python # -*- coding: utf-8 -*- def multi_get_letter(str_input): if isinstance(str_input, unicode): unicode_str = str_input else: try: unicode_str = str_input.decode('utf8') except: try:

python实现将汉字转换成汉语拼音的库

本文实例讲述了python实现将汉字转换成汉语拼音的库.分享给大家供大家参考.具体分析如下: 下面的这个python库可以很容易的将汉字转换成拼音,其中用到了一个word.data 的字典,可点击此处本站下载. #!/usr/bin/env python # -*- coding:utf-8 -*- __version__ = '0.9' __all__ = ["PinYin"] import os.path class PinYin(object): def __init__(sel

Android实现ListView的A-Z字母排序和过滤搜索功能 实现汉字转成拼音

直入主题,今天给大家带来ListView的A-Z字母排序和过滤搜索功能并且实现汉字转成拼音的功能,我们知道一般我们对联系人,城市列表等实现A-Z的排序,因为联系人和城市列表我们可以直接从数据库中获取他的汉字拼音,而对于一般的数据,我们怎么实现A-Z的排序,我们需要将汉字转换成拼音就行了,接下来就带大家实现一般数据的A-Z排序功能,首先先看下效果图 上面是一个带删除按钮的EditText,我们在输入框中输入可以自动过滤出我们想要的东西,当输入框中没有数据自动替换到原来的数据列表,然后下面一个Lis

解决JSON.stringify()自动将中文转译成unicode的问题

最近在工作中,发现在IE8下JSON.stringify()自动将中文转译为unicode编码,原本选择的中文字符,传到后台变为了unicode编码,即\u****的形式.查找资料后发现,与标准的JSON.stringify()不同,IE8内置的JSON.stringify()会自动将编码从utf-8转为unicode编码,导致出现这种类似于乱码的情况. 解决方法分为两种,第一种是后台接收到数据之后,将该数据再进行一次转码,重新转为utf-8,然后再保存到数据库中,这样,再次从数据库取出传给前端