2016-09-29 111 views
0

我想從我的Java-App中的MS-Word模板中打開一個新文檔,但只能編輯模板本身。從模板創建新文檔

這是我的情況: 我的jar文件裏面是一個單詞模板,它被複制到用戶指定的位置,所以他/她可以編輯它。之後,應用程序可以打開這個經過編輯的模板,將數據插入並用文字打開。這一切都很好(使用Apache-POI),但最後一步並不完全是我想要的。

通常,雙擊Word模板時,Word將打開一個新文檔(標題爲Document1),該文檔尚未保存在任何地方。在我的情況下,Word打開要編輯的文字模板(標題爲blablaMyTemplate),意思是已經保存的文檔應該從哪個模板創建。我如何設法使用Java從模板中打開新創建的文檔?

這是我的代碼(try/catch語句和流收盤略):

File bbb = new File(new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile().getParentFile().getAbsolutePath() + "/blablaMyTemplate.dotx"); 
    if (!bbb.exists()) { //copy file to outside of jar for user editing 
     Files.copy(Buchungsbegleitblatt.class.getResourceAsStream("bbb.dotx"), bbb.toPath(), StandardCopyOption.REPLACE_EXISTING); 
    } 
    File tmp = File.createTempFile("bbb", ".dotx"); //create tmp file to insert data 
    InputStream in = new FileInputStream(bbb); 
    OutputStream out = new FileOutputStream(tmp); 
    XWPFDocument document = new XWPFDocument(in); 
    //here, some data is filled into the document using Apache-POI (omitted, because it works fine) 
    document.write(out); 
    if (Desktop.isDesktopSupported()) { 
     Desktop.getDesktop().open(tmp); //this opens the template for editing, it does not create a new doc from template 
    } 

問題在於最後一行中,但我不知道還有什麼我可以打電話給在這裏。

爲了使它更清晰一點,這裏的上下文菜單中我得到的模板文件的圖像,什麼是應該發生的:

context menu on template

回答

2

你已經完全描述了這個問題。 Desktop.open將完全按照它所說的去做。它將爲分配給文件類型的被調用應用程序執行open事件。

你需要的是執行new事件。這可以使用startup command-line switches to start WordWord中實現。

在鏈接的知識基礎入門,你可以找到:

...

/ttemplate_name Starts Word with a new document based on a template other than the Normal template.

...

要做到這一點與Java要麼Runtime.getRuntime().execProcessBuilder可以使用。對於這兩種情況,我都會建議先啓動命令解釋程序CMD作爲shell,然後使用start命令啓動應用程序。所以我們避免了需要知道應用程序的確切路徑。

例子:

import java.io.*; 

class RuntimeExec { 
    public static void main(String[] args) { 
     try { 
     // Execute a command as a single line 
     File f = new File("C:/Users/axel/Documents/The Template.dotx"); 
     System.out.println(f.getAbsolutePath()); 
     String cmd = "cmd /C start winword.exe /t\"" + f.getAbsolutePath() + "\""; 
     Process child = Runtime.getRuntime().exec(cmd); 

     } catch (IOException e) { 
     e.printStackTrace(); 
     } 

    } 
} 

class UseProcessBuilder { 
    public static void main(String[] args) { 
     try { 
     //use ProcessBuilder to have more control 
     File f = new File("C:/Users/axel/Documents/The Template.dotx"); 
     System.out.println(f.getAbsolutePath()); 
     String application = "winword.exe"; 
     String switchNewFromTemplate = "/t"; 
     String file = f.getAbsolutePath(); 
     ProcessBuilder pb = new ProcessBuilder("cmd", "/C", "start", application, switchNewFromTemplate+file); 
     Process process = pb.start(); 

     } catch (IOException e) { 
     e.printStackTrace(); 
     } 
    } 
} 

有一種可能性,沒有明確啓動winword應用。該start命令有根據給定文件的擴展名,如果我們給一個空字符串""作爲應用程序名稱進行默​​認操作的功能:

start "" "The name of the file.ext"

例子:

start "" "The name of the file.dotx"

這將在winword應用程序中執行默認操作new,該應用程序與註冊表數據庫中的dotx擴展名相關。

所以:

class RuntimeExec { 
    public static void main(String[] args) { 
     try { 
     // Execute a command as a single line 
     File f = new File("C:/Users/Axel Richter/Documents/The Template.dotx"); 
     System.out.println(f.getAbsolutePath()); 
     String cmd = "cmd /C start \"\" \"" + f.getAbsolutePath() + "\""; 
     Process child = Runtime.getRuntime().exec(cmd); 

     InputStream in = child.getErrorStream(); 
     int c; 
     while ((c = in.read()) != -1) { 
      System.out.print((char)c); 
     } 
     in.close(); 

     } catch (IOException e) { 
     e.printStackTrace(); 
     } 

    } 
} 

class UseProcessBuilder { 
    public static void main(String[] args) { 
     try { 
     //use ProcessBuilder to have more control 
     File f = new File("C:/Users/Axel Richter/Documents/The Template.dotx"); 
     System.out.println(f.getAbsolutePath()); 
     String file = f.getAbsolutePath(); 
     ProcessBuilder pb = new ProcessBuilder("cmd", "/C", "start", "\"\"", file); 
     Process process = pb.start(); 

     InputStream in = process.getErrorStream(); 
     int c; 
     while ((c = in.read()) != -1) { 
      System.out.print((char)c); 
     } 
     in.close(); 

     } catch (IOException e) { 
     e.printStackTrace(); 
     } 
    } 
} 
+0

這個工程,非常感謝!我只是有一個輕微的後續問題:有沒有辦法檢測winword.exe是否真的存在?如果沒有,顯然會出現一個錯誤(「找不到windord.exe」,或者其他東西),但是對於我能夠產生的任何錯誤(例如:訪問被拒絕),該過程返回'1',所以我不能只在那個... – user2336377

+0

目的是什麼?避免Windows錯誤消息?這是不可能的。爲此,我們將不得不在**之前檢查整個Windows系統是否安裝應用程序,我們嘗試啓動它。否則,'ProcessBuilder'可以將錯誤流與輸出流一起重定向到一個文件。或者你可以使用'process.getErrorStream();'從Process獲得錯誤流並從中讀取。 –

+0

他們的目標是如下所述:檢查MSWord是否已正確安裝,如果是,請使用「ProcessBuilder」從模板啓動一個新文檔,否則從臨時文件夾中的模板中創建一個保存的文檔並打開它經常使用'Desktop.open(...)'(例如使用LibreOffice或用戶安裝的任何軟件)。 我會玩弄一下,看看我可以用'process.getErrorStream();'來管理什麼。再次感謝你的幫助。 – user2336377

0

的一種方式做,這是開始在模板上進行處理,以便Windows將處理該開幕並使用默認意圖。自從我碰到Java之後已經有一段時間了,但是如果它像C#一樣,它會像new Process(tmp).Start()一樣。

雖然,我不太確定這是不是你要找的東西。

+0

那正是最後一行做什麼......它調用本機操作系統(在這種情況下於Windows)打開指定的文件。請參閱此處:https://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#open-java.io.File- – user2336377

+0

它的確有這種聲音。它也可能會跳過意圖部分。值得嘗試'進程'IMO。 – Chris

+0

我從來沒有用C#做過多的工作,但我不認爲Java的'Process'和C#是一樣的。至少我不知道如何將文件傳遞給它,並像你說的那樣啓動它。^^ – user2336377