您的位置:首页 > 编程语言 > Java开发

Java Web 中的各种路径问题(草稿)

2014-01-21 13:39 106 查看
|--[通则:已过期,参见"通则修改"]
由于每个路径的意义实际上是由上下文环境最终决定的,所以有些路径的含义是完全由该语言环境"规定"出来的,比如html的<img/>路径中"/"有能力表示所有app集合的路径,也可以表示当前app的根路径,但"规定"为app集合根目录.某些路径含义需要"死记".
|--[通则修改]
|--html中的<img/>或<form action/>路径为何从app集合根路径开始?
|--因为有可能出现这种情况:"http://localhost:8080/index.jsp",意味着html的嵌入资源无法确定开头的"/"是属于哪个app(因为可能根本就不存在!).
|--[路径确定法1]-[反证法]-[案例]
|--	如果"/"确实能表示当前app根路径,那"/index.jsp"就该去当前app目录找.
但是"OnlineShop"要访问Tomcat的欢迎页面"http://localhost:8080/index.jsp"要怎么访问?
因此"/"表示当前app根路径是会引起歧义的,不成立.
|--	"/"确实可以"规定"为当前app根路径,但至少有两处地方不合适:
1.浏览器对不完整的路径是是先拼接为完整路径后发送请求的,对于"/"开头的路径,会期望浏览器拼接到"appName",但是浏览器只有"远程服务器"的概念,没有所谓的"app"概念,Tomcat 确实是"port"后的第一个字符串为appName,但其他服务器可能不这么规定,不应强行令浏览器解析第一个字符串为appName;
2."/"在多种系统环境均表示系统根目录[?],使用"/"开头应能够访问到所有资源,但规定"/"为当前app目录时,访问类似"http://localhost:8080/index.jsp"的资源通常要引进"../"等额外法则,一定程度上否定了"/"自身的合理性.
|--浏览器端是没有app概念的,app概念是服务器的概念,
|--[]浏览器解析"../"时,最上级不超过"ip:port",就像计算机的没有更上级目录一样
|--[Assumption]★★★★☆
|--	"一种法则在不引进额外法则的情况下,应能访问到本服务器的所有资源."
|--这并不意味着"服务器端"的"/images/a.jpg"形式能访问所有服务器应用图片,因为该法则本来就规定从"本应用"根目录找资源;但在"不同"的app中使用该形式确实访问到各自的图片,符合原则规定.
|--	[详解148]["死记"]转发时,ServletContext.getRequestDispatcher()用绝对路径,ServletRequest.getRequestDispatcher()用相对/绝对都行.因为 ServletRequest 带有请求的网址信息,ServletContext 则代表整个当前WEB应用,所以不难理解后者只有绝对路径.

assume:
appname应用下有
假设Web应用road中,应用的根路径下有一个dir1文件夹和dir2文件夹。c.jsp在dir1中,a.jsp和b.jsp在dir2中。Web应用的结构如图如下:
appname
|--dir1
|--c.jsp
|--dir2
|--a.jsp	b.jsp

|--jsp(其实应属于html范畴):[?]
直接写路径,表示在同一级
../表示上一级
"/"表示"ip:port/":网页中的<img/>是可能引用任何网站的url的!

|--servlet:
转发时,"/"表示"ip:port/appname",比如
String forward = "/dir1/c.jsp"
RequestDispatcherrd = request.getQRequestDispatcher(forward);

request.getContextPath()得到的是 "ip:port/appname"

重定向时,"/"表示"ip:port",如
String str =  request.getContextPath();
response.sendRedirect(str + "/dir1/c.jsp");

|--web.xml:
url-mapping中,"/"表示"ip:port/appname"

|--在浏览器端:“/”表示的是一台WEB服务器,"http://机器IP:8080"
|--在服务器端(请求转发):“/”表示的是一个WEB服务器端的应用,"http://机器IP:8080/Web应用"
|--在服务器端(重定向):“/”表示的是一个WEB服务器,"http://机器IP:8080"

