JAVA and JAVA WEB with TOMCAT and ECLIPSE 学习过程中遇到的字符乱码问题及解决方法汇总(随时补充)
JAVA语言具有跨平台,unicode字符集编码的特点。
但是在开发过程中处理数据时涉及到的字符编码问题零零散散,尤其是处理中文字符时一不留神就可能出现一堆奇奇怪怪的符号,俗称乱码。
对于乱码,究其原因,就是因为编码和解码过程中使用了错误的字符编码方案导致的。
首先在开头说明本人对 编码 解码 这两个概念的理解(如有错误烦请dalao指出,如有疑问也欢迎交流!):
首先,有一个字符串:
String str="hello,编码";
使用String类的方法getBytes(String charset);指定一个字符编码方案由字符串str其ByteArray形式,称之为为编码过程:
byte[] b_str = str.getBytes("utf-8");
使用String类重载的构造方法之一String(byte[] b,String charset);指定一个字符编码方案从一个ByteArray生成一个字符串,称之为解码过程:
String str_b = new String(b_str, "utf-8");
类似的,在某些在字节流与字符流之间进行转换工作的类及方法也都如此理解,即:
字符→字节:编码
字节→字符:解码
对于java源文件编码的说明:
在编写java源文件时,可能使用了各种编码,只要在编译时通过编译参数指定使用的编码方案即可
-encoding 字符集
无论是.java还是.jsp,涉及java源码的地方,都需要告知编译器使用哪种字符编码方案来处理该源码。
(JSP中:pageEncoding="UTF-8" 的作用是设置JSP编译成Servlet时使用的编码。)
现在这一工作大多已经由各种集成开发环境代为完成了,但我们仍需对其有一定了解以备不时之需。
对于java程序中的编码:
在一个java程序中,涉及到编码问题地方集中在文件读写,各种输入输出流的使用上,本小节着重分析java程序运行时的编码问题。
在对存储内容为字符的文件进行读写的时候,多数情况下是使用了包装类对文件输入输出流进行了包装。
这些字符读写包装类表面上没有涉及编码问题,实际上包装类产生的字符流在调用底层字节流的时候也是需要将数据在字符-字节间进行相应转换的,只不过默认情况下其采用了平台默认字符编码方案来完成编码-解码过程。
当我们有特殊需要的时候,可以主动控制这一过程,让包装类使用我们指定的字符编码方案进行字符-字节的转换。
此处以,字符流(输出字符的包装类PrintWriter,缓冲读取字符的包装类BufferedReader),底层流(文件IO流)为例:
我们利用在包装类使用Writer或Reader作为参数的构造方法,使用InputStreamReader和OutputStreamWriter两个中间类来指定字符-字节转换使用的字符编码方案
try {
File f = new File("d:\\coding.txt");
FileOutputStream fos = new FileOutputStream(f);
FileInputStream fis = new FileInputStream(f);
PrintWriter pw = new PrintWriter(new OutputStreamWriter(fos, "utf-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(fis, "utf-8"));
} catch (Exception e) {
e.printStackTrace();
}
通过上述代码,我们就实现了使用包装类且使用我们指定的字符编码方案更便捷的进行字符操作。
对于其他的包装的方法与此相同的以字节为基础的流,此处不再赘述。
有一点值得注意:不同的字符编码方案在错误的解码之后可能会丢失字节。
例如奇数个中文字符以UTF-8编码后以GBK解码再编码后再以UTF-8解码导致部分乱码:
try {
String str = "哈哈哈";
byte[] encode_by_utf8 = str.getBytes("utf-8");
String decode_by_gbk = new String(encode_by_utf8, "gbk");
byte[] encode_by_gbk = decode_by_gbk.getBytes("gbk");
String decode_by_utf8 = new String(encode_by_gbk, "utf-8");
System.out.println(decode_by_utf8); //Output:哈哈??
} catch (Exception e) {
e.printStackTrace();
}
简述其根本原因:两种编码方案对单个中文字符编码时使用的字节数不同导致中间过程中丢失了字节,虽然总体上编码还原了但是边界丢失的字节导致了乱码。
更详细的分析见此文章:http://blog.csdn.net/beyondlpf/article/details/7519786
java程序中有关编码的基础内容到此结束。下面将汇总在java web开发过程中多个软件协同工作时的编码问题。
不想看分析的请看这个简单粗暴的解决办法:http://blog.csdn.net/cfpl12011124/article/details/53488931
1:html页面设置编码 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
2:web.xml中设置编码
<mime-mapping> <extension>htm</extension> <mime-type>text/html;charset=UTF-8</mime-type> </mime-mapping> <mime-mapping> <extension>html</extension> <mime-type>text/html;charset=UTF-8</mime-type> </mime-mapping>
3:Tomcat server.xml中设置编码
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
4:如果是IDE启动,设置启动参数 Debug configurations->tomat 8.0->argument
-Dfile.encoding=UTF8
如果是Tomcat服务形式启动,设置catalina.bat
set "JAVA_OPTS=%JAVA_OPTS% %JSSE_OPTS%" -Dfile.encoding=UTF8
5:将文件用记事本或者EditPlus打开,另存为UTF-8格式
以上5种基本可以告别tomcat中文乱码问题.
本人使用的开发环境:
JDK1.8.0_151
外部jar包直接引用Tomcat/lib下的servlet-api.jar
软件工具:
Eclipse Oxygen EE :用于编写.java源文件,编码格式为默认的GBK
Visual Studio Code :用于编写各种前端代码,编码格式均为UTF-8
Tomcat(8.5.24) :通过Eclipse默认配置调用运行。
首先分析一个http请求的正常流程
Tomcat收到http请求后,将相关数据封装成request对象和response对象,通过调用链的形式开始处理请求
调用链的调用从过滤器加载顺序的第一个过滤器开始调用
执行doFilter开始到调用调用链(chain.doFilter(request, response);)处的前半段处理并通过调用调用链(chain.doFilter(request, response);)将request和response传递下去
直到到达目标资源(Servlet或JSP或其他被过滤器过滤的资源),即调用链的终点
再依次折返回到调用调用链(chain.doFilter(request, response);)处执行此处到doFilter方法结束的后半段处理
特别说明:
每个过滤器的doFilter方法可以根据逻辑选择不调用调用链(chain.doFilter(request, response);),使自己成为调用链的终点,同时通过response对象做出应有的响应。
何时调用 request对象和response对象的setCharacterEncoding()方法?
对于request对象,该方法是设置用何种字符编码方案从request对象中解码获得字符数据
该方法必须在获取请求参数(getParameterNames,getParameter,getParameterValues等)和获得字符输入流(getReader)之前使用。
so:尽可能早的调用,通常在第一个过滤器中就调用此方法指定请求数据的解码方式。
附API原文:
setCharacterEncoding
public void setCharacterEncoding(java.lang.String env)
throws java.io.UnsupportedEncodingException
- Overrides the name of the character encoding used in the body of this request. This method must be called prior to reading request parameters or reading input using getReader().
- Parameters:
env
- aString
containing the name of the character encoding.- Throws:
java.io.UnsupportedEncodingException
- if this is not a valid encoding
这项设置对POST方式的请求有效
POST方式提交的数据一般是浏览器根据提交页面的Content-Type中charset指定的字符编码方案来编码,并将编码后的数据放在http请求头中发送。
容器中的应用在提取数据时指定以与页面指定相同的字符编码方案解码http请求头中的数据即可。
这项设置在默认情况下对GET方式的请求无效
GET方式是通过URL传递数据的,浏览器使用哪种字符编码方案编码则具有不确定性,将编码后的数据放在URL后作为URL的一部分提交。
对附加在URL后的数据,若为在容器中特殊配置,往往是由容器使用默认URI编码方案直接解码。可以通过修改配置文件Tomcat/conf/server.xml中的<Connector ...>标签来指定默认URI编码方案(设置属性URIEncoding='UTF-8')。
特别说明:要求容器直接使用request的解码方式(设置属性useBodyEncodingForURI='true'),不再是默认情况,即:容器用setCharacterEncoding的设置决定如何解码。
因为:
在不同的字符编码方案中
英文字符的编码方式较为一致,所以即使使用了错误的字符编码方案解码也基本不会导致英文字符乱码,容错性高。
中文字符的编码方式基本不同,所以这种方式很容易导致中文乱码,容错性低。
所以:
实际应用中若需要通过GET方式传递中文数据,往往在提交前将其处理(使用encodeURI编码得到带%的英文字符串,再对该字符串encodeURI编码),容器任意自动解码一次得到带%的英文字符串,再次对该字符串URLDecoder.decode解码得到原始数据。
该方法利用了英文字符在不同编码方案间错误解码时的高容错特性。
更详细的说明见此文章:https://www.cnblogs.com/shazhou-blog/p/6150199.html
对于response对象,该方法是设置用何种字符编码方案编码要发送的响应数据
该方法必须在之前提交响应和获得字符输出流(getWriter)之前使用。
该方法可以多次调用,以最后一次有效调用为准。
该方法的设置会覆盖setContcentType(String)或setLocal()中的charset
setContentType("text/html") 且 setCharacterEncoding("utf-8") 和 setContentType("text/html;charset=utf-8") 是等价的。
so:尽可能早的调用,通常在第一个过滤器中就调用此方法设置响应数据的编码方式。
(优先使用的响应编码方式:setCharacterEncoding > contentType > pageEncoding)
附API原文:
setCharacterEncoding
public void setCharacterEncoding(java.lang.String charset)
- Sets the character encoding (MIME charset) of the response being sent to the client, for example, to UTF-8. If the character encoding has already been set by
setContentType(java.lang.String)
orsetLocale(java.util.Locale)
, this method overrides it. CallingsetContentType(java.lang.String)
with theString
oftext/html
and calling this method with theString
ofUTF-8
is equivalent with callingsetContentType
with theString
oftext/html; charset=UTF-8
.This method can be called repeatedly to change the character encoding. This method has no effect if it is called after
getWriter
has been called or after the response has been committed.Containers must communicate the character encoding used for the servlet response's writer to the client if the protocol provides a way for doing so. In the case of HTTP, the character encoding is communicated as part of the
Content-Type
header for text media types. Note that the character encoding cannot be communicated via HTTP headers if the servlet does not specify a content type; however, it is still used to encode text written via the servlet response's writer.
- Parameters:
charset
- a String specifying only the character set defined by IANA Character Sets (http://www.iana.org/assignments/character-sets)- Since:
- 2.4
- See Also:
#setLocale
关于Tomcat处理请求的方式:
上文已经说明了Tomcat收到请求时的处理流程,每一个请求的调用链终点即为该请求的目标资源。
对于不同类型的资源,Tomcat最终都是交由Servlet处理的,总共分三种:
1.Servlet:交由web.xml文件中映射的类来处理(Tomcat 7以前的版本交由一个叫做 InvokerServlet的类来处理)
2.JSP:将JSP编译为Servlet在交由其处理
3.静态资源(html,css,js,jpg,png等):交由一个叫做DefaultServlet的类来处理
对于前两种调用,只要正确的处理了java源文件编码和java程序中数据的编码解码就不会出现问题。
而第三种则是调用了Tomcat的默认Servlet进行处理,关于该类的详细分析见此文章:http://blog.csdn.net/husan_3/article/details/23792517
简单来说,这个类负责读取请求的各种静态资源并完成响应。
DefaultServlet在读取内容为字符类的文件时,默认情况下该类会用平台默认编码来解码得到字符串,然后将其写入response.getWriter()方法获取到的字符流中。
对于UTF-8编码的文本类文件,在这一步被错误的解码后,即使再次编码再用正确的字符集解码,也有可能出现文章中提到的字节丢失导致的部分乱码。
根据官方帮助文档的描述,我们可以在Tomcat/conf/web.xml中找到这个类的映射并可以为其设置初始化参数fileEncoding及其值UTF-8,使该类用指定的字符编码方案来解码文本类静态资源文件。
原文地址:http://tomcat.apache.org/tomcat-8.5-doc/default-servlet.html
Where is it declared?
It is declared globally in $CATALINA_BASE/conf/web.xml. By default here is it's declaration:
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>
org.apache.catalina.servlets.DefaultServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> ... <servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>So by default, the default servlet is loaded at webapp startup and directory listings are disabled and debugging is turned off.
What can I change?
The DefaultServlet allows the following initParamters:
Property Description ...... ...... fileEncoding File encoding to be used when reading static resources. [platform default] ...... ......
通过添加初始化参数来指定读取静态资源中文本类文件即可避免在这一环节出现问题导致乱码。
Eclipse与Tomcat:
当在Eclipse中调用Tomcat时需要格外注意,Eclipse默认勾选了自动发布的选项,即Eclipse只认得在它里面部署的项目,因此它会在项目使用的服务器项目下重新生成的web.xml等配置文件替代Tomcat/conf下配置过的文件来启动服务器。
对于这个问题有两种解决办法:
原文地址:https://www.cnblogs.com/ystq/p/6007183.html
当我们在处理中文乱码或是配置数据源时,我们要修改Tomcat下的server.xml和content.xml文件。
但是当我们修改完后重启Tomcat服务器时发现xml文件又被还原了,修改无效果。
为什么会还原?
Tomcat服务器在Eclipse中启动时,会自动发布Eclipse中部署的项目,但是我的项目是自己手动在外面部署的,Eclipse只认得在它里面部署的项目,因此它会创建一个新的server.xml文件覆盖原来的文件,里面只有Eclipse中部署的项目。
解决方法一:
设置Ecplise,取消掉自动发布功能。
依次选择 Window-Preferences-Server-Launching,取消Automatically publish wen starting servers,点击OK,搞定
解决方法二:
Ecplise项目中有一个Server项目,有一个Tomcat v7.0 Server at localhost-config,
跳过这个坑基本就没问题了。
ing
JAVA and JAVA WEB with TOMCAT and ECLIPSE 学习过程中遇到的字符乱码问题及解决方法汇总(随时补充)的更多相关文章
- Java web应用中的常见字符编码问题的解决方法
以下是 Java Web应用的常见编码问题 1. html页面的编码 在web应用中,通常浏览器会根据http header: Content-type的值来决定用什么encoding, 比如遇到Co ...
- [转载]Java web应用中的常见字符编码问题的解决方法
以下是 Java web应用的常见编码问题 1. html页面的编码 在web应用中,通常浏览器会根据http header: Content-type的值来决定用什么encoding, 比如遇到Co ...
- Tomcat 在win7/win8 系统下tomcat-users.xml.new(拒绝访问)解决方法
tomcat启动报错No UserDatabase component found under key UserDatabase 也可以这样处理 Tomcat 在win7/win8 系统下tomcat ...
- eclipse中找不到base64包的解决方法
eclipse中找不到base64包的解决方法 2017年08月26日 11:05:26 yzp_leo 阅读数:634 标签: javaeclipsebase64更多 个人分类: 日记 ecli ...
- java.lang.IllegalStateException:Web app root system property already set to different value 错误原因及解决 Log4j
Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口 服务器.NT的事件记录器.UNIX Syslog守护进程等: ...
- 错误/异常:java.io.FileNotFoundException: .\src\db.properties (系统找不到指定的路径。);的解决方法
1.异常视图 2.解决方法 与之相关的部分代码: static{ try { //读取db.properties Properties props = new Properties(); FileIn ...
- Java读带有BOM的UTF-8文件乱码原因及解决方法
原因: 关于utf-8编码的txt文件,windows以记事本方式保存时会在第一行最开始处自动加入bom格式的相关信息,大概三个字节! 所以java在读取此类文件时第一行时会多出三个不相关的字节,这样 ...
- maven编译java代码报“非法字符: \65279 ”错误的解决方法
前段时间开发一个项目,使用maven进行编译时报“非法字符: \65279 ”,但是眼睛看怎么都正确的,文件转成utf-8编码还是报错. 最后没办法,暴力解决了这个问,步骤如下 1.把文件内容复制出来 ...
- Java读properties文件中文乱码问题的解决方法
java读properties文件,包含中文字符的主要有两种: 1.key中包含中文字符的(value中也有可能包含) 2.key中不包含中文字符的(value中有可能包含) 1.key中包含中文字符 ...
随机推荐
- bzoj4513 储能表
求 $\sum\limits_{i=0}^{n-1} \sum\limits_{j=0}^{m-1} max((x \space xor \space j) - k,0)$ ,膜 $p$ $n,m \ ...
- python if语句,while语句
一,if语句: python中最常用的判断语句,基本格式: 1.if else格式 if 条件: 结果 else: 结果 """ if 条件: 满足条件执行代码 els ...
- bootstrap排版实战
bootstrap+angular实战 CASE-01:页面总体排版 说明:页面排版整体分为三个部分(见产品图):上导航条(红色区域).左导航条(紫色区域).内容区域(蓝色区域).左导航条的区域是由整 ...
- Java编程思想第七章复用类
7.1组合语法 在一个类中引入多个对象,以提高代码的复用性与功能. 7.2继承语法 使用继承子类可以获得,导出类可以获得基类的成员(变量与方法). 注:这里注意权限控制,若基类中的成员为默认权限,只有 ...
- ArcGis教程
91卫图助手帮助中心-如何导出ArcGIS Server瓦片格式并进行发布 http://help.91weitu.com/rhdcarcgis%20serverwpgsbjxfb.html ArcG ...
- ThreadPoolTaskExecutor异常收集
ThreadPoolTaskExecutor ipFinderThreads = new ThreadPoolTaskExecutor(); ipFinderThreads.setCorePoolSi ...
- Oracle 文件
参数文件 跟踪文件 告警文件 数据文件 临时文件 控制文件 重做日志文件 密码文件 闪回日志 dum文件 数据泵文件 1参数文件 Parameter file:告诉oracle实例在那里可以找到控制文 ...
- Java学习之ZooKeeper瑞士军刀简介
1.简介 ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现.分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅.负载均衡.命名服务 ...
- C语言在32位和64位机器下数字数据类型的字节数取决于编译器和平台, 主要由编译器决定。
C语言中数字数据类型的字节数 C声明 32位机器 64位机器 char 1 1 short int 2 2 int 4 4 //整型在32位和64位下都是4个字节 long int 4 8 l ...
- 2016.2.13 (年初六) oracle两张表update方法
A表customers和B表tmp_cust_city有3个相同字段, customer_id,city_name,customer_type 现要根据b表更新a表 更新一个字段情况: update ...