2016-09-29 92 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