package com.test;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
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.XWPFStyle;
import org.apache.poi.xwpf.usermodel.XWPFStyles;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
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;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
public class ReadDoc {
private static Map<String, Map<String, Object>> orderMap = new HashMap<String, Map<String, Object>>();
public void init(String targetPath, String sourcePath) {
InputStream is = null;
XWPFDocument doc = null;
OutputStream out = null;
try {
XWPFDocument createDoc = new XWPFDocument();
is = new FileInputStream(sourcePath);
doc = new XWPFDocument(is);
// 获取段落
List<XWPFParagraph> paras = doc.getParagraphs();
for (XWPFParagraph para : paras) {
// System.out.println(para.getCTP());//得到xml格式
System.out.println(para.getStyleID());// 段落级别
System.out.println(para.getParagraphText());// 段落内容
String titleLvl = getTitleLvl(doc, para);// 获取段落级别
if ("a5".equals(titleLvl) || "HTML".equals(titleLvl) || "".equals(titleLvl) || null == titleLvl) {
titleLvl = "8";
}
System.out.println(titleLvl + "-----");// 0,1,2
if (!"8".equals(titleLvl)) {
System.out.println(titleLvl + "====" + para.getParagraphText());
}
XWPFParagraph ctPara = createDoc.createParagraph();
// 一个XWPFRun代表具有相同属性的一个区域。
XWPFRun ctRun = ctPara.createRun();
String ctText = para.getParagraphText();
ctRun.setFontFamily("宋体");// 字体
ctRun.setFontSize(12);
if (null != titleLvl && !"".equals(titleLvl) && !"8".equals(titleLvl)) {
addCustomHeadingStyle(createDoc, titleLvl, Integer.parseInt(titleLvl));
String orderCode = getOrderCode(titleLvl);// 获取编号
ctText = orderCode + " " + ctText;
ctRun.setBold(true);// 标题加粗
ctRun.setFontSize(14);
ctPara.setStyle(titleLvl);
} else {// 正文
ctPara.setIndentationFirstLine(567);// 首行缩进:567==1厘米
// ctRun.setTextPosition(6);//设置行间距
}
ctRun.setText(ctText);// 内容
}
out = new FileOutputStream(targetPath);
createDoc.write(out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != out) {
out.close();
}
if (null != is) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Word中的大纲级别,可以通过getPPr().getOutlineLvl()直接提取,但需要注意,Word中段落级别,通过如下三种方式定义:
* 1、直接对段落进行定义; 2、对段落的样式进行定义; 3、对段落样式的基础样式进行定义。
* 因此,在通过“getPPr().getOutlineLvl()”提取时,需要依次在如上三处读取。
*
* @param doc
* @param para
* @return
*/
private static String getTitleLvl(XWPFDocument doc, XWPFParagraph para) {
String titleLvl = "";
try {
// 判断该段落是否设置了大纲级别
if (para.getCTP().getPPr().getOutlineLvl() != null) {
// System.out.println("getCTP()");
// System.out.println(para.getParagraphText());
// System.out.println(para.getCTP().getPPr().getOutlineLvl().getVal());
return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) {
e.printStackTrace();
}
try {
// 判断该段落的样式是否设置了大纲级别
if (doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) {
// System.out.println("getStyle");
// System.out.println(para.getParagraphText());
// System.out.println(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
return String.valueOf(
doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) {
e.printStackTrace();
}
try {
// 判断该段落的样式的基础样式是否设置了大纲级别
if (doc.getStyles().getStyle(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal())
.getCTStyle().getPPr().getOutlineLvl() != null) {
// System.out.println("getBasedOn");
// System.out.println(para.getParagraphText());
String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal();
// System.out.println(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
return String
.valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (para.getStyleID() != null) {
return para.getStyleID();
}
} catch (Exception e) {
e.printStackTrace();
}
return titleLvl;
}
/**
* 增加自定义标题样式。这里用的是stackoverflow的源码
*
* @param docxDocument 目标文档
* @param strStyleId 样式名称
* @param headingLevel 样式级别
*/
private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {
CTStyle ctStyle = CTStyle.Factory.newInstance();
ctStyle.setStyleId(strStyleId);
CTString styleName = CTString.Factory.newInstance();
styleName.setVal(strStyleId);
ctStyle.setName(styleName);
CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
indentNumber.setVal(BigInteger.valueOf(headingLevel));
// lower number > style is more prominent in the formats bar
ctStyle.setUiPriority(indentNumber);
CTOnOff onoffnull = CTOnOff.Factory.newInstance();
ctStyle.setUnhideWhenUsed(onoffnull);
// style shows up in the formats bar
ctStyle.setQFormat(onoffnull);
// style defines a heading of the given level
CTPPr ppr = CTPPr.Factory.newInstance();
ppr.setOutlineLvl(indentNumber);
ctStyle.setPPr(ppr);
XWPFStyle style = new XWPFStyle(ctStyle);
// is a null op if already defined
XWPFStyles styles = docxDocument.createStyles();
style.setType(STStyleType.PARAGRAPH);
styles.addStyle(style);
}
/**
* @param id
* @param width
* 宽
* @param height
* 高
* @param paragraph
* 段落
*/
public static void createPicture(XWPFDocument docxDocument, int id, int width, int height, XWPFParagraph paragraph) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
String blipId = docxDocument.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=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
+ " <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("图片名称");
docPr.setDescr("描述信息");
}
/**
* 获取标题编号
*
* @param titleLvl
* @return
*/
private static String getOrderCode(String titleLvl) {
String order = "";
if ("0".equals(titleLvl) || Integer.parseInt(titleLvl) == 8) {// 文档标题||正文
return "";
} else if (Integer.parseInt(titleLvl) > 0 && Integer.parseInt(titleLvl) < 8) {// 段落标题
// 设置最高级别标题
Map<String, Object> maxTitleMap = orderMap.get("maxTitleLvlMap");
if (null == maxTitleMap) {// 没有,表示第一次进来
// 最高级别标题赋值
maxTitleMap = new HashMap<String, Object>();
maxTitleMap.put("lvl", titleLvl);
orderMap.put("maxTitleLvlMap", maxTitleMap);
} else {
String maxTitleLvl = maxTitleMap.get("lvl") + "";// 最上层标题级别(0,1,2,3)
if (Integer.parseInt(titleLvl) < Integer.parseInt(maxTitleLvl)) {// 当前标题级别更高
maxTitleMap.put("lvl", titleLvl);// 设置最高级别标题
orderMap.put("maxTitleLvlMap", maxTitleMap);
}
}
// 查父节点标题
int parentTitleLvl = Integer.parseInt(titleLvl) - 1;// 父节点标题级别
Map<String, Object> cMap = orderMap.get(titleLvl);// 当前节点信息
Map<String, Object> pMap = orderMap.get(parentTitleLvl + "");// 父节点信息
if (0 == parentTitleLvl) {// 父节点为文档标题,表明当前节点为1级标题
int count = 0;
// 最上层标题,没有父节点信息
if (null == cMap) {// 没有当前节点信息
cMap = new HashMap<String, Object>();
} else {
count = Integer.parseInt(String.valueOf(cMap.get("cCount")));// 当前序个数
}
count++;
order = count + "";
cMap.put("cOrder", order);// 当前序
cMap.put("cCount", count);// 当前序个数
orderMap.put(titleLvl, cMap);
} else {// 父节点为非文档标题
int count = 0;
// 如果没有相邻的父节点信息,当前标题级别自动升级
if (null == pMap) {
return getOrderCode(String.valueOf(parentTitleLvl));
} else {
String pOrder = String.valueOf(pMap.get("cOrder"));// 父节点序
if (null == cMap) {// 没有当前节点信息
cMap = new HashMap<String, Object>();
} else {
count = Integer.parseInt(String.valueOf(cMap.get("cCount")));// 当前序个数
}
count++;
order = pOrder + "." + count;// 当前序编号
cMap.put("cOrder", order);// 当前序
cMap.put("cCount", count);// 当前序个数
orderMap.put(titleLvl, cMap);
}
}
// 字节点标题计数清零
int childTitleLvl = Integer.parseInt(titleLvl) + 1;// 子节点标题级别
Map<String, Object> cdMap = orderMap.get(childTitleLvl + "");//
if (null != cdMap) {
cdMap.put("cCount", 0);// 子节点序个数
orderMap.get(childTitleLvl + "").put("cCount", 0);
}
}
return order;
}
public static void main(String[] args) {
InputStream is = null;
OutputStream out = null;
try {
XWPFDocument createDoc = new XWPFDocument();
addCustomHeadingStyle(createDoc, "z标题 1", 1);
addCustomHeadingStyle(createDoc, "z标题 2", 2); // 标题 1
XWPFParagraph paragraph = createDoc.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("z标题 1");
run.setFontFamily("宋体");// 字体
run.setBold(true);
run.setFontSize(24);
paragraph.setStyle("z标题 1"); // 标题 2
paragraph.setAlignment(ParagraphAlignment.CENTER);//对齐方式
XWPFParagraph paragraph2 = createDoc.createParagraph();
XWPFRun run2 = paragraph2.createRun();
run2.setText("z标题 2");
run2.setFontFamily("宋体");// 字体
run2.setBold(true);
run2.setFontSize(20);
paragraph2.setStyle("z标题 2"); // 正文
paragraph2.setAlignment(ParagraphAlignment.CENTER);//对齐方式
XWPFParagraph paragraphX = createDoc.createParagraph();
XWPFRun runX = paragraphX.createRun();
runX.setText("正文"); // word 写入到文件
/*is = new FileInputStream("D:/20190417-MRO-工程设计-招标书(标段一).docx");
doc = new XWPFDocument(is);
// 获取段落
List<XWPFParagraph> paras = doc.getParagraphs();*/
// for (XWPFParagraph para : paras) {
// System.out.println("得到xml格式-->" + para.getCTP());//得到xml格式
// System.out.println("段落级别-->" + para.getStyleID());// 段落级别
// System.out.println("段落内容-->" + para.getParagraphText());// 段落内容
/*
* String titleLvl = getTitleLvl(doc, para);// 获取段落级别 if ("a5".equals(titleLvl)
* || "HTML".equals(titleLvl) || "".equals(titleLvl) || null == titleLvl) {
* titleLvl = "8"; } System.out.println("获取段落级别-->" + titleLvl);// 0,1,2 if
* (!"8".equals(titleLvl)) { System.out.println("获取段落级别-->" + titleLvl +
* "====段落内容-->" + para.getParagraphText()); }
*/
XWPFParagraph ctPara = createDoc.createParagraph();
// 一个XWPFRun代表具有相同属性的一个区域。
XWPFRun ctRun = ctPara.createRun();
ctPara.setIndentationFirstLine(567);// 首行缩进:567==1厘米 //
// String ctText = para.getParagraphText();
ctRun.setFontFamily("宋体");// 字体
ctRun.setFontSize(12);
ctRun.setTextPosition(6);//设置行间距
String con = "areaTxt--><h1 style=\"text-align: center;\"><span style=\"font-weight: bold; font-family: 宋体; background-color: rgb(194, 79, 74);\">15</span></h1><div><span style=\"font-family: 宋体; background-color: rgb(255, 255, 255);\">1sdfsdf</span></div><div><span style=\"font-family: 宋体; background-color: rgb(255, 255, 255);\">2水电费都是发生的</span></div>";
ctRun.setText(con);// 内容
// }
XWPFParagraph ctPara2 = createDoc.createParagraph();
XWPFRun ctRun2 = ctPara2.createRun();
// String ctText = para.getParagraphText();
ctRun2.setFontFamily("宋体");// 字体
ctRun2.setFontSize(12);
String con2 = "areaTxt--><h1 style=\"text-align: center;\"><span style=\"font-weight: bold; font-family: 宋体; background-color: rgb(194, 79, 74);\">15</span></h1><div><span style=\"font-family: 宋体; background-color: rgb(255, 255, 255);\">1sdfsdf</span></div><div><span style=\"font-family: 宋体; background-color: rgb(255, 255, 255);\">2水电费都是发生的</span></div>";
ctRun2.setText(con2);// 内容
// XWPFDocument doc = new XWPFDocument(); // 创建一个 5 行 5 列的表格
XWPFTable table = createDoc.createTable(5, 5); // 这里增加的列原本初始化创建的那 5 行在通过 getTableCells()方法获取时获取不到,但通过 row 新增的就可以。
//table.addNewCol(); // 给表格增加一列,变成 6 列
table.createRow(); // 给表格新增一行,变成 6 行
List<XWPFTableRow> rows = table.getRows(); // 表格属性
CTTblPr tablePr = table.getCTTbl().addNewTblPr(); // 表格宽度
CTTblWidth width = tablePr.addNewTblW();
width.setW(BigInteger.valueOf(8000));
XWPFTableRow row;
List<XWPFTableCell> cells;
XWPFTableCell cell;
for (int i1 = 0; i1 < rows.size(); i1++) {
row = rows.get(i1); // 新增单元格
row.addNewTableCell(); // 设置行的高度
row.setHeight(500); // 行属性 //CTTrPr rowPr = row.getCtRow().addNewTrPr(); // 这种方式是可以获取到新增的 cell 的。
// //List list = row.getCtRow().getTcList();
cells = row.getTableCells();
for (int j = 0; j < cells.size(); j++) {
cell = cells.get(j);
if ((i1 + j) % 2 == 0) { // 设置单元格的颜色
cell.setColor("ff0000"); // 红色
} else {
cell.setColor("0000ff"); // 蓝色
} // 单元格属性
CTTcPr cellPr = cell.getCTTc().addNewTcPr();
cellPr.addNewVAlign().setVal(STVerticalJc.CENTER);
if (j == 3) { // 设置宽度
cellPr.addNewTcW().setW(BigInteger.valueOf(3000));
}
cell.setText(i1 + "," + j);
}
}
FileInputStream in = new FileInputStream("IMG20190130_160416.png");
byte[] ba = new byte[in.available()];
in.read(ba);
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(ba);
XWPFParagraph picture = createDoc.createParagraph();
//添加图片
createDoc.addPictureData(byteInputStream, XWPFDocument.PICTURE_TYPE_PNG);
//图片大小、位置
createPicture(createDoc, createDoc.getAllPictures().size() - 1, 500, 500, picture);
// 文件不存在时会自动创建
out = new FileOutputStream("new1.docx");
createDoc.write(out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != out) {
out.close();
}
if (null != is) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}