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