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