大家都知道,对于springboot的app,我们都是通过maven构建出war或jar,然后通过java -jar X.war/X.jar的方式来运行项目。在这篇文章中,我们来探讨一下,不同的包文件后缀和打包方式,jsp的文件路径应该如何设置才能正常显示。
这里我们讨论三种情况
1.正常通过maven build成app.war包,即在pom.xml指定<packaging>war</packaging>
2.基于1中build好的war包,强行改名为faker.jar (之所以讨论这种情况,是因为这种case真实存在于我们的项目中,只单纯作为一个研究的case)
3.正常通过maven build成real.jar包,即在pom.xml指定<packaging>jar</packaging>
首先我们先简单捋一下jsp页面的加载流程。对于一个请求,会mapping到对应mvc view的template (比如这里对应的是/a),这个template会根据已经配置好的template base path prefix, (比如这里项目里面配置的是/WEB-INF/jsp), 构建出/WEB-INF/jsp/a.jsp的相对路径,然后通过这个相对路径,去web resources里面遍历匹配是否jsp文件真实存在(具体如何匹配,下面会详细介绍)。如果不存在,最终返回给前端的是404 not found exception。如果存在,会基于这个jsp进行java文件的生成以及class文件的编译,然后解析返回给前端显示。
image.png所以jsp页面正常显示问题的关键在于,如何在上述的三种情况下,保证jsp都可以在web resource里面找到。这里我们先针对第一种情况下介绍一下web resource生成的过程以及jsp路径匹配的过程。
web resource本身是一个List,用来存放文件的路径,包括五种resource,这里我们只需要讨论main resource和jar resource,
org/apache/catalina/webresources/StandardRoot.class
image.png
web resource初始化的大致调用链如下
org/springframework/boot/SpringApplication.class----run()
org/springframework/context/support/AbstractApplicationContext.class----refresh()
org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.class----onRefresh()
org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.class----getWebServer()
org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.class----prepareContext()
可以看到这里开始获取DocumentRoot,具体实现细节会执行三个方法返回具体路径。因为这里我们的命令行是java -jar app.war, 所以判断后缀为.war,返回路径为/Users/hzzou/Downloads/cronus/demo/app.war
image.pngimage.png
然后基于刚才返回的DocumentRoot设置DocBase,为/Users/hzzou/Downloads/cronus/demo/app.war
image.png
设置好了DocBase,开始启动tomcat
image.png
image.png
这里开始涉及到web resource的初始化
image.png
(1)设置main resource
image.png
image.png
image.png
这里需要注意这里的internalPath为“/”,初始化会自动转成“”
image.png
image.png
main resource初始化成功如下
image.png
(2)设置jar resource
获取拥有META-INF/resources的jar
image.png
image.png
jar resource初始化成功如下
image.png
刚才提到的jsp的relative path /WEB-INF/jsp/a.jsp,会遍历web resource,根据base path和internal path构造绝对路径,粗略构造效果等同与base path + internal path + jsp relative path。我们可以看到,对于情况1,是可以在main resource知道到对应jsp页面的。所以我们针对情况1,a.jsp页面只需要放置在/WEB-INF/jsp目录下面即可。
而针对情况2,我们发现在设置DocumentRoot的时候出现不同,getWarFileDocumentRoot 和getExplodedWarFileDocumentRoot 和 getCommonDocumentRoot 都是返回null,导致DocBase为一个temp dir,/var/folders/hn/87t2n4nx7hdbxq1chffy7gpr0000gq/T/tomcat-docbase.8080.11206243289434379479
image.png
image.png
这也直接导致最后的main resource里面构建的是一个dir resource
image.png
image.png
所以对于情况2,我们没有办法适配,因为此时的main resource并不能帮助定位到jsp的具体位置
image.png
而针对情况3,对于main resource的构建如情况2,但是在构建jar resouce的时候出现不同。因为我们知道,构建jar resource的集合是有META-INF/resources的jar,所以本身项目的jar也会被加载进去jar resource里面,具体效果如下
image.png
image.png
image.png
所以对于情况3,我们可以把WEB-INF/jsp/a.jsp放在META-INF/resources下面,也是可以让jsp正常被展示的, 具体如下
image.png结论:
针对情况1,jsp路径为webapp/WEB-INF/jsp/a.jsp
针对情况2,无法适配
针对情况3,jsp路径为jsp路径为META-INF/resources/WEB-INF/jsp/a.jsp
网友评论