IntelliJ IDEA作为一款优秀的集成开发环境,为Java程序的开发带来了极大的便利,从Eclipse切换到IDEA也有一段时间了,期间一直在开发Web应用,IDEA强大的代码补完和索引功能让我总是能够感慨其强大的能力,虽然其间也曾因为因为不熟悉使用Artifacts打war包的问题遇到了小小的挫折,但是这些都没有影响到我自认为已经成功适应IDEA的自评。直到昨天……
上午10:30,主任办公室。
主任:小M,我这里有个XX学校过来做本科毕业设计的学生,我想让他跟你用MQTT做下移动节点间发布订阅的试验。学生没什么经验,你先去做个发布订阅的最基本的例子给他做参考,这是他邮箱,记得还要写个文档给他。
我:好嘞,小Case,下午下班前给他发过去。
离开主任办公室,我心里窃喜,前几天刚好把这部分功能做完,只要把核心的收发代码剥离出来就可以了,不费力还能帮主任搞定这件事,对于我一个新入职的人而言,可以开心一天了。
下午1:30,收发功能已经搞完,为了让学生用起来方便些,还特意给他做了个简单的GUI界面,测试通过,使用文档也写完了,只要把这两个客户端打包这件事情就可以向主任交差了。IDEA木有像Eclipse那样的打包导出功能,要建Artifacts来生成,这我懂,之前搞过war的导出,已经不会再有问题了。
打开菜单File>>Project Structure... 可以看到工程组织结构的对话框。按照下图所示,在Artifacts标签页中点选+按钮在弹出菜单中选择JAR>>From modules with dependencies..。

之后会弹出JAR类型Artifacts的编辑对话框,如下图。分别选定需要打包的Module和相应的主类后,考虑依赖库的打包模式,IDEA提供了两种模式,一种是解压依赖库的Jar包后封装斤目标Jar。另一种是通过在manifest.mf文件中指定class-path的方式。为了便于jar包的移交,我选择了解压的模式。同时系统会默认在工程的源代码目录下的特定位置生成manifest.mf文件。

点击OK后,可以看到在工程结构中出如下图所示的Artifest。

在菜单中选择Build>>Build Artifests..,可以生成jar包。但是当我通过终端运行jar包时,意外地发现终端提示没有主清单属性。

解压生成的jar包后,可以看到jar包内有META-INF/manifest.MF文件,但是当我打开manifest.MF文件后,发现这个文件居然是项目以来的MQTT Paho库的清单,难怪无法运行。

于是我检查了Artifacts的设置,发现在Artifacts的结构中没有META-INF,于是我手动建立了META-INF的目录,并在其中添加了之前系统生成的manifest.MF文件。重新build生成jar包,运行,问题依旧,还是缺少主清单属性。再检查新生成的jar包中的manifest.MF,原来jar包中的manifest.MF被Paho库解压出来的对应文件给覆盖了。这下抓瞎了,只好上网上查资料,尝试了若干种方法后,幸运地在Stack Overflow上发现了类似问题的解答,原来在配置Artifests的对话框中,应该讲manifest.MF文件的输出位置指定到resources目录下,而不能在java目录下。照着试试,在下图所示的环节,我特意修改了manifest.MF的输出路径。

这次生成的Artifact居然自动增加了META-INF路径和manifest.MF文件。

再次build生成jar包,运行后果然出现了正确运行的结果。

之后又尝试将发送端代码导出,这次意外地发现Artifact中没有自动增加META-INF目录,于是我手动建立了相应的结构,build生成的jar包同样可以正常运行。
希望我的这次经历能够让IDEA的新手们少走些弯路。
在网上查资料时,发现还有依赖库签名等问题导致的导出错误,以后遇上了在补充解决方案。最后感慨一句,工具各有优劣,IDEA千般好,在这个jar包导出的功能上,却让我怀念Eclipse的好。
最后附上StackOverflow上问题的链接:
http://stackoverflow.com/questions/20952713/wrong-manifest-mf-in-intellij-idea-created-jar




