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

  • 相关阅读:
    [LeetCode] 399. Evaluate Division Java
    图的遍历
    [LeetCode] 332. Reconstruct Itinerary Java
    [LeetCode] 310. Minimum Height Trees Java
    sql like 查询
    递归树
    用SQL语句,删除掉重复项只保留一条
    Exception in thread “main” com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
    如何利用java得到当前的时间和前一天的时间
    Java 字符串用逗号并接
  • 原文地址:https://www.cnblogs.com/gg128/p/9436493.html
Copyright © 2020-2023  润新知