UTF-8 在 Tomcat 服务器中运行的 Java 应用程序中不起作用

Par*_*o63 6 java encoding tomcat utf-8 spring-boot

我正在开发一个 Java 应用程序。我需要在 Java Web 应用程序中获取 UTF-8 编码以支持孟加拉语 (\xe0\xa6\xac\xe0\xa6\xbe\xe0\xa6\x82\xe0\xa6\xb2\xe0\xa6\xbe) 文本。我做了以下事情:

\n

Tomcat的server.xml

\n
<Connector port="8080"\n    protocol="HTTP/1.1"\n    connectionTimeout="20000"\n    redirectPort="8443"\n    URIEncoding="UTF-8" />\n\n<Connector executor="tomcatThreadPool"\n    port="8080"\n    protocol="HTTP/1.1"\n    connectionTimeout="20000"\n    redirectPort="8443"\n    URIEncoding="UTF-8" />\n\n<Connector protocol="AJP/1.3"\n    address="::1"\n    port="8009"\n    redirectPort="8443"\n    URIEncoding="UTF-8" />\n
Run Code Online (Sandbox Code Playgroud)\n

catalina.bat 文件中的 JVM defaultCharset

\n
set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8\n
Run Code Online (Sandbox Code Playgroud)\n

application.properties 中的属性

\n
spring.datasource.url=jdbc:mysql://localhost:3306/database_name?useUnicode=true\\&characterEncoding=UTF-8\nspring.datasource.tomcat.connection-properties=useUnicode=true;characterEncoding=UTF-8\n\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\nspring.http.encoding.force=true\n\nserver.tomcat.uri-encoding=UTF-8\nspring.webflux.multipart.headers-charset=UTF-8\nspring.thymeleaf.encoding=UTF-8\n
Run Code Online (Sandbox Code Playgroud)\n

html 文件中的元标记

\n
<!doctype html>\n<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">\n    <head>\n        <meta charset="utf-8">\n    </head>\n\n    <body>\n    </body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n

表单标签支持 utf-8

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

MySQL 配置(my.ini)

\n
[client]\ndefault-character-set = utf8mb4\n\n[mysql]\ndefault-character-set = utf8mb4\n
Run Code Online (Sandbox Code Playgroud)\n

MySQL 属性:

\n
Database:\nDefault collation: utf8mb4_0900_ai_ci\nDefault charactterset: utf8mb4\n\nTable:\nTable collation: utf8mb4_0900_ai_ci\n\nColumn:\nType: varchar(255)\nCharacter Set: utf8mb4\nCollation: utf8mb4_0900_ai_ci\n
Run Code Online (Sandbox Code Playgroud)\n

配置:

\n
    \n
  • Java 11.0.2
  • \n
  • 雄猫8.5
  • \n
  • MySQL 8.0.16
  • \n
  • 春季启动2.2.4
  • \n
  • Maven 3.8.1
  • \n
  • Windows Server 2019 标准版(生产)+ Windows 10 家庭版(开发)
  • \n
\n

当我提交带有 value 的表单时\xe0\xa6\x86\xe0\xa6\xa8\xe0\xa7\x8b\xe0\xa7\x9f\xe0\xa6\xbe\xe0\xa6\xb0,它被保存为\xc3\xa0\xc2\xa6\xe2\x80\xa0\xc3\xa0\xc2\xa6\xc2\xa8\xc3\xa0\xc2\xa7\xe2\x80\xb9\xc3\xa0\xc2\xa7\xc5\xb8\xc3\xa0\xc2\xa6\xc2\xbe\xc3\xa0\xc2\xa6\xc2\xb0

\n

我怎么解决这个问题?

\n

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

\n

我尝试了以下代码。\xc3\xa0\xc2\xa6\xe2\x80\xa0\xc3\xa0\xc2\xa6\xc2\xa8\xc3\xa0\xc2\xa7\xe2\x80\xb9\xc3\xa0\xc2\xa7\xc5\xb8\xc3\xa0\xc2\xa6\xc2\xbe\xc3\xa0\xc2\xa6\xc2\xb0它在 tomcat8-stdout 文件中打印。所以我认为从浏览器到服务器传输数据时出现问题,从服务器到数据库传输数据没问题。

\n
@PostMapping("/create")\npublic String create(@ModelAttribute("object") Object object, @RequestParam("photo") MultipartFile photo) throws IOException {\n    System.out.println(object.getName());\n    return "redirect:/index";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

jcc*_*ero 6

当您使用Spring时,您可以尝试使用CharacterEncondingFilter强制UTF-8编码。

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

基本上,您需要在 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;
}
Run Code Online (Sandbox Code Playgroud)

事实上,这个注册过程应该由 Spring Boot 自动执行HttpEncodingAutoConfiguration。请注意以下要求:

@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)
Run Code Online (Sandbox Code Playgroud)

可以看到,过滤器的注册与带有server.servlet.encoding前缀的属性相关。

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

server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true
Run Code Online (Sandbox Code Playgroud)

您当前在配置中使用的是基于 prefix 的属性spring.http.encoding而不是旧版本的属性application.properties

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

首先,如果使用 Maven,则将commons-fileupload依赖项包含在您的依赖项中;如果使用 Gradle,则将依赖项包含在您的依赖项中:pom.xml

server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true
Run Code Online (Sandbox Code Playgroud)

然后,在 Java 配置中的任意位置包含以下 bean:

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

如您所见,我们将默认编码属性配置为适当的值:

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

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

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

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

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

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

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

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


Oli*_*ier 3

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

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

将其添加到您的 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>
Run Code Online (Sandbox Code Playgroud)