起步软件技术论坛
搜索
 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 17506|回复: 37

使用X5生成复杂的word合同模板

  [复制链接]

396

主题

2433

帖子

4863

积分

论坛元老

Rank: 8Rank: 8

积分
4863
QQ
发表于 2015-4-30 17:00:49 | 显示全部楼层 |阅读模式
本帖最后由 67886387 于 2015-5-8 16:28 编辑

首先技术路线是参考网上案例(JAVA + FreeMarker + jacob_1.9),说复杂其实也不复杂,只是在配置XML的时候需要仔细点,所有用到jar和js都在最后的附件中,以自身项目为例做下面步骤:

1,业务流程是在grid列表下点击某条数据生成合同并通过windowDialog组件打开合同详情;
2,创建action,名称为:CreateDoc
  1.         private static Configuration configuration = null;
  2.         private static WordToPDF wordToPDF = null;

  3.         /**
  4.          * 生成word
  5.          * @param fid 主键
  6.          * @param type 模板类型
  7.          * @return
  8.          */
  9.         public static String CreateDoc(String fid, String type) {
  10.                 return getDoc(fid, type);
  11.         }

  12.         //生成模板
  13.         public static String getDoc(String fid, String type) {
  14.                 configuration = new Configuration();
  15.                 configuration.setDefaultEncoding("utf-8");
  16.                 configuration.setClassicCompatible(true);
  17.                 // 要填入模本的数据文件
  18.                 Map<String, Object> dataMap = new HashMap<String, Object>();
  19.                 getData_XF(fid, dataMap);

  20.                 FileSystem fileSystem = FileSystemWrapper.instance();
  21.                 String real = fileSystem.getRealPath("/LandManagerSys/template");
  22.                 File file = new File(real);
  23.                 try {
  24.                         configuration.setDirectoryForTemplateLoading(file);
  25.                 } catch (IOException e2) {
  26.                         e2.printStackTrace();
  27.                 }
  28.                 Template t = null;
  29.                 try {
  30.                         // test.ftl为要装载的模板
  31.                         t = configuration.getTemplate(type + ".ftl");
  32.                 } catch (IOException e) {
  33.                         e.printStackTrace();
  34.                 }
  35.                 String ul = getHome() + "/model/UI/LandManagerSys/doc/" + fid + type + ".doc";
  36.                 System.out.println(ul);
  37.                 File outFile = new File(ul);
  38.                 if (outFile.exists()) {
  39.                         outFile.delete();
  40.                 }
  41.                 Writer out = null;
  42.                 try {
  43.                         out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
  44.                 } catch (FileNotFoundException e1) {
  45.                         e1.printStackTrace();
  46.                 }
  47.                 try {
  48.                         t.process(dataMap, out);
  49.                 } catch (TemplateException e) {
  50.                         e.printStackTrace();
  51.                 } catch (IOException e) {
  52.                         e.printStackTrace();
  53.                 } finally {
  54.                         try {
  55.                                 out.flush();
  56.                                 out.close();
  57.                         } catch (IOException e) {
  58.                                 e.printStackTrace();
  59.                         }
  60.                 }
  61.                 wordToPDF = new WordToPDF();
  62.                 String pdfUrl = getHome() + "/model/UI/LandManagerSys/doc/" + fid + type + ".pdf";
  63.                 wordToPDF.wordToPDF(ul, pdfUrl);
  64.                 return outFile.getName();
  65.         }
  66.         
  67.         /**
  68.          *
  69.          * @param fid
  70.          * @param dataMap
  71.          */
  72.         public static void getData_XF(String fid, Map<String, Object> dataMap) {
  73.                 String oracle = "SELECT JZ_XX.*, TO_CHAR(FSQRCSNY, 'YYYY-MM-DD') AS SQRCSNY , TO_CHAR(FSLRQ, 'YYYY-MM-DD') AS SLRQ , TO_CHAR(FTJRQ, 'YYYY-MM-DD') AS TJRQ , TO_CHAR(FZCSQRQ, 'YYYY-MM-DD') AS ZCSQRQ , TO_CHAR(FCJRQ, 'YYYY-MM-DD') AS CJRQ FROM JZ_XX";
  74.                 String mssql = "SELECT JZ_XX.*,  CONVERT(VARCHAR(10), FSQRCSNY, 23) AS SQRCSNY , CONVERT(VARCHAR(10), FSLRQ, 23) AS SLRQ , CONVERT(VARCHAR(10), FTJRQ, 23) AS TJRQ , CONVERT(VARCHAR(10), FZCSQRQ, 23) AS ZCSQRQ , CONVERT(VARCHAR(10), FCJRQ, 23) AS CJRQ, DateName(year,FZCSQRQ) as NIAN, DateName(month,FZCSQRQ) as YUE, DateName(day,FZCSQRQ) as RI FROM JZ_XX JZ_XX";
  75.                 String mysql = "SELECT JZ_XX.*,  date_format(FSQRCSNY, '%Y-%m-%d') AS SQRCSNY, date_format(FSLRQ, '%Y-%m-%d') AS SLRQ, date_format(FTJRQ, '%Y-%m-%d') AS TJRQ, date_format(FZCSQRQ, '%Y-%m-%d') AS ZCSQRQ, date_format(FCJRQ, '%Y-%m-%d') AS CJRQ, date_format(now(), '%Y') AS NIAN, date_format(now(), '%m') AS YUE, date_format(now(), '%d') AS RI FROM JZ_XX JZ_XX";
  76.                 if (!"".equals(fid)) {
  77.                         oracle += " WHERE JZ_XX.FID='" + fid + "'";
  78.                         mssql += " WHERE JZ_XX.FID='" + fid + "'";
  79.                         mysql += " WHERE JZ_XX.FID='" + fid + "'";
  80.                 }
  81.                 System.out.println(mssql);
  82.                 HashMap<String, String> sqlMap = new HashMap<String, String>();
  83.                 sqlMap.put(SQL.DEFAULT_DB_NAME, mssql);
  84.                 sqlMap.put(DatabaseProduct.ORACLE.name(), oracle);
  85.                 sqlMap.put(DatabaseProduct.MSSQL.name(), mssql);
  86.                 sqlMap.put(DatabaseProduct.KINGBASE.name(), oracle);
  87.                 sqlMap.put(DatabaseProduct.SYBASE.name(), mssql);
  88.                 sqlMap.put(DatabaseProduct.DB2.name(), oracle);
  89.                 sqlMap.put(DatabaseProduct.MYSQL.name(), mysql);
  90.                 Table table = SQL.select(sqlMap, null, "/LandManagerSys/LandDAM/data");        
  91.                 Iterator<Row> rows = table.iterator();
  92.                 Collection<String> list = table.getColumnNames();
  93.                 String[] strArray1 = (String[]) list.toArray(new String[0]);
  94.                 while (rows.hasNext()) {
  95.                         Row row = rows.next();
  96.                         for (int i = 0; i < table.getColumnCount(); i++) {
  97.                                 dataMap.put(strArray1[i], row.getValue(strArray1[i]));
  98.                         }
  99.                 }
  100.         }
  101.         
  102.         //获取服务端安装地址
  103.         public static String getHome() {
  104.                 String home = System.getenv("JUSTEP_HOME");
  105.                 if (home == null) {
  106.                         File fl = new File(ContextHelper.getSessionContext().getSession().getServletContext().getRealPath("/WEB-INF/justep.xml"));
  107.                         if (fl.exists()) {
  108.                                 try {
  109.                                         SAXReader reader = new SAXReader();
  110.                                         Document doc = reader.read(fl);
  111.                                         Element e = doc.getRootElement().element("JUSTEP_HOME");
  112.                                         if (e != null) {
  113.                                                 home = e.getText().trim();
  114.                                         } else {
  115.                                                 home = fl.getParent() + "/../../..";
  116.                                         }
  117.                                 } catch (DocumentException e) {
  118.                                         e.printStackTrace();
  119.                                         throw new UnsupportedOperationException(fl.getPath() + "不是标准的XML!", e);
  120.                                 }
  121.                         } else {
  122.                                 throw new UnsupportedOperationException("没有找到" + fl.getPath());
  123.                         }
  124.                 }
  125.                 try {
  126.                         File f = new File(home);
  127.                         home = f.getCanonicalPath();
  128.                 } catch (IOException e) {
  129.                         throw new RuntimeException("JUSTEP_HOME: “" + home + "“不存在!");
  130.                 }
  131.                 return home;
  132.         }
