简介
word编程最重要的类是org.apache.poi.xwpf.usermodel.xwpfdocument。涉及的东西十分复杂。而且apache poi操作word的技术非常不成熟。代码中本身有很多bug。
maven的依赖为
<dependency> <groupid>org.apache.poi</groupid> <artifactid>poi-ooxml</artifactid> <version>5.0.0</version> </dependency>
以下代码创建一个空word文档。
public class emptyword { public static void main(string[] args) throws ioexception { xwpfdocument document = new xwpfdocument(); file file = new file("test.word"); document.write(new fileoutputstream(file)); } }
段落
首先看看段落与字体设置。
假设有需要生成一个一级标题,利用document创建段落。每个段落又有多个run组成。run不能继续拆分,一个run拥有共同的字体。如以下代码创建一个段落:
final xwpfparagraph paragraph = document.createparagraph(); paragraph.setnumilvl(biginteger.valueof(1l)); final xwpfrun run = paragraph.createrun(); run.settext("老了"); run.setfontsize(10); run.setcolor("ffff00"); run.setfontfamily("宋书");
而段落的大纲级别的设置比较复杂,代码如下
ctppr ppr = paragraph.getctp().getppr(); if (ppr == null) { ppr = paragraph.getctp().addnewppr(); } final ctdecimalnumber ctdecimalnumber = ppr.addnewoutlinelvl(); ctdecimalnumber.setval(biginteger.valueof(1)); ppr.setoutlinelvl(ctdecimalnumber);
这里有一个难懂的概念,什么是ctp。
其效果如下:
页头与页脚
页头与页脚测试时发现生成的页头和页脚只能在word中看到,在wps里看不到。这可能是poi的一个bug。生成页头和页脚都比较简单。
final xwpfdocument document = new xwpfdocument(); final xwpfheader header = document.createheader(headerfootertype.default); final xwpfparagraph paragraph = header.createparagraph(); final xwpfrun run = paragraph.createrun(); run.settext("我是页头"); run.setfontsize(12); run.setcolor("ff00ff"); system.out.println(header.gettext());
页脚为:
// 页脚呢 final xwpffooter footer = document.createfooter(headerfootertype.default); final xwpfparagraph footerparagraph = footer.createparagraph(); final xwpfrun footerparagraphrun = footerparagraph.createrun(); footerparagraphrun.settext("页脚"); footerparagraphrun.setfontsize(12);
完整效果如下:
页码
生成页码的方法比较复杂。但是值得挑战一下。
final xwpffooter footer = document.createfooter(headerfootertype.default); xwpfparagraph paragraph = footer.createparagraph(); xwpfrun run = paragraph.createrun(); run.settext("第"); run = paragraph.createrun(); ctfldchar ctfldchar = run.getctr().addnewfldchar(); ctfldchar.setfldchartype(stfldchartype.begin); // 又一段 run = paragraph.createrun(); cttext cttext = run.getctr().addnewinstrtext(); cttext.setstringvalue("page \\* mergeformat"); cttext.setspace(spaceattribute.space.enum.forstring("preserve")); ctfldchar = run.getctr().addnewfldchar(); ctfldchar.setfldchartype(stfldchartype.end); run = paragraph.createrun(); run.settext("页 总共"); run = paragraph.createrun(); ctfldchar = run.getctr().addnewfldchar(); ctfldchar.setfldchartype(stfldchartype.begin); run = paragraph.createrun(); cttext = run.getctr().addnewinstrtext(); cttext.setstringvalue("numpages \\* mergeformat"); cttext.setspace(spaceattribute.space.enum.forstring("preserve")); ctfldchar = run.getctr().addnewfldchar(); ctfldchar.setfldchartype(stfldchartype.end); run = paragraph.createrun(); run.settext("页");
同样,兼容word,不兼容wps。
效果如下:
表格
word里插入表格,是非常常见的功能。
final xwpfdocument document = new xwpfdocument(); final xwpftable table = document.createtable(3, 3); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { table.getrow(i).getcell(j).settext(i+"-"+j); } }
表格有点丑,但是勉强可以用哈:
图片
插入图片也是必要的功能啊,代码示例如下:
string imagepath = "image.png"; // 图片路径 fileinputstream imagestream = new fileinputstream(imagepath); // 设置图片尺寸(单位:emu) int width = units.toemu(300); // 宽度(约4厘米) int height = units.toemu(200); // 高度 final xwpfparagraph paragraph = document.createparagraph(); final xwpfrun run = paragraph.createrun(); // 插入图片 run.addpicture( imagestream, xwpfdocument.picture_type_png, // 图片格式 "image.png", // 描述文本 width, height ); imagestream.close();
插入图片效果:
批注
word编程加批注是十分困难的、十分复杂的。在poi里,有同名的包,不能导错,以下是正确的包:
import org.openxmlformats.schemas.wordprocessingml.x2006.main.ctcomment; import org.openxmlformats.schemas.wordprocessingml.x2006.main.ctcomments; import org.openxmlformats.schemas.wordprocessingml.x2006.main.cttext;
首先要写一个辅助类,辅助类倒是比较简单:
public class myxwpfcommentsdocument extends poixmldocumentpart { private ctcomments ctcomments; private myxwpfcommentsdocument(packagepart part) { super(part); ctcomments = commentsdocument.factory.newinstance().addnewcomments(); } public ctcomments getctcomments() { return ctcomments; } @override protected void commit() throws ioexception { xmloptions xmloptions = new xmloptions(poixmltypeloader.default_xml_options); xmloptions.setsavesyntheticdocumentelement(new qname(ctcomments.type.getname().getnamespaceuri(), "comments")); packagepart part = getpackagepart(); outputstream out = part.getoutputstream(); ctcomments.save(out, xmloptions); out.close(); } public static myxwpfcommentsdocument createcommentsdocument(xwpfdocument document) throws exception { opcpackage opcpackage = document.getpackage(); packagepartname partname = packagingurihelper.createpartname("/word/comments.xml"); packagepart part = opcpackage.createpart(partname, "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"); myxwpfcommentsdocument myxwpfcommentsdocument = new myxwpfcommentsdocument(part); string rid = "rid" + (document.getrelationparts().size()+1); document.addrelation(rid, xwpfrelation.comment, myxwpfcommentsdocument); return myxwpfcommentsdocument; } }
以下是加入批注的方法:
myxwpfcommentsdocument myxwpfcommentsdocument = myxwpfcommentsdocument.createcommentsdocument(document); ctcomments comments = myxwpfcommentsdocument.getctcomments(); ctcomment ctcomment; xwpfparagraph paragraph; //first comment biginteger cid = biginteger.zero; ctcomment = comments.addnewcomment(); cttext cttext = ctcomment.addnewp().addnewr().addnewt(); cttext.setstringvalue("the first comment."); ctcomment.setauthor("axel ríchter"); ctcomment.setinitials("ar"); ctcomment.setid(cid); paragraph = document.createparagraph(); paragraph.getctp().addnewcommentrangestart().setid(cid); xwpfrun run; run = paragraph.createrun(); run.settext("paragraph with the first comment."); paragraph.getctp().addnewcommentrangeend().setid(cid); paragraph.getctp().addnewr().addnewcommentreference().setid(cid);
以下是批注的效果:
文本框
文本框的插入也是比较复杂,代码如下:
xwpfparagraph paragraph = document.createparagraph(); xwpfrun run=paragraph.createrun(); run.settext("the body text: "); ctgroup ctgroup = ctgroup.factory.newinstance(); ctshape ctshape = ctgroup.addnewshape(); ctshape.setstyle("width:100pt;height:24pt"); cttxbxcontent cttxbxcontent = ctshape.addnewtextbox().addnewtxbxcontent(); cttxbxcontent.addnewp().addnewr().addnewt().setstringvalue("the textbox text..."); node ctgroupnode = ctgroup.getdomnode(); ctpicture ctpicture = ctpicture.factory.parse(ctgroupnode); run=paragraph.createrun(); ctr ctr = run.getctr(); ctr.addnewpict(); ctr.setpictarray(0, ctpicture);
简单展示下效果:
目录
目录本来就一句话doc.createtoc(),但是很容易失败。使用ctppr可以设置段落的大纲级别,以下是代码:
try (xwpfdocument document = new xwpfdocument()) { document.createtoc(); final xwpfparagraph paragraph = document.createparagraph(); // 获取段落属性,若不存在则新建 ctppr ppr = paragraph.getctp().issetppr() ? paragraph.getctp().getppr() : paragraph.getctp().addnewppr(); // 设置大纲级别为 1 ctdecimalnumber outlinelvl = ppr.issetoutlinelvl() ? ppr.getoutlinelvl() : ppr.addnewoutlinelvl(); outlinelvl.setval(biginteger.valueof(1)); final xwpfrun run = paragraph.createrun(); run.settext("标题一"); run.setfontsize(10); run.setfontfamily("宋书"); file file = new file("toc.docx"); document.write(files.newoutputstream(file.topath())); }
虽然代码运行不报错,但是结果是生成不了目录。以下是效果图:
图表
英文叫chart,chart是需要关联excel表格的。所以这个特别复杂。完整代码如下:
// create the data string[] categories = new string[] { "lang 1", "lang 2", "lang 3" }; double[] valuesa = new double[] { 10d, 20d, 30d }; double[] valuesb = new double[] { 15d, 25d, 35d }; // create the chart xwpfchart chart = doc.createchart(15 * units.emu_per_centimeter, 10 * units.emu_per_centimeter); // create data sources int numofpoints =categories. length; string categorydatarange = chart.formatrange(new cellrangeaddress(1, numofpoints, 0, 0)); string valuesdatarangea = chart.formatrange(new cellrangeaddress(1, numofpoints, 1, 1)); string valuesdatarangeb = chart.formatrange(new cellrangeaddress(1, numofpoints, 2, 2)); xddfdatasource<string> categoriesdata = xddfdatasourcesfactory.fromarray(categories, categorydatarange, 0); xddfnumericaldatasource<double> valuesdataa = xddfdatasourcesfactory.fromarray(valuesa, valuesdatarangea, 1); xddfnumericaldatasource<double> valuesdatab = xddfdatasourcesfactory.fromarray(valuesb, valuesdatarangeb, 2); // create axis xddfcategoryaxis bottomaxis = chart.createcategoryaxis(axisposition.bottom); xddfvalueaxis leftaxis = chart.createvalueaxis(axisposition.left); leftaxis.setcrosses(axiscrosses.auto_zero); // set axiscrossbetween, so the left axis crosses the category axis between the categories. // else first and last category is exactly on cross points and the bars are only half visible. leftaxis.setcrossbetween(axiscrossbetween.between); // create chart data xddfchartdata data = chart.createdata(charttypes.bar, bottomaxis, leftaxis); ((xddfbarchartdata) data).setbardirection(bardirection.col); // create series // if only one series do not vary colors for each bar ((xddfbarchartdata) data).setvarycolors(false); xddfchartdata.series series = data.addseries(categoriesdata, valuesdataa); // xddfchart.setsheettitle is buggy. it creates a table but only half way and incomplete. // excel cannot opening the workbook after creatingg that incomplete table. // so updating the chart data in word is not possible. //series.settitle("a", chart.setsheettitle("a", 1)); series.settitle("a", settitleindatasheet(chart, "a", 1)); /* // if more than one series do vary colors of the series ((xddfbarchartdata)data).setvarycolors(true); series = data.addseries(categoriesdata, valuesdatab); //series.settitle("b", chart.setsheettitle("b", 2)); series.settitle("b", settitleindatasheet(chart, "b", 2)); */ // plot chart data chart.plot(data); // create legend xddfchartlegend legend = chart.getoraddlegend(); legend.setposition(legendposition.left); legend.setoverlay(false);
还有一个私有方法:
static cellreference settitleindatasheet(xwpfchart chart, string title, int column) throws exception { xssfworkbook workbook = chart.getworkbook(); xssfsheet sheet = workbook.getsheetat(0); xssfrow row = sheet.getrow(0); if (row == null) row = sheet.createrow(0); xssfcell cell = row.getcell(column); if (cell == null) cell = row.createcell(column); cell.setcellvalue(title); return new cellreference(sheet.getsheetname(), 0, column, true, true); }
运行效果如下:
以上就是java操作word的全面指南的详细内容,更多关于java操作word的资料请关注代码网其它相关文章!
发表评论