保存非英文字符时出现问题

5

我们正在开发一个应用程序,需要将数据保存在古吉拉特语中。

应用程序中使用的技术如下:

  • Spring MVC 版本 4.1.6.RELEASE
  • Hibernate 版本 4.3.5.Final
  • MySQL 6.0.11

我的 JSP 已配置为:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

并且
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

Hibernate配置是

<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>

MySQL的URL是

jdbc:mysql://host:port/dbName?useUnicode=true&connectionCollation=utf8_general_ci&characterSetResults=utf8

这段文本涉及到IT技术,需要翻译成中文。其中的内容是:一个普通Java对象(Pojo)有一个String类型的字段来存储数据。

MySQL有一个VARCHAR数据类型,可以用charset=utf8Collation=utf8_general_ci来存储数据。

当我尝试保存任何非英语(古吉拉特语)字符时,它会显示一些垃圾字符,例如àª?à«?àª?代替“ગુજ”。

是否有其他配置我在这里错过了。


如果你看到与字符一样多的问号,可能没有问题,但是在更改调试器字体后检查字符可以更加确定。另外,您可以检查通过string.getBytes()获取的字节值。 - Turan Yüksel
@Rick:HEX(col) 的结果为 ગુજ 的十六进制编码 C3A0C2AAC297C3A0C2ABC281C3A0C2AAC29C。 - Yogesh Prajapati
你应该在项目、POM.xml、JSP和数据库中设置UTF-8,这样就不会出现问题。如果这是你想要的,请告诉我,我会告诉你所有需要设置的地方,除了MySQL,我更熟悉Postgres而不是MySQL。 - We are Borg
如果您正在使用Apache Tomcat,则在Connector中也必须指定UTF-8,例如URIEncoding="utf-8"。如果需要代码,请告诉我。 - We are Borg
当您在JSP、MySQL终端或其他I/O设备上显示这些字符时,您会在哪里看到它们?后两种情况可能不支持UTF-8字符编码或未配置使用它。如果只有这种情况,则与JSP/Spring(MVC)/Hibernate甚至使用的容器无关。(除了具体问题:MySQL中的UTF-8使用1到3个字节。它不完全符合UTF-8的要求。如果您需要4字节字符集,您将需要utf8mb4,它仅自MySQL 5.5.3以来可用)。 - Tiny
显示剩余5条评论
5个回答

7

我在将“tamil”字符插入数据库时遇到了相同的问题。在经过大量搜索后,我找到了一个更好的、可行的解决方案,它解决了我的问题。在这里,我与您分享我的解决方案。我希望它能帮助您消除有关非英语字符的疑虑。

INSERT INTO 
STUDENT(name,address) 
VALUES 
(N'பெயர்', N'முகவரி');

由于您并没有提供表格和字段名称的结构,因此我正在使用示例。


4
这并没有真正回答这个问题。 - Uwe Allner

5

我猜您想要翻译的是ગુજ(带有元音符号U的GA JA)?

我认为您可能在某种程度上指定了"latin5"编码。(是的,我看到您在所有地方都使用了UTF-8,但是"latin5"是我能够使事情正常工作的唯一方法。)

CONVERT(CONVERT(UNHEX('C3A0C2AAC297C3A0C2ABC281C3A0C2AAC29C')
       USING utf8) USING latin5) = 'ગુજ'

此外,您最终可能会出现“双重编码”; 我怀疑发生了以下情况:
  • 客户端将字符编码为utf8(很好); 和
  • 使用了SET NAMES latin5,但它谎称客户端具有latin5编码; 和
  • 表中的列声明了CHARACTER SET utf8(很好)。

如果可能的话,最好从头开始 - 清空表格,确保在从客户端连接到数据库时具有SET NAMES utf8或建立utf8。 然后重新填充表格。

如果您更愿意尝试恢复现有数据,则可能会起作用:

UPDATE ... SET col = CONVERT(BINARY(CONVERT(
                         CONVERT(UNHEX(col) USING utf8)
                         USING latin5)) USING utf8);

但是对于每个表中出现混乱列的情况,你需要针对每列进行这样的操作。

该代码的部分测试为执行以下操作:

SELECT CONVERT(BINARY(CONVERT(
                         CONVERT(UNHEX(col) USING utf8)
                         USING latin5)) USING utf8)
     FROM table;

我使用“部分测试”是因为看上去正确并不意味着它一定正确。

在进行UPDATE之后,对SELECT HEX(col)执行操作会得到ગુજ的值为E0AA97E0AB81E0AA9C。请注意,大多数古吉拉特语十六进制应该以E0AAyyE0AByy的形式出现。您也可能发现空格的十六进制为20

