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,否则会出现路径可能与你的需要的路径不匹配。

原文地址:https://www.cnblogs.com/gg128/p/9436493.html