刚开始做开发的时候,对于要路径前是否加斜杠“/”一直比较疑惑,即绝对路径和相对路径问题。最近写了一个demo用来测试这个问题,对这个问题做了一个总结。
这里先贴上项目的结构,方便能看到各资源的实际位置。
下面是web.xml的配置,主要是各个servlet的资源路径
pathDemoApp
index.html
index.jsp
Demo1
com.lk.demo.Demo1
Demo1
/demo1
Demo2
com.lk.demo.Demo2
Demo2
/demo2
Demo3
com.lk.demo.Demo3
Demo3
/test/demo3
Demo4
com.lk.demo.Demo4
Demo4
/demo4
Demo5
com.lk.demo.Demo5
Demo5
/test/demo5
Demo6
com.lk.demo.Demo6
Demo6
/test/demo6
需要强调,路径的问题要区别开是“服务器(或者说servlet处理的路径)”还是“客户端(即浏览器要发送的请求)”。
1、先说“客户端”:
1.1 HTML页面的请求。
下面的代码是在HTML页面中,浏览器请求图片资源的情况。
test1.html
Insert title here
结果如下图所示,只有第一个图片请求成功。
1.2 Response的重定向。
response.sendRedirect(path);
虽然response重定向资源是在servlet代码中实现的,但是,是将要重定向的路径返回给浏览器,让浏览器重新请求,因此,其规律和HTML页面请求资源是一样的,所以这里将重定向归为客户端请求这一类。
代码如下:
Demo3.java
package com.lk.demo;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 该类用于测试Response的重定向
* 将该类的访问路径特别设置为/test/demo3
*/
public class Demo3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我是Demo3");
/*
* 总结:
* response的重定向方法,是将路径返回给浏览器,让浏览器重新请求,因此可以发现,
* 重定向的规律和浏览器在页面中发送请求的规律是一样的。
* “/”表示服务器站点的根路径,这里是 http://localhost:8080/,
* 如果参数路径前不加“/”,则浏览器会将URI的最后一个斜杠后的资源名称替换为参数请求的路径。
*/
response.sendRedirect("/pathDemoApp/demo4");//正确
// response.sendRedirect("pathDemoApp/demo4");//路径为http://localhost:8080/pathDemoApp/test/pathDemoApp/demo4
// response.sendRedirect("/demo4");//错误路径为http://localhost:8080/demo4
// response.sendRedirect("demo4");//错误路径为http://localhost:8080/pathDemoApp/test/demo4
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
HTML中,“/”表示的是服务器站点的根路径,案例中为http://localhost:8080/;
如果不加“/”,则是在当前页面的路径基础上,将请求的URI替换掉最后一个“/”后的资源名称。
2、服务器
2.1 ServletContext.getRealPath()方法获取资源的路径。
ServletContext的getRealPath方法可以获取项目下任何位置资源的路径。
Demo2.java
package com.lk.demo;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 用于测试ServletContext的getRealPath方法的结果
*
*/
public class Demo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* ServletContext的getRealPath方法可以获取项目下任何资源的路径
* 总结:
* 该方法都是从项目根路径(即站点+项目名称)下查找参数传递的资源路径,不论参数前是否有斜杠。
* 然后将参数代表的资源路径拼接到项目根路径之后。
*/
String path1 = getServletContext().getRealPath("pathDemoApp/iamge/pic.jpg");
System.out.println(path1);
// D:\WorkProgramFiles\apache-tomcat-7.0.35\webapps\pathDemoApp\pathDemoApp\iamge\pic.jpg
String path2 = getServletContext().getRealPath("/iamge/pic.jpg");
System.out.println(path2);
// D:\WorkProgramFiles\apache-tomcat-7.0.35\webapps\pathDemoApp\iamge\pic.jpg
String path3 = getServletContext().getRealPath("iamge/pic.jpg");
System.out.println(path3);
// D:\WorkProgramFiles\apache-tomcat-7.0.35\webapps\pathDemoApp\iamge\pic.jpg
String path4 = getServletContext().getRealPath("/pic.jpg");
System.out.println(path4);
// D:\WorkProgramFiles\apache-tomcat-7.0.35\webapps\pathDemoApp\pic.jpg
String path5 = getServletContext().getRealPath("/");
System.out.println(path5);
// D:\WorkProgramFiles\apache-tomcat-7.0.35\webapps\pathDemoApp\
String path6 = getServletContext().getRealPath("");
System.out.println(path6);
// D:\WorkProgramFiles\apache-tomcat-7.0.35\webapps\pathDemoApp
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
该方法都是从项目根路径(即站点+项目名称)下查找参数传递的资源路径,不论参数前是否有斜杠“/”, 然后将参数代表的资源路径拼接到项目根路径之后。
2.2 Request的转发请求。
request.getRequestDispatcher(path).forward(request, response);
Demo5.java
package com.lk.demo;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 用于测试Request的转发
* 将该类的访问路径特别设置为/test/demo5
*/
public class Demo5 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 总结:
* 经过测试,可以发现
* “/”表示项目的根路径,这里是 http://localhost:8080/pathDemoApp/,
* 如果参数路径前不加“/”,则会将当前资源的请求路径中,最后一个斜杠后的资源名称替换为参数请求的路径。
*/
System.out.println("我是Demo5");
// String path = "/pathDemoApp/test/demo6";//错误404:/pathDemoApp/pathDemoApp/test/demo6
// String path = "pathDemoApp/test/demo6";//错误404:/pathDemoApp/test/pathDemoApp/test/demo6
String path = "/test/demo6";//正确
// String path = "test/demo6";//错误404:/pathDemoApp/test/test/demo6
request.getRequestDispatcher(path).forward(request, response);
System.out.println("又回到了Demo5");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
该方法中,“/”表示项目的根路径,这里是 http://localhost:8080/pathDemoApp/;
如果参数路径前不加“/”,则会将当前资源的请求路径中,最后一个斜杠后的资源名称替换为参数请求的路径,不加“/”类似于重定向的请求。
总结:
上述的例子是我现在能想到的一些情况。
对于浏览器端,“/”表示的是服务器根站点,即http://localhost:8080/ 。
对于服务器端,“/”表示的是项目的根路径,即http://localhost:8080/pathDemoApp/ 。
总的来说,可以发现,在使用资源路径时,最好使用当前项目的根据路,这样不会出现什么大问题。
对于浏览器请求,比如在jsp的渲染引擎中,我们可以使用request.getContextPath的方法获取当前项目的项目名称,在后面拼接具体资源的路径,以避免在代码中将项目名称写为固定值。