复制代码

QQ67886387

396

主题

2433

帖子

4863

积分

论坛元老

Rank: 8Rank: 8

积分
4863
QQ
 楼主| 发表于 2015-4-30 17:00:52 | 显示全部楼层
本帖最后由 67886387 于 2015-4-30 16:56 编辑

5,以上就是整个代码的详情,现在具体说一下如何配置word模板,office的word可以另存为XML文件,比如你现在有一份合同,另存为XML文件,最好是另存为word 2003 XML文档,然后用一个支持XML编辑器打开(Firstobject free XML editor
XML模板.png

如图中,${CBHTBM}是FreeMarker使用的标签,其中CBHTBM是关系名称,一楼代码第100行 dataMap.put(strArray1, row.getValue(strArray1));,这个Map的key就是关系名,不太清楚的X5论坛里有,都是现成的,而模板中标签里通过Map的key取的值,这个是一条数据的展示,如果遇到循环输出,参考如图标签 循环标签.png
6,其他说明,附件中有个jacob.dll文件,这个应该放到X5里面jdk目录下,具体放入\jdk\jre\bin下面,服务器端必须安装office2007以上版本,客户端需要有PDF插件Adobe Reader。
7,附效果图
效果图.png 表格循环.png


attachment.zip

853.53 KB, 下载次数: 1750

点评

支持  发表于 2015-10-9 09:49
QQ67886387
回复 支持 1 反对 0

使用道具 举报

396

主题

2433

帖子

4863

积分

论坛元老

Rank: 8Rank: 8

积分
4863
QQ
 楼主| 发表于 2015-5-8 16:55:38 | 显示全部楼层
xiaowang 发表于 2015-5-8 16:26
您好 麻烦再问一下,你1楼 getData_XF(fid, dataMap); 获取业务数据装入Map 没看到你这个方法, 75行开始 ...

getData_XF在第75行(复制的时候复制错了方法,已重新编辑),word另存xml到BIZ你自己的应用下,文件夹你自己定义,1楼代码的第23、24行就是指定你模板的目录,例子中我的应用是LandManagerSys文件夹
QQ67886387
回复 支持 1 反对 0

使用道具 举报

396

主题

2433

帖子

4863

积分

论坛元老

Rank: 8Rank: 8

积分
4863
QQ
 楼主| 发表于 2015-4-30 17:00:50 | 显示全部楼层
继续楼上:
简单的说明,configuration是freemarker里面操作模板的类,第21行中getData_XF方法是获取业务数据装入Map里,从而才能将此Map写入到模板里,具体写入模板方法在第51行;第64行wordToPDF是将生成的word转换成PDF,页面显示的时候就是展示的PDF文件,具体转PDF方法如下:
  1. import java.io.File;

  2. import com.jacob.activeX.ActiveXComponent;
  3. import com.jacob.com.ComThread;
  4. import com.jacob.com.Dispatch;
  5. import com.jacob.com.Variant;

  6. public class WordToPDF {

  7.         static final int wdFormatPDF = 17;// PDF 格式  

  8.         public void wordToPDF(String sfileName, String toFileName) {

  9.                 System.out.println("启动Word...");
  10.                 long start = System.currentTimeMillis();
  11.                 ActiveXComponent app = null;
  12.                 Dispatch doc = null;
  13.                 try {
  14.                         app = new ActiveXComponent("Word.Application");
  15.                         app.setProperty("Visible", new Variant(false));
  16.                         Dispatch docs = app.getProperty("Documents").toDispatch();
  17.                         doc = Dispatch.call(docs, "Open", sfileName).toDispatch();
  18.                         System.out.println("打开文档..." + sfileName);
  19.                         System.out.println("转换文档到PDF..." + toFileName);
  20.                         File tofile = new File(toFileName);
  21.                         if (tofile.exists()) {
  22.                                 tofile.delete();
  23.                         }
  24.                         Dispatch.call(doc, "SaveAs", toFileName, wdFormatPDF);
  25.                         long end = System.currentTimeMillis();
  26.                         System.out.println("转换完成..用时:" + (end - start) + "ms.");

  27.                 } catch (Exception e) {
  28.                         System.out.println("========Error:文档转换失败:" + e.getMessage());
  29.                 } finally {
  30.                         Dispatch.call(doc, "Close", false);
  31.                         System.out.println("关闭文档");
  32.                         if (app != null)
  33.                                 app.invoke("Quit", new Variant[] {});
  34.                 }
  35.                 //如果没有这句话,winword.exe进程将不会关闭
  36.                 ComThread.Release();
  37.         }

  38.         public static void main(String[] args) {
  39.                 WordToPDF d = new WordToPDF();
  40.                 d.wordToPDF("E:\\123.doc", "E:\\123.pdf");
  41.         }

  42. }
复制代码


QQ67886387
回复 支持 反对

使用道具 举报

396

主题

2433

帖子

4863

积分

论坛元老

Rank: 8Rank: 8

积分
4863
QQ
 楼主| 发表于 2015-4-30 17:00:51 | 显示全部楼层
3,页面如何展示PDF,页面中加一个html组件中的div,id为pdf,展示PDF方法是在windowReceiver组件的onReceive事件里,如下:
  1. docView.windowReceiver1Receive = function(event){
  2.         res = event.data.res;//文件名
  3.         name = event.data.name;
  4.         var a = res.split(".");
  5.         var url = window.location.protocol+"//"+ window.location.host + "/x5/UI/LandManagerSys/doc/" + a[0] + ".pdf";
  6.         var success = new PDFObject({url:url}).embed("pdf");
  7. };
复制代码
在word转换为PDF后我把生成的PDF文件放到了UI的某个目录下,具体参考1楼66行代码,js中new PDFObject({url:url}).embed("pdf");的url里访问的PDF路径就是UI目录下的。
当然这个W页面需要引用一个js文件:pdfobject.js
4,整个页面流程事件代码如下,点击一个按钮事件:
  1. mainActivity.trigger3Click = function(event){
  2.         var dataMain = justep.xbl("listData");
  3.         var fid = dataMain.getValue("CBHTBM");
  4.         if(!fid) {
  5.                 return;
  6.         }
  7.         createDoc(fid, "_hts", "农村土地承包合同书");       
  8. };
复制代码
  1. function createDoc(fid, type, name) {
  2.         var actionParam = new justep.Request.ActionParam();
  3.         actionParam.setString("fid", fid);
  4.         actionParam.setString("type", type);
  5.         justep.Request.sendBizRequest2({
  6.                 dataType : "application/json",
  7.                 action : "CreateDoc",
  8.                 parameters : actionParam,
  9.                 callback : function(result) {
  10.                         if (result.state) {
  11.                                 var res = result.response;
  12.                                 getURL(res,name);
  13.                         } else {
  14.                                 throw new Error("调用失败!|" + result.response.message);
  15.                         }
  16.                 }
  17.         });
  18. }
  19. function getURL(res,name) {
  20.         var runner = justep.xbl("windowRunner1");
  21.         runner.setURL("/UI/LandManagerSys/LandQueriesMgr/process/CBHTQuery/docView.w");
  22.         runner.setTitle(name);
  23.         runner.open({
  24.                 res:res,
  25.                 name:name
  26.         });       
  27. }
复制代码




QQ67886387
回复 支持 反对

使用道具 举报

99

主题

317

帖子

880

积分

高级会员

Rank: 4

积分
880
QQ
发表于 2015-5-6 15:36:06 | 显示全部楼层
67886387 发表于 2015-4-30 17:00
5,以上就是整个代码的详情,现在具体说一下如何配置word模板,office的word可以另存为XML文件,比如你现在 ...

我现在也想实现这个功能,麻烦问你你用的是哪个版本? 这种方式要用到X5的文档中心功能吗?
回复 支持 反对

使用道具 举报

33

主题

213

帖子

1158

积分

金牌会员

Rank: 6Rank: 6

积分
1158
QQ
发表于 2015-5-6 15:39:24 来自手机 | 显示全部楼层
这太厉害了
回复 支持 反对

使用道具 举报

396

主题

2433

帖子

4863

积分

论坛元老

Rank: 8Rank: 8

积分
4863
QQ
 楼主| 发表于 2015-5-6 16:03:31 | 显示全部楼层
xiaowang 发表于 2015-5-6 15:36
我现在也想实现这个功能,麻烦问你你用的是哪个版本? 这种方式要用到X5的文档中心功能吗? ...

X5.2.7版本
QQ67886387
回复 支持 反对

使用道具 举报

998

主题

4330

帖子

1万

积分

论坛元老

Rank: 8Rank: 8

积分
10718
QQ
发表于 2015-5-8 12:06:53 | 显示全部楼层
支持
孤舟蓑笠翁,独钓寒江雪。
X5牛刀交流民间第一群:30057529
提供有偿服务,联系WX:18332024
bex5疑难问题解决方案
回复

使用道具 举报

99

主题

317

帖子

880

积分

高级会员

Rank: 4

积分
880
QQ
发表于 2015-5-8 16:26:09 | 显示全部楼层

您好 麻烦再问一下,你1楼 getData_XF(fid, dataMap); 获取业务数据装入Map 没看到你这个方法, 75行开始 getData_ZC()这个方法是做什么呢?还有word另存xml后放在哪个目录下?谢谢
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|X3技术论坛|Justep Inc.    

GMT+8, 2024-4-19 04:39 , Processed in 0.075218 second(s), 27 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表