|--ServletContext.getContextPath():返回斜杠+项目名,"/appname"
|--ServletContext.getRealPath():返回包含到项目名的绝对路径,结尾不加斜杠,"E:\Program Files\Java\Libs\apache-tomcat-6.0.16\webapps\appname"
|--ServletContext.getResource,"jndi:/localhost/Day19_upload/"
|--HttpServletRequest.getServletPath(),返回紧接着项目名后的"/something",不含请求参数,待深究...

|--Class.getResource(""),web-inf/classes类的路径,包括包(以"/"分隔),file:/E:/Program%20Files/Java/Libs/apache-tomcat-6.0.16/webapps/Day19_upload/WEB-INF/classes/gr/enathord/controller/
|--Class.getResource("/"),web-inf/classes类的路径,不包括包,file:/E:/Program%20Files/Java/Libs/apache-tomcat-6.0.16/webapps/Day19_upload/WEB-INF/classes/
|--总结以上两条:不加"/",默认与本类同级;加"/",从classes开始.getResourceAsStream遵循同理!

|--Class.getResourceAsStream("/res.suffix"),classes根目录下的res.suffix文件
|--Class.getResourceAsStream("res.suffix"),本类下的res.suffix文件(具体到包)
|--ClassLoader.getResourceAsStream("res.suffix")或ClassLoader.getResourceAsStream("/res.suffix")
|--classloader使用的就是classes的根目录(classpath),加不加"/"都是.

/**
Class.getResourceAsStream
public InputStream getResourceAsStream(String name)查找具有给定名称的资源。查找与给定类相关的资源的规则是通过定义类的 class loader 实现的。此方法委托此对象的类加载器。如果此对象通过引导类加载器加载,则此方法将委托给 ClassLoader.getSystemResourceAsStream(java.lang.String)。
在委托前,使用下面的算法从给定的资源名构造一个绝对资源名:

如果 name 以 '/' 开始 ('\u002f'),则绝对资源名是 '/' 后面的 name 的一部分。
否则,绝对名具有以下形式:
modified_package_name/name
其中 modified_package_name 是此对象的包名,该名用 '/' 取代了 '.' ('\u002e')。

参数:
name - 所需资源的名称
返回:
一个 InputStream 对象;如果找不到带有该名称的资源,则返回 null
抛出:
NullPointerException - 如果 name 是 null
从以下版本开始:
JDK1.1
*/

总结:
web应用中
服务器默认只访问本app下的目录,根目录为:appname的webroot,后面加不加"/"都行,打印出来是没有的.getRealPath遵循此则.
浏览器默认访问远程主机目录,为webapps,要加"appname"才能进一步访问
要访问src的资源,需用class或classloader的getResource/getResourceAsStream方法;
比如:QueryLoader有个load方法直接load("/sqls.properties"),其实底层源代码用的是getResource().
以后使用时,
若是重定向,使用getContextPath()+"/(webroot下的)资源名";注意getContextPath返回"/appname",末尾无斜杠.
若是转发,直接资源?
ServletContext 的 getResource() 和 getResourceAsStream() 方法不同于Class和ClasLoader的.
|--都必须以"/"开头,否则报错;都是从webroot开始算起的.
比如: context.getResource("/WEB-INF/web.xml")

/**
String javax.servlet.http.HttpServletRequest.getServletPath()

Returns the part of this request's URL that calls the servlet. This path starts with a "/" character and includes either the servlet name or a path to the servlet, but does not include any extra path information or a query string. Same as the value of the CGI variable SCRIPT_NAME.

This method will return an empty string ("") if the servlet used to process this request was matched using the "/*" pattern.

Returns:
a String containing the name or path of the servlet being called, as specified in the request URL, decoded, or an empty string if the servlet used to process the request is matched using the "/*" pattern.
*/

