使用Java命令行编译和打包jar
背景:
原先测试一个OCR识别的接口为了方便调用,写了一个main方法的java类,打成了jar包,在windows环境下用bat脚本调用。bat脚本中也就是利用java -jar去掉用,然后利用main方法的args数组参数动态传参,最后记一下输出和错误。
java -jar testocr.jar param1 param2 param3 http://127.0.0.1/cxfServerX/ 1>>work.log 2>>err.txt
今天由于接口变动,这个main方法中的一个地方需要修改,也就是这个jar包需要重新打,最开始这个jar包是用myeclipse直接打的,并且在jar包里也保留了java源文件,总共就一个java文件,其他都是一些依赖的jar包。因为文件数量不多也不复杂,所以干脆直接在cmd下用命令编译打包。
使用JAVAC编译:
-
找到上次打好的jar包testocr.jar,复制一下留作备份,然后解压成目录testocr
目录结构:
testocr -com/ // 存放源码文件 com/xxx/xxx.java -jar/ // 里面是所有依赖的jar包文件 -META-INF/ // 里面有MANIFEST.MF文件,描述jar文件所依赖的文件 .classpath // 描述项目引用的jar包 .project // 项目描述文件
-
先修改源码文件,进入到com/test/目录下,修改TestOCR.java文件
-
修改后要对源文件进行编译,先随便试一下。
# 刚开始没有指定编码时报错了中文乱码,这里就先加上了,其中 -encoding "UTF-8" 和-encoding UTF-8 加不加引号都可以 base$ javac -encoding UTF-8 TestOCR.java TestOCR.java:6: 错误: 程序包net.sf.json不存在 import net.sf.json.JSONObject; ^ TestOCR.java:8: 错误: 程序包org.apache.http不存在 import org.apache.http.HttpEntity; ^ TestOCR.java:9: 错误: 程序包org.apache.http.client.methods不存在 import org.apache.http.client.methods.CloseableHttpResponse; ^ TestOCR.java:10: 错误: 程序包org.apache.http.client.methods不存在 import org.apache.http.client.methods.HttpPost; ^ TestOCR.java:11: 错误: 程序包org.apache.http.entity不存在 import org.apache.http.entity.StringEntity; ... # 这个报错是意料之中的,因为TestOCR.java中import了很多三方jar包,需要指定一下类路径
-
指定依赖的三方jar包类路径后执行
# 首先就是javac -cp 和 javac -classpath是一样的,直接输入javac在帮助命令中也可以看出来 ... -classpath <路径> 指定查找用户类文件和注释处理程序的位置 -cp <路径> 指定查找用户类文件和注释处理程序的位置 ... # 这里我用相对路径,TestOCR.java依赖的jar包都放在这个jar目录下 base$ javac -encoding UTF-8 -cp ../../jar/ TestOCR.java TestOCR.java:6: 错误: 程序包net.sf.json不存在 import net.sf.json.JSONObject; ^ TestOCR.java:8: 错误: 程序包org.apache.http不存在 ... # 结果还是报错 很明显还是找不到依赖包 但是路径确实是正确的 # 然后我去掉最后一个/ 执行 base$ javac -encoding UTF-8 -cp ../../jar TestOCR.java # 很遗憾还是报错,然后我又尝试一下使用*去匹配所有.jar后缀的文件 base$ javac -encoding UTF-8 -cp ../../jar/*.jar TestOCR.java javac: 无效的标记: ../../jar/XmlSchema-1.4.3.jar 用法: javac <options> <source files> -help 用于列出可能的选项 # 这里感觉好像是javac直接怼到 依赖的jar包上去了,所以直接报错了,换一种写法 base$ javac -encoding UTF-8 -cp ../../jar/* TestOCR.java javac: 无效的标记: ../../jar/XmlSchema-1.4.3.jar 用法: javac <options> <source files> -help 用于列出可能的选项 # 加个引号试试 base$ javac -encoding UTF-8 -cp "../../jar/*" TestOCR.java # 编译正确,在TestOCR.java文件的相同目录下出现了TestOCR.class文件 # 可以使用-d指定class文件的生成路径,并且会按java文件的 package包名生成文件目录结构 base$ javac -encoding UTF-8 -cp "../../jar/*" -d . TestOCR.java # 加上-d . 后,就在当前目录下生成了TestOCR.java的package包名结构的文件目录,并将TestOCR.class放在此目录下
打JAR包
-
因为jar包刚开始是从Myeclipse中打好的,所以MANIFEST.MF都是有的,当时也是手动写的,按照格式指定一下主类和依赖的包路径,记得需要注意几点:
-
这个Class-Path后面的路径名称太多了话不能写到一行,写很多到一行会报错行太长,直接换行写就行,但是换行时从第二行开始要先敲两个空格,后面再换行也要先有两个空格。
-
key: value,key之后跟冒号再跟空格,这点跟yaml很像,还有Class-Path中的多个jar包路径之间也是用空格分隔的。
-
Class-Path写完之后最后一定要有一个空行。
-
注意Class-Path的路径和生成好的Jar包的路径,这里我写的相对路径,相当于打好的jar包和lib在同一目录下,这样才能找到依赖的jar包路径。
testocr -testocr.jar // 打好的jar包 -lib/ // 里面是所有依赖的jar包文件
- MANIFEST.MF文件,最后两个参数是包密封用的,详情参考大佬的博客:META-INF/MANIFEST.MF文件中Sealed头的作用与含义
Manifest-Version: 1.0 Main-Class: com.test.TestOCR Class-Path: lib/commons-beanutils.jar lib/commons-collections-3.2.jar lib/commons-httpclient.jar lib/commons-io-2.2.jar lib/commons-lang-2.4.jar lib/commons-logging.jar Name: com/test/ Sealed: true
-
-
使用jar命令进行打包
# 看一下参数 base$ jar 用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ... 选项: -c 创建新档案 -t 列出档案目录 -x 从档案中提取指定的 (或所有) 文件 -u 更新现有档案 -v 在标准输出中生成详细输出 -f 指定档案文件名 -m 包含指定清单文件中的清单信息 -n 创建新档案后执行 Pack200 规范化 -e 为捆绑到可执行 jar 文件的独立应用程序 指定应用程序入口点 -0 仅存储; 不使用任何 ZIP 压缩 -P 保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件 -M 不创建条目的清单文件 -i 为指定的 jar 文件生成索引信息 -C 更改为指定的目录并包含以下文件 如果任何文件为目录, 则对其进行递归处理。 清单文件名, 档案文件名和入口点名称的指定顺序 与 'm', 'f' 和 'e' 标记的指定顺序相同。 示例 1: 将两个类文件归档到一个名为 classes.jar 的档案中: jar cvf classes.jar Foo.class Bar.class 示例 2: 使用现有的清单文件 'mymanifest' 并 将 foo/ 目录中的所有文件归档到 'classes.jar' 中: jar cvfm classes.jar mymanifest -C foo/ . # 使用描述清单将当前目录下所有文件打包成 testocr.jar base$ jar -cvfm testocr.jar META-INF/MANIFEST.MF * 已添加清单 正在忽略条目META-INF/ 正在忽略条目META-INF/MANIFEST.MF 正在添加: META-INF/REFACTORINGS.XML(输入 = 64) (输出 = 52)(压缩了 18%) 正在添加: com/(输入 = 0) (输出 = 0)(存储了 0%) 正在添加: com/test/(输入 = 0) (输出 = 0)(存储了 0%) 正在添加: com/test/TestOCR.java(输入 = 4309) (输出 = 1816)(压缩了 57%) 正在添加: com/test/TestOCR.class(输入 = 3420) (输出 = 1841)(压缩了 46%) 正在添加: jar/(输入 = 0) (输出 = 0)(存储了 0%) ... # 使用 jar -tf testocr.jar 查看一下jar包内的文件 base$ jar -tf testocr.jar META-INF/ META-INF/MANIFEST.MF META-INF/REFACTORINGS.XML com/ com/test/ com/test/TestOCR.java com/test/TestOCR.class jar/ jar/spring-context-2.0.8.jar jar/json.jar ... # 检查后没有问题 可以使用了,最后运行就java -jar testocr.jar即可,已经用bat脚本写好了交互,完成
总结:
使用这些命令处理一些简单的类还是很方便的,对于复杂的还是使用开发工具去搞比较合适。
-