JavaWeb(Servlet, SpringMVC, SSM)中文乱码问题总结
参考:https://blog.csdn.net/qq_53037676/article/details/125907391
0. 太长不看版
0.1 Servlet
-
Post请求中文乱码解决
- 方式1:
//也可以使用 request.setCharacterEncoding("utf-8"); String username = request.getParameter("username");
- 方式2:
String username = request.getParameter("username"); username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
-
Get请求中文乱码解决
- 解决方式
String username = request.getParameter("username"); username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
0.2 SSM
-
前端数据传后端乱码
- web.xml中配置字符集过滤器
<!--加入过滤器--> <filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
后端数据传前端乱码
- 注解@RequestMapping中的Produces属性指定返回返回值的字符编码。
@RequestMapping(value = "/demo02", produces = "text/html;charset=utf8")
1.解决servlet中post请求和get请求中文乱码现象
1.1 解决post请求中文乱码问题
1.1.1 为什么post请求会产生中文乱码问题?
我们要知道为啥会产生异常?
- post请求(数据在请求体中)参数是通过Request的getReader()来获取流中的数据。
- TOMCAT在获取流中的数据时采用的编码方式是IOS-8859-1
- 而IOS-8859-1并不支持中文,所以产生乱码显现。
1.1.2 解决方法
解决方式:
- 页面设置的编码方式为utf-8
- 把tomcat在获取数据流之前将数据的编码改为utf-8
- 通过request.setCharacterEncoding(“UTF-8”)设置编码,utf-8小写也可以。
1.1.3 代码示例
- 新建一个javaWeb项目
添加模块demo01:
![image-20220728145010552](https://i-blog.csdnimg.cn/blog_migrate/6522479e7e992b5cfed4c04688dd2211.png)
添加web应用程序:
![image-20220728145104766](https://i-blog.csdnimg.cn/blog_migrate/e8b9d9d786ffab3043ec4b0474da61bf.png)
![image-20220728145122060](https://i-blog.csdnimg.cn/blog_migrate/0f06fe67f7e19df8e5e85f7e97e32a3d.png)
- 添加servlet库
添加Jar
![image-20220728145334035](https://i-blog.csdnimg.cn/blog_migrate/023551291377f928ecfbf3595874a467.png)
在tomcat下lib文件夹中,选择servlet-api.jar 和 jsp-api
![image-20220728145458491](https://sttypora.oss-cn-beijing.aliyuncs.com/img/image-20220728145458491.png
![image-20220728150029458](https://i-blog.csdnimg.cn/blog_migrate/d1a30d27ca502e2316fcc165e46d8f24.png)
![image-20220728150047885](https://i-blog.csdnimg.cn/blog_migrate/a8d9e0fe88b3e64d2e6fd50fdb67765a.png)
- 开启注解支持
点击web–>WEB-INF–>web.xml
metadata-complete="false"
表示开启注解
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
metadata-complete="false"
version="4.0">
</web-app>
- 编写MyServlet
package com.st.Servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/demo01")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 解决乱码: POST getReader()
//设置字符输入流的编码,设置的字符集要和页面保持一致
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
- 部署到tomcat测试
![image-20220728150400173](https://i-blog.csdnimg.cn/blog_migrate/8653315064bb9dcc969134538841b119.png)
![image-20220728150425176](https://i-blog.csdnimg.cn/blog_migrate/6d19651617bda0b9df992df28f0aab1d.png)
应用上下文改为/demo
![image-20220728150452574](https://i-blog.csdnimg.cn/blog_migrate/1252224d804ab097de249a5c048b0e7e.png)
启动tomcat,打开postman进行测试
在控制台可以看见中文输出正常
1.2解决post请求中文乱码问题
1.2.1 为什么get请求会产生中文乱码问题?
这里我们要想为何post请求的中文乱码解决不适用于get请求?
- get请求获取请求参数的方式是request.getQueryString();
- post请求获取请求获取请求参数的方式是request.getReader();
- request.setCharacterEncoding(“utf-8”)是设置request处理流的编码
- getQueryString方法并没有通过流的方式获取数据
所以get请求不能用设置编码的方式来解决中文乱码问题,那我们就要思考如何来解决get请求中文乱码问题?
- 首先我们需要先分析下get请求出现乱码的原因:
- 浏览器通过HTTP协议发送请求和数据给后台服务器(Tomcat)
- 浏览器在发送HTTP的过程中会对中文数据进行URL编码
- 在进行URL编码的时候会采用页面标签指定的UTF-8的方式进行编码,比如张三编码后的结果为%E5%BC%A0%E4%B8%89
- 后台服务器(tomcat)接收到%E5%BC%A0%E4%B8%89后会默认按照ISO-8859-1进行URL解码
- 由于前后编码与解码采用不一致,就会导致后台取到的数据乱码
思考:如果把前端页面的标签的charset属性修改为ISO-8859-1进行URL编码,后台不做操作,能解决中文乱码吗?
- 答案当然是否定的,因为ISO-8859-1是不支持中文展示的,改了之后会导致页面上的内容无法正常展示
1.2.2 什么是URL编码和解码
这块知识我们只需要了解下即可,具体编码过程分两步,分别是:
(1) 将字符串按照编码方式转为二进制
(2) 每个字节转为2个16进制数并在前边加上%
张三
按照UTF-8的方式转换成二进制的结果为:1110 0101 1011 1100 1010 0000 1110 0100 1011 1000 1000 1001
在Java中已经为我们提供了编码和解码的API工具类可以让我们更快速的进行编码和解码:
- 编码:
java.net.URLEncoder.encode("需要被编码的内容","字符集(UTF-8)");
- 解码:
java.net.URLDecoder.decode("需要被解码的内容","字符集(UTF-8)");
测试一下是否能解码和编码成功:
public class URLDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String username = "张三";
//1. URL编码
String encode = URLEncoder.encode(username, "utf-8");
System.out.println(encode); //打印:%E5%BC%A0%E4%B8%89
//2. URL解码
//String decode = URLDecoder.decode(encode, "utf-8");//打印:张三
String decode = URLDecoder.decode(encode, "ISO-8859-1");//打印:`å¼ ä¸ `
System.out.println(decode);
}
}
1.2.3 乱码原因
根据以上,我们就可以分析出GET请求中文参数出现乱码的原因了:
- 浏览器把中文参数按照
UTF-8
进行URL编码 - Tomcat对获取到的内容进行了
ISO-8859-1
的URL解码 - 在控制台就会出现类上
å¼ ä¸‰
的乱码,最后一位是个空格
1.2.4 解决步骤
根据以上分析,我们只需要在最后使用UTF-8解码获取内容就可以啦,具体的实现步骤为:
-
按照ISO-8859-1编码获取乱码
å¼ ä¸‰
对应的字节数组 -
按照UTF-8编码获取字节数组对应的字符串
示例代码:
public class URLDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String username = "张三";
//1. URL编码
String encode = URLEncoder.encode(username, "utf-8");
System.out.println(encode);
//2. URL解码
String decode = URLDecoder.decode(encode, "ISO-8859-1");
System.out.println(decode); //此处打印的是对应的乱码数据
//3. 转换为字节数据,编码
byte[] bytes = decode.getBytes("ISO-8859-1");
for (byte b : bytes) {
System.out.print(b + " ");
}
//此处打印的是:-27 -68 -96 -28 -72 -119
//4. 将字节数组转为字符串,解码
String s = new String(bytes, "utf-8");
System.out.println(s); //此处打印的是张三
}
}
1.2.5 代码示例
修改MyServlet
代码:
/**
* 中文乱码问题解决方案
*/
@WebServlet("/demo")
public class RequestDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取username
String username = request.getParameter("username");
System.out.println("解决乱码前:"+username);
//2. GET,获取参数的方式:getQueryString
// 乱码原因:tomcat进行URL解码,默认的字符集ISO-8859-1
/* //2.1 先对乱码数据进行编码:转为字节数组
byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1);
//2.2 字节数组解码
username = new String(bytes, StandardCharsets.UTF_8);*/
username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
System.out.println("解决乱码后:"+username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
1.3 注意事项
- 把
request.setCharacterEncoding("UTF-8")
代码注释掉后,会发现GET请求参数乱码解决方案同时也可也把POST请求参数乱码的问题也解决了 - 只不过对于POST请求参数一般都会比较多,采用这种方式解决乱码起来比较麻烦,所以对于POST请求还是建议使用设置编码的方式进行
- Tomcat8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8 ==> 也就是说对于Servlet中文乱码问题,只需设置
request.setCharacterEncoding("UTF-8")
即可
2. SSM(SpringMVC)页面中文乱码问题
2.1 前端中文数据传入后端乱码
2.1.1 乱码问题
项目结构:
![image-20220728175647005](https://i-blog.csdnimg.cn/blog_migrate/96866dd6a7035b33e556381c700a2e20.png)
-
新建一个maven项目,pom文件:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>ssmEncoding</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <spring.version>5.3.20</spring.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2.1-b03</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.20</version> </dependency> </dependencies> </project>
-
添加web应用程序,web.xml代码:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:conf/dispatcherServlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
resources中新建conf文件夹,文件夹下新建dispatcherServlet.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--springmvc的配置--> <context:component-scan base-package="com.st.Controller"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:annotation-driven /> </beans>
-
编写Controller类
package com.st.Controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class Encoding { @RequestMapping(value = "/demo1", method = RequestMethod.POST) public String test(Model model, String name){ System.out.println(name); model.addAttribute("name",name); //获取表单提交的值 model.addAttribute("zw","中文测试"); //获取表单提交的值 return "test"; //跳转到test页面显示输入的值 } }
-
index.jsp代码:
<html> <head> <title>$Title$</title> </head> <body> <form action="demo1" method="post"> <input type="text" name="name"> <input type="submit"> </form> </body> </html>
test.jsp代码:
<html> <head> <title>Title</title> </head> <body> name=${name}; zw=${zw}; </body> </html>
-
输入中文测试,发现乱码
2.1.2 解决方式1:配置SpringMVC提供的过滤器
向web.xml加入字符集过滤器:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--加入过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/dispatcherServlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
加入过滤器后,乱码问题解决:
2.1.3 解决方式2:自定义过滤器
方法1可以解决大部分乱码问题,但有些极端情况下,这个过滤器对get的支持不好。
新建一个Filter:
package com.st.Filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
public class GenericEncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
}
@Override
public void destroy() {
}
}
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
//取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}
//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
web.xml进行配置:
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.st.Filter.GenericEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
中文结果测试
2.2 后端中文数据传入前端乱码
2.2.1 乱码问题
@RequestMapping("/demo2")
public String test1(String username){
String msg = "";
if(username != null){
System.out.println("check a1");
if(username.equals("admin")){
msg = "ok";
}else{
msg = "用户名有误";
}
}
return msg;
}
运行结果:
在SpringMVC中的Controller类中返回了一个中文字符串,在前端HTML页面显示"????
"
2.2.2 解决方法
在SpringMVC中可以通过注解@RequestMapping中的Produces属性指定返回返回值的字符编码。
@RequestMapping(value = "/demo2",produces = "text/html;charset=utf8")
public String test1(String username){
String msg = "";
if(username != null){
System.out.println("check a1");
if(username.equals("admin")){
msg = "ok";
}else{
msg = "用户名有误";
}
}
return msg;
}