【问题标题】:UTF-8 not working in Java Application running in Tomcat serverUTF-8 在 Tomcat 服务器中运行的 Java 应用程序中不起作用
【发布时间】:2021-12-27 07:28:30
【问题描述】:

我正在开发一个 Java 应用程序。我需要在我的 Java webapp 中获得 UTF-8 编码以支持孟加拉语 (বাংলা) 文本。我做了以下事情:

Tomcat 的 server.xml

<Connector port="8080"
    protocol="HTTP/1.1"
    connectionTimeout="20000"
    redirectPort="8443"
    URIEncoding="UTF-8" />

<Connector executor="tomcatThreadPool"
    port="8080"
    protocol="HTTP/1.1"
    connectionTimeout="20000"
    redirectPort="8443"
    URIEncoding="UTF-8" />

<Connector protocol="AJP/1.3"
    address="::1"
    port="8009"
    redirectPort="8443"
    URIEncoding="UTF-8" />

catalina.bat 文件中的 JVM defaultCharset

set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8

application.properties 中的属性

spring.datasource.url=jdbc:mysql://localhost:3306/database_name?useUnicode=true\&characterEncoding=UTF-8
spring.datasource.tomcat.connection-properties=useUnicode=true;characterEncoding=UTF-8

spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true

server.tomcat.uri-encoding=UTF-8
spring.webflux.multipart.headers-charset=UTF-8
spring.thymeleaf.encoding=UTF-8

html 文件中的元标记

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
    <head>
        <meta charset="utf-8">
    </head>

    <body>
    </body>
</html>

表单标签支持utf-8

<form enctype="multipart/form-data" accept-charset="UTF-8" action="#" th:action="@{/create}" th:object="${object}" th:method="POST">
    <div class="form-group">
        <label for="name" class="col-form-label">Name</label>
        <input type="text" class="form-control" id="name" name="name" th:field="*{name}" placeholder="Enter Name">
    </div>
<div class="form-group">
    <label for="photo">Photo</label>
    <input type="file" class="form-control-file" id="photo" name="photo"/>
</div>
    <div>
        <button class="btn" type="submit">Submit</button>
    </div>
</form>

MySQL 配置 (my.ini)

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

MySQL 属性:

Database:
Default collation: utf8mb4_0900_ai_ci
Default charactterset: utf8mb4

Table:
Table collation: utf8mb4_0900_ai_ci

Column:
Type: varchar(255)
Character Set: utf8mb4
Collation: utf8mb4_0900_ai_ci

配置:

  • Java 11.0.2
  • Tomcat 8.5
  • MySQL 8.0.16
  • Spring Boot 2.2.4
  • Maven 3.8.1
  • Windows Server 2019 标准版(生产版)+ Windows 10 家庭版(开发版)

当我提交一个值为আনোয়ার的表单时,它被保存为আনোয়ার

我该如何解决这个问题?

当我从 Eclipse 运行应用程序时,它工作正常。但是当war文件部署在Tomcat服务器中时,它就不起作用了。

我尝试了以下代码。它在 tomcat8-stdout 文件中打印আনোয়ার。所以我认为在将数据从浏览器传输到服务器、从服务器传输到数据库时会出现问题。

@PostMapping("/create")
public String create(@ModelAttribute("object") Object object, @RequestParam("photo") MultipartFile photo) throws IOException {
    System.out.println(object.getName());
    return "redirect:/index";
}

【问题讨论】:

  • 从 HTML 表单中移除 accept-charset 属性。它不是你想的那样(没有人会)。
  • 如果你在名字之外打印object.getName().length(),你会得到什么?

标签: java spring-boot tomcat encoding utf-8


【解决方案1】:

在使用 Spring 时,可以尝试使用 CharacterEncondingFilter 强制执行 UTF-8 编码。

您可以找到多个有关如何执行此操作的示例。例如考虑thisthis other

基本上,您需要在 Java 配置中的某处注册过滤器。举一个指定的例子:

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public FilterRegistrationBean<CharacterEncodingFilter> characterEncodingFilterRegistration() {
  CharacterEncodingFilter filter = new CharacterEncodingFilter();
  filter.setEncoding("UTF-8"); // use your preferred encoding
  filter.setForceEncoding(true); // force the encoding

  FilterRegistrationBean<CharacterEncodingFilter> registrationBean =
    new FilterRegistrationBean<>(filter); // register the filter
  registrationBean.addUrlPatterns("/*"); // set preferred url
  return registrationBean;
}

其实这个注册过程应该是由Spring BootHttpEncodingAutoConfiguration自动完成的。请注意以下要求:

@Configuration(proxyBeanMethods=false)
@EnableConfigurationProperties(value=ServerProperties.class)
@ConditionalOnWebApplication(type=SERVLET)
@ConditionalOnClass(value=org.springframework.web.filter.CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix="server.servlet.encoding",
                       value="enabled",
                       matchIfMissing=true)

如您所见,过滤器的注册与带有server.servlet.encoding 前缀的属性有关。

