之前使用Runtime.getRuntime().exec調用外部程序,在Tomcat下會有當前線程一直等待的現象。當時爲了解決這個問題,使用新建線程接收外部程序的輸出信息,詳情請看博客http://blog.csdn.net/accountwcx/article/details/46785437。
後來在網上找到開源的Java調用外部程序類庫Apache Commons Exce,這個類庫提供非阻塞方法調用外部程序。
官方網址 http://commons.apache.org/proper/commons-exec/
maven地址 http://mvnrepository.com/artifact/org.apache.commons/commons-exec/1.3
官方教程 http://commons.apache.org/proper/commons-exec/tutorial.html 官方教程提供的非阻塞方法在1.3版中不適用
Commons Exec對調用外部程序進行了封裝,只需要少量代碼即可實現外部程序調用,如執行命令"AcroRd32.exe /p /h c:\help.pdf"。
- String line = "AcroRd32.exe /p /h c:\help.pdf";
- CommandLine cmdLine = CommandLine.parse(line);
- DefaultExecutor executor = new DefaultExecutor();
- //設置命令執行退出值爲1,如果命令成功執行並且沒有錯誤,則返回1
- executor.setExitValue(1);
- int exitValue = executor.execute(cmdLine);
Commons Exec支持通過添加參數方式構建命令,執行命令"AcroRd32.exe /p /h c:\help.pdf"也可以按如下方法創建。
- CommandLine cmdLine = new CommandLine("AcroRd32.exe");
- cmdLine.addArgument("/p");
- cmdLine.addArgument("/h");
- Map map = new HashMap();
- map.put("file", new File("c:\help.pdf"));
- cmdLine.addArgument("${file}");
- cmdLine.setSubstitutionMap(map);
- DefaultExecutor executor = new DefaultExecutor();
- executor.setExitValue(1);
- int exitValue = executor.execute(cmdLine);
Commons Exec支持設置外部命令執行等待時間,如果超過等等時間則中斷執行。
- CommandLine cmdLine = new CommandLine("AcroRd32.exe");
- cmdLine.addArgument("/p");
- cmdLine.addArgument("/h");
- Map map = new HashMap();
- map.put("file", new File("c:\help.pdf"));
- cmdLine.addArgument("${file}");
- cmdLine.setSubstitutionMap(map);
- DefaultExecutor executor = new DefaultExecutor();
- //創建監控時間60秒,超過60秒則中端執行
- ExecuteWatchdog watchdog = new ExecuteWatchdog(60*1000);
- executor.setWatchdog(watchdog);
- executor.setExitValue(1);
- int exitValue = executor.execute(cmdLine);
上面的執行外部命令都是阻塞式,也就是在執行外部命令時,當前線程是阻塞的。如果不想在執行外部命令的時候,把當前線程阻塞,可以使用DefaultExecuteResultHandler處理外部命令執行的結果,釋放當前線程。
- CommandLine cmdLine = new CommandLine("AcroRd32.exe");
- cmdLine.addArgument("/p");
- cmdLine.addArgument("/h");
- Map map = new HashMap();
- map.put("file", new File("c:\help.pdf"));
- cmdLine.addArgument("${file}");
- cmdLine.setSubstitutionMap(map);
- DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
- DefaultExecutor executor = new DefaultExecutor();
- executor.setExitValue(1);
- executor.execute(cmdLine, resultHandler);
- resultHandler.waitFor();
博客http://blog.csdn.net/accountwcx/article/details/46785437的HtmlToPdf類可以改成如下。
- import java.io.File;
- import org.apache.commons.exec.CommandLine;
- import org.apache.commons.exec.DefaultExecuteResultHandler;
- import org.apache.commons.exec.DefaultExecutor;
- public class HtmlToPdf {
- //wkhtmltopdf在系統中的路徑
- private static final String toPdfTool = "c:\\wkhtmltopdf.exe";
- /**
- * @param srcPath html路徑,可以本地硬盤路徑或者url
- * @param destPath pdf保存路徑
- * @return 轉換成功返回true
- */
- public static boolean convert(String srcPath, String destPath){
- File file = new File(destPath);
- File parent = file.getParentFile();
- //如果pdf保存路徑不存在,則創建路徑
- if(!parent.exists()){
- parent.mkdirs();
- }
- CommandLine cmdLine = new CommandLine(toPdfTool);
- cmdLine.addArgument(srcPath, true);
- cmdLine.addArgument(destPath, true);
- DefaultExecutor executor = new DefaultExecutor();
- //設置執行命令成功的退出值爲1
- executor.setExitValue(1);
- //非阻塞
- DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
- boolean result = true;
- try {
- executor.execute(cmdLine, resultHandler);
- resultHandler.waitFor();
- } catch (Exception e) {
- result = false;
- e.printStackTrace();
- }
- return result;
- }
- }