1. File, FileInputStream等路徑問題
@Test
public void testFile1(){
//在src的當前文件夾下
File file = new File("config.properties");
File absoluteFile = file.getAbsoluteFile();
System.out.println(absoluteFile);
System.out.println(file.exists());
}
@Test
public void testFile2(){
//盤符目錄
File file = new File("/config.properties");
File absoluteFile = file.getAbsoluteFile();
System.out.println(absoluteFile);
}
@Test
public void testFile3(){
//絕對路徑
File file = new File("F:\\ide\\PathTest\\config.properties");
File absoluteFile = file.getAbsoluteFile();
System.out.println(absoluteFile);
System.out.println(file.exists());
}
2.class.getResourceAsStream與class.getClassLoader() .getResourceAsStream以及class.getResource
1)基於eclipse
@Test//PathTest的當前目錄(與PathTest同包下)
public void testClassGetResourceAsStream1(){
InputStream is = PathTest.class.getResourceAsStream("config.properties");
System.out.println(is);
}
@Test//src目錄下
public void testClassGetResourceAsStream2(){
InputStream is = PathTest.class.getResourceAsStream("/config.properties");
System.out.println(is);
}
@Test//src目錄下
public void testClassLoaderGetResourceAsStream1(){
InputStream is = PathTest.class.getClassLoader().getResourceAsStream("config.properties");
System.out.println(is);
}
@Test//PathTest的當前目錄
public void testClassGetResourceAsStream12() throws Exception {
URL resource = PathTest.class.getResource("");
System.out.println(resource.getPath());
}
2)基於eclispe的maven
@Test/*在resouces文件夾下,假如在test環境下,那么首先查找test下resouces下相應位置的文件,假如沒有會去main下resources
下尋找相應位置的文件,但是在main環境下只能在main的resources中尋找相應位置的文件,eclispe與idea都有這個特點(maven自身的特點)*/ public void testClassGetResourceAsStream() throws Exception { InputStream is = PathTest.class.getResourceAsStream("/config.properties"); System.out.println(is); } @Test /*在resouces文件夾下,假如在test環境下,那么首先查找test下resouces下相應位置的文件,假如沒有會去main下resources
下尋找相應位置的文件,但是在main環境下只能在main的resources中尋找相應位置的文件,在eclispe與idea下一樣,eclispe與idea都有這個特點(maven自身的特點)*/ public void testClassLoaderGetResourceAsStream() throws Exception { InputStream is = PathTest.class.getClassLoader().getResourceAsStream("config.properties"); System.out.println(is); } @Test//PathTest的當前目錄 public void testClassGetResource() throws Exception { URL resource = PathTest.class.getResource(""); System.out.println(resource.getPath()); }
3)總結(實質原因)
a)源碼分析
/*由以下可以得出,class.getResourceAsStream是經過處理后(假如沒有/,就會加上class的全類名,所以在同包下),
然后通過class.getClassLoader() .getResourceAsStream相同的處理*/ private String resolveName(String name) { if (name == null) { return name; } if (!name.startsWith("/")) { Class<?> c = this; while (c.isArray()) { c = c.getComponentType(); } String baseName = c.getName(); int index = baseName.lastIndexOf('.'); if (index != -1) { name = baseName.substring(0, index).replace('.', '/') +"/"+name; } } else { name = name.substring(1); } return name; }
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
public InputStream getResourceAsStream(String name) {
URL url = getResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}
b)結論:
<i> class.getResourceAsStream的實際路徑為:解析后的根目錄(eclipse(bin(默認)),idea略不同(默認為out/production/project名稱),eclipse基於maven的目錄為classes目錄,本質是java與javac的關系,運行的是解析后的文件)加上經過上述源碼處理后的name,就是我們的實際地址;
<ii>class.getClassLoader() .getResourceAsStream的實際路徑為:解析后的根目錄+我們填入的path;
3.eclipse/idea/maven的java路徑與javac
1)eclipse(可以自己設置)

備注:src下的java文件解析成class文件保存在bin目錄相應的位置下,其他文件不會解析直接放入bin目錄相應的位置下
2)基於eclipse的maven的java路徑與javac

maven的文件結構

備注:
main下的java文件夾中文件解析成class文件放入classes目錄相應的位置下,其他文件不會放入classes目錄;main下的resources文件中文件不會解析直接放入classes目錄相應的位置下;
test下的java文件夾中文件解析成class文件放入test-classes目錄相應的位置下,其他文件不會放入test-classes目錄;test下的resources文件中文件不會解析直接放入test-classes目錄相應的位置下;
3)idea的java路徑與javac