因此,作为替代方案,要正确配置字符集过滤器,您可以尝试的另一件事是使用 server.servlet.encoding.* 相关属性配置您的应用程序:

server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true

您当前在application.properties 配置中使用的是old version of that properties, based on the spring.http.encoding prefix,而不是application.properties

问题可能与 multipart 请求的处理有关。虽然建议使用 Spring Boot 和底层容器公开的默认机制,但您可以尝试的一件事是使用commons-multipart 处理文件上传,并将库配置为处理标题和表单字段为UTF-8 .该过程可以实现如下。

首先,如果使用 Maven,则在 pom.xml 中包含 commons-fileupload 依赖项,如果使用 Gradle,则等效地包含:

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

然后,在您的 Java 配置中的任何位置,包括以下 bean:

@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    // Note how we set the encoding
    multipartResolver.setDefaultEncoding("UTF-8");
    return multipartResolver;
}

如您所见,我们正在将default encoding property 配置为适当的值:

设置用于解析请求的默认字符编码,以 应用于各个部分的标题和表单字段。 根据 Servlet 规范,默认值为 ISO-8859-1

CommonsMultipartResolver 提供了不同的方法,您可以根据需要自定义上传行为。

除了这些提示以及@Olivier 在他的回答中的建议,乍一看,您似乎正确配置了所有内容。无论如何,请考虑阅读 this related SO question,尽管对于 PHP,它可以提供有价值的信息。

至于您的 cmets,您的服务器和数据库之间的信息似乎正确传输,请尝试调试您的 HTML 页面和服务器之间的通信。

一个有价值的工具可能是浏览器检查器网络选项卡:查看从您的页面提交到您的服务器的内容,几乎可以肯定任何浏览器都会为您提供“按原样”交换的实际信息,在它的实际编码中已发送。

另一个用于相同目的的有价值的工具可能是网络流量分析器,如 Wireshark 或 Fiddler。

除非您有能力远程调试您的代码并查看变量值,否则请不要依赖System.out 提供的输出:当您在文件中查看时,有很多因素到位,它几乎肯定会给你一个错误的信息。

在寻找有关此问题的信息时,我遇到了这个excellent article。特别是,它提供了一个分析构成String的不同代码点的示例:这种分析可以提供有价值的信息,而不是直接将信息输出到System.out

【讨论】:

  • 我已经更改了我的属性。它没有用。我是否需要同时注册过滤器和更改应用程序属性?
  • 我想我在尝试所有的教程/示例时弄得一团糟。您能否给我一个链接,其中按顺序记录了所有最少的必要步骤?这样我就可以从头开始并按照链接进行操作。
  • 感谢您的反馈@Partho63。好吧,事实上,我认为您已经正确配置了所有内容。我将尝试找到任何有用的附加链接或以任何方式澄清答案中的过程。无论如何,我根据CommonsMultipartResolver 的配置使用可能的替代方法更新了答案。拜托,你能试试建议的改变吗?我希望它有所帮助。
  • @Partho63 你能尝试CommonsMultipartResolver 建议的方法吗?我用更多提示更新了答案,尽管正如我之前在之前的 cmets 中告诉你的那样,你的设置对我来说看起来不错。我希望任何建议的信息可以帮助您解决问题。
  • 我没试过CommonsMultipartResolver。相反,我提交了另一个没有任何图像/文件输入的简单表单。该表单的行为方式相同(不支持 utf-8)。所以我认为这个问题与 MultipartResolver 无关。
【解决方案2】:

POST 参数的编码不是设置在Connector 级别,而是设置在ServletRequest 对象上。

Tomcat 提供了一个过滤器来设置它,如documentation 中所述。

将此添加到您的 web.xml 文件中:

<filter>
  <filter-name>setCharacterEncodingFilter</filter-name>
  <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
  <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>setCharacterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

【讨论】:

  • 我的项目中没有任何 web.xml 文件。我应该把它放在tomcat的web.xml文件中吗?
  • @Partho63 是的,可以将过滤器添加到服务器 web.xml。
  • 另一件事。我还需要在我的项目中添加任何过滤器类吗?或者只是添加这个过滤器就可以了?
  • @Partho63 只需在 web.xml 中添加过滤器就足够了。确保重新启动 Tomcat。
  • 没用。 ☹ 这个过滤器和过滤器映射已经存在于 web.xml 文件中。但被注释掉了。我取消了过滤器和过滤器映射的注释,然后重新启动了tomcat。但没有运气。
【解决方案3】:

您是否尝试在 server.xml 中为 tomcat 设置以下内容以允许 URL 中的转义字符

<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" relaxedPathChars="[]|" relaxedQueryChars="&#x5B;&#x5D;&#x7C;&#x7B;&#x7D;&#x5E;&#x5C;&#x60;&#x22;&#x3C;&#x3E;" redirectPort="8443" />

【讨论】:

  • 问题不在 URL 而在 POST 参数中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-26
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 2012-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多