很抱歉我无法更加确定。我已经解决了字符集问题十年了,但这是一个新的变体。


我没能更快地解决它,因为我看到的是 àªà«àª,这与你的 àª?à«?àª? 不太一致。我仍然无法解释那部分。但这不应该有影响;十六进制更具决定性。 - Rick James
尝试了你的解决方案,但对我不起作用。看起来我在配置方面漏掉了一些东西。 - Yogesh Prajapati
在您的“MySQL URL”中,您只设置了出站设置(&characterSetResults=utf8)。我不知道应该放什么,但也许应该是 characterEncoding=UTF-8 - Rick James

4

你可能会有一些遗漏的事情。我在linux上遇到了与mysql相关的同样的问题,我需要做的就是像这样编辑my.cnf

[client]
default-character-set = utf8

[mysqld]
character-set-server = utf8

例如,在Centos上,此文件位于/etc/my.cnf,在Windows(我的电脑)上,C:\ProgramData\MySQL\MySQL Server 5.5\my.ini。请注意,ProgramData可能会被隐藏。
此外,如果您正在使用Tomcat,则必须指定UTF-8用于URI编码。只需编辑server.xml并修改主要的Connector元素即可:
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           URIEncoding="UTF-8"
           redirectPort="8443" />

请确保在您的应用程序中添加了字符编码过滤器:
@WebFilter(filterName = "CharacterEncodingFilter", urlPatterns = {"/*"})
public class CharacterEncodingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig)
            throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        request.setCharacterEncoding("UTF-8");
        servletResponse.setContentType("text/html; charset=UTF-8");

        filterChain.doFilter(request, servletResponse);
    }

    @Override
    public void destroy() {
    }

}

希望这能帮到您。

3
另一个提示,不要仅依赖设置 characterEncoding 作为hibernate属性 <prop key="hibernate.connection.characterEncoding">UTF-8</prop> ,确保你将其明确地添加为DB URL的连接变量,并指定如下内容: jdbc:mysql://host:port/dbName?useUnicode=true&characterEncoding=UTF-8&connectionCollation=utf8_general_ci&characterSetResults=utf8。此外,由于存在许多层次可能会丢失编码,您可以尝试分离层次并更新问题所在的层次,例如,在存储到数据库之前或其他某个时间点上。

2

您的applicationContext文件应该像这样:

为了使Spring MVC应用程序支持国际化,请注册两个bean:

  1. SessionLocaleResolver Register a “SessionLocaleResolver” bean, named it exactly the same characters “localeResolver“. It resolves the locales by getting the predefined attribute from user’s session. Note If you do not register any “localeResolver”, the default AcceptHeaderLocaleResolver will be used, which resolves the locale by checking the accept-language header in the HTTP request.

  2. LocaleChangeInterceptor Register a “LocaleChangeInterceptor” interceptor and reference it to any handler mapping that need to supports the multiple languages. The “paramName” is the parameter value that’s used to set the locale.

    <bean id="localeResolver"
        class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
        <property name="defaultLocale" value="en" />
    </bean>
    
    <bean id="localeChangeInterceptor"
        class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
        <property name="paramName" value="language" />
    </bean>
    
    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
        <property name="interceptors">
           <list>
            <ref bean="localeChangeInterceptor" />
           </list>
        </property>
    </bean>
    
    <!-- Register the bean -->
    <bean class="com.common.controller.WelcomeController" />
    
    <!-- Register the welcome.properties -->
    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="welcome" />
    </bean>
    
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix">
            <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
    

  1. 创建文件(source.txt)

创建名为“source.txt”的文件,其中包含一些中文字符,并以“UTF-8”格式保存。

  1. native2ascii

使用native2ascii命令将其转换为Unicode格式。

C:> native2ascii -encoding utf8 c:\source.txt c:\output.txt

native2ascii将从“c:\source.txt”读取所有字符,并使用“utf8”格式对其进行编码,并将所有编码字符输出到“c:\output.txt”

  1. 读取输出

打开“c:\output.txt”,您将看到所有编码字符,例如\ufeff\u6768\u6728\u91d1

welcome.properties

welcome.springmvc = \u5feb\u4e50\u5b66\u4e60

调用上述字符串并将值存储在数据库中。

如果要在JSP页面中显示:

记住在jsp页面的顶部添加以下行:“<%@ page contentType=”text/html;charset=UTF-8″ %>” ,否则页面可能无法正确显示UTF-8(中文)字符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接