POI分段落生成纯Word动态模板并导入数据

导出数据,可以用word另存为xml格式的ftl文件,变量用${变量名}表示,然后在类中通过

freemarker去替换变量。

但是怎么导入word数据。发现如果是xml格式,数据格式很易变。如一个标题中如果有中文,

后面是个数字,另存成xml时就变成了2个元素了。太郁闷了。

后来找到方法可以分段落读入纯word文档。要找到了word基于模板替换的相关例子。于是方

案如下。

纯word文件变量用${变量名}表示。导出动态模板时,把业务数据替换变量。导入是分段落读入数据。

注意模板中的KEY最好在文本中写好,然后复制到模板中。
否则可以出现解析问题(比如:${user}代码写解析成三段文本1.${  2.user  3.})

POIReportUtil.java文件
package com.sunrise.wbmp.manage.project.report.util;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.*;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.model.StyleDescription;
import org.apache.poi.hwpf.model.StyleSheet;
import org.apache.poi.hwpf.usermodel.CharacterProperties;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.hwpf.usermodel.Table;
import org.apache.poi.hwpf.usermodel.TableCell;
import org.apache.poi.hwpf.usermodel.TableIterator;
import org.apache.poi.hwpf.usermodel.TableRow;

public class POIReportUtil {
    public static void main(String[] args) throws Exception {
        Map<String, POIText> replaces = new HashMap<String, POIText>();
        System.out.println("导出数据:");
       
        replaces.put("${projectName}", POIText.str("CMMI"));       
        replaces.put("${graph1}", POIText.str("rongzhi_li"));
        replaces.put("${内容1}", POIText.str("1123456"));

replaces.put("${graph2}", POIText.str("graph"));
        replaces.put("${内容2}", POIText.str("2222"));

replaces.put("${graph3}", POIText.str("graph"));
        replaces.put("${内容3}", POIText.str("33333"));

replaces.put("${graph4}", POIText.str("<END>"));
        replaces.put("${内容4}", POIText.str(""));
       
        for (int i=5;i<10;i++){
            replaces.put("${graph"+i+"}", POIText.str(""));
            replaces.put("${内容"+i+"}", POIText.str(""));
        }

// 读入模板文件并替换参数 
    HWPFDocument hwpf=poiWordTableReplace

("E:\\temp\\template\\templateTest.doc",replaces);

// 另存模板文件为exportTestg.doc
    FileOutputStream out = new FileOutputStream("E:\\temp\\template\\exportTestg.doc");
    hwpf.write(out);
    out.flush();
    out.close(); 
   
    // 把exportTestg.doc文件内容读出来
    System.out.println("读入数据:");
    FileInputStream in = new FileInputStream("E:\\temp\\template\\exportTestg.doc");
    HWPFDocument hwpf2 = new HWPFDocument(in);
    Map<String,String> map=readWord(hwpf2);   
    for (Iterator iter=map.entrySet().iterator();iter.hasNext();){
    java.util.Map.Entry entry=(java.util.Map.Entry)iter.next();
    System.out.println(entry.getKey()+":"+entry.getValue());
    }
    }

// 读取文件内容反回MAP
    public static Map<String,String> readWord(HWPFDocument hwpf
            ) throws Exception {
//        FileInputStream in = new FileInputStream(sourceFile);
//        HWPFDocument hwpf = new HWPFDocument(in);
    Map<String, String> oldMap=new HashMap<String, String>();
        Range r = hwpf.getRange();
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < r.numParagraphs(); i++) {
            Paragraph p = r.getParagraph(i);
            // check if style index is greater than total number of styles
            int numStyles =hwpf.getStyleSheet().numStyles();
            int styleIndex = p.getStyleIndex();
            if (numStyles > styleIndex) {
                StyleSheet style_sheet = hwpf.getStyleSheet();
                StyleDescription style = style_sheet.getStyleDescription(styleIndex);
                String styleName = style.getName();
                if (styleName!=null&&styleName.contains("标题 3")) {
                    // write style name and associated text
                    System.out.println(styleName + " -> " + p.text());
                    //System.out.println(p.text());
                    String text = p.text();
                    text=text.substring(0,text.length()-1);
                    list.add(text);
                    oldMap.put(text, null);
                    if ("<END>".equals(text)){
                    break;
                    }
                }else{
                if (list.size()>0){
                String key=list.get(list.size()-1);
                String oldS=oldMap.get(list.get(list.size()-1));
                String s=( p.text()==null)?"": p.text();
                oldS=(oldS==null)?s:(oldS+s);
                if (oldS!=null && oldS.trim().length()>0){
                oldMap.put(key, oldS);
                }
                }
                }
            }
        }
        return oldMap;
    }

public static HWPFDocument poiWordTableReplace(String sourceFile,
            Map<String, POIText> replaces) throws Exception {
        FileInputStream in = new FileInputStream(sourceFile);
        HWPFDocument hwpf = new HWPFDocument(in);
//        Range range = hwpf.getRange();// 得到文档的读取范围
//        TableIterator it = new TableIterator(range);
//        // 迭代文档中的表格
//        while (it.hasNext()) {
//            Table tb = (Table) it.next();
//            // 迭代行,默认从0开始
//            for (int i = 0; i < tb.numRows(); i++) {
//                TableRow tr = tb.getRow(i);
//                // 迭代列,默认从0开始
//                for (int j = 0; j < tr.numCells(); j++) {
//                    TableCell td = tr.getCell(j);// 取得单元格
//                    // 取得单元格的内容
//                    for (int k = 0; k < td.numParagraphs(); k++) {
//                        Paragraph para = td.getParagraph(k);
//
//                        String s = para.text();
//                        final String old = s;
//                        for (String key : replaces.keySet()) {
//                            if (s.contains(key)) {
//                                s = s.replace(key, replaces.get(key).getText());
//                            }
//                        }
//                        if (!old.equals(s)) {// 有变化
//                            para.replaceText(old, s);
//                            s = para.text();
//                            System.out.println("old:" + old + "->" + "s:" + s);
//                        }
//
//                    } // end for
//                } // end for
//            } // end for
//        } // end while

Range r = hwpf.getRange();
        CharacterProperties props = new CharacterProperties();
        props.setFontSize(10);
       
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < r.numParagraphs(); i++) {
            Paragraph p = r.getParagraph(i);
            // check if style index is greater than total number of styles
            int numStyles =hwpf.getStyleSheet().numStyles();
            int styleIndex = p.getStyleIndex();
            if (numStyles > styleIndex) {
                StyleSheet style_sheet = hwpf.getStyleSheet();
                StyleDescription style = style_sheet.getStyleDescription(styleIndex);
                String styleName = style.getName();
//                if (styleName!=null&&styleName.contains("标题")) {
//                    // write style name and associated text
//                    //System.out.println(styleName + " -> " + p.text());
//                    System.out.println(p.text());
//                    String text = p.text();
//                    list.add(text);
//                }else{
//                    System.out.println(  p.text());
//                }
               
                System.out.println(  styleName);
               
                String s = p.text();
                final String old = s;
                for (String key : replaces.keySet()) {
                    if (s.contains(key)) {
                        s = s.replace(key, replaces.get(key).getText());
                    }
                }
                if (!old.equals(s)) {// 有变化
                    p.replaceText(old, s);
                    s = p.text();
                    System.out.println("old:" + old + "->" + "s:" + s);
                }
            }
        }
        return hwpf;
    }
}

POIReportUtil.java文件
package com.sunrise.wbmp.manage.project.report.util;

public abstract class POIText {

public abstract String getText();

public static POIText str(final String string) {
        return new POIText() {
            @Override
            public String getText() {
                return string;
            }
        };
    }
}

利用poi操作word文档

一:利用POI提取Word文本内容及批注
97-2003:

import org.apache.poi.POITextExtractor;
import org.apache.poi.hwpf.extractor.WordExtractor;
//得到.doc文件提取器
org.apache.poi.hwpf.extractor.WordExtractor doc = new WordExtractor(new

FileInputStream(filePath));
//提取.doc正文文本
String text = doc.getText();
//提取.doc批注
String[] comments = doc. getCommentsText();

2007

import org.apache.poi.POITextExtractor;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFComment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
//得到.docx文件提取器
org.apache.poi.xwpf.extractor.XWPFWordExtractor docx = new XWPFWordExtractor

(POIXMLDocument.openPackage(filePath));
//提取.docx正文文本
String text = docx.getText();
//提取.docx批注
org.apache.poi.xwpf.usermodel.XWPFComment[] comments = docx.getDocument

()).getComments();
for(XWPFComment comment:comments){
comment.getId();//提取批注Id
comment.getAuthor();//提取批注修改人
comment.getText();//提取批注内容
}

二:利用POI提取Word总页数、总字符数...
97-2003
WordExtractor doc = new WordExtractor(new FileInputStream(filePath));//.doc格式Word文

件提取器
int pages = doc.getSummaryInformation().getPageCount();//总页数
int wordCount = doc.getSummaryInformation().getWordCount();//总字符数
2007:

XWPFDocument docx = nnew XWPFDocument(POIXMLDocument.openPackage(filePath));
int pages = docx.getProperties().getExtendedProperties().getUnderlyingProperties

().getPages();//总页数
int characters = docx.getProperties().getExtendedProperties().getUnderlyingProperties

().getCharacters();// 忽略空格的总字符数 另外还有getCharactersWithSpaces()方法获取带空

格的总字数。

小技巧:
2007采用了全新的OFFICE OPEN XML格式来存储,跟以前二进制文件格式的office 97-2003

(.doc、.xls...)不同,所以可以直接重命名xx.docx的文件为xx.zip,用WinRar打开可以看到

office2007的存储文件,其中word/document.xml里面保存了最重要的正文内容,

word/comments.xml保存的是批注内容,可以多研究一下这些文件,有助于开发~

POI word模板 文字 图片替换

Word模板:


替换后效果:

代码:
1、入口文件
public class Test { 
     
    public static void main(String[] args) throws Exception { 
         
        Map<String, Object> param = new HashMap<String, Object>(); 
        param.put("${name}", "huangqiqing"); 
        param.put("${zhuanye}", "信息管理与信息系统"); 
        param.put("${sex}", "男"); 
        param.put("${school_name}", "山东财经大学"); 
        param.put("${date}", new Date().toString()); 
         
        Map<String,Object> header = new HashMap<String, Object>(); 
        header.put("width", 100); 
        header.put("height", 150); 
        header.put("type", "jpg"); 
        header.put("content", WordUtil.inputStream2ByteArray(new FileInputStream

("c:\\new.jpg"), true)); 
        param.put("${header}",header); 
         
Map<String,Object> twocode = new HashMap<String, Object>(); 
        twocode.put("width", 100); 
        twocode.put("height", 100); 
        twocode.put("type", "png"); 
        twocode.put("content", ZxingEncoderHandler.getTwoCodeByteArray("测试二维

码,huangqiqing", 100,100)); 
        param.put("${twocode}",twocode); 
         
        CustomXWPFDocument doc = WordUtil.generateWord(param, "c:\\1.docx"); 
        FileOutputStream fopts = new FileOutputStream("c:/2.docx"); 
        doc.write(fopts); 
        fopts.close(); 
    } 
}

2、封装的工具类WordUtil.java
import java.io.ByteArrayInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 
import org.apache.poi.POIXMLDocument; 
import org.apache.poi.openxml4j.opc.OPCPackage; 
import org.apache.poi.xwpf.usermodel.XWPFParagraph; 
import org.apache.poi.xwpf.usermodel.XWPFRun; 
import org.apache.poi.xwpf.usermodel.XWPFTable; 
import org.apache.poi.xwpf.usermodel.XWPFTableCell; 
import org.apache.poi.xwpf.usermodel.XWPFTableRow; 
 
/**
* 适用于word 2007
* poi 版本 3.7
*/ 
public class WordUtil { 
 
    /**
     * 根据指定的参数值、模板,生成 word 文档
     * @param param 需要替换的变量
     * @param template 模板
     */ 
    public static CustomXWPFDocument generateWord(Map<String, Object> param, String

template) { 
        CustomXWPFDocument doc = null; 
        try { 
            OPCPackage pack = POIXMLDocument.openPackage(template); 
            doc = new CustomXWPFDocument(pack); 
            if (param != null && param.size() > 0) { 
                 
                //处理段落 
                List<XWPFParagraph> paragraphList = doc.getParagraphs(); 
                processParagraphs(paragraphList, param, doc); 
                 
                //处理表格 
                Iterator<XWPFTable> it = doc.getTablesIterator(); 
                while (it.hasNext()) { 
                    XWPFTable table = it.next(); 
                    List<XWPFTableRow> rows = table.getRows(); 
                    for (XWPFTableRow row : rows) { 
                        List<XWPFTableCell> cells = row.getTableCells(); 
                        for (XWPFTableCell cell : cells) { 
                            List<XWPFParagraph> paragraphListTable =  cell.getParagraphs(); 
                            processParagraphs(paragraphListTable, param, doc); 
                        } 
                    } 
                } 
            } 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
        return doc; 
    } 
    /**
     * 处理段落
     * @param paragraphList
     */ 
    public static void processParagraphs(List<XWPFParagraph> paragraphList,Map<String,

Object> param,CustomXWPFDocument doc){ 
        if(paragraphList != null && paragraphList.size() > 0){ 
            for(XWPFParagraph paragraph:paragraphList){ 
                List<XWPFRun> runs = paragraph.getRuns(); 
                for (XWPFRun run : runs) { 
                    String text = run.getText(0); 
                    if(text != null){ 
                        boolean isSetText = false; 
                        for (Entry<String, Object> entry : param.entrySet()) { 
                            String key = entry.getKey(); 
                            if(text.indexOf(key) != -1){ 
                                isSetText = true; 
                                Object value = entry.getValue(); 
                                if (value instanceof String) {//文本替换 
                                    text = text.replace(key, value.toString()); 
                                } else if (value instanceof Map) {//图片替换 
                                    text = text.replace(key, ""); 
                                    Map pic = (Map)value; 
                                    int width = Integer.parseInt(pic.get("width").toString()); 
                                    int height = Integer.parseInt(pic.get("height").toString()); 
                                    int picType = getPictureType(pic.get("type").toString()); 
                                    byte[] byteArray = (byte[]) pic.get("content"); 
                                    ByteArrayInputStream byteInputStream = new

ByteArrayInputStream(byteArray); 
                                    try { 
                                        int ind = doc.addPicture(byteInputStream,picType); 
                                        doc.createPicture(ind, width , height,paragraph); 
                                    } catch (Exception e) { 
                                        e.printStackTrace(); 
                                    } 
                                } 
                            } 
                        } 
                        if(isSetText){ 
                            run.setText(text,0); 
                        } 
                    } 
                } 
            } 
        } 
    } 
    /**
     * 根据图片类型,取得对应的图片类型代码
     * @param picType
     * @return int
     */ 
    private static int getPictureType(String picType){ 
        int res = CustomXWPFDocument.PICTURE_TYPE_PICT; 
        if(picType != null){ 
            if(picType.equalsIgnoreCase("png")){ 
                res = CustomXWPFDocument.PICTURE_TYPE_PNG; 
            }else if(picType.equalsIgnoreCase("dib")){ 
                res = CustomXWPFDocument.PICTURE_TYPE_DIB; 
            }else if(picType.equalsIgnoreCase("emf")){ 
                res = CustomXWPFDocument.PICTURE_TYPE_EMF; 
            }else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){ 
                res = CustomXWPFDocument.PICTURE_TYPE_JPEG; 
            }else if(picType.equalsIgnoreCase("wmf")){ 
                res = CustomXWPFDocument.PICTURE_TYPE_WMF; 
            } 
        } 
        return res; 
    } 
    /**
     * 将输入流中的数据写入字节数组
     * @param in
     * @return
     */ 
    public static byte[] inputStream2ByteArray(InputStream in,boolean isClose){ 
        byte[] byteArray = null; 
        try { 
            int total = in.available(); 
            byteArray = new byte[total]; 
            in.read(byteArray); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        }finally{ 
            if(isClose){ 
                try { 
                    in.close(); 
                } catch (Exception e2) { 
                    System.out.println("关闭流失败"); 
                } 
            } 
        } 
        return byteArray; 
    } 
}

3、重写的类 CustomXWPFDocument
   
import java.io.IOException; 
import java.io.InputStream; 
import org.apache.poi.openxml4j.opc.OPCPackage; 
import org.apache.poi.xwpf.usermodel.XWPFDocument; 
import org.apache.poi.xwpf.usermodel.XWPFParagraph; 
import org.apache.xmlbeans.XmlException; 
import org.apache.xmlbeans.XmlToken; 
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; 
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; 
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline; 
   
/**
* 自定义 XWPFDocument,并重写 createPicture()方法
*/ 
public class CustomXWPFDocument extends XWPFDocument {   
    public CustomXWPFDocument(InputStream in) throws IOException {   
        super(in);   
    }   
   
    public CustomXWPFDocument() {   
        super();   
    }   
   
    public CustomXWPFDocument(OPCPackage pkg) throws IOException {   
        super(pkg);   
    }   
   
    /**
     * @param id
     * @param width 宽
     * @param height 高
     * @param paragraph  段落
     */ 
    public void createPicture(int id, int width, int height,XWPFParagraph paragraph) {   
        final int EMU = 9525;   
        width *= EMU;   
        height *= EMU;   
        String blipId = getAllPictures().get(id).getPackageRelationship().getId();   
        CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline();   
        String picXml = ""   
                + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"   
                + "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"   
                + "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"   
                + "         <pic:nvPicPr>" + "            <pic:cNvPr id=\""   
                + id   
                + "\" name=\"Generated\"/>"   
                + "            <pic:cNvPicPr/>"   
                + "         </pic:nvPicPr>"   
                + "         <pic:blipFill>"   
                + "            <a:blip r:embed=\""   
                + blipId   
                + "\" xmlns:r=\">"   
                + "            <a:stretch>"   
                + "               <a:fillRect/>"   
                + "            </a:stretch>"   
                + "         </pic:blipFill>"   
                + "         <pic:spPr>"   
                + "            <a:xfrm>"   
                + "               <a:off x=\"0\" y=\"0\"/>"   
                + "               <a:ext cx=\""   
                + width   
                + "\" cy=\""   
                + height   
                + "\"/>"   
                + "            </a:xfrm>"   
                + "            <a:prstGeom prst=\"rect\">"   
                + "               <a:avLst/>"   
                + "            </a:prstGeom>"   
                + "         </pic:spPr>"   
                + "      </pic:pic>"   
                + "   </a:graphicData>" + "</a:graphic>";   
   
        inline.addNewGraphic().addNewGraphicData();   
        XmlToken xmlToken = null;   
        try {   
            xmlToken = XmlToken.Factory.parse(picXml);   
        } catch (XmlException xe) {   
            xe.printStackTrace();   
        }   
        inline.set(xmlToken);  
         
        inline.setDistT(0);     
        inline.setDistB(0);     
        inline.setDistL(0);     
        inline.setDistR(0);     
         
        CTPositiveSize2D extent = inline.addNewExtent();   
        extent.setCx(width);   
        extent.setCy(height);   
         
        CTNonVisualDrawingProps docPr = inline.addNewDocPr();     
        docPr.setId(id);     
        docPr.setName("图片" + id);     
        docPr.setDescr("测试");  
    }   
}

利用POI将word转换成html

1.      POI介绍:

Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式

对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母

缩写,意为“可怜的模糊实现”。

Apache POI 是创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合

文档格式(OLE2)的Java API。用它可以使用Java读取和创建,修改MS Excel文件.而且,还可以

使用Java读取和创建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解决方案

(适用于Excel97-2008)。

基本结构:

HSSF -提供读写Microsoft Excel XLS格式档案的功能。

XSSF -提供读写Microsoft Excel OOXML XLSX格式档案的功能。

HWPF -提供读写Microsoft Word DOC格式档案的功能。

HSLF -提供读写Microsoft PowerPoint格式档案的功能。

HDGF -提供读Microsoft Visio格式档案的功能。

HPBF -提供读Microsoft Publisher格式档案的功能。

HSMF -提供读Microsoft Outlook格式档案的功能。

其实,POI比较拿手的是处理Excel表格,即上面的HSSF及XSSF,我们的很多项目,只要涉及

报表的,基本上都有用到它吧。用对于HWPF即处理DOC的包,功能就没有那么健全了,且API

也不完善。

2.      代码实现

Word2Html文件
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import javax.imageio.ImageIO;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.model.PicturesTable;
import org.apache.poi.hwpf.usermodel.CharacterRun;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.hwpf.usermodel.Table;
import org.apache.poi.hwpf.usermodel.TableCell;
import org.apache.poi.hwpf.usermodel.TableIterator;
import org.apache.poi.hwpf.usermodel.TableRow;
import org.apache.xmlbeans.impl.piccolo.io.FileFormatException;

/**
 * @Description: 利用poi将word简单的转换成html文件
 * @author 柯颖波
 * @date 2013-12-20 上午09:32:44
 * @version v1.0
 */
public class Word2Html {
 /**
  * 回车符ASCII码
  */
 private static final short ENTER_ASCII = 13;

/**
  * 空格符ASCII码
  */
 private static final short SPACE_ASCII = 32;

/**
  * 水平制表符ASCII码
  */
 private static final short TABULATION_ASCII = 9;

private static String htmlText = "";
 private static String htmlTextTbl = "";
 private static int counter = 0;
 private static int beginPosi = 0;
 private static int endPosi = 0;
 private static int beginArray[];
 private static int endArray[];
 private static String htmlTextArray[];
 private static boolean tblExist = false;

/**
  * 项目路径
  */
 private static String projectRealPath = "";
 /**
  * 临时文件路径
  */
 private static String tempPath = "/upfile/" + File.separator + "transferFile" +

File.separator;
 /**
  * word文档名称
  */
 private static String wordName = "";

public static void main(String argv[]) {
  try {
   wordToHtml("F:\\SVN\\BobUtil\\web\\", "test.doc");
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

/**
  * 读取每个文字样式
  *
  * @param fileName
  * @throws Exception
  */

private static void getWordAndStyle(String fileName) throws Exception {
  FileInputStream in = new FileInputStream(new File(fileName));
  HWPFDocument doc = new HWPFDocument(in);

Range rangetbl = doc.getRange();// 得到文档的读取范围
  TableIterator it = new TableIterator(rangetbl);

int num = 100;
  beginArray = new int[num];
  endArray = new int[num];
  htmlTextArray = new String[num];
  tblExist = false;

// 取得文档中字符的总数
  int length = doc.characterLength();
  // 创建图片容器
  PicturesTable pTable = doc.getPicturesTable();
  // 创建段落容器

htmlText = "<html><head><meta http-equiv=\"Content-Type\"

content=\"text/html; charset=utf-8\" /><title>"
    + doc.getSummaryInformation().getTitle()
    + "</title></head><body><div

style='margin:60px;text-align:center;'><div style='width:620px;text-align:left;line-

height:24px;'>";
  // 创建临时字符串,好加以判断一串字符是否存在相同格式

if (it.hasNext()) {
   readTable(it, rangetbl);
  }

int cur = 0;
  String tempString = "";
  for (int i = 0; i < length - 1; i++) {
   // 整篇文章的字符通过一个个字符的来判断,range为得到文档的

范围
   Range range = new Range(i, i + 1, doc);
   CharacterRun cr = range.getCharacterRun(0);
   // beginArray=new int[num];
   // endArray=new int[num];
   // htmlTextArray=new String[num];
   if (tblExist) {
    if (i == beginArray[cur]) {
     htmlText += tempString + htmlTextArray

[cur];
     tempString = "";
     i = endArray[cur] - 1;
     cur++;
     continue;
    }
   }
   if (pTable.hasPicture(cr)) {
    htmlText += tempString;
    // 读写图片
    try {
     readPicture(pTable, cr);
    } catch (Exception e) {
     e.printStackTrace();
    }
    tempString = "";
   } else {

Range range2 = new Range(i + 1, i + 2, doc);
    // 第二个字符
    CharacterRun cr2 = range2.getCharacterRun(0);
    char c = cr.text().charAt(0);
    // System.out.println(c);
    // /System.out.println(i+"::"+range.getEndOffset()

+"::"+range.getStartOffset()+"::"+c);

// 判断是否为回车符
    if (c == ENTER_ASCII) {
     tempString += "<br/>";
    }
    // 判断是否为空格符
    else if (c == SPACE_ASCII)
     tempString += "&nbsp;";
    // 判断是否为水平制表符
    else if (c == TABULATION_ASCII)
     tempString += " &nbsp;&nbsp;&nbsp;";
    // 比较前后2个字符是否具有相同的格式
    boolean flag = compareCharStyle(cr, cr2);
    if (flag)
     tempString += cr.text();
    else {
     String fontStyle = "<span style=\"font-

family:" + cr.getFontName() + ";font-size:"
       + cr.getFontSize() / 2 +

"pt;";

if (cr.isBold())
      fontStyle += "font-weight:bold;";
     if (cr.isItalic())
      fontStyle += "font-style:italic;";
     if (cr.isStrikeThrough())
      fontStyle += "text-

decoration:line-through;";

int fontcolor = cr.getIco24();
     int[] rgb = new int[3];
     if (fontcolor != -1) {
      rgb[0] = (fontcolor >> 0) & 0xff;

// red;
      rgb[1] = (fontcolor >> 8) & 0xff;

// green
      rgb[2] = (fontcolor >> 16) &

0xff; // blue
     }
     fontStyle += "color: rgb(" + rgb[0] + "," +

rgb[1] + "," + rgb[2] + ");";
     htmlText += fontStyle + "\">" +

tempString + cr.text() + "</span>";
     tempString = "";
    }
   }
  }

htmlText += tempString + "</div></div></body></html>";
  // System.out.println(htmlText);
 }

/**
  * 读写文档中的表格
  *
  * @param pTable
  * @param cr
  * @throws Exception
  */
 private static void readTable(TableIterator it, Range rangetbl) throws Exception {

htmlTextTbl = "";
  // 迭代文档中的表格

counter = -1;
  while (it.hasNext()) {
   tblExist = true;
   htmlTextTbl = "";
   Table tb = (Table) it.next();
   beginPosi = tb.getStartOffset();
   endPosi = tb.getEndOffset();

// System.out.println("............"+beginPosi+"...."+endPosi);
   counter = counter + 1;
   // 迭代行,默认从0开始
   beginArray[counter] = beginPosi;
   endArray[counter] = endPosi;

htmlTextTbl += "<table border='1' cellpadding='0'

cellspacing='0' >";
   for (int i = 0; i < tb.numRows(); i++) {
    TableRow tr = tb.getRow(i);

htmlTextTbl += "<tr align='center'>";
    // 迭代列,默认从0开始
    for (int j = 0; j < tr.numCells(); j++) {
     TableCell td = tr.getCell(j);// 取得单元格
     int cellWidth = td.getWidth();

// 取得单元格的内容
     for (int k = 0; k < td.numParagraphs();

k++) {
      Paragraph para =

td.getParagraph(k);
      CharacterRun crTemp =

para.getCharacterRun(0);
      String fontStyle = "<span

style=\"font-family:" + crTemp.getFontName() + ";font-size:"
        +

crTemp.getFontSize() / 2 + "pt;color:" + crTemp.getColor() + ";";

if (crTemp.isBold())
       fontStyle += "font-

weight:bold;";
      if (crTemp.isItalic())
       fontStyle += "font-

style:italic;";

String s = fontStyle + "\">" +

para.text().toString().trim() + "</span>";
      if (s == "") {
       s = " ";
      }
      // System.out.println(s);
      htmlTextTbl += "<td width=" +

cellWidth + ">" + s + "</td>";
      // System.out.println(i + ":" + j +

":" + cellWidth + ":" + s);
     } // end for
    } // end for
   } // end for
   htmlTextTbl += "</table>";
   htmlTextArray[counter] = htmlTextTbl;

} // end while
 }

/**
  * 读写文档中的图片
  *
  * @param pTable
  * @param cr
  * @throws Exception
  */
 private static void readPicture(PicturesTable pTable, CharacterRun cr) throws

Exception {
  // 提取图片
  Picture pic = pTable.extractPicture(cr, false);
  BufferedImage image = null;// 图片对象
  // 获取图片样式
  int picHeight = pic.getHeight() * pic.getAspectRatioY() / 100;
  int picWidth = pic.getAspectRatioX() * pic.getWidth() / 100;
  if (picWidth > 500) {
   picHeight = 500 * picHeight / picWidth;
   picWidth = 500;
  }
  String style = " style='height:" + picHeight + "px;width:" + picWidth +

"px'";

// 返回POI建议的图片文件名
  String afileName = pic.suggestFullFileName();
  //单元测试路径
  String directory = "images/" + wordName + "/";
  //项目路径
  //String directory = tempPath + "images/" + wordName + "/";
  makeDir(projectRealPath, directory);// 创建文件夹

int picSize = cr.getFontSize();
  int myHeight = 0;

if (afileName.indexOf(".wmf") > 0) {
   OutputStream out = new FileOutputStream(new File

(projectRealPath + directory + afileName));
   out.write(pic.getContent());
   out.close();
   afileName = Wmf2Png.convert(projectRealPath + directory +

afileName);

File file = new File(projectRealPath + directory + afileName);

try {
    image = ImageIO.read(file);
   } catch (Exception e) {
    e.printStackTrace();
   }

int pheight = image.getHeight();
   int pwidth = image.getWidth();
   if (pwidth > 500) {
    htmlText += "<img style='width:" + pwidth +

"px;height:" + myHeight + "px'" + " src=\"" + directory
      + afileName + "\"/>";
   } else {
    myHeight = (int) (pheight / (pwidth / (picSize * 1.0))

* 1.5);
    htmlText += "<img style='vertical-

align:middle;width:" + picSize * 1.5 + "px;height:" + myHeight
      + "px'" + " src=\"" + directory +

afileName + "\"/>";
   }

} else {
   OutputStream out = new FileOutputStream(new File

(projectRealPath + directory + afileName));
   // pic.writeImageContent(out);
   out.write(pic.getContent());
   out.close();
   // 处理jpg或其他(即除png外)
   if (afileName.indexOf(".png") == -1) {
    try {
     File file = new File(projectRealPath +

directory + afileName);
     image = ImageIO.read(file);
     picHeight = image.getHeight();
     picWidth = image.getWidth();
     if (picWidth > 500) {
      picHeight = 500 * picHeight /

picWidth;
      picWidth = 500;
     }
     style = " style='height:" + picHeight +

"px;width:" + picWidth + "px'";
    } catch (Exception e) {
     // e.printStackTrace();
    }
   }
   htmlText += "<img " + style + " src=\"" + directory +

afileName + "\"/>";
  }
  if (pic.getWidth() > 450) {
   htmlText += "<br/>";
  }
 }

private static boolean compareCharStyle(CharacterRun cr1, CharacterRun cr2) {
  boolean flag = false;
  if (cr1.isBold() == cr2.isBold() && cr1.isItalic() == cr2.isItalic()
    && cr1.getFontName().equals(cr2.getFontName())

&& cr1.getFontSize() == cr2.getFontSize()) {
   flag = true;
  }
  return flag;
 }

/**
  * 写文件(成功返回true,失败则返回false)
  *
  * @param s
  *            要写入的内容
  * @param filePath
  *            文件
  */
 private static boolean writeFile(String s, String filePath) {
  FileOutputStream fos = null;
  BufferedWriter bw = null;
  s = s.replaceAll("EMBED", "").replaceAll("Equation.DSMT4", "");
  try {
   makeDir(projectRealPath, tempPath);// 创建文件夹
   File file = new File(filePath);
   if (file.exists()) {
    return false;
   }
   fos = new FileOutputStream(file);
   bw = new BufferedWriter(new OutputStreamWriter(fos, "utf-

8"));
   bw.write(s);
   // System.out.println(filePath + "文件写入成功!");
  } catch (FileNotFoundException fnfe) {
   fnfe.printStackTrace();
  } catch (IOException ioe) {
   ioe.printStackTrace();
  } finally {
   try {
    if (bw != null)
     bw.close();
    if (fos != null)
     fos.close();
   } catch (IOException ie) {
    ie.printStackTrace();
   }
  }
  return true;
 }

/**
  * 根据路径名生成多级路径
  *
  * @param url
  *            参数要以"\classes\cn\qtone\"或者"/classes/cn/qtone/"
  */
 private static String makeDir(String root, String url) {
  String[] sub;
  url = url.replaceAll("

\\/", "\\\\");
  if (url.indexOf("\\") > -1) {
   sub = url.split("\\\\");
  } else {
   return "-1";
  }

File dir = null;
  try {
   dir = new File(root);
   for (int i = 0; i < sub.length; i++) {
    if (!dir.exists() && !sub[i].equals("")) {
     dir.mkdir();
    }
    File dir2 = new File(dir + File.separator + sub[i]);
    if (!dir2.exists()) {
     dir2.mkdir();
    }
    dir = dir2;
   }
  } catch (Exception e) {
   e.printStackTrace();
   return "-1";
  }
  return dir.toString();
 }

/**
  * 将word文档转化,返回转化后的文件路径
  *
  * @param projectPath
  *            项目路径
  * @param relativeFilePath
  *            文件相对路径
  * @return 返回生成的htm路径(如果出错,则返回null)
  */
 public static String wordToHtml(String projectPath, String relativeFilePath) {
  String resultPath = null;
  projectRealPath = projectPath;// 项目路径
  String filePath = "";
  // System.out.println(projectRealPath + tempPath);
  // System.out.println(makeDir(projectRealPath, tempPath));
  try {
   File file = new File(projectPath + relativeFilePath);
   if (file.exists()) {
    if (file.getName().indexOf(".doc") == -1 ||

file.getName().indexOf(".docx") > 0) {
     throw new FileFormatException("请确认文

件格式为doc!");
    } else {
     wordName = file.getName();
     wordName = wordName.substring(0,

wordName.indexOf("."));

filePath = projectRealPath + tempPath +

wordName + ".htm";
     synchronized (relativeFilePath) {// 处理线程

同步问题
      File ff = new File(filePath);
      if (!ff.exists()) {// 如果不存在则进

行转换
       getWordAndStyle

(projectPath + relativeFilePath);
       writeFile(htmlText,

filePath);
      }
     }
     resultPath = tempPath + wordName +

".htm";
    }
   } else {
    throw new FileNotFoundException("没找到相关文件!

");
   }
  } catch (NullPointerException e) {
   e.printStackTrace();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return resultPath;
 }
}

Wmf2Png文件
package com;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;
import java.util.zip.GZIPOutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import net.arnx.wmf2svg.gdi.svg.SvgGdi;
import net.arnx.wmf2svg.gdi.wmf.WmfParser;

import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.TranscodingHints;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.transcoder.wmf.tosvg.WMFTranscoder;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class Wmf2Png {
 public static void main(String[] args) throws Exception {
  // convert("F:\\SVN\\BobUtil\\web\\25177.wmf");
  // System.out.println((20 / (21 * 1.0)));
  // svgToPng("F:\\SVN\\BobUtil\\web\\25177.svg",

"F:\\SVN\\BobUtil\\web\\25177.png");
 }

/**
  * @Description: 进行转换
  * @param filePath
  *            文件路径
  * @return 设定文件
  */
 public static String convert(String filePath) {
  String pngFile = "";
  File wmfFile = new File(filePath);
  try {
   if (!wmfFile.getName().contains(".wmf")) {
    throw new Exception("请确认输入的文件类型是

wmf");
   }
   // wmf -> svg
   String svgFile = filePath.replace("wmf", "svg");
   wmfToSvg(filePath, svgFile);
   // 对svg做预出理
   PreprocessSvgFile(svgFile);
   // svg -> png
   pngFile = filePath.replace("wmf", "png");
   svgToPng(svgFile, pngFile);
   // 删除 svg
   File file = new File(svgFile);
   if (file.exists()) {
    file.delete();
   }
   // 删除 wmf
   if (wmfFile.exists()) {
    wmfFile.delete();
   }

} catch (Exception e) {
   try {
    e.printStackTrace();
    wmfToJpg(filePath);
   } catch (Exception e1) {
    e1.printStackTrace();
   }
  }
  return wmfFile.getName().replace("wmf", "png");
 }

/**
  * 将wmf转换为svg
  *
  * @param src
  * @param dest
  */
 public static void wmfToSvg(String src, String dest) throws Exception {
  boolean compatible = false;
  try {
   InputStream in = new FileInputStream(src);
   WmfParser parser = new WmfParser();
   final SvgGdi gdi = new SvgGdi(compatible);
   parser.parse(in, gdi);

Document doc = gdi.getDocument();
   OutputStream out = new FileOutputStream(dest);
   if (dest.endsWith(".svgz")) {
    out = new GZIPOutputStream(out);
   }

output(doc, out);
  } catch (Exception e) {
   throw e;
  }
 }

/**
  * @Description: 输出svg文件
  * @param doc
  * @param out
  * @throws Exception
  *             设定文件
  */
 private static void output(Document doc, OutputStream out) throws Exception {
  TransformerFactory factory = TransformerFactory.newInstance();
  Transformer transformer = factory.newTransformer();
  transformer.setOutputProperty(OutputKeys.METHOD, "xml");
  transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
  transformer.setOutputProperty(OutputKeys.INDENT, "yes");
  transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,

"-//W3C//DTD SVG 1.0//EN");
  transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
    "http://www.w3.org/TR/2001/REC-SVG-

20010904/DTD/svg10.dtd");
  transformer.transform(new DOMSource(doc), new StreamResult(out));
  out.flush();
  out.close();
  out = null;
 }

/**
  * @Description:对svg文件做预处理(这里主要是调整大小,先缩小10倍,如果还大

于默认值,则按比例缩小)
  * @param svgFile
  * @throws Exception
  *             设定文件
  */
 private static void PreprocessSvgFile(String svgFile) throws Exception {
  int defaultWeight = 500;// 默认宽度
  FileInputStream inputs = new FileInputStream(svgFile);
  Scanner sc = new Scanner(inputs, "UTF-8");
  ByteArrayOutputStream os = new ByteArrayOutputStream();
  while (sc.hasNextLine()) {
   String ln = sc.nextLine();
   if (!ln.startsWith("<!DOCTYPE")) {
    os.write((ln + "\r\n").getBytes());
   }
  }
  os.flush();
  
  DocumentBuilderFactory factory =

DocumentBuilderFactory.newInstance();
  DocumentBuilder builder;
  builder = factory.newDocumentBuilder();
  Document doc = null;
  try {
   doc = builder.parse(new ByteArrayInputStream

(os.toByteArray()));
  } catch (Exception e) {
   inputs = new FileInputStream(svgFile);
   os = new ByteArrayOutputStream();
   int noOfByteRead = 0;
   while ((noOfByteRead = inputs.read()) != -1) {
    os.write(noOfByteRead);
   }
   os.flush();
   doc = builder.parse(new ByteArrayInputStream

(os.toByteArray()));
  } finally {
   os.close();
   inputs.close();
  }
  
  int height = Integer.parseInt(((Element) doc.getElementsByTagName

("svg").item(0)).getAttribute("height"));
  int width = Integer.parseInt(((Element) doc.getElementsByTagName

("svg").item(0)).getAttribute("width"));
  int newHeight = 0;// 新高
  int newWidth = 0;// 新宽
  newHeight = height / 10;// 高缩小10倍
  newWidth = width / 10; // 宽缩小10倍
  // 如果缩小10倍后宽度还比defaultHeight大,则进行调整
  if (newWidth > defaultWeight) {
   newWidth = defaultWeight;
   newHeight = defaultWeight * height / width;
  }

((Element) doc.getElementsByTagName("svg").item(0)).setAttribute

("width", String.valueOf(newWidth));
  ((Element) doc.getElementsByTagName("svg").item(0)).setAttribute

("height", String.valueOf(newHeight));
  OutputStream out = new FileOutputStream(svgFile);
  output(doc, out);
 }

/**
  * 将svg图片转成png图片
  *
  * @param filePath
  * @throws Exception
  */
 public static void svgToPng(String svgPath, String pngFile) throws Exception {
  File svg = new File(svgPath);
  FileInputStream wmfStream = new FileInputStream(svg);
  ByteArrayOutputStream imageOut = new ByteArrayOutputStream();
  int noOfByteRead = 0;
  while ((noOfByteRead = wmfStream.read()) != -1) {
   imageOut.write(noOfByteRead);
  }
  imageOut.flush();
  imageOut.close();
  wmfStream.close();

ByteArrayOutputStream jpg = new ByteArrayOutputStream();
  FileOutputStream jpgOut = new FileOutputStream(pngFile);

byte[] bytes = imageOut.toByteArray();
  PNGTranscoder t = new PNGTranscoder();
  TranscoderInput in = new TranscoderInput(new ByteArrayInputStream

(bytes));
  TranscoderOutput out = new TranscoderOutput(jpg);
  t.transcode(in, out);
  jpgOut.write(jpg.toByteArray());
  jpgOut.flush();
  jpgOut.close();
  imageOut = null;
  jpgOut = null;
 }

/**
  * 将wmf图片转成png图片(备用方法,即当上面的转换失败时用这个)
  *
  * @param filePath
  * @throws Exception
  */
 public static String wmfToJpg(String wmfPath) throws Exception {
  //先wmf-->svg
  File wmf = new File(wmfPath);
  FileInputStream wmfStream = new FileInputStream(wmf);
  ByteArrayOutputStream imageOut = new ByteArrayOutputStream();
  int noOfByteRead = 0;
  while ((noOfByteRead = wmfStream.read()) != -1) {
   imageOut.write(noOfByteRead);
  }
  imageOut.flush();
  imageOut.close();
  wmfStream.close();

// WMFHeaderProperties prop = new WMFHeaderProperties(wmf);
  WMFTranscoder transcoder = new WMFTranscoder();
  TranscodingHints hints = new TranscodingHints();
  transcoder.setTranscodingHints(hints);
  TranscoderInput input = new TranscoderInput(new

ByteArrayInputStream(imageOut.toByteArray()));
  ByteArrayOutputStream svg = new ByteArrayOutputStream();
  TranscoderOutput output = new TranscoderOutput(svg);
  transcoder.transcode(input, output);
  
  //再svg-->png
  ByteArrayOutputStream jpg = new ByteArrayOutputStream();
  String jpgFile = StringUtils.replace(wmfPath, "wmf", "png");
  FileOutputStream jpgOut = new FileOutputStream(jpgFile);

byte[] bytes = svg.toByteArray();
  PNGTranscoder t = new PNGTranscoder();
  TranscoderInput in = new TranscoderInput(new ByteArrayInputStream

(bytes));
  TranscoderOutput out = new TranscoderOutput(jpg);
  t.transcode(in, out);
  jpgOut.write(jpg.toByteArray());
  jpgOut.flush();
  jpgOut.close();
  return jpgFile;
 }
}

重点难点解释探讨:

1)  读取表格部分:

a)        找出表格的开始与结束标记;

b)        遍历整个表格内容,逐个单元格的内容取出并追加到变量中。

2)  读取图片部分

a)        图片文件的格式问题。

如果图片格式为png或者jpg,则可以直接进行处理并加入标签中,前台的html展示没有问题,

但是,如果图片格式为wmf(详细看附录1),则html无法对基解释,那么我们只能对其进行

转换格式:

百度后,网上很多说法都建议用batik工具包进行格式转换,其实思路就是:wmfàsvgàpng。

查阅相关资料(如附录2),发现其处理svg文件的能力相当的强,即从svg—>png这一步是比

较完美的。但是,在处理wmf—>svg这一步却导致部分图像丢失,即失真的情况,且很严重。

查看相关的api看是否参数设置问题,但是无论怎么设置,结果还是不尽人意。一度想放弃,

找别的包。

后来,无意中,在csdn中有网友建议先用wmf2svg工具类将wmf转换为svg,再用batik将svg转

换为png。Very good!!有了这个思路,感觉已经看到署光了。

类写出来后,进行类型转换测试,确实效果很好,完全没有失真。于是将其嵌入word—>html

这个工具类中。再用各种包含了wmf图片的文档进行测试。生成的html文件,基本没有问题,

当时那个开心啊!!(我去,程序员也就这德行)

好景不长,放到正式项目进行测试过程中,发现有个别文档一进行转换,服务器就跨了,直接

报内存溢出。通过排查检测,原来就是进行图片转换过程中,将内存给挤爆了。奇怪了,虽然

知道图片处理是比较耗内存,但也没想到1G的内存,一下子就被挤爆(刚跑起来占去300M左

右,一跑word转换功能,不过一会就报OutOfMemorry)。

一度怀疑,是不是batik这个工具包是不是有bug,处理不了大的svg。还将问题放上了bakit的

官网。后来,查看相关资料后,发现是wmf2svg工具生成的svg的高与宽都太大了,举个例子

:15040* 13088,宽高都达到上万级别,结果得到的象素是上亿的,不爆内存才怪。

用dom工具,将每一个生成的svg文件再进行预处理,即将其高与宽都先缩小一倍,如果宽度

依然比500要大,则将其设成500,并将高也按比例缩小。经过此步骤生成的svg再用batik进行

转换就没有任何问题了。

到这里,差不多已经解决图片转换的问题了,但是,在使用过程中,发现wmf2svg这个工具也

不是很稳定,偶尔会报异常,并且,我测试发现,报异常的这个wmf用之前batik直接进行wmf

—>svgàpng的方案可以成功生成没有失真的png,于是,在wmf2svg的产生异常进行捕捉,并

调用了wmfToJpg(String wmfPath)的备用方法。到此,大部分的wmf转换问题已经解决。

b)        生成html文本的<img />标签的width与height问题。

如果图片格式原本为png的话,直接用

// 获取图片样式
  int picHeight = pic.getHeight() * pic.getAspectRatioY() / 100;
  int picWidth = pic.getAspectRatioX() * pic.getWidth() / 100;

即可以将图片的宽与高设置与word文档一致;但是,发果wmf格式,要分两种情况分析:
Ø  如果转换生成的png宽度不小于500,则将期作为一般图片处理:
BufferedImage  image = ImageIO.read(file);
int pheight = image.getHeight();
int pwidth = image.getWidth();

Ø  如果转换生成的png宽度小于500,则认为是一般的公式,则应该与它旁边的字体宽度相近

,这里设成字体的1.5倍宽度,高度为:
myHeight= (int) (pheight / (pwidth / (picSize * 1.0)) * 1.5);

如果图片即非wmf与非png(如jpg)的情况下,上面获取高与宽的方法不起作用,不知道是不

是POI的bug。只能按以下方式处理:
BufferedImage  image = ImageIO.read(file);
int pheight = image.getHeight();
int pwidth = image.getWidth();
即跟上面处理wmf的第一种方式一致。

结束语

讲到这,将word转换成html的处理也大体上讲完了。这几天的边学边用,特别是真正能解决问

题的时候,非常有成就感。其实,上面的处理还存在以下的问题待解决的:

1)读取表格部分:

a)        表格中如果再含有表格,POI无法进行很好的区分,比如,有一个两行两列的表格中,

第一行第一列中又包含了一个两行两列的表格,那POI会将此表格解释成:第一行为2+2*2 =

6个单元格;第二行为2个单元格,这样解释出来的表格就很怪异了。

b)        表格中有果有合并单格的情况,程序暂未做此处理(后续看不能优化),表格也很怪

异。

c)        表格中如果有图像,程序没有做相应的处理。

2)读取图片部分:

a) 有部分wmf->png的方式有个别图片还是没有转换成功,会报异常,但没有影响整体的功能

b) word有部分公式生成的图片无法识别模式,不知道是不是POI无法将其解释,还是其他原因

,就是有文档,生成没有后缀的图片文件,且这部分文件无法读取,用图片工具也打不开,暂

时未找到很好的解决方案。

3)读取word的目录:

在读取目录会出现将格式化符号也解释出来。

4)其他未知的一些问题,反正,就觉得用POI来解释word是件很坚苦的事情,如果全是文本

还好,如果里面包含图片,表格,公式等这些对象的时候,POI就显得太弱了。

附:

1.       wmf文件:

MicrosoftOffice 的剪贴画使用的就是这个格式。

Wmf是WindowsMetafile 的缩写,简称图元文件,它是微软公司定义的一种Windows平台下的

图形文件格式。

wmf格式文件的特点如下:

1)                 wmf格式文件是MicrosoftWindows操作平台所支持的一种图形格式文件,目前

,其它操作系统尚不支持这种格式,如Unix、Linux等。

2)                 与bmp格式不同,wmf格式文件是和设备无关的,即它的输出特性不依赖于具

体的输出设备。

3)                 其图象完全由Win32 API所拥有的GDI函数来完成。

4)                 wmf格式文件所占的磁盘空间比其它任何格式的图形文件都要小得多。

5)                 在建立图元文件时,不能实现即画即得,而是将GDI调用记录在图元文件中,

之后,在GDI环境中重新执行,才可显示图象。

6)                 显示图元文件的速度要比显示其它格式的图象文件慢,但是它形成图元文件的

速度要远大于其它格式。

2.      Batik介绍

Batik是使用svg格式图片来实现各种功能的应用程序以及Applet提供的一个基于java的工具包

通过Batik,你可以在JAVA可以使用的地方操作SVG文档,您还可以在你的应用程序使用Batik模

块来生成, 处理和转码SVG图像。Batik很容易让基于Java的应用程序或小程序来处理SVG内容

。 例如,使用Batik的SVG的发生器模块 ,Java应用程序或小程序可以很轻松地导出SVG格式

的图形到。用Batik的SVG的查看组件,应用程序或小程序可以很容易地集成SVG的浏览和交互

功能。另一种可能性是使用Batik的模块转换成各种格式SVG的通过,如光栅图像(JPEG,PNG

或TIFF格式)或其它矢量格式(EPS或PDF格式,后两者由于转码器由Apache FOP提供)。

Batik工程创建的目的是为开发者提供一系列可以结合或单独使用来支持特殊的svg解决方案的

核心模块。模块主要有SVGParser,SVGGernerator,SVGDOM。Batik工程的其他目的是使它具有

高度的扩展性。

(SVG的规范:可缩放矢量图形(SVG),是一个W3C的推荐标准。 它定义了丰富的2D图形的

XML语法,其中包括诸如透明度功能,几何形状,滤镜效果(阴影,灯光效果等),脚本和动

画)

POI Word 模板导出教程

word2007功能比较完善,2003只有值替换的功能
功能目标,读取word模板,解析数据导出word,对数据赋值
功能点1: 值替换
功能点2: 表格的创建
功能点3: 图片的插入
下面将根据这个三个功能点来做讲解
1.值替换 最基础的功能
在word中需要插入数据的地方加入{{test}}Or{{obj.test}}
支持实体对象,和map类型的取值
例如
取值的时候就是 {{workers}}
替换的对象会保留原格式,如加粗,则替换后仍然加粗

2.表格
表格也是Word里面经常出现的
解析是放在一个List里面,这个也是大家经常这样的
里面的对象同样可以是map也可以是实体
例如:
其中in 表示需要变量这个对象 psrsons是一个person的list(需要独占一行)
紧接着下一行是他的属性
之后程序会进行迭代,生成表格
3.图片
这里就要介绍一个实体了WordImageEntity
会把这个类型的实体转变成图片,同样准信值替换的原则
例如
最后我们看一下效果
生成的对象

poi操作word模板(word2003,word2007)

Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。Word2003的方法比较简单,大致通过Range替换文本,Word2007比较复杂点,遍历替换文本,参考了网上的案例,写了个demo,直接上代码。
package com.poi.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import com.poi.model.Person;

public class WordUtil {
 private Map<String, String> map = new HashMap<String, String>();//存放标签与替换的值
 private String templatePath;//模版路径

public WordUtil(String templatePath,Person person) {
  this.templatePath = templatePath;
  if (templatePath.endsWith("docx")) {
   try {
    @SuppressWarnings("resource")
    XWPFWordExtractor docx = new XWPFWordExtractor(
      POIXMLDocument.openPackage(templatePath));
    String docxText = docx.getText();
    getValueMap(docxText,person);
   } catch (Exception e) {
    e.printStackTrace();
   }
  } else {
   try {
    @SuppressWarnings("resource")
    WordExtractor doc = new WordExtractor(new FileInputStream(
      templatePath));
    String docText = doc.getText();
    getValueMap(docText,person);
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
 }
 //遍历获取标签与通过对象替代的值
 private void getValueMap(String text,Person person) {
  Pattern pattern = Pattern.compile("%(.*?)%");
  Matcher matcher = pattern.matcher(text);
  while (matcher.find()) {
   String key = matcher.group(1);
   String value = person.getString(key);
   if (value == null) {
    value = "";
   }
   map.put(key, value);
  }
 }
 public void createDoc(String newPath) {
  if (templatePath.endsWith("docx")) {
   replaceDoc2007(newPath);
  } else {
   replaceDoc2003(newPath);
  }
 }

public void replaceDoc2007(String newPath) {
  try {
   OPCPackage pack = POIXMLDocument.openPackage(templatePath);
   XWPFDocument doc = new XWPFDocument(pack);
   // 处理段落
   List<XWPFParagraph> paragraphList = doc.getParagraphs();
   processParagraphs(paragraphList, map);
   // 处理表格
   Iterator<XWPFTable> it = doc.getTablesIterator();
   while (it.hasNext()) {
    XWPFTable table = it.next();
    List<XWPFTableRow> rows = table.getRows();
    for (XWPFTableRow row : rows) {
     List<XWPFTableCell> cells = row.getTableCells();
     for (XWPFTableCell cell : cells) {
      List<XWPFParagraph> paragraphListTable = cell
        .getParagraphs();
      processParagraphs(paragraphListTable, map);
     }
    }
   }
   FileOutputStream fos = new FileOutputStream(newPath);
   doc.write(fos);
   fos.flush();
   fos.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

public void replaceDoc2003(String newPath) {
  String[] str = newPath.split(".doc");
  newPath = str[0] + ".doc";
  try {
   FileInputStream fis = new FileInputStream(new File(templatePath));
   HWPFDocument doc = new HWPFDocument(fis);
   Range bodyRange = doc.getRange();
   for (Map.Entry<String, String> entry : map.entrySet()) {
    bodyRange.replaceText("%" + entry.getKey() + "%",
      entry.getValue());
   }
   // 输出word文件
   ByteArrayOutputStream ostream = new ByteArrayOutputStream();
   doc.write(ostream);
   OutputStream outs = new FileOutputStream(newPath);
   outs.write(ostream.toByteArray());
   outs.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

private void processParagraphs(List<XWPFParagraph> paragraphList,
   Map<String, String> map) {
  for (XWPFParagraph paragraph : paragraphList) {
   List<XWPFRun> runs = paragraph.getRuns();
   for (XWPFRun run : runs) {
    String text = run.getText(0);
    boolean isSetText = false;
    for (Map.Entry<String, String> entry : map.entrySet()) {
     String key = entry.getKey();
     if (text.indexOf(key) != -1) {
      isSetText = true;
      text = text.replace("%" + entry.getKey() + "%",entry.getValue());
     }
    }
    if (isSetText) {
     run.setText(text, 0);
    }
   }
  }
 }

}

POI处理WORD的另类方式

大致的思路是先用office2003或者2007编辑好word的样式,然后另存为xml,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Doc。经测试这样方式生成的word文档完全符合office标准,样式、内容控制非常便利,打印也不会变形,生成的文档和office中编辑文档完全一样。

看看实际效果:

首先用office【版本要2003以上,以下的不支持xml格式】编辑文档的样式,图中红线的部分就是我要输出的部分:doc1

将编辑好的文档另存为XML

doc2

再用Firstobject free XML editor【Firstobject free XML editor的使用见这里】将xml中我们需要填数据的地方打上FreeMarker标记【FreeMarker的语法见这里】

doc3

最后生成的文档样式

doc4

package com.havenliu.document;
 
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
 
public class DocumentHandler {
private Configuration configuration = null;
 
public DocumentHandler() {
configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
}
 
public void createDoc() {
//要填入模本的数据文件
Map dataMap=new HashMap();
getData(dataMap);
//设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
//这里我们的模板是放在com.havenliu.document.template包下面
configuration.setClassForTemplateLoading(this.getClass(), "/com/havenliu/document/template");
Template t=null;
try {
//test.ftl为要装载的模板
t = configuration.getTemplate("test.ftl");
} catch (IOException e) {
e.printStackTrace();
}
//输出文档路径及名称
File outFile = new File("D:/temp/outFile.doc");
Writer out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
 
        try {
t.process(dataMap, out);
} catch (TemplateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
 
/**
* 注意dataMap里存放的数据Key值要与模板中的参数相对应
* @param dataMap
*/
private void getData(Map dataMap)
 {
 dataMap.put("author", "张三");
 dataMap.put("remark", "这是测试备注信息");
 List
 _table1=new ArrayList
();
 
 Table1 t1=new Table1();
 t1.setDate("2010-10-1");
 t1.setText("制定10月开发计划内容。");
 _table1.add(t1);
 
 Table1 t2=new Table1();
 t2.setDate("2010-10-2");
 t2.setText("开会讨论开发计划");
 _table1.add(t2);
 
 dataMap.put("table1", _table1);
 
 List
 _table2=new ArrayList
();
 for(int i=0;i<5;i++)
 {
 Table2 _t2=new Table2();
 _t2.setDetail("测试开发计划"+i);
 _t2.setPerson("张三——"+i);
 _t2.setBegindate("2010-10-1");
 _t2.setFinishdate("2010-10-31");
 _t2.setRemark("备注信息");
 _table2.add(_t2);
 }
 dataMap.put("table2", _table2);
 }
}

poi操作word文档总结相关推荐

  1. 使用poi操作word文档实现套打功能

    使用poi操作word文档实现套打功能 本文目的是为了分享一个实现套打功能,但是不同于简单的word的文本替换而是采用poi对word的文本框就行操作实现的功能: poi中各种jar的说明 套打的实现 ...

  2. POI操作Word文档工具

    POI操作Word文档工具 1.POI简单介绍 2.POI操作Word文档基本方法 3.POI操作Word文档基本方法应用 4.POI操作Word文档工具类 1.POI简单介绍 POIFS(可疑混淆执 ...

  3. Poi 操作Word文档设置页边距 解决CTPageMar类找不到

    Poi操作Word文档设置页边距 CTPageMar类找不到 已解决 在百度上搜了一顿,找到了相关的解决方案,但是缺失了一个类,在百度怎么也找不到! 给大家一个参考数据 1厘米≈567 CTSectP ...

  4. POI操作word文档-添加上标下标

    背景: 接了新需求,前端提供一个大概的word模板,包含通用信息,用户在前端填写可修改内容至模板完善,然后将整个数据传递给后端进行保存,后端提供导出word的功能. 数据中包含这种类型,由于前端输出框 ...

  5. POI操作word文档,生成书签

    近期做动态的word文档生成, 需要在指定XWPFRun生成书签的功能,有两种情况: 创建新word文档时候,直接在createRun前后调用生成书签的方法 XWPFRun oldRun = runs ...

  6. poi处理word内容的公式_利用poi操作word文档

    关键字:POI JAVA 批注 总页数 总字符数 一:认识POI Apache POI是一个开源的利用Java读写Excel.WORD等微软OLE2组件文档的项目.最新的3.5版本有很多改进,加入了对 ...

  7. 利用poi操作word文档(针对docx格式)

    一:认识POI  Apache POI是一个开源的利用Java读写Excel.WORD等微软OLE2组件文档的项目.最新的3.5版本有很多改进,加入了对采用OOXML格式的Office 2007支持, ...

  8. poi操作word文档(替换,插入图片)

    前段时间项目上要用到一个替换word中的字符以及插入图片并导出的功能,google了一番发现别人的代码跑起来多多少少有些问题,所以就自己照着poi的api写了一个工具类,在此记录下来,如果有需要的朋友 ...

  9. java用poi导出word,Java使用POI导出Word文档的操作教程,poiword

    Java使用POI导出Word文档的操作教程,poiword 一.主要pom依赖 org.apache.poi poi-ooxml 3.16 二.需要导出word模板 三.相关导出代码 package ...

最新文章

  1. Redis最佳实践:7个维度+43条使用规范,带你彻底玩转Redis | 附实践清单
  2. 乐视电视明明可以降低配置,为什么偏偏要涨价?
  3. java监控队列_java-Spring Rabbit监听输出队列或接收
  4. Docker-构建/启停容器镜像及常用命令介绍
  5. 移动国家号(MCC)
  6. 定点乘法运算之原码一位乘法
  7. Mysql like ' ' 会不会用到索引
  8. mybatis 存储过程 tmp_count_mysql存储过程(一)-navicat与mybatis
  9. Tcl Tutorial 笔记9 · proc 参数传递与return
  10. 行业研究方法与框架合集
  11. python adf单位根检验 如何查看结果
  12. Don't let the things you own end up owing you
  13. 乔纳森·艾维:iPhoneX准备了五年,苹果仍在不断创新
  14. 天线远场定义_天线场区划分的定义
  15. retroarch java,跨平台模拟器 RetroArch
  16. java jmx 监控tomcat_通过Tomcat开启JMX监控的方法图解
  17. [FAQ21007] 电信VoLTE开关默认值设置
  18. QGIS 1. qgis的下载和安装(Windows和macOS)
  19. 那些你可能不知道的谷歌浏览器实用技巧
  20. H5页面背景音乐,C33 360°旋转效果

热门文章

  1. 你问我答:听说你做订阅号挣了 100W ?
  2. python打印26个英文字母和数字
  3. check 和nocheck
  4. upupoo启动不了 mysql_显示桌面快捷方式
  5. oCam 中文绿色版 - 免费实用的屏幕录像与截图软件 (制作视频教程/录制直播视频)
  6. 《花雕学AI》07:AI脑洞大开-盘点最火爆人工智能ChatGPT的23种新颖用法
  7. H3C系列交换机系统版本升级及导入配置
  8. 带劲!厂内全流程智能仓储物流系统
  9. 虎年第一条微信,拜年啦
  10. 高德地图宣布品牌升级,打造出门好生活开放服务平台