首页 > 解决方案 > 在 Tomcat 的 servlet 上编码俄语和中文文本的问题

问题描述

再会。

我有一个 Tomcat 的 jsp/servlet 应用程序,它可以在 mysql 上保存在多语言页面上插入的文本。文本插入到 jsp 页面中的文本区域中。为了保存它们,我调用了一个读取请求发布参数并将其复制到数据库中的 java servlet。Tomcat 版本是 7.0.63。当我在 servlet 中读取用俄语和中文编写的请求参数时,会出现问号。我用 system out println 和具有相同字符的 mysql 表读取它们。jsp 页面使用 UT-8 编码(@page pageEncoding 和 meta http-equiv="Content-Type"),servlet 请求(setCharacterEncoding)也使用 UTF-8 编码。server.xml 中的 Tomcat 连接器以 UTF-8 编码 (URIEncoding)。我在 Apache HTTP Server AddDefaultCharset UTF-8 上添加了 httpd.conf。

我该如何解决这个问题?

最好的问候和良好的工作。

斯特凡诺·埃拉尼

标签: tomcatservletshtml-encode

解决方案


Tomcat 7 实现了规范 Servlet (3.0) 和 JSP (2.2)。在这些规范中,有些地方与编码相关,并且定义的默认编码是 ISO-8859-1。

如果您希望最终用户能够在您的 web 应用程序中输入 UTF-8 文本,并正确接收它以将其存储在数据库中,您必须采取一些步骤。

所在的html页面<form>必须用UTF-8编码

如果页面是由 Servlet 生成的,在调用之前getWriter必须调用 response.setContentType("text/html; charset=UTF-8"); 或者只是: response.setCharacterEncoding("UTF-8");

正如此处的 Servlet 规范所述:

如果 Servlet 在调用 ServletResponse 接口的 getWriter 方法或提交响应之前没有指定字符编码,则使用默认的 ISO-8859-1。

您可以阅读规范的第 5.4 节以获取更多信息。例如,您可以根据语言环境设置一个 econding。

如果 html 是由 JSP 页面生成的,则响应字符编码的规则在 JSP 规范的 4.2 节中确定:

初始响应字符编码设置为 page 指令的 contentType 属性的 CHARSET 值。如果页面不提供该属性或者该属性没有CHARSET值,则初始响应字符编码确定如下:

• 对于 XML 语法的文档,它是 UTF-8。

• 对于标准语法的JSP 页面,它是由BOM、页面指令的pageEncoding 属性或URL 模式与页面匹配的JSP 配置元素page-encoding 指定的字符编码。仅使用为请求页面指定的字符编码;不考虑通过 include 指令包含的文件的编码。如果没有这样的规范,则不会将初始响应字符编码传递给 ServletResponse.setContentType() - 使用 ServletResponse 对象的默认值 ISO-8859-1。

所以,你可以设置它包括 <%@ page contentType="text/html; charset=UTF-8" %>

在生成表单的 JSP 页面上。请注意,如果在您的 JSP 页面中逐字文本上有 UTF-8 编码字符,则 pageEncoding 也是必需的。

为您的 Web 应用程序中的所有页面设置通用属性的一种便捷方法是使用 jsp-property-group,包括您身上的此配置web.xml

<jsp-config>
    <jsp-property-group>
        <description>Apply to all JSPs</description>
        <url-pattern>*.jsp</url-pattern>
        <page-encoding>UTF-8</page-encoding>
        <default-content-type>text/html; charset=UTF-8</default-content-type>
    </jsp-property-group>
</jsp-config>

提交的请求必须以 UTF-8 格式读取

在第 3.10 节中,servlet 规范指出:

目前,许多浏览器不发送带有 Content-Type 标头的字符编码限定符,从而为读取 HTTP 请求而确定字符编码。如果客户端请求没有指定,容器用于创建请求读取器和解析 POST 数据的请求的默认编码必须是“ISO-8859-1”。但是,为了向开发者表明,在这种情况下,客户端发送字符编码失败,容器从 getCharacterEncoding 方法返回 null。

如果客户端未设置字符编码,并且请求数据使用不同于上述默认编码的编码进行编码,则可能会发生损坏。为了解决这种情况,ServletRequest 接口中添加了一个新方法 setCharacterEncoding(String enc)。开发者可以通过调用该方法覆盖容器提供的字符编码。必须在解析任何发布数据或从请求中读取任何输入之前调用它。读取数据后调用此方法不会影响编码。

因此,您需要request.setCharacterEncoding("UTF-8")在对请求内容进行任何访问之前调用 set 。

如果尚未设置字符编码,最好的方法是实现一个过滤器来设置字符编码:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException {
    if (request.getCharacterEncoding() == null) {
        request.setCharacterEncoding("UTF-8");
    }
    chain.doFilter(request, response);
}

并在 web.xml 的开头声明过滤器(是的,顺序很重要),如下所示:

<filter>
    <filter-name>Character Encoding Filter</filter-name>
    <filter-class>yourpackage.YourCharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>Character Encoding Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

这样,此过滤器首先适用于所有请求,然后是任何其他过滤器,因此我们可以确定请求数据尚未被访问。

您可以更改<url-pattern>元素,以便<servlet-name>将过滤器仅应用于一个 servlet。

请注意,这仅适用于 POST 请求。对于 GET 请求,Tomcat 7 默认使用 ISO-8859-1 来解码 % 编码的 URI 字节。如 Tomcat 7 文档中所述,这可以通过<Connector>在文件的元素上添加 URIEconding 属性来覆盖。https://tomcat.apache.org/tomcat-7.0-doc/config/http.html#Common_Attributesserver.xml

我怎么知道参数被正确读取了?

确保您的 web 应用程序正确读取参数的最佳方法是编写来自 servlet 的响应,以 UTF-8 编码,并查看在您的浏览器上打印的参数。

你可以在你的 servlet 中做这样的事情:

response.setContentType("text/html; charset=UTF-8");

PrintWriter writer = response.getWriter();
writer.println("<html><body>");
writer.println("UTF-8 encoded parameter: " + request.getParameter("yourparam");
writer.println("</body></html>");

您不能依赖打印System.out.println到控制台的文本,因为例如,在 Windows 中,控制台的默认编码是 CP1252,与 ISO-8859-1 几乎相同。

因此,如果您在控制台上打印 CP1252 不支持的 UTF-8 字符,您将在控制台上看到乱码或问号。(要更改 Windows 上控制台的编码,请参见例如:https ://superuser.com/questions/269818/change-default-code-page-of-windows-console-to-utf-8 )

Webapp 读取和写入 UTF-8 文本,但未存储在数据库中

如果上述所有方法都有效,但您仍然无法在数据库中存储 UTF-8,则一定是您的数据库配置有问题。

默认情况下,Mysql 8.0 似乎在 UTF-8 下工作,但之前的版本 5.7 默认情况下与 Latin1 (= ISO-8859-1) 一起工作,需要采取特殊步骤才能与 UTF-8 一起工作。见:https ://dev.mysql.com/doc/refman/5.7/en/charset-applications.html

此外,请务必使用与您的数据库版本兼容的最新可用 JDBC 驱动程序。


推荐阅读