开发JDBC+MS SQL SERVER 相关的内容时,遇到Tomcat 7下UTF-8编码的页面无法正常显示中文文字,而相对地英文字母可以正常显示。如:
Medicine. medBook ntext:Nullable | Medicine. medNameEN ntext:Nullable |
0-NNS,gI?0 | root of Hemsley cowparsnip |
实际页面其字节数为
0-NNS,gI?0/12 | root of Hemsley cowparsnip/52 |
(即事实上英文字每个前都有类似0x00之类的不可见字符)
根据各种测试,基本得出问题所在:
首先,出现乱码的数据类型为NVARCHAR,使用Unicode编码存储;
我所使用的JDBC尚未实现getNString(int) 方法,这也就意味着在JDBC的读取数据流中,并不能按照nvarchar的方式双字节读取,反而是将一个字拆分为两个单独的字节处理;
SQL SERVER 2008中的编码方式应该是默认的ANSI/GBK。
以上,基本得出上述乱码的来源为N字开头的类型的数据之每一个字都被拆成了2个字节,每个字节在JDBC中转码为JAVA内部使用的Unicode,之后再以对应的字母(基本就是ASCII码)的形式显示出来。
理论上分析的结论是很明显的,可以通过逆转换推出原数据。然而实际上还未成功实现。
相对而言,拿自己之前写过的通用C#SQL查询程序对同一数据库进行连接之后,明显,C#对N字类型的支持要远远好于JAVA,即几乎不需要人工干预,当然这得益于C#的字符类型实现。
//sleep(several_hours);
醒来之后继续研究,这回决定从点到面,先把上述乱码的文字编码全部解析一遍,结果如下:
Unicode | UTF-8 | GBK | CHAR | raw |
300A | e3 80 8a | a1 b6 | 《 | 0a 30 |
4E2D | e4 b8 ad | d6 d0 | 中 | 2d 4e |
534E | e5 8d 8e | bb aa | 华 | 4e 53 |
672C | e6 9c ac | b1 be | 本 | 2c 67 |
8349 | e8 8d 89 | b2 dd | 草 | 48 -125(ffffff83) |
300B | e3 80 8b | a1 b7 | 》 | 0b 30 |
附,NetBeans 7+jdk7下的解析结果
run:
《中华本草》
got rei codes(6):300a 4e2d 534e 672c 8349 300b
got raw codes(12):a 30 2d 4e 4e 53 2c 67 49 3f b 30
got uni codes(12):30 a 4e 2d 53 4e 67 2c 3f 49 30 b
《中华本㽉》
Using bytes!
got raw codes(12):a 30 2d 4e 4e 53 2c 67 49 ffffff83 b 30
got uni codes(12):30 a 4e 2d 53 4e 67 2c ffffff83 49 30 b
《中华本草》
成功生成(总时间:1 秒)
包含英文字母的中文内容实例:
public static void main(String[] argv) throws SQLException, UnsupportedEncodingException {
ResultSet rs = DBQuery("select medEnvironment from Medicine where medId=58");
boolean hasfirst = rs.first();
System.out.println("Using bytes!");
if (hasfirst) {
byte[] bytes = rs.getBytes(1);
byte[] nbytes=new byte[bytes.length];
System.out.print("got raw codes(" + bytes.length + "):");
for (byte b : bytes) {
System.out.print(Integer.toHexString((int) b) + " ");
}
System.out.println();
System.out.print("got uni codes("+bytes.length+"):");
for (int i = 0; i < bytes.length; i += 2) {
nbytes[i] = bytes[i+1];
nbytes[i + 1] =bytes[i];
System.out.print(Integer.toHexString(nbytes[i]) + " " + Integer.toHexString(nbytes[i + 1]) + " ");
}
System.out.println();
String newUnicode = new String(nbytes, "Unicode");
System.out.println(newUnicode);
}
}
运行结果为:
run:
Using bytes!
got raw codes(116):1f 75 1 60 ffffffaf 73 ffffff83 58 1a ffffffff 1f 75 ffffff8e 4e 77 6d ffffffd4 62 31 0 30 0 30 0 30 0 6d 0 ffffffe5 4e b 4e ffffff84 76 37 ffffff8c 1 30 53 ffffff90 ffffffef ffffff8d ffffffc1 65 1 30 34 6c ffffff9f 6c ffffffb9 ffffff8f 16 62 ffffff97 67 2d 4e 6e 6f 7f 6e 30 57 2 30 44 ffffff8d ffffff90 6e 6 52 3 5e 1a ffffffff 6 52 3 5e ffffff8e 4e 59 6d 5f 6c 1 30 5f 6c 7f ffffff89 1 30 ffffff8f 79 fffffffa 5e 1 30 56 6e 57 53 1 30 7f 5e 1c 4e 49 7b 30 57 2 30
got uni codes(116):75 1f 60 1 73 ffffffaf 58 ffffff83 ffffffff 1a 75 1f 4e ffffff8e 6d 77 62 ffffffd4 0 31 0 30 0 30 0 30 0 6d 4e ffffffe5 4e b 76 ffffff84 ffffff8c 37 30 1 ffffff90 53 ffffff8d ffffffef 65 ffffffc1 30 1 6c 34 6c ffffff9f ffffff8f ffffffb9 62 16 67 ffffff97 4e 2d 6f 6e 6e 7f 57 30 30 2 ffffff8d 44 6e ffffff90 52 6 5e 3 ffffffff 1a 52 6 5e 3 4e ffffff8e 6d 59 6c 5f 30 1 6c 5f ffffff89 7f 30 1 79 ffffff8f 5e fffffffa 30 1 6e 56 53 57 30 1 5e 7f 4e 1c 7b 49 57 30 30 2
生态环境:生于海拔1000m以下的谷、道路旁、水沟边或林中潮湿地。资源分布:分布于浙江、江西、福建、湖南、广东等地。
成功生成(总时间:1 秒)