总结2:
|--web
|--前面加不加"/"都是一样的,
对于服务器,默认从本app(即webroot)开始解析;
对于浏览器,默认从远程主机开始解析,∵"浏览器可能访问服务器的任何app",∴在此必须指定.
|--有两个特例:context的getResource()和getResourceAsStream方法,必须以"/"开始;而且不同于class寻址,上述都是以appname开始的.
|--注意 ServletContext.getContextPath() 单纯地返回"/appname",前面讲的加不加"/"都无所谓是针对路径起始的字符串的,但getContextPath()默认已经加了,∴不能用"/"+getContextPath(),否则返回"//appname".而且后面还得加"/",∵这只是单纯地字符串相加.
|--class
class.getResource()
不加"/",与当前类同级;加"/",为classpath.
class.getResourceAsStream()
不加"/",与当前类同级;加"/",为classpath.
ClassLoader.getResource()
加不加都是classpath.
ClassLoader.getResourceAsStream()
加不加都是classpath.
|--就目前的规律,getResource()和getResourceAsStream()规则是一样的.(底层system.getxxx待深究...)
||--class:"/"敏感;
classloader:"/"不敏感;
ServletContext.getxxx:强制"/"

|--[jsp][详解189]
source.jsp中:
|--不以"/"开头,表示相对于当前source.jsp的路径
<jsp:forward page="dirinner/target.jsp">
|--以"/"开头,表示采用绝对路径
<jsp:forward page="/diroutter/dirinner/target.jsp">

[配置文件中的路径总结]
要记得:
服务器是知道自己当前的应用在什么目录的,所以不必提供该信息.
浏览器只知道ip:port;

jsp分两半看待
脚本(在浏览器是没有脚本的,全得翻译好成html送过去):翻译时用到的都应该是以服务器的角度.
模板(html,js:js本身就是html的一部分,翻译好后会发过去的):在浏览器里必须知道appname.
但是,"嵌入"在浏览器中的src等,因为请求道该页面就表示你获取到了网址"url",该"url"以及更提供了足够的信息,于是可用相对路径,比如img和js的src
[/]	网页中加不加斜杠
|--	参考 Linux 规则:
linux的绝对路径是指从根目录说起的. 例如 /dev/somedir/..
而相对路径则是从当前目录说起: 即 ./
有4个相对路径的表示方法:
当前目录 .
父目录 ..
某用户的根目录 ~user
自己的根目录 ~
|--	<a/>的"href",
1.	加"/"表示根目录,即服务器根目录,"localhost:8080"目录;该"/"可以看成"8080"后面那条斜杠;
2.	不加"/",表示相对路径,网页是可以从"url"获取当前路径的,就是最后一个"/"前的目录名.该斜杠可看成最后一条"/".加"./"应该也是一样的.
|--	总结:先加斜杠,再加相对于谁的路径;加空为"根目录",加"."为当前,加".."为父;"./"可省.
|--	记住:"${pageContext.request.contextPath}"开头是带斜杠的.
|--[File]
File file = new File("./a.png");
file.getAbsolutePath() = "D:\文档\WorkSpace_MyEclipse_2014\GeneralTest\.\a.png"

File file = new File("a.png");
file.getAbsolutePath() = "D:\文档\WorkSpace_MyEclipse_2014\GeneralTest\a.png"

File file = new File("/a.png");
file.getAbsolutePath() = "D:\a.png"

|--	[转发-易错点]使用转发的时候, Html 页面中的链接地址是相对于"浏览器URL"显示的网址的, 而不是本页面文件在服务器中的地址. 因此在jsp文件中调用css等外部文件时, 写相对于本jsp的网址很可能出错. 在 Struts 中大量使用到转发, 应予以注意!
[举例]:比如jsp在"webroot/jsp/index.jsp", 而URL显示"ip:port/webapp/goAction", 如果页面中引用了文件:
<link rel="stylesheet" type="text/css" href="../css/prettyprint.css" />
实际上会去"ip:port/css/prettyprint.css", 甚至缺少了webapp名称,无法访问到该资源.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: