`

导入word到Fckeditor(java实现)

阅读更多

 

     

     最近项目可以说到达了一个里程碑,借这篇文章把前面的技术进行总结.

      我们的项目是给一个政府单位开发的,后台其实是个CMS系统,客户非要完成一个功能就是把WORD直接导入到Web 编辑器中,我们是用的是Fckeditor2.5版本,这个功能让我很头疼,想了几天没有思路,但是忽然看到了网上的一篇文章 地址如下:
     3楼的哥们把代码贴了上了,不错的思路。
 
    首先用调用COM组件把Word转为html ,然后通过截取重要的源代码 ,最后把这代码放到fck编辑器中,我在做的中间还遇到了很多技术细节问题,下面来看我的实现
   使用jacob 来把word转成html
  
Java代码 复制代码
  1. /**   
  2.     * 把word文件转换成html文件   
  3.     *      
  4.     * @param src   
  5.     *                        原文件   
  6.     * @param out   
  7.     *                        目标文件   
  8.     */    
  9.   public static synchronized void word2Html(String src, String out) {    
  10.     ActiveXComponent app = null;    
  11.     try {    
  12.       app = new ActiveXComponent("Word.Application");// 启动word    
  13.   
  14.       app.setProperty("Visible"new Variant(false));    
  15.   
  16.       // 设置word不可见    
  17.       Dispatch docs = app.getProperty("Documents").toDispatch();    
  18.   
  19.       Dispatch doc = Dispatch.invoke(docs, "Open", Dispatch.Method, new Object[] { src, new Variant(false), new Variant(true) }, new int[1]).   
  20. toDispatch();    
  21.       // 打开word文件 8转为 html 9转为 mht    
  22.       Dispatch.invoke(doc, "SaveAs", Dispatch.Method, new Object    []    {out, new Variant(8) }, new int[1]);    
  23.   
  24.       Variant f = new Variant(false);    
  25.   
  26.       Dispatch.call(doc, "Close", f);    
  27.   
  28.     } catch (Exception e) {    
  29.       e.printStackTrace();    
  30.     } finally {    
  31.     // 注意这里一定 要关闭否则服务器端会有很多winword.exe进程   
  32.       app.invoke("Quit"new Variant[] {});    
  33.       app = null;    
  34.     }    
  35.   
  36.   }  
/** 
    * 把word文件转换成html文件 
    *    
    * @param src 
    *                        原文件 
    * @param out 
    *                        目标文件 
    */ 
  public static synchronized void word2Html(String src, String out) { 
    ActiveXComponent app = null; 
    try { 
      app = new ActiveXComponent("Word.Application");// 启动word 

      app.setProperty("Visible", new Variant(false)); 

      // 设置word不可见 
      Dispatch docs = app.getProperty("Documents").toDispatch(); 

      Dispatch doc = Dispatch.invoke(docs, "Open", Dispatch.Method, new Object[] { src, new Variant(false), new Variant(true) }, new int[1]).
toDispatch(); 
      // 打开word文件 8转为 html 9转为 mht 
      Dispatch.invoke(doc, "SaveAs", Dispatch.Method, new Object    []    {out, new Variant(8) }, new int[1]); 

      Variant f = new Variant(false); 

      Dispatch.call(doc, "Close", f); 

    } catch (Exception e) { 
      e.printStackTrace(); 
    } finally { 
    // 注意这里一定 要关闭否则服务器端会有很多winword.exe进程
      app.invoke("Quit", new Variant[] {}); 
      app = null; 
    } 

  }
 
上面的代码其实完成的功能其实就是通过调用COM组件打开word程序然后隐藏窗口然后把打开的word文件另存为html.
2.用Apache的CommonsIO读取文件
Java代码 复制代码
  1. /**   
  2.     * 根据文件名读取出html代码   
  3.     *      
  4.     * @param fileName   
  5.     * @return   
  6.     */    
  7.   public static synchronized String getHtmlCode(String fileName) {    
  8.   
  9.     InputStream in = null;    
  10.     String result = null;    
  11.     try {    
  12.       in = new FileInputStream(fileName);    
  13.       result = IOUtils.toString(in, "gb2312");    
  14.     } catch (Exception e) {    
  15.       e.printStackTrace();    
  16.     } finally {    
  17.       IOUtils.closeQuietly(in);    
  18.     }    
  19.     return result;    
  20.   }  
/** 
    * 根据文件名读取出html代码 
    *    
    * @param fileName 
    * @return 
    */ 
  public static synchronized String getHtmlCode(String fileName) { 

    InputStream in = null; 
    String result = null; 
    try { 
      in = new FileInputStream(fileName); 
      result = IOUtils.toString(in, "gb2312"); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } finally { 
      IOUtils.closeQuietly(in); 
    } 
    return result; 
  }
 默认转成的html文件就是gb2312编码的 这里注意你读取出来的字符串必须是包含空格的,意思就是把读取出来的字符串拷出来放到文本文档里面的代码和html的源代码格式完全一样.
 
 
  3.截取body代码
  
Java代码 复制代码
  1. /**  
  2.  * 截取body内容  
  3.  *   
  4.  * @param bodyCode  
  5.  * @return  
  6.  */  
  7. public static synchronized String performBodyCode(String htmlCode) {   
  8.     String bodyCode = "";   
  9.     // 处理body   
  10.     int bodyIndex = htmlCode.indexOf("<body");   
  11.   
  12.     int bodyEndIndex = htmlCode.indexOf("</html>");   
  13.   
  14.     if (bodyIndex != -1 && bodyEndIndex != -1) {   
  15.         htmlCode = htmlCode.substring(bodyIndex, bodyEndIndex);   
  16.         //bodyCode = StringUtils.replace(htmlCode, "v:imagedata", "img");   
  17.         //bodyCode = StringUtils.replace(bodyCode, "</v:imagedata>", "");   
  18.         bodyCode=htmlCode;    
  19.     }   
  20.     htmlCode = null;   
  21.     return bodyCode;   
  22. }  
	/**
	 * 截取body内容
	 * 
	 * @param bodyCode
	 * @return
	 */
	public static synchronized String performBodyCode(String htmlCode) {
		String bodyCode = "";
		// 处理body
		int bodyIndex = htmlCode.indexOf("<body");

		int bodyEndIndex = htmlCode.indexOf("</html>");

		if (bodyIndex != -1 && bodyEndIndex != -1) {
			htmlCode = htmlCode.substring(bodyIndex, bodyEndIndex);
			//bodyCode = StringUtils.replace(htmlCode, "v:imagedata", "img");
			//bodyCode = StringUtils.replace(bodyCode, "</v:imagedata>", "");
			bodyCode=htmlCode; 
		}
		htmlCode = null;
		return bodyCode;
	}
 
 
 转成的html代码中很多一部分是无用的代码 我们需要对他进行减肥 已经标签的替换.
 
 4.处理html代码中的style标签
 
 
Java代码 复制代码
  1. /**  
  2.  * 处理Style标签中的内容  
  3.  *   
  4.  * @param htmlCode  
  5.  * @return  
  6.  */  
  7. public static synchronized String performStyleCode(String htmlCode) {   
  8.     String result = "";   
  9.   
  10.     int index = 0;   
  11.   
  12.     int styleStartIndex = 0;   
  13.   
  14.     int styleEndIndex = 0;   
  15.   
  16.     // 截取<style>标签中开始部分的坐标   
  17.   
  18.     while (index < htmlCode.length()) {   
  19.         int styleIndexStartTemp = htmlCode.indexOf("<style>", index);   
  20.   
  21.         if (styleIndexStartTemp == -1) {   
  22.             break;   
  23.         }   
  24.         int styleContentStartIndex = htmlCode.indexOf("<!--", styleIndexStartTemp);   
  25.   
  26.         if (styleContentStartIndex - styleIndexStartTemp == 9) {   
  27.             styleStartIndex = styleIndexStartTemp;   
  28.             break;   
  29.         }   
  30.         index = styleIndexStartTemp + 7;   
  31.     }   
  32.   
  33.     // 截取style标签中后面部分的坐标   
  34.     index = 0;   
  35.     while (index < htmlCode.length()) {   
  36.         int styleContentEndIndex = htmlCode.indexOf("-->", index);   
  37.   
  38.         if (styleContentEndIndex == -1) {   
  39.             break;   
  40.         }   
  41.         int styleEndIndexTemp = htmlCode.indexOf("</style>", styleContentEndIndex);   
  42.   
  43.         if (styleEndIndexTemp - styleContentEndIndex == 5) {   
  44.             styleEndIndex = styleEndIndexTemp;   
  45.             break;   
  46.         }   
  47.         index = styleContentEndIndex + 4;   
  48.     }   
  49.   
  50.     result = htmlCode.substring(styleStartIndex, styleEndIndex + 8);   
  51.   
  52.     return result;   
  53. }  
	/**
	 * 处理Style标签中的内容
	 * 
	 * @param htmlCode
	 * @return
	 */
	public static synchronized String performStyleCode(String htmlCode) {
		String result = "";

		int index = 0;

		int styleStartIndex = 0;

		int styleEndIndex = 0;

		// 截取<style>标签中开始部分的坐标

		while (index < htmlCode.length()) {
			int styleIndexStartTemp = htmlCode.indexOf("<style>", index);

			if (styleIndexStartTemp == -1) {
				break;
			}
			int styleContentStartIndex = htmlCode.indexOf("<!--", styleIndexStartTemp);

			if (styleContentStartIndex - styleIndexStartTemp == 9) {
				styleStartIndex = styleIndexStartTemp;
				break;
			}
			index = styleIndexStartTemp + 7;
		}

		// 截取style标签中后面部分的坐标
		index = 0;
		while (index < htmlCode.length()) {
			int styleContentEndIndex = htmlCode.indexOf("-->", index);

			if (styleContentEndIndex == -1) {
				break;
			}
			int styleEndIndexTemp = htmlCode.indexOf("</style>", styleContentEndIndex);

			if (styleEndIndexTemp - styleContentEndIndex == 5) {
				styleEndIndex = styleEndIndexTemp;
				break;
			}
			index = styleContentEndIndex + 4;
		}

		result = htmlCode.substring(styleStartIndex, styleEndIndex + 8);

		return result;
	}
 
     word转为html后里面有很多的style标签 其中
    <style>
         <!---   内容省略
          --->
    <style>
    类似于如上带html注释的style标签才是有用的 其余全是无用的.上面的代码就是把这有用的代码截取出来.如果你在第2部的时候格式读取正确,那么上面的代码截取出来的代码肯定没问题.
 
 
5.处理word文件中的图片
 
Java代码 复制代码
  1. /**  
  2.  * 处理body中的图片内容  
  3.  * @param bodyContent  
  4.  * @return  
  5.  */  
  6. public static synchronized String performBodyImg(String bodyContent) {   
  7.   
  8.     //根据图片名称预览图片action的地址   
  9.     String newImgSrc = "tumbnail.action?fileName=";   
  10.   
  11.     //存放word文件的物理位置   
  12.     String filePath = ResourceBundle.getBundle("sysConfig").getString("userFilePath.word");   
  13.   
  14.     //存放图片的物理位置   
  15.     String imgPath = ResourceBundle.getBundle("sysConfig").getString("userFilePath.image");   
  16.   
  17.     Parser parser = Parser.createParser(bodyContent, "gb2312");   
  18.   
  19.     ImgTagVisitor imgTag = new ImgTagVisitor();   
  20.   
  21.     try {   
  22.         parser.visitAllNodesWith(imgTag);   
  23.         // 得到所有图片地址   
  24.         List<String> imgUrls = imgTag.getSrcStringList();   
  25.   
  26.         for (String url : imgUrls) {   
  27.             String uuid = UUID.randomUUID().toString();   
  28.   
  29.             String extName = url.substring(url.lastIndexOf("."));   
  30.   
  31.             String newImgFileName = newImgSrc + uuid + extName;   
  32.   
  33.             bodyContent = StringUtils.replace(bodyContent, url, newImgFileName);   
  34.   
  35.             bodyContent = StringUtils.replace(bodyContent, url, newImgFileName);   
  36.   
  37.             ImageUtils.copy(filePath + url, imgPath + uuid + extName);   
  38.   
  39.         }   
  40.   
  41.     } catch (ParserException e) {   
  42.         e.printStackTrace();   
  43.     }   
  44.     String result = bodyContent;   
  45.        
  46.     //去除多余的代码   
  47.     result = StringUtils.replace(result, "<![endif]>""");   
  48.   
  49.     result = StringUtils.replace(result, "<![if !vml]>""");   
  50.   
  51.     bodyContent = null;   
  52.   
  53.     return result;   
  54. }  
	/**
	 * 处理body中的图片内容
	 * @param bodyContent
	 * @return
	 */
	public static synchronized String performBodyImg(String bodyContent) {

	    //根据图片名称预览图片action的地址
		String newImgSrc = "tumbnail.action?fileName=";

		//存放word文件的物理位置
		String filePath = ResourceBundle.getBundle("sysConfig").getString("userFilePath.word");

		//存放图片的物理位置
		String imgPath = ResourceBundle.getBundle("sysConfig").getString("userFilePath.image");

		Parser parser = Parser.createParser(bodyContent, "gb2312");

		ImgTagVisitor imgTag = new ImgTagVisitor();

		try {
			parser.visitAllNodesWith(imgTag);
			// 得到所有图片地址
			List<String> imgUrls = imgTag.getSrcStringList();

			for (String url : imgUrls) {
				String uuid = UUID.randomUUID().toString();

				String extName = url.substring(url.lastIndexOf("."));

				String newImgFileName = newImgSrc + uuid + extName;

				bodyContent = StringUtils.replace(bodyContent, url, newImgFileName);

				bodyContent = StringUtils.replace(bodyContent, url, newImgFileName);

				ImageUtils.copy(filePath + url, imgPath + uuid + extName);

			}

		} catch (ParserException e) {
			e.printStackTrace();
		}
		String result = bodyContent;
		
		//去除多余的代码
		result = StringUtils.replace(result, "<![endif]>", "");

		result = StringUtils.replace(result, "<![if !vml]>", "");

		bodyContent = null;

		return result;
	}
 
 上面的代码中用到了开源的html解析工具htmlparser 用他来进行分析得到所有图片的链接 然后把图片的链接用Apache的Commons-lang包中的StrutsUtils替换成我修改了fck中预览图片的action
 
 
   下面是我自己实现ImgTagVisitor 代码
  
 
Java代码 复制代码
  1. package com.bettem.cms.web.utils.htmlparser;    
  2.   
  3. import java.util.ArrayList;    
  4. import java.util.List;    
  5.   
  6. import org.htmlparser.Tag;    
  7. import org.htmlparser.Text;    
  8. import org.htmlparser.visitors.NodeVisitor;    
  9. /**   
  10.     *      
  11.     * 说明:htmlparser 解析 Img 标签所用类   
  12.     * *******************   
  13.     * 日期 人员       
  14.     * 2010-2-3 Liqiang   
  15.     */    
  16. public class ImgTagVisitor extends NodeVisitor {    
  17.   
  18.   private List<String> srcList;    
  19.   private StringBuffer textAccumulator;    
  20.   
  21.   public ImgTagVisitor() {    
  22.     srcList = new ArrayList<String>();    
  23.   
  24.     textAccumulator = new StringBuffer();    
  25.   
  26.   }    
  27.   
  28.   public void visitTag(Tag tag) {    
  29.     if (tag.getTagName().equalsIgnoreCase("img")) {    
  30.       srcList.add(tag.getAttribute("src"));    
  31.     }    
  32.   }    
  33.   
  34.   public List<String> getSrcStringList() {    
  35.     return srcList;    
  36.   }    
  37.   
  38.   public void visitStringNode(Text stringNode) {    
  39.     String text = stringNode.getText();    
  40.   
  41.     textAccumulator.append(text);    
  42.   }    
  43.   
  44.   public String getText() {    
  45.   
  46.     return textAccumulator.toString();    
  47.   }    
  48.   
  49. }  
package com.bettem.cms.web.utils.htmlparser; 

import java.util.ArrayList; 
import java.util.List; 

import org.htmlparser.Tag; 
import org.htmlparser.Text; 
import org.htmlparser.visitors.NodeVisitor; 
/** 
    *    
    * 说明:htmlparser 解析 Img 标签所用类 
    * ******************* 
    * 日期 人员     
    * 2010-2-3 Liqiang 
    */ 
public class ImgTagVisitor extends NodeVisitor { 

  private List<String> srcList; 
  private StringBuffer textAccumulator; 

  public ImgTagVisitor() { 
    srcList = new ArrayList<String>(); 

    textAccumulator = new StringBuffer(); 

  } 

  public void visitTag(Tag tag) { 
    if (tag.getTagName().equalsIgnoreCase("img")) { 
      srcList.add(tag.getAttribute("src")); 
    } 
  } 

  public List<String> getSrcStringList() { 
    return srcList; 
  } 

  public void visitStringNode(Text stringNode) { 
    String text = stringNode.getText(); 

    textAccumulator.append(text); 
  } 

  public String getText() { 

    return textAccumulator.toString(); 
  } 

}
 
   6.移除多余的v:imagedata标签
  
Java代码 复制代码
  1. /**  
  2.  * 移除多余的v:imagedata标签  
  3.  * @param content  
  4.  * @return  
  5.  */  
  6. public static synchronized String removeImagedataTag(String content) {   
  7.     Parser parser = null;   
  8.     Lexer lexer = null;   
  9.     AndFilter andFilter = null;   
  10.     NodeList nl = null;   
  11.     try {   
  12.         parser = new Parser(content, Parser.STDOUT);   
  13.         lexer = new Lexer(content);   
  14.         andFilter = new AndFilter(new NotFilter(new TagNameFilter("v:imagedata")), new NotFilter(new TagNameFilter("v:imagedata")));   
  15.         nl = parser.extractAllNodesThatMatch(andFilter);   
  16.     } catch (ParserException e) {   
  17.         e.printStackTrace();   
  18.     }   
  19.     return nl.toHtml();   
  20.   
  21. }  
	/**
	 * 移除多余的v:imagedata标签
	 * @param content
	 * @return
	 */
	public static synchronized String removeImagedataTag(String content) {
		Parser parser = null;
		Lexer lexer = null;
		AndFilter andFilter = null;
		NodeList nl = null;
		try {
			parser = new Parser(content, Parser.STDOUT);
			lexer = new Lexer(content);
			andFilter = new AndFilter(new NotFilter(new TagNameFilter("v:imagedata")), new NotFilter(new TagNameFilter("v:imagedata")));
			nl = parser.extractAllNodesThatMatch(andFilter);
		} catch (ParserException e) {
			e.printStackTrace();
		}
		return nl.toHtml();

	}
 
      在word转html的时候大图片会被自动压缩成小图片 但是原来的大图片还会存在在代码里,上面的代码把多余的标签过滤掉.
  最后看下我action中的代码
 
Java代码 复制代码
  1. /**   
  2.       * 导入word文件   
  3.       *      
  4.       * @return   
  5.       */    
  6.      public synchronized String exportWord()    
  7.      {    
  8.              String content = null;    
  9.              String path = ResourceBundle.getBundle("sysConfig").getString("userFilePath.word");    
  10.              InputStream ins = null;    
  11.              OutputStream wordFile = null;    
  12.              String htmlPath = null;    
  13.              String wordPath = null;    
  14.              // 处理上传的word文件    
  15.              try    
  16.              {    
  17.                      String uuid = UUID.randomUUID().toString();    
  18.                      // 截取扩展名    
  19.                      String fileName = uuid + filedataFileName.substring(filedataFileName.lastIndexOf("."));    
  20.                      // 生存html文件名    
  21.                      String wordHtmlFileName = uuid + ".html";    
  22.                      ins = new FileInputStream(filedata);    
  23.                      wordPath = path + fileName;    
  24.                      wordFile = new FileOutputStream(wordPath);    
  25.   
  26.                      IOUtils.copy(ins, wordFile);    
  27.   
  28.                      // word转html    
  29.   
  30.                      htmlPath = path + wordHtmlFileName;    
  31.   
  32.                      WordUtils.word2Html(wordPath, htmlPath);    
  33.                      String wordHtmlContent = WordUtils.getHtmlCode(htmlPath);    
  34.                      // 处理样式    
  35.                      String styleCode = WordUtils.performStyleCode(wordHtmlContent);    
  36.   
  37.                      String bodyCode = WordUtils.performBodyCode(wordHtmlContent);    
  38.                      // 处理文章中的图片    
  39.                      bodyCode = WordUtils.performBodyImg(bodyCode);    
  40.   
  41.                      content = styleCode + bodyCode;    
  42.                      styleCode = null;    
  43.                      bodyCode = null;    
  44.   
  45.                      WordUtils.removeImagedataTag(content);    
  46.   
  47.              }    
  48.              catch (FileNotFoundException e)    
  49.              {    
  50.                      e.printStackTrace();    
  51.              }    
  52.              catch (IOException e)    
  53.              {    
  54.                      e.printStackTrace();    
  55.              }    
  56.              finally    
  57.              {    
  58.                      IOUtils.closeQuietly(wordFile);    
  59.                      IOUtils.closeQuietly(ins);    
  60.                      try    
  61.                      {    
  62.                              File word = new File(wordPath);    
  63.                              File file = new File(htmlPath);    
  64.                              if (file.exists())    
  65.                              {    
  66.                                      file.delete();    
  67.                                      word.delete();    
  68.                                      FileUtils.deleteDirectory(new File(htmlPath.substring(0, htmlPath.lastIndexOf(".")) + ".files"));    
  69.                              }    
  70.   
  71.                      }    
  72.                      catch (IOException e)    
  73.                      {    
  74.                              e.printStackTrace();    
  75.                      }    
  76.              }    
  77.   
  78.              // 读取word文件内容,添加到content中    
  79.              // 放到request中    
  80.              ServletActionContext.getRequest().setAttribute("content", content);    
  81.              ServletActionContext.getRequest().setAttribute("add"true);    
  82.              return SUCCESS;    
  83.      }  
   /** 
         * 导入word文件 
         *    
         * @return 
         */ 
        public synchronized String exportWord() 
        { 
                String content = null; 
                String path = ResourceBundle.getBundle("sysConfig").getString("userFilePath.word"); 
                InputStream ins = null; 
                OutputStream wordFile = null; 
                String htmlPath = null; 
                String wordPath = null; 
                // 处理上传的word文件 
                try 
                { 
                        String uuid = UUID.randomUUID().toString(); 
                        // 截取扩展名 
                        String fileName = uuid + filedataFileName.substring(filedataFileName.lastIndexOf(".")); 
                        // 生存html文件名 
                        String wordHtmlFileName = uuid + ".html"; 
                        ins = new FileInputStream(filedata); 
                        wordPath = path + fileName; 
                        wordFile = new FileOutputStream(wordPath); 

                        IOUtils.copy(ins, wordFile); 

                        // word转html 

                        htmlPath = path + wordHtmlFileName; 

                        WordUtils.word2Html(wordPath, htmlPath); 
                        String wordHtmlContent = WordUtils.getHtmlCode(htmlPath); 
                        // 处理样式 
                        String styleCode = WordUtils.performStyleCode(wordHtmlContent); 

                        String bodyCode = WordUtils.performBodyCode(wordHtmlContent); 
                        // 处理文章中的图片 
                        bodyCode = WordUtils.performBodyImg(bodyCode); 

                        content = styleCode + bodyCode; 
                        styleCode = null; 
                        bodyCode = null; 

                        WordUtils.removeImagedataTag(content); 

                } 
                catch (FileNotFoundException e) 
                { 
                        e.printStackTrace(); 
                } 
                catch (IOException e) 
                { 
                        e.printStackTrace(); 
                } 
                finally 
                { 
                        IOUtils.closeQuietly(wordFile); 
                        IOUtils.closeQuietly(ins); 
                        try 
                        { 
                                File word = new File(wordPath); 
                                File file = new File(htmlPath); 
                                if (file.exists()) 
                                { 
                                        file.delete(); 
                                        word.delete(); 
                                        FileUtils.deleteDirectory(new File(htmlPath.substring(0, htmlPath.lastIndexOf(".")) + ".files")); 
                                } 

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

                // 读取word文件内容,添加到content中 
                // 放到request中 
                ServletActionContext.getRequest().setAttribute("content", content); 
                ServletActionContext.getRequest().setAttribute("add", true); 
                return SUCCESS; 
        }
 
  
分享到:
评论
7 楼 zpl 2012-02-14  
C:\Documents and Settings\Administrator\桌面
6 楼 zpl 2012-02-14  
[img][/img] asdfasdfasdfa
5 楼 fonkyjon 2011-10-11  
兄弟,有没有整个可以下载的Demo project出来啊?
4 楼 Jackie_GP 2011-07-03  
这个功能比较鸡肋呀!不能跨平台,服务器必须安装Word才可以的呀!不如用POI实现的好呀!
3 楼 Jackie_GP 2011-07-01  
可惜代码没有给全呀
2 楼 Mybeautiful 2010-12-15  
兄弟,有没有整个可以下载的Demo project出来啊?
1 楼 yuan_xulong 2010-12-10  
正好需要,谢谢兄弟了。

相关推荐

Global site tag (gtag.js) - Google Analytics