Javaweb - 10.7 乱码和路径问题
目录
乱码问题
HTML 乱码问题
Tomcat 控制台乱码问题
sout 乱码问题
请求乱码问题
GET 请求方式乱码分析
POST请求方式乱码分析
总结
响应乱码问题
路径问题
相对路径与绝对路径
前端路径问题
相对路径问题
相对路径情况 1:
相对路径情况 2:
相对路径情况 3:
绝对路径问题
绝对路径情况 1:
绝对路径情况 2:
绝对路径情况 3:
总结:
base 标签
缺省项目上下文路径
后端路径问题
重定向中的路径问题
相对路径写法
绝对路径写法
请求转发中的路径问题
相对路径写法
绝对路径写法
在目标资源内,相对路径的处理
乱码问题
乱码问题产生的根本原因是什么?
1. 数据的编码和解码,使用的不是同一个字符集
2. 使用了不支持某个语言的字符集
字符集:我们可以将其理解为一本字典,二进制的 0 1 组合,我们无法理解利益,字符集,就是一本字典,将二进制的 01 转换称我们可以理解的字符
各个字符集的兼容性:
由上图可知,上述字符集都兼容了 ASCII
ASCII 中,包含的是英文字母和一些通常使用的符号,所以这些东西,无论使用什么字符集,都不会乱码~
HTML 乱码问题
我们在记事本中,编写 html 页面的编码,采用的是 UTF-8,但我们在 head 标签中,特意设置 <meta charset = "GBK">,告诉浏览器,使用 GBK 对当前文件解码,两种对数据解码的方式对不上,于是就会出现乱码问题~
这个在 idea 上,倒是无法测试,因为 idea 十分智能,当它检测到,我们的在 meta 标签中,设置了 GBK 方式解码,它就会自动将编码的方式转变为 GBK
在 idea 中,我们可以查看项目字符集配置
可以对 Global Encoding 全局字符集,Project Encoding 项目字符集,Properties Files 属性配置文件的字符集设置为 UTF-8
Tomcat 控制台乱码问题
我们系统的日志窗口,默认是使用 GBK 解码的
但我们之前在配置 Tomcat 的时候,也发现,在 conf/logging.properties 文件中,Tomcat 中全是使用 UTF-8 进行便阿门的
两种数据编码方式不一样,自然出现乱码,让 Tomcat 适应我们系统的配置,当时我们将控制台的编码方式,由 UTF-8 转变成了 GBK~
现在可以把所有的 UTF-8 转成 GBK~(注意,设置完成后,需要重启 Tomcat 才能生效~)
sout 乱码问题
当我们将上面 idea 内的Global Encoding 全局字符集,Project Encoding 项目字符集,Properties Files 属性配置文件的字符集设置为 UTF-8 后,可能就会出现下面的 sout 乱码问题
这是因为,我们写的 java 代码,经过编译成 .class 文件后,JVM 进行解析的时候,使用的字符集可能是 GBK,导致乱码
我们可以设置虚拟机加载 .class 文件的字符集,和我们编译时候使用的字符集保持一致~
补充:如果没有出现 sout 乱码问题,不要调换虚拟机的编码配置啦~
请求乱码问题
GET 请求方式乱码分析
GET 方式,提交参数的方式,是将参数放置到 URL 后面,如果使用的不是 UTF-8,那么会对参数进行 URL 编码处理
HTML 中的 <meta charset='字符集'> 就会影响 GET 方式提交参数的 URL 编码
Tomcat 10 的 URL 编码默认是 UTF-8
当 GET 方式提交的参数 URL 编码和 Tomcat 默认的 URL 编码不一致时,就会出现乱码
在前端中,我们设置字符编码为 GBK 会影响我们的表单中的数据编码
当我们提交表单的数据为中文时候
会对数据进行 URL 编码处理,将 GBK 转码为“百分号码”
Tomcat10 默认使用 UTF-8 对 URI 进行解析,就会造成前后端使用的字符集不一致,出现乱码:
解决办法:
1. 设置 GET 方式提交的编码和 Tomcat10 的 URI 的默认的解析编码保持一致即可(推荐使用)
2:设置 Tomcat10 的 URI 解析字符集和 GET 请求发送时所使用的 URL 转码时候的字符集即可。修改 conf/server.xml 中的 Connecter 添加 URIEncoding="GBK"(不推荐)
如此改完之后,即前端请求中,仍然使用 GBK 编码,在 Tomcat 中也添加了URIEncoding="GBK",在打印台可能还是有乱码,此时,可能还是我们前面 Java 虚拟机的修改有了问题,我们在前面设置了 JVM 的解析使用 UTF-8
此时,就仍然出现了解析方式的不同,把这个 UTF-8 转换为 GBK,就可以正常打印了~
(上面的问题,也是博主实战测试出现的问题,灵机一动解决了~~~)
方法 2 仅仅在此处提一嘴,不建议大家使用~
(此处补充一点心得:大家在学习的时候,不要担心配置文件乱动了会出现什么大问题,只要不是非常粗心,在不知道的地方,随意修改了什么东西,一般不会出现什么问题,及时 CTRL + Z 撤回操作即可,应该大胆的对一些配置进行修改,并探究修改后发生的变化~~~)
POST请求方式乱码分析
form 表单的 POST 请求,将参数放在请求体中进行发送
请求体中使用的字符集受到了<meta charset="字符集">的影响
Tomcat10 默认使用 UTF-8 了字符集来对请求体进行解析
如果请求体的 URL 转码和 Tomcat 的请求体解析编码不一致,就容易出现乱码
此时,我们如果再设置 Tomcat 中的 server.xml 就不能生效了,因为 URIEncoding = "GBK",智能针对 URI 中的解析方式,此时,我们的 请求方法是 POST,请求的数据是在请求体中的!
解决办法:
1. 请求时,使用 UTF-8 字符集提交表单(推荐)
2. 后端在获取参数之前,设置解析请求体使用的字符集,和请求发送时,使用的字符集,保持一致(此时不推荐~)
总结
GET 乱码问题,form 表单提交的参数,会放在 uri 后面,编码受到 charset 的影响。可以通过在 server.xml 中 connector 中添加 URIEncoding=“GBK“来解决
请求行:GET URI?username=010101 http/1.1
请求头
请求体
POST 乱码问题,form 表单提交的参数会放在请求体中,编码受到 charset 的影响。可以在后端获取参数之前,设置解析请求头使用的字符集。(req.setCharacterEncoding(""))
请求行:GET URI http/1.1
请求头
请求体 username = 010101
响应乱码问题
在 Tomcat10 中,向响应体中放入的数据,默认使用了 UTF-8 编码
浏览器在接收响应信息的时候,使用了不同的字符集或是不支持中文字符集,就会出现乱码
在浏览器解析如下:
解决方式:
1. 后端通过设置响应体的字符集,和浏览器解析响应体的默认字符集保持一致
2. 通过设置 Content-Type 响应头,来告诉浏览器,以指定的字符集解析响应体(推荐)
路径问题
相对路径与绝对路径
相对路径:
相对路径的规则是:以当前资源所在的路径为出发点,去寻找目标资源
相对路径,不以 / 开头
在 file 协议下,使用的是 磁盘路径
在 http 协议下,使用的是 url 路径
在相对路径中,可以使用 ./ 表示当前资源所在的路径,可以省略不写
在相对路径中,可以使用 ../ 表示当前资源所在的路径的上一层路径,需要时要手动添加
绝对路径:
绝对路径的规则是:使用一个固定的路径,做出发点,去寻找目标资源,和当前资源所在的路径没有关系
绝对路径要以 / 开头
绝对路径的写法中,不以当前资源的所在路径为出发点,所有不会出现 ./ 和 ../ 开头
不同项目和不同的协议下,绝对路径的基础位置可能不同,需要通过测试来确定
绝对路径的好处:无论当前资源位置在哪里,寻找目标资源的路径的写法都是一致的
前端路径问题
相对路径问题
我们首先需要准备下面的项目结构:
相对路径情况 1:
web/index.html 中引入 web/static/img/test.png
访问 index.html 的 URL 为:http://localhost8080/web05/index.html
当前资源为:index.html
当前资源所在的路径为:http://localhost8080/web05/
index.html 中定义:<img src = "static/img/test.png" />(相对路径,省略 ./)
寻找方式,就是在当前资源所在的路径(http://localhost8080/web05)后面,拼接 src 的属性值(static/img/test.png),正好就是目标资源正常获取的 URL(http://localhost8080/web05/static/img/test.png)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<img src = "static/img/test.png" />
</body>
</html>
相对路径情况 2:
web/a/b/c/test.html 中,引入 web/static/img/test.png
访问 test.html 的 URL 为:http://localhost:8080/web05/a/b/c/test.html
当前资源为:test.html
当前资源的所在路径为:http://localhost:8080/web05/a/b/c/
要获取的目标资源的路径为:http://localhost:8080/web05/static/img/test.png
test.html 中定义:<img src = ../../../static/img/test.png />(三个 ../ 就是为了抵消 /a/b/c 三层目录)
寻找方式,就是在当前资源所在路径(http://localhost:8080/web05/a/b/c/)后拼接 src 的属性(../../../static/img/test.png),当三个 ../ 抵消了 三层目录后,正好是目标资源正常获取的 URL(http://localhost:8080/web05/a/b/c/static/img/test.png)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<img src = "../../../static/img/test.png" />
</body>
</html>
相对路径情况 3:
web/WEB-INF/views/view1.html 中引入 web/static/img/test.png
view1.html 在 WEB-INF 中,需要通过 Servlet 请求转发获得~
请求转发的路径,因为 WEB-INF 对于客户端是不可见的,所以无法使用相对路径进行转发,这里先直接使用绝对路径,后面会对绝对路径进行讲解~
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:02* @description:*/
@WebServlet("/view1Servlet")
public class View1Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.getRequestDispatcher("WEB-INF/views/view1.html").forward(req,resp);}
}
访问 view1.html 的 URL:http://localhost:8080/web05/view1Servlet
当前资源为:view1Servlet
当前资源所在路径:http://localhost:8080/web05/
要获取的资源 URL 为:http://localhost:8080/web05/static/img/test.png
view1.html 中定义:<img src = "static/img/test.png />
寻找方式:在当前的资源所在路径(http://localhost:8080/web05/)后面,拼接 src 属性值(static/img/test.png),正好是目标资源正常获取的 URL(http://localhost:8080/web05/static/img/test.png)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<img src = "static/img/test.png" />
</body>
</html>
在写相对路径的时候,只看文件和文件之间的目录结构,是不稳妥的。应该站在客户端浏览器的角度,以 URL 的结构为基础,来进行分析
绝对路径问题
不同项目中,固定的路径的出发点可能不一致,可以尝试一下~
绝对路径情况 1:
web/index.html 中引入 web/static/img/test.png
访问 index.html 的 URL 为:http://localhost:8080/web05/index.html
绝对路径的基准路径为:http://localhost:8080
要获取的目标资源的 URL 为:http://localhost:8080/web05/static/img/test.png
index.html 中定义为:<img src = "/web05/static/img/test.png" />
寻找方式:在基准路径(http://localhost:8080)后面,拼接 src 的属性值(/web05/static/img/test.png)得到的是目标资源访问的正确路径
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--绝对路径-->
<img src = "/web05/static/img/test.png" />
</body>
</html>
绝对路径情况 2:
web/a/b/c/test.html 中 引入 web/static/img/test.png
访问 test.html 的 URL 为:http://localhost:8080/web05/a/b/c/test.html
绝对路径的基准路径为:http://localhost:8080/
要获取的目标资源 URL 为:http://localhost:8080/web05/static/img/test.png
test.html 中定义为:<img src = "/web05/static/img/test.png" />
寻找方式:在基准路径(http://localhost:8080)后面拼接 src 属性值(/web05/static/img/test.png),得到的,就是目标资源访问的正确路径
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<img src ="/web05/static/img/test.png" />
</body>
</html>
绝对路径情况 3:
web/WEB-INF/views/view1.html 引入 web/static/img/test.png
view1.html 在 WEB-INF 下,需要 Servlet 请求转发获得
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:02* @description:*/
@WebServlet("/view1Servlet")
public class View1Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.getRequestDispatcher("WEB-INF/views/view1.html").forward(req,resp);}
}
访问 view1.html 的 URL 为:http://localhost:8080/web05/view1Servlet
绝对路径的基准路径为:http://localhost:8080
要获取的目标资源的 URL 为:http://localhost:8080/web05/static/img/test.png
view1.html 中定义为:<img src = /web05/static/img/test.png" />
寻找方式:在基准路径(http://localhost:8080)后面拼接 src 属性值(/static/img/test.png),即得到了目标资源你访问的正确路径
总结:
相对路径:
以当前资源的所在路径为出发点去寻找目标资源
不以 / 开头 ./ 可以省略
缺点:目标资源路径受到当前资源路径的影响
绝对路径:
始终以固定的资源作为出发点去寻找目标资源
优点:目标资源的路径的写法,不会受到当前资源路径的影响
缺点:绝对路径要补充项目的上下文,项目中上下文是可以改变的~
base 标签
可以通过 head -> base -> href 属性,定义相对路径公共前缀,通过公共前缀,把一个相对路径,转换为绝对路径
base 标签定义的公共前缀,只在相对路径上有效,绝对路径中无效
如果相对路劲的开头有 ./ 和 ../ 修饰,则 base 标签对该路径同样无效
例如:index.html 和 a/b/c/test.html 以及 view1Servlet 中的路径处理:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
<!--定义相对路径的公共前缀,将相对路径转化成了绝对路径--><base href = "/web05/" />
</head>
<body>
<img src = "static/img/test.png" />
</body>
</html>
缺省项目上下文路径
项目上下文路径变化问题:
通过 base 标签,虽然解决了相对路径转变绝对路径问题,但是 base 中,定义的是项目的上下文路径。
项目的上下文路径(/web05)又是可以随意变化的
一旦项目的上下文路径发生变化,所有 base 标签中的路径又要进行变化
==>
直接将项目的上下文路径进行缺省设置,设置为 / ,则所有的绝对路径中,就不需要填写项目的上下文开头了,直接以 / 开头即可~
后端路径问题
重定向中的路径问题
由x/y/z/servletA 重定向到 a/b/c/test.html
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:01* @description:*/
@WebServlet("/x/y/z/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
}
相对路径写法
访问 ServletA 的 URL 为:http://localhost:8080/web05/x/y/z/servletA
当前资源为:servletA
当前资源的所在路径为:http://localhost:8080/web05/x/y/z/
要获取的目标资源 URL 为:http://localhost:8080/web05/a/b/c/test.html
ServletA 重定向的路径为:../../../a/b/c/test.html
寻找方式:在当前资源的路径下(http://localhost:8080/web05/x/y/z/)拼接(../../../a/b/c/test.html),形成(http://localhost:8080/web05/x/y/z/../../../a/b/c/test.html),每个 ../ 抵消一层目录,正好是目标资源正常获取的 URL(http://localhost:8080/web05/a/b/c/test.html)
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:01* @description:*/
@WebServlet("/x/y/z/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 相对路径重定向到 test.htmlresp.sendRedirect("../../../a/b/c/test.html");}
}
绝对路径写法
访问 ServletA 的 URL:http://localhost:8080/web05/x/y/z/servletA
绝对资源的基准路径为:http://localhost:8080
要获取的目标资源 URL 为:http://localhost:8080/web05/a/b/c/test.html
ServletA 重定向的路径为:/web/a/b/c/test.html
寻找方式:在基准路径(http://localhost:8080)后,拼接(web05/a/b/c/test.html)得到(http://localhost:8080/web05/a/b/c/test.html),正是目标资源访问的正确路径
补充:
绝对路径中,需要填写项目的上下文路径,但,上下文路径是变换的
1. 可以通过 ServletContext 的 getContextPath() 获取上下文路径
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:01* @description:*/
@WebServlet("/x/y/z/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 通过 ServletContext 的 getContextPath 方法 动态获取上下文路径resp.sendRedirect(getServletContext().getContextPath() + "a/b/c/test.html");}
}
2. 可以将项目的上下文路径定义为 / 缺省路径,那么资源中直接以 / 开头即可~
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:01* @description:*/
@WebServlet("/x/y/z/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 缺省项目上下文路径,直接以 / 开头即可resp.sendRedirect("/a/b/c/test.html");}
}
请求转发中的路径问题
由x/y/servletB 请求转发到 a/b/c/test.html
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:02* @description:*/
@WebServlet("/x/y/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
}
相对路径写法
访问 ServletB 的 URL 为:http://localhost:8080/web05/x/y/servletB
当前资源为:servletB
当前资源的所在路径为:http://localhost:8080/web05/x/y
要获取的目标资源的 URL 为:http://localhost:8080/web05/a/b/c/test.html
ServletA 请求转发路径为:../../test.html
寻找方式:在当前资源所在路径(http://localhost:8080/web05/x/y)后,拼接(../../test.html)。形成(http://localhost:8080/web05/x/y../../a/b/c/test.html),每个 ../ 抵消一层目录,正好是目标资源正常获取的 URL(http://localhost:8080/web05/a/b/c/test.html)
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:02* @description:*/
@WebServlet("/x/y/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.getRequestDispatcher("../../a/b/c/test.html").forward(req,resp);}
}
绝对路径写法
请求转发只能转发到项目内部的资源,其绝对路径无需添加项目上下文路径
请求转发绝对路径的基准路径相当于:http://localhost:8080/web05
当项目上下文路径为缺省值,也无需改变,直接以 / 开头即可~
package com.zzz.servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/** @author zzr* @date: 2025/07/08 00:02* @description:*/
@WebServlet("/x/y/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.getRequestDispatcher("/a/b/c/test.html").forward(req,resp);}
}
在目标资源内,相对路径的处理
此时要注意,请求转发是服务器的行为,浏览器是不知道的,地址栏并不会变化,相当于我们此时访问 test.html ,但是浏览器的 URL 仍然为:http://localhost:8080/web05/x/y/servletB
那么此时 test.html 资源所在的路径,就是 http://localhost:8080/web05/x/y/ 所以,test.html 中相对路径就要基于该路径编写
如果在目标资源类,再转发别的资源,使用绝对路径就不需要考虑
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--当前的资源路径是: http://localhost:8080/web05/x/y/servletB当前资源所在的路径是:http://localhost:8080/web05/x/y/目标资源路径 = 所在资源路径 + src 属性值即目标资源的路径为: http://localhost:8080/web05/x/y/../../static/img/test.png-->
<img src ="../..//static/img/test.png" />
</body>
</html>