備注:sources對應eclispe的main的java,tests對應eclispe的test的java,resources對應eclispe的main的resources,test resources對應eclispe的test的resources,其它一致
4.web中的路徑問題
1)req.getRequestDispatcher("/index").forward(req, resp)帶‘/’與不帶“/”的區別
a)源碼分析
public RequestDispatcher getRequestDispatcher(String path) {
Context context = this.getContext();
if (context == null) {
return null;
} else if (path == null) {
return null;
} else if (path.startsWith("/")) {
return context.getServletContext().getRequestDispatcher(path);//帶/
} else {//不帶/
String servletPath = (String)this.getAttribute("javax.servlet.include.servlet_path");
if (servletPath == null) {
servletPath = this.getServletPath();
}
String pathInfo = this.getPathInfo();
String requestPath = null;
if (pathInfo == null) {
requestPath = servletPath;
} else {
requestPath = servletPath + pathInfo;
}
int pos = requestPath.lastIndexOf(47);//以下是對相對路徑進行處理,處理成與/一致
String relative = null;
if (context.getDispatchersUseEncodedPaths()) {
if (pos >= 0) {
relative = URLEncoder.DEFAULT.encode(requestPath.substring(0, pos + 1), StandardCharsets.UTF_8) + path;
} else {
relative = URLEncoder.DEFAULT.encode(requestPath, StandardCharsets.UTF_8) + path;
}
} else if (pos >= 0) {
relative = requestPath.substring(0, pos + 1) + path;
} else {
relative = requestPath + path;
}
return context.getServletContext().getRequestDispatcher(relative);//交給帶/的處理
}
}
if (this.getContext().getDispatchersUseEncodedPaths()) {
String decodedPath;
try {
decodedPath = URLDecoder.decode(normalizedPath, "UTF-8");
} catch (UnsupportedEncodingException var14) {
return null;
}
normalizedPath = RequestUtil.normalize(decodedPath);
if (!decodedPath.equals(normalizedPath)) {
this.getContext().getLogger().warn(sm.getString("applicationContext.illegalDispatchPath", new Object[]{path}), new IllegalArgumentException());
return null;
}
uri = URLEncoder.DEFAULT.encode(this.getContextPath(), StandardCharsets.UTF_8) + uri;//getContextPath+uri(path)
} else {
uri = URLEncoder.DEFAULT.encode(this.getContextPath() + uri, StandardCharsets.UTF_8);//getContextPath+uri(path)
}
b)總結:由以上可知,不論是帶/還是不帶/,最后還是轉換成帶/處理,轉換成getContextPath+uri(path),一般我們都是使用絕對路徑,不使用相對路徑,防止相對路徑轉換后不是我們需要的路徑,eclispe的/默認表示當前項目的根目錄,idea默認是代表站點目錄

備注:需要進入tomcat源碼,需要導入如下依賴
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.1</version>
<scope>provided</scope>
</dependency>
2)response.sendRedirect(path)帶/與不帶/的區別
路徑處理源碼基本和上述類似,但是response.sendRedirect(path)帶/表示站點目錄(主機地址:例如localhost:8080)
3)@WebServlet("/login")等路徑
必須帶/表示getRealPath(path),不帶會拋出異常,/與/*的區別,/不會攔截jsp頁面,/*會攔截所有頁面
5. tomcat的路徑問題
當使用Tomcat作為Web服務器,項目一般部署在Tomcat下的webapps的目錄下。具體來說主要用兩種部署的路徑:
方式1:將web項目中的webRoot下的文件直接拷貝到webapps/ROOT下(刪除ROOT下的原有文件),request.getContextPath()的返回值為空(即:"",中間無空格,注意區分null)。
方式2:在Tomcat下的webapps中創建以項目名稱命名(當然也可以用其他的名稱)的文件夾,並將webRoot下的文件直接拷貝到該文件夾下,其返回值為:/創建的文件夾的名稱。
總結:所以在IntelliJ IDEA中的request.getContextPath()在沒有設置Application Context的時候request.getContextPath()的返回值為空(即:"",中間無空格,注意區分null)。
6.getContextpath的問題
getContextpath在IntelliJ IDEA中盡量的少用,加在IntelliJ IDEA中沒有設置Application Context的時候那么沒什么問題,假如設置了之后會造成Application Context的時候的名稱重復,在eclispe中並沒有這個問題,所以在web環境下我們需要建立文件夾,不要使用getContextpath,否則會出現路徑可能與你的需要的路徑不匹配。
