关于basePath

1. 什么是 basePath

basePath 是我们声明的一个变量,这个变量是通过 request 对象分别获取协议,IP,端口和应用上下文,并把它们组合在一起后形成的字符串。把该字符串设定为 HTML 的 base 标签的 href 属性的值,可以达到这样的效果:在当前 JSP 页面中,凡是出现相对引用的地方,相对引用的路径都是相对于 basePath 来说的。换句话说,所有的相对引用都不再是相对于当前 JSP 页面的所在位置,而是相对于当前应用上下文的根目录来说的。

2. basePath 的写法

<%String basePath = request.getScheme() + "://" + request.getServerName()+ ":" + request.getServerPort() + request.getContextPath() + "/";%>
2.1 注意点1

request.getContextPath() 得到的结果中开头包含了一个斜杠/,所以端口和应用上下文之间不用再加斜杠了。
关于basePath_第1张图片

2.2 注意点2

最后一个斜杠一定要加上,不然 basePath 和相对路径结合以后会出错。
比如:basePath 是 http://localhost:8080/day190117 ,当前页面中有个相对路径是 jsp/a.jsp。当发送请求的时候,浏览器其实是把 basePath 直接和相对路径合并,结果就变成了 http://localhost:8080/day190117jsp/a.jsp 而不是我们期望的 http://localhost:8080/day190117/jsp/a.jsp

3. 为什么要使用 basePath

使用 basePath 的理由很简单,就是为了解决页面跳转中出现的找不到目标网页的问题。

3.1 正常情况

比如我们有如下目录结构:
关于basePath_第2张图片
a.jsp 和 target.jsp 在 web 应用根目录下的 jsp 文件夹里,b.jsp 在 web 应用根目录下的 jsp/jsp1 文件夹里。
在 a.jsp 中,我们设定通过超链接访问 b.jsp。相对于 a.jsp,b.jsp 在当前目录的 jsp1 文件夹里,所以相对路径为 jsp1/b.jsp
在这里插入图片描述
在 b.jsp 中,我们设定通过超链接访问 target.jsp。相对于 b.jsp,target.jsp 在当前目录的上一层目录里,所以相对路径为 ../target.jsp
在这里插入图片描述
运行的结果是通过在 a.jsp 点击超链接确实能到达 b.jsp,在 b.jsp 中点击超链接也确实能到达 target.jsp。
关于basePath_第3张图片
关于basePath_第4张图片

3.2 异常情况

现在把从 a.jsp 到 b.jsp 的跳转方式改变一下,a.jsp 如下:
在这里插入图片描述
通过 web.xml 进行拦截如下:
关于basePath_第5张图片
在对应的 Servlet 中通过 转发 的方式响应 b.jsp 页面给浏览器:
关于basePath_第6张图片
结果是从 a.jsp 通过转发确实能够到达 b.jsp。但是从 b.jsp 没法到达 target.jsp 了。
关于basePath_第7张图片
关于basePath_第8张图片

3.3 原因分析

注意看上图中的地址栏,浏览器发送请求的时候是从 web 应用的根目录下找 target.jsp,这一点异常很重要。
其实问题出在 转发 上。
最开始的路径是 http://localhost:8080/day190117/jsp/a.jsp 。在 a.jsp 中点击了链接,在后台转发到 jsp/jsp1/b.jsp 了。但是对于浏览器来说,它并不知道后台是经过了几次转发,在后台的目录结构上是往上走了几层还是往下深入了几层。浏览器只是发送了一个请求地址:http://localhost:8080/day190117/jsp/login.do ,服务器只是给浏览器响应了一个 HTML 页面 b.jsp 而已。既然当前在 b.jsp 页面,当前的 URL 为: http://localhost:8080/day190117/jsp/login.do ,那么浏览器只能把 login.do 看做一个静态资源(相当于 login.do 就是 b.jsp),把 http://localhost:8080/day190117/jsp 作为当前目录。因此在b.jsp中通过超链接中的相对路径向上一层去找 target.jsp,浏览器就会发送一个这样的请求 URL:http://localhost:8080/day190117/target.jsp 。很显然,在服务器端,web 应用 day190117 的根目录下并没有 target.jsp。
这里出现了一个前端和后端的不一致,从后端看target.jsp在b.jsp的上一层,但是从前端看,由于浏览器不知道a.jsp到b.jsp在后端是怎么转发的,只能以 http://localhost:8080/day190117/jsp/login.do 所在的目录作为当前 HTML 页面中相对路径的起点。

4. 解决办法——basePath 配合 HTML 的 base 标签

