文章目录
一、相对路径和绝对路径
1)相对路径
- 相对路径的规则是:以当前资源所在的路径为出发点去寻找目标资源
- 相对路径不以 / 开头
- 在file协议下,使用的是磁盘路径
- 在http协议下,使用的是url路径
- 相对路径中可以使用
./
表示当前资源所在路径,可以省略不写 - 相对路径中可以使用
../
表示当前资源所在路径的上一层路径,需要时要手动添加
2)绝对路径
-
绝对路径的规则是: 使用以一个固定的路径做出出发点去寻找目标资源,和当前资源所在的路径没有关系
-
绝对路径要以/ 开头
-
绝对路径的写法中,不以当前资源的所在路径为出发点,所以不会出现 ./ 和…/
-
不同的项目和不同的协议下,绝对路径的基础位置可能不同,要通过测试确定
-
绝对路径的好处就是:无论当前资源位置在哪,寻找目标资源路径的写法都一致
-
应用场景
- 前端代码中,href src action 等属性
- 请求转发和重定向中的路径
二、前端相对路径问题
前端项目结构
情况1:web/index.html中引入web/static/img/logo.png
- 访问index.html的url为 : http://localhost:8080/web03_war_exploded/index.html
- 当前资源为 : index.html
- index.html中定义的了 :
<img src="static/img/logo.png"/>
- 当前资源的所在路径为 : http://localhost:8080/web03_war_exploded/
- 客户端解析
static/img/logo.png
路径,而客户端在解析的过程中,压根不知道服务器中目录结构是什么样的,所以我们如果在后端单纯用目录结构去判断请求路径的规则的话是有问题的。所以我们一定要站在浏览器的角度去分析!!! - 但是客户端知道
http://localhost:8080/web03_war_exploded/index.html
,因此客户端会在当前路径上去分析 - 要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
- 寻找方式就是在当前资源所在路径(http://localhost:8080/web03_war_exploded/)后拼接src属性值(
static/img/logo.png
),正好是目标资源正常获取的url(http://localhost:8080/web03_war_exploded/static/img/logo.png) - 如果这个路径能够正确的匹配到这个png图片,那么服务端就会把这个logo.png响应回来,此时这个资源就拿到了
- 总结:此时这个相对路径并不是看你的磁盘结构,而是客户端在解析当前资源的URL的基础上进行相对路径的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="static/img/logo.png">
</body>
</html>
通过F12抓包,也可以看见浏览器发送了两个请求
并且鼠标放上去也有一个小提示,可以显示出对这张图片请求的地址
情况2:web/a/b/c/test.html中引入web/static/img/logo.png
- 访问test.html的url为 : http://localhost:8080/web03_war_exploded/a/b/c/test.html
- 当前资源为 : test.html
- 当前资源的所在路径为 : http://localhost:8080/web03_war_exploded/a/b/c/
- 要获取的目标资源url应该为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
- test.html中定义的了 :
<img src="../../../static/img/logo.png"/>
- 因此目标资源的相对路径为:
../../../static/img/logo.png
- 寻找方式就是在当前资源所在路径(http://localhost:8080/web03_war_exploded/a/b/c/)后拼接src属性值(
../../../static/img/logo.png
),其中../
可以抵消一层路径,正好是目标资源正常获取的url(http://localhost:8080/web03_war_exploded/static/img/logo.png)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- ../代表上一层路径 -->
<img src="../../../static/img/logo.png">
</body>
</html>
情况3:web/WEB-INF/views/view1.html中引入web/static/img/logo.png
这种情况就是:磁盘结构和URL结构是不匹配的,此时只看磁盘结构就不行了。所以我们一定要站在浏览器的角度去分析!!!
- view1.html在WEB-INF下,需要通过Servlet请求转发获得
@WebServlet("/view1Servlet")
public class View1Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/views/view1.html");
requestDispatcher.forward(req,resp);
}
}
- 访问view1.html的url为 : http://localhost:8080/web03_war_exploded/view1Servlet
- 因为是请求转发,因此浏览器的URL是不变的,因此接下来的相对路径都是以
http://localhost:8080/web03_war_exploded/view1Servlet
来进行分析的,而不是以view1.html的磁盘结构
或者目录结构
来进行分析的 - 当前资源为 : view1Servlet
- 当前资源的所在路径为 : http://localhost:8080/web03_war_exploded/
- view1.html中定义的了 :
<img src="static/img/logo.png"/>
- 因此目标资源的相对路径为:
static/img/logo.png
- 要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
- 寻找方式就是在当前资源所在路径(http://localhost:8080/web03_war_exploded/)后拼接src属性值(static/img/logo.png),正好是目标资源正常获取的url(http://localhost:8080/web03_war_exploded/static/img/logo.png)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="static/img/logo.png">
</body>
</html>
三、前端绝对路径情况分析
我们发现,用相对路径让我们难受的地方是:我们当前文件的位置或者当前资源的路径,会影响到我们对于目标资源路径的编写。
例如请求转发的时候,还需要看这个请求转发的路径是什么,这让我们感觉十分难受,此时就可以使用绝对路径。
绝对路径:始终以固定的路径作为出发点去找目标资源,和当前资源所在的路径没有关系。
语法:以 /
开头,但是这样会导致不同的项目中,固定的路径出发点可能会不一致,我们可以测试一下我们这个项目固定的路径出发点是什么。
测试方式:先在html文件中随便请求一个绝对路径,看看它完整的路径是什么
抓包发现,它是在 http://localhost:8080/
后面去找 /x/y/z
,因此如果我们以 /
开头的话,那么它前面就是 http://localhost:8080
,缺的就是项目的上下文路径
情况1:web/index.html中引入web/static/img/logo.png
- 访问index.html的url为 : http://localhost:8080/web03_war_exploded/index.html
- 绝对路径的基准路径为 : http://localhost:8080
- 要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
- index.html中定义的了 :
<img src="/web03_war_exploded/static/img/logo.png"/>
- 寻找方式就是在基准路径(http://localhost:8080)后面拼接src属性值(/web03_war_exploded/static/img/logo.png),得到的正是目标资源访问的正确路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 绝对路径写法 -->
<img src="/web03_war_exploded/static/img/logo.png">
</body>
</html>
情况2:web/a/b/c/test.html中引入web/static/img/logo.png
- 访问test.html的url为 : http://localhost:8080/web03_war_exploded/a/b/c/test.html
- 绝对路径的基准路径为 : http://localhost:8080
- 要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
- test.html中定义的了 :
<img src="/web03_war_exploded/static/img/logo.png"/>
- 寻找方式就是在基准路径(http://localhost:8080)后面拼接src属性值(/web03_war_exploded/static/img/logo.png),得到的正是目标资源访问的正确路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 绝对路径写法 -->
<img src="/web03_war_exploded/static/img/logo.png">
</body>
</html>
情况3:web/WEB-INF/views/view1.html中引入web/static/img/logo.png
- view1.html在WEB-INF下,需要通过Servlet请求转发获得
@WebServlet("/view1Servlet")
public class View1Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/views/view1.html");
requestDispatcher.forward(req,resp);
}
}
- 访问view1.html的url为 : http://localhost:8080/web03_war_exploded/view1Servlet
- 绝对路径的基准路径为 : http://localhost:8080
- 要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
- view1.html中定义的了 :
<img src="/web03_war_exploded/static/img/logo.png"/>
- 寻找方式就是在基准路径(http://localhost:8080)后面拼接src属性值(/static/img/logo.png),得到的正是目标资源访问的正确路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="/web03_war_exploded/static/img/logo.png">
</body>
</html>
四、base标签的使用
我们可以通过 head>base>href
属性,定义页面相对路径公共前缀,通过公共前缀把一个相对路径转换为绝对路径
- base 标签定义在head标签中,用于定义相对路径的公共前缀
- 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="/web03_war_exploded/">
</head>
<body>
<!-- 当前页面中,所有不加任何修饰的相对路径前,会自动补充href中的内容 -->
<img src="static/img/logo.png">
</body>
</html>
但是现在base标签只是一个临时解决方案,我希望的是我的项目上下文路径再怎么变,我也不想去修改页面上任何一个绝对路径的代码。
五、缺省项目上下文路径
项目上下文路径变化问题
- 通过 base标签虽然解决了相对路径转绝对路径问题,但是base中定义的是项目的上下文路径
- 项目的上下文路径是可以随意变化的
- 一旦项目的上下文路径发生变化,所有base标签中的路径都需要改
解决方案
- 将项目的上下文路径进行缺省设置,设置为
/
,所有的绝对路径中就不必填写项目的上下文了,直接就是/
开头即可
并且这种让我们项目不设置项目上下文路径,未来在开发工程中真的会这么干。也就是说我们没有必要为这个项目设置项目上下文,我们只需要将IP和端口号设置好了,就可以通过IP和端口号找到这台服务器,默认对应到这个项目就完了。
即:我们一个服务器专门就放这个App。
六、重定向中的路径问题
当我请求servletA时,它会响应302状态码以及需要重定向的地址,由下图可知,它响应回来的是相对路径。
当浏览器请求servletB的时候也是在当前资源所在的路径后面拼接你目标资源的相对路径。
结论:跟前端处理相对路径、绝对路径的方式是一样的
1)目标
由/x/y/z/servletA重定向到a/b/c/test.html
2)相对路径写法
- 访问ServletA的url为 : http://localhost:8080/web03_war_exploded/x/y/z/servletA
- 当前资源为 : servletA
- 当前资源的所在路径为 : http://localhost:8080/web03_war_exploded/x/x/z/
- 要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/a/b/c/test.html
- ServletA重定向的路径 : …/…/…/a/b/c/test/html
- 寻找方式就是在当前资源所在路径(http://localhost:8080/web03_war_exploded/x/y/z/)后拼接(…/…/…/a/b/c/test/html),形成(http://localhost:8080/web03_war_exploded/x/y/z/…/…/…/a/b/c/test/html)每个…/抵消一层目录,正好是目标资源正常获取的url(http://localhost:8080/web03_war_exploded/a/b/c/test/html)
@WebServlet("/x/y/z/servletA")
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 相对路径重定向到test.html
resp.sendRedirect("../../../a/b/c/test.html");
}
}
3)绝对路径写法
-
访问ServletA的url为 : http://localhost:8080/web03_war_exploded/x/y/z/servletA
-
绝对路径的基准路径为 : http://localhost:8080
-
要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/a/b/c/test.html
-
ServletA重定向的路径 : /web03_war_exploded/a/b/c/test.html
-
寻找方式就是在基准路径(http://localhost:8080)后面拼接(/web03_war_exploded/a/b/c/test.html),得到( http://localhost:8080/web03_war_exploded/a/b/c/test.html)正是目标资源访问的正确路径
-
绝对路径中需要填写项目上下文路径,但是上下文路径是变换的
- 可以通过
ServletContext
的getContextPath()
获取上下文路径 - 可以将项目上下文路径定义为
/
缺省路径,那么路径中直接以/
开头即可
//绝对路径中,要写项目上下文路径 resp.sendRedirect("/web03_war_exploded/a/b/c/test.html"); // 通过ServletContext对象动态获取项目上下文路径 resp.sendRedirect(getServletContext().getContextPath()+"/a/b/c/test.html"); // 缺省项目上下文路径时,直接以/开头即可 resp.sendRedirect("/a/b/c/test.html");
- 可以通过
七、请求转发中的路径问题
1)目标
由x/y/servletB请求转发到a/b/c/test.html
2)相对路径写法
结论:跟前端处理相对路径的方式是一样的
-
访问ServletB的url为 : http://localhost:8080/web03_war_exploded/x/y/servletB
-
当前资源为 : servletB
-
当前资源的所在路径为 : http://localhost:8080/web03_war_exploded/x/y/
-
要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/a/b/c/test.html
-
ServletA请求转发路径 : …/…/a/b/c/test/html
-
寻找方式就是在当前资源所在路径(http://localhost:8080/web03_war_exploded/x/y/)后拼接(…/…/a/b/c/test/html),形成(http://localhost:8080/web03_war_exploded/x/y/…/…/a/b/c/test/html)每个
../
抵消一层目录,正好是目标资源正常获取的url(http://localhost:8080/web03_war_exploded/a/b/c/test/html)@WebServlet("/x/y/servletB") public class ServletB extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { RequestDispatcher requestDispatcher = req.getRequestDispatcher("../../a/b/c/test.html"); requestDispatcher.forward(req,resp); } }
3)绝对路径写法
-
请求转发只能转发到项目内部的资源,其绝对路径无需添加项目上下文路径
-
请求转发绝对路径的基准路径相当于
http://localhost:8080/web03_war_exploded
-
在项目上下文路径为缺省值时,也无需改变,直接以
/
开头即可@WebServlet("/x/y/servletB") public class ServletB extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { RequestDispatcher requestDispatcher = req.getRequestDispatcher("/a/b/c/test.html"); requestDispatcher.forward(req,resp); } }
总结:除了请求转发,其他的绝对路径前面都要加项目上下文路径。
八、目标资源内相对路径处理
这点虽然上面已经提过了,但是比较特殊,单独拿出来再讲一下
-
此时需要注意,请求转发是服务器行为,浏览器不知道,地址栏不变化,相当于我们访问test.html的路径为http://localhost:8080/web03_war_exploded/x/y/servletB
-
那么此时 test.html 资源的所在路径就是http://localhost:8080/web03_war_exploded/x/y/所以test.html中相对路径要基于该路径编写,如果使用绝对路径则不用考虑
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 当前资源路径是 http://localhost:8080/web03_war_exploded/x/y/servletB 当前资源所在路径是 http://localhost:8080/web03_war_exploded/x/y/ 目标资源路径=所在资源路径+src属性值 http://localhost:8080/web03_war_exploded/x/y/../../static/img/logo.png http://localhost:8080/web03_war_exploded/static/img/logo.png 得到目标路径正是目标资源的访问路径 --> <img src="../../static/img/logo.png"> </body> </html>
九、处理请求参数
需要注意的是,设置编码(post)这一句代码必须在所有的获取参数动作之前,如果出现在获取完fname之后,不仅fname是乱码,计算是在request.setCharacterEncoding(“UTF-8”);之后的,也会是乱码
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
// post方式下,设置编码,防止中文乱码
// 需要注意的是,设置编码(post)这一句代码必须在所有的获取参数动作之前,如果出现在获取玩fname之后,不仅fname是乱码,计算是在request.setCharacterEncoding("UTF-8");之后的,也会是乱码
request.setCharacterEncoding("UTF-8");
-----------------------------------------------------------------------------------------------------------
// get方式目前不需要设置编码(基于tomcat8以后)
// 如果是get请求发送的中文数据,转码稍微有点麻烦(tomcat8之前)
String fname = request.getParameter("fname");
// 1.将字符串打散成字节数组
byte[] bytes = fname.getBytes("ISO-8859-1");// 因为tomcat8之前底层的编码默认使用的编码就是ISO-8859-1
// 2.将字节数组按照设定的编码重新组装成字符串,第二个参数是你想要的编码格式
fname = new String(bytes, "UTF-8");
...
}