奇怪的结果与字符编码

Use*_*709 2 java encoding utf-8

这是情景 -

  • DB2数据库位于大型机系统(z/OS)上
  • Web服务器在USS(z/OS的Unix部分)上运行,使用Spring JDBC运行Java代码
  • 我们测试过的浏览器和Windows 7上运行的客户端程序(默认编码是windows-1252)

我们有一个包含西班牙语字符(ú)的字符串,它使用Spring的JDBCTemplate存储在数据库中,因此基本上是JDBC.

  • 当使用JDBC客户端(Squirrel,用Java编写)查询时,它会显示为其他内容(ú).
  • 当使用示例JDBC程序查询并将结果打印为字符串时,它会显示为其他内容(ú).
  • 当使用示例JDBC程序查询并将结果打印为UTF-8编码的字符串[new String(str,"UTF-8")]时,它会正确显示(ú).
  • 使用此-Dfile.encoding = utf-8以UTF-8编码启动JVM时,结果将在上述两种情况下打印为其他内容(ú).
  • 运行应用程序前端的浏览器也将其显示为Ã,但HTML的内容标题设置为UTF-8.

在这个阶段我有点困惑,并有这些问题 -

  • 如果以UTF-8格式打印字符串特别有效,那么当JVM以UTF-8编码启动时,为什么它不起作用.
  • 在哪一层实际上可能发生问题,数据库还是JVM?

我应该在应用程序级别而不是列级别解决这个问题?

任何指针都会有所帮助.

Dan*_*tin 5

您所看到的效果都可以通过假设数据以UTF-8字节写入数据库,但数据库认为这些字节是其他字符集(ISO-LATIN-1或Windows-1252)来解释. ),然后当您读取数据时,您获得的字符串是解释为ISO-LATIN-1或相关字符集的字节.

úUTF-8中的字符是两个字节0xC3 0xBA.当这些字节被解释为ISO-LATIN-1或win-1252时,您将获得两个字符ú.

ú以UTF-8写入时的两个字符是四个字节0​​xC3 0x83 0xC2 0xBA.当这四个字节被解释为ISO-LATIN-1(或win-1252)时,您将获得四个字符ú.

(Windows-1252和ISO-LATIN-1碰巧就所讨论的所有字节/字符达成一致,所以根据证据我无法区分它们之间的区别)

我相信,你发生了什么事:

  1. JDBC客户端正在查询数据库,并且正在返回包含ú数据库中两个字符的字符串.

  2. 当JVM将结果打印到windows 7控制台框时,如果它没有启动-Dfile.encoding=utf-8,它会向控制台框发送表示win-1252中字符串所需的字节.如果JVM 开始与选项,将其发送到控制箱来表示UTF-8串所需的字节数.

  3. 您的Windows 7控制台框设置为windows-1252,并通过解释java根据windows-1252发送的字节来显示java打印出的内容

  4. 当您.getBytes()不带参数调用时,您使用JVM的默认编码将字符串转换为字节.因此,new String(str.getBytes(), "UTF-8")如果默认JVM编码为UTF-8 ,将导致相同的字符串,并且如果默认编码与UTF-8不同,则只会导致实际发生的事情.

这解释了您提供的所有证据:JDBC检索的java字符串包含字符ú,然后当非utf-8 JVM尝试将其打印到控制台框时,将其打印为ú.当utf-8 JVM尝试将此字符串打印到控制台框时,它会输出四个字节0​​xC3 0x83 0xC2 0xBA,并且控制台将其解释为四个字符ú.当java Web服务器尝试将此字符串发送回浏览器时,它会这样做 - 浏览器看到的是java应用程序从JDBC接收的内容.

首先要检查的是Spring JDBCTemplate是否正确接收数据并正确写入数据库.你能让Spring记录它从浏览器收到的内容,并确保浏览器发送UTF-8,并且Spring知道浏览器正在发送UTF-8吗?(你可能想要检查一件事是记录接收到的字符串以及字符串在每个字段中的长度.这可以让你知道事情是否被正确解释为UTF-8)

假设数据正确进入数据库,并且正如您所说无法在数据库端进行更改,并且希望仅从应用程序端进行更改,则可以对从JDBC接收的每个字符串执行此操作:

new String(str.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)
Run Code Online (Sandbox Code Playgroud)

无论JVM的默认编码是什么,这都应该将您的字符串转换回您想要的字符串.

为了将来参考,从windows命令行运行jvm -Dfile.encoding=utf-8通常需要首先更改控制台上的代码页,以便正确查看内容.(这可以通过命令完成chcp 65001.只需记住chcp 1252在运行没有设置该选项的JVM命令之前使用更改回来)