java中的路徑問題(getResourceAsStream/tomcat/maven/getContextpath)等各種路徑問題


 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,否則會出現路徑可能與你的需要的路徑不匹配。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM