需求描述:本次主要是对后端生成word的页眉的改造,之前是使用前端控件WebOffice生成的,这种生成方式,对于PC端的操作是没有什么问题,但是对于手机App端生成页眉就造成了影响,没办法通过前端控件去实现。所以必须要把整个word的生成,全部通过后端去实现,到时候App只需要实现调用后端代码就行。由于前期word的生成,是POI技术通过替换合同模板的占位符形式实现的,所以本次主要的改造点主要就是实现页眉的生成,但是页眉的生成还要考虑以下几点情况:
1.合同文本的首页页眉与其它页页眉是不同的,首页页眉是展示条形码,条形码就是直接使用word里面的字体:C39HrP24DlTt实现的,其它页展示的是合同编号。
2.页眉的生成还有3种情况,第一种是本身合同模板是有页眉的,且页眉是有内容的;第二种是合同模板是没有页眉的;第三种是合同模板加了页眉,但是页眉里面是没有值的,值为空。所以在生成页眉的时候,需要考虑这几种情况,处理的方式会有些许差别。
好了,问题分析完了之后,进入正题:
首先需要强调一点的是,目前生成word页眉的POI版本貌似都是4.0之后的版本才行,4.0之前的版本我试了很多种方案都不行(我用的是4.1.1的版本,4.0.1也是OK的)。如果你的系统本来用的是4.0之前的版本,那么升级4.0之后,很多类对应的属性也会改变,尤其是生成EXCEL的很多属性,具体可以百度一下,改变前后的都有对照说明。
还要补充一点的是,如果你的pom.xml文件中有xbean这个依赖,一定要删除,否则会和4.0之后的POI依赖产生冲突。
我就卡在这个坑里,卡了很久,一直报: java.lang.NoClassDefFoundError: Could not initialize class org.apache.poi.ooxml.POIXMLTypeLoader的错,但是打开对应的类里面,明明是可以直接跳转过去,jar包里面明明是有POIXMLTypeLoader这个jar包的,最后才发现了是这个原因导致的。
下面直接上代码:
public static void main(String[] args) throws Exception{
File is = new File(“D:\Desktop\oldWord.docx”);//文件路径
FileInputStream fis = new FileInputStream(is);
XWPFDocument doc = new XWPFDocument(fis);//文档对象
//获取页眉,判断页眉是否为空
List<XWPFHeader> pageHeaders = doc.getHeaderList();
//若判断合同没有页眉时
if(pageHeaders.isEmpty()) {
//生成首页页眉
XWPFParagraph paragraph=doc.createHeader(HeaderFooterType.FIRST).createParagraph();
XWPFRun run =paragraph.createRun();
paragraph.setAlignment(ParagraphAlignment.CENTER);
run.setText("我是一个首页页眉");
run.setFontFamily("C39HrP24DlTt");//设置页眉字体,这里是条形码字体
//生成偶数页的页眉
paragraph=doc.createHeader(HeaderFooterType.EVEN).createParagraph();
run =paragraph.createRun();
paragraph.setAlignment(ParagraphAlignment.LEFT);
run.setText("我是与首页页眉不一样的其它页页眉");
run.setFontSize(8);//设置页眉字体大小
//生成奇数页的页眉
paragraph=doc.createHeader(HeaderFooterType.DEFAULT).createParagraph();
run =paragraph.createRun();
paragraph.setAlignment(ParagraphAlignment.LEFT);
run.setText("我是与首页页眉不一样的其它页页眉");//其它页页眉内容与首页不同,但奇数页和偶数页要单独设置成一样的内容
Field filedSet = XWPFDocument.class.getDeclaredField("settings");
filedSet.setAccessible(true);
XWPFSettings xwpfsettings = (XWPFSettings)filedSet.get(doc);
Field filedCtSet = XWPFSettings.class.getDeclaredField("ctSettings");
filedCtSet.setAccessible(true);
CTSettings ctSettings =(CTSettings)filedCtSet.get(xwpfsettings);
ctSettings.addNewEvenAndOddHeaders();
}else {
//当合同文本有页眉时,内容不为空,将原内容进行替换
for(XWPFHeader pageHeader : pageHeaders){
List<XWPFParagraph> paragraphs = pageHeader.getParagraphs();
for(XWPFParagraph paragraph : paragraphs){
List<XWPFRun> runs = paragraph.getRuns();
//合同有页眉,但是内容可能为空,对照上面第2 点
if(!runs.isEmpty()) {
for(int i=0;i<runs.size();i++){
XWPFRun run = runs.get(i);
run.setText("我是一个页眉,我要替换本来的页眉",0);
paragraph.setAlignment(ParagraphAlignment.RIGHT);//设置页眉左对齐
}
}else {
//生成首页页眉
XWPFParagraph paragraph2=doc.createHeader(HeaderFooterType.FIRST).createParagraph();
XWPFRun run =paragraph2.createRun();
paragraph2.setAlignment(ParagraphAlignment.CENTER);//设置页眉居中
run.setText("我是一个首页页眉");
run.setFontFamily("C39HrP24DlTt");
//生成偶数页的页眉
paragraph2=doc.createHeader(HeaderFooterType.EVEN).createParagraph();
run =paragraph2.createRun();
paragraph2.setAlignment(ParagraphAlignment.LEFT);
run.setText("我是与首页页眉不一样的其它页页眉");
run.setFontSize(8);
//生成奇数页的页眉
paragraph2=doc.createHeader(HeaderFooterType.DEFAULT).createParagraph();
run =paragraph2.createRun();
paragraph2.setAlignment(ParagraphAlignment.LEFT);
run.setText("我是与首页页眉不一样的其它页页眉");
Field filedSet = XWPFDocument.class.getDeclaredField("settings");
filedSet.setAccessible(true);
XWPFSettings xwpfsettings = (XWPFSettings)filedSet.get(doc);
Field filedCtSet = XWPFSettings.class.getDeclaredField("ctSettings");
filedCtSet.setAccessible(true);
CTSettings ctSettings =(CTSettings)filedCtSet.get(xwpfsettings);
ctSettings.addNewEvenAndOddHeaders();
//此处一定要断开循环
break;
}
}
}
}
doc.write(new FileOutputStream("D:\\Users\\newWord.docx"));
doc.close();
System.out.println("OK");
}
以上生成的逻辑说明:我们的情况是,如果合同没有页眉,则默认首页塞入条形码,其它页塞入合同编号;
若合同有页眉且有值的情况下,就全部页眉都塞入合同编号,不区分首页和其它页。