昨天开始学习Java Web中的Servlet,学到用IntelliJ IDEA创建Java Web项目时,跟着课程上老师的步骤一步步做,却发现运行时Servlet找不到。坑爹的是,练习建项目时,一模一样的操作过程,走了几遍,有的没问题,有的有问题。
创建项目的过程:
- 新建Maven项目,不使用任何Archetype
- 创建目录:项目根目录/src/main/webapp/
- 在Project Structure的Modules中添加Web
- 将Deployment Descriptors和Web Resource Directories的项都做到项目根目录/src/main/webapp/
- 点击自动提示的“Create Artifact”自动创建一个Artifact(类型:Web Application: Exploded)
- 在Run/Debug Configuration中添加Tomcat Server,其中添加上面的Artifact,能正常启动
- 在项目根目录/src/main/webapp/添加HTML文件、JSP文件等,都能正常访问
- 在项目根目录/src/main/中编写Servlet,不能访问,报ClassNotFoundException
观察Java Web的输出目录项目根目录/out/artifacts/xxx_Web_exploded/可以发现,WEB-INF/目录下根本没有classes/目录,当然找不到Servlet。此外,对比没出问题的项目,可以发现连Maven的输出目录项目根目录/target/都没有。手动mvn compile,此时target/目录才会生成,但即使在此基础上再做rebuild Artifact,其中的.class文件也不会复制到WEB-INF/中。
所以问题的直接原因很明了,就是IDE根本就没有做Servlet的编译和复制。
在IDE中的操作过程都是一样的,所以盯着界面找了半天也没找到什么不同。最终,通过使用VSCode直接一一diff正常项目和问题项目文件的办法,找到了出问题的地方——IDEA项目的.iml文件。
在项目的.iml文件中,有这么一段:
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
将这一段删除,再重启Tomcat,发现target/目录和WEB-INF/classes/目录马上就都有了,此时程序运行就一切正常了。
我没去专门查资料搞清这一段到底是什么含义,具体是什么机制导致了上面的现象,有知道的朋友可以留言说一下。