HTML 中有一个 base 标签,它的 href 属性可以规定当前 HTML 页面中所有相对路径的基准。
那么,通过 request 对象获取相关的信息,拼接成一个字符串代表当前 web 应用的根目录,然后把这个根目录作为 href 的属性值,就可以保证当前页面中所有的相对路径都是以 web 应用根目录为起点。
既然是从 b.jsp 到 target.jsp 的过程中发生了问题,那么我们在 b.jsp 中作如下修改:
关于basePath_第9张图片可以看到,我们新加了一个 basePath 变量,并把它作为 base 标签的 href 属性的值。这样,b.jsp 中所有的相对路径都是以这个 basePath 为基准的。那么,我们要想从 b.jsp 到 target.jsp,就不需要考虑 b.jsp 和 target.jsp 的相对关系了,而是需要考虑目标文件即 target.jsp 和 web 应用根目录的相对关系。target.jsp 位于当前 web 应用根目录下的 jsp 文件夹里,那么相对路径就是 jsp/target.jsp。
测试一下,确实能从 b.jsp 跳转到 target.jsp。注意看 URL,和我们预想的也一样。
关于basePath_第10张图片

5. 其它事项

5.1 不用每个相对路径前都加 basePath 变量

从网上看到的其它文章中,有一些设置了 basePath 变量,但是没有设定 HTML 的 base 标签,所以在 JSP 页面中的每一个相对路径前都加了 <%=basePath%>。这样相当于替代了浏览器,我们自己主动把每一个相对路径都变换成绝对路径。画面跳转确实没有问题,只不过在每一个相对路径前面都加 basePath 变量显得有些麻烦了,应该充分利用 HTML 的 base 标签。在 JSP 页面中设置了 base 标签的 href 属性后,每一个相对路径都不需要加 basePath 变量了。

5.2 页面中的相对路径都是以当前 web 应用的根目录为基准的

再次强调一下而已。如果设置了 basePath 变量和 base 标签的 href 属性,所有的相对路径都应该相对于当前 web 应用的根目录去写。

5.3 作为根目录的斜杠在 JSP(HTML)和 Servlet 中的不同含义

首先说明,在路径的开头写斜杠/代表当前路径为绝对路径。这一点在 JSP(HTML)和 Servlet 中是一样的。
我们平常理解的绝对路径是以盘符开头的,如:C:\AppData\Roaming,这是以 windows 系统为基础的。但是 web 应用真正上线的时候,往往部署在 LINUX 服务器上。在 LINUX 服务器上,斜杠/代表根目录。所以 JSP(HTML)和 Servlet 应该都是考虑到这一点所以有这样的设计。
问题是,在前端(浏览器)和后端(服务器)中这个斜杠/所代表的根目录是不同的。浏览器把当前访问的站点作为根目录,而服务器中,由于当前处理 HTTP 请求的 Servlet 是某个具体的 web 应用下的 Servlet,所以它把当前 web 应用的根目录作为根目录。
一个网站上面可以部署很多个 web 应用,JSP 页面中的路径既可以在本次访问的 web 应用内部跳转,也可以跳转当前访问站点的其它 web 应用里,甚至可以跳转到其它站点,所以折中的办法是把斜杠当做当前访问站点的根目录。如:http://localhost:8080。而服务器端,Servlet 中写的斜杠肯定不能代表当前站点的根目录,那样几乎没有任何意义,用斜杠代表当前 web 应用的根目录则是合情合理的。如:http://localhost:8080/day190117。在上面的 TestServlet 类中,我们写的转发到的 path 是 “/jsp/jsp1/b.jsp”,这里就是绝对路径的写法,斜杠代表当前 web 应用 day190117 的根目录。
比如:我们把上面的 b.jsp 页面修改一下。
关于basePath_第11张图片其中,basePath 最后的斜杠取消了,超链接的相对路径的开头加一个斜杠。我们的预期是,basePath 和超链接的相对路径拼在一起正好是要访问的 URL。
但是测试的结果是访问不了。
关于basePath_第12张图片注意看一下地址栏的 URL,浏览器是去 localhost 这个站点的根目录下去找 jsp 文件夹里的 target.jsp 的。也就是说,超链接中的斜杠是绝对路径,代表当前站点的根目录,浏览器就不再以相对路径的方式去拼接 URL 进行 HTTP 请求了。

5.4 把 base 标签放在所有相对引用的前面

请把 标签排在 元素中第一个元素的位置,这样 head 区域中其他元素就可以使用 元素中的信息了。 ---- 菜鸟教程

你可能感兴趣的:(Java,basePath,base标签)