首先摆出一个项目的目录结构图吧,由于IDE内部的结构树会隐藏一些中间临时目录,所以换成sublime来展示。
说明:从上到下,.idea和.settings分别是intelliJ和eclipse的相关依赖。build目录是class文件输出路径,这一点默认和eclipse是一样的。out目录是所谓artifact输出路径,即提供给tomcat的web程序目录,具体的web根目录就是下级的web_test_Web_explorded。接着下面就是src和WebContent两个开发目录也很常规。
那么,当你点击运行tomcat时,在默认设置下,就开始做以下事情
- 编译, intelliJ在保存/自动保存后不会做编译,不像eclipse的保存即编译,因此在运行server前会做一次编译。图标是一个含有00 01 10字样的,非常形象。编译后class文件存放在build目录下。
- 创建Artifact目录结构
- 拷贝web根目录(WebContent)下的所有文件到out/artifacts/web_test_Web_explorded/下,即artifact目录下
- 拷贝build下的classes目录到artifact下的WEB-INF下
- 拷贝lib目录下所需的jar包到artifact下的WEB_INF下
- 运行server,运行成功后,如有需要,会自动打开浏览器访问指定url
我们看到整个过程中,有着多次的拷贝行为,这个过程的目的就是为了让编译目录,资源目录和运行目录分开。同时,开发阶段的目录也无法让tomcat识别,比如classes放在了build目录下。所以若我们想要简化这个过程,就是需要减少拷贝的行为次数。
这个简化的结果并不会带来真正意义上的效率提高,因为IDE不会笨到每次拷贝都是全量拷贝。因此,今天我们的行为更像是一种加深web开发理解,熟悉IDE选项配置的过程。
目前tomcat所识别的web根目录为out/artifacts/web_test_Web_explorded/,如果我们能将这个指向换成我们的开发目录WebContent,就可以省下拷贝到artifact的过程;另外,WebContent下没有classes目录,所以我们要将编译输出路径改为WebContent/WEB-INF下,让输出的class文件直接放入WEB-INF下。
进入项目的设置窗口Project Structure(选中项目名按F4)
在Output path输入框中,原始值如下图高亮处。需要修改编译输出路径为:F:/work_spaceweb_test/WebContent/WEB-INF/classes
在Output directory输入框中(忘打高亮了),修改Artifact的输出路径为:F:/work_spaceweb_test/WebContent/
这样一来,我们就不需要额外的build目录和target目录了,这是我们最熟悉的eclipse思维。
下面讲一下一个一般情况下不需要去关注的目录。当tomcat运行起来后,在console会输出log信息,其中有一条是:
引用
Using CATALINA_BASE: "C:\Users\Dev\.IntelliJIdea13\system\tomcat\Unnamed_web_test"
在这个目录下,放置了tomcat配置,如context.xml, server.xml等,这些配置都是intelliJ从tomcat安装目录的conf目录中拷贝过来的,每个项目会有一套。另外,还有catalina log, localhost log等。
这里有一个有趣的现象,Unnamed_web_test,这是这个目录的名字,很明显,Unnamed是默认加上去的prefix,但是我始终没有在idea的图形界面中找到这个设置name的地方,应该是这部分对使用者没有任何修改的意义,所以就不提供界面修改了。但是怀着研究的兴趣,我还是在idea的配置文件中找到了修改的办法。在项目下的.idea/workspace.xml文件中指定了命名,只要修改这里就OK了。但是必须用外部编辑器修改,在idea中修改会被还原。
引用
下一个环节,我要说一下我曾经遇到过的一个意外的事情。开始以为是IntelliJ的Bug,但是后来想通了,这是设计理念上和eclipse的不同造成。
项目中所使用到的jar包,大多数都是需要部署进server的,但有少数jar包只需要编译期或者测试期使用,无需部署进tomcat,甚至有的会与tomcat内置jar起冲突。而在一般的IDE或者maven中,jar包都是可以设置scope的,如provide,test, compile等等,前两者就是属于不需要部署进server的类型。
我的一个项目就遇到一个jar包编译期需要但是运行期绝对不能投进tomcat的情况。这本不是什么难事,如图,这里举例导入两个jar包,scope分别设置了provided和compile,(默认都是compile)。
然后到下图界面,看右侧available elements Panel的列表中出现了一个jar,即scope为compile的,然后右键它选择第一项,移入/WEB-INF/lib。而provided得jar则无法选择,这说明了,provided不会被部署进运行目录(artifact)。这就是前面IntelliJ逻辑步骤中灰色字体的含义。
但是!万万没想到,运行的时候,还是被加了进去!看了artifact目录下,还是出现了这个jar!这难道是IntelliJ的bug吗?百思不得其解。
后来一次机会发现问题的根源在哪里,答案就是:在IntelliJ的设计理念中,lib目录根本不是放在开发目录的WEB-INF下!请参考前面逻辑步骤中蓝色字体的句子,“拷贝根目录下所有文件......”,而我发现这个问题的原因是,是有一次通过IntelliJ创建web项目时,发现lib目录默认放在了src同级下…… 确实很意外
另外一个相关问题,之前一篇文章 IntelliJ使用指南—— 导入Eclipse的Web项目中,谈到available elements部分时说:
引用
因为你会发现你即使不把jar包导入左边,运行时,lib下的所有jar包依然会拷贝到artifact目录下
现在应该清楚了,因为lib目录在WebContent下,因此会一起带过去。所以如果你的项目lib在这之下的话,avaiable elements这部分操作就无需做了,错误提醒也可以无视。
所以,以上就是IntelliJ IDEA在做web - tomcat开发的部署逻辑,以及IDE一些独有的特性。说实话,刚开始配的时候,觉得怎么这么难配,流程太复杂了,好像以前玩eclipse时候没怎么配就可以跑起来。但是现在清楚了配置和实现的关系以后,再回头看两者,就好像脱掉了衣服看到本质一样,其实是一模一样的,底下都需要符合jee的规范,上层么,只是一个界面而已。