适用场景
通过 apache poi 库导出带表格的 word 文件,并且表格的宽度可能过宽,需要纸张横向或者更大的纸张
需要的包
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.1</version>
</dependency>
模板代码
import cn.hutool.extra.spring.SpringUtil;
import com.ylkj.tydb.common.service.UserService;
import com.ylkj.tydb.export.domain.HeaderCell;
import com.ylkj.tydb.export.domain.WordStyle;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import java.math.BigInteger;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
public abstract class AbstractFileTemplate {
private Date exportDate;
/**
* 换行符标记
*/
private static final String LINE_MARK = "\n";
/**
* A4纸宽度
*/
private static final BigInteger PAPER_A4_W = BigInteger.valueOf(11907);
/**
* A4纸高度
*/
private static final BigInteger PAPER_A4_H = BigInteger.valueOf(16840);
public XWPFDocument exportWord() {
UserService userService = SpringUtil.getBean(UserService.class);
userService.setSessionUser();
XWPFDocument document = new XWPFDocument();
createDocument(document);
return document;
}
/**
* 创建文档方法
* @param document 文档
*/
abstract protected void createDocument(XWPFDocument document);
/**
* 获取导出文件名称
* @return 导出文件名称
*/
abstract public String getFileName();
/**
* 设置换行
* @param value 需要换行的内容
* @param paragraph 当前段落
* @param style 文字格式
*/
protected void setText(String value, XWPFParagraph paragraph, WordStyle style) {
XWPFRun run = paragraph.createRun();
if (value.indexOf(LINE_MARK) > 0) {
//设置换行
String[] text = value.split(LINE_MARK);
run = paragraph.insertNewRun(0);
for (int f = 0; f < text.length; f++) {
if (f == 0) {
run.setText(text[f].trim());
} else {
run.addCarriageReturn();//硬回车
run.setText(text[f].trim());
}
}
} else {
run.setText(value);
}
run.setColor(style.getColor());
run.setFontSize(style.getFontSize());
run.setBold(style.isBold());
}
protected WordStyle getMainTextWordStyle(){
return new WordStyle();
}
protected WordStyle getKeyPointTextWordStyle(){
WordStyle style = new WordStyle();
style.setBold(true);
return style;
}
protected void setTable(List<HeaderCell> headerData, List<LinkedHashMap<String,Object>> dataList, String tableName, XWPFDocument document, boolean pageHorizontal){
//若是需要将纸张方向改变为横向,需要提前将之前的方向设定为纵向作为分割,否则会将之前的内容也变为横向
if(pageHorizontal){
XWPFParagraph paragraph = document.createParagraph();
CTSectPr ctSectPr = paragraph.getCTP().addNewPPr().addNewSectPr();
CTPageSz ctPageSz = ctSectPr.addNewPgSz();
// 必须要设置下面两个参数,否则整个的代码是无效的
ctPageSz.setW(PAPER_A4_W);
ctPageSz.setH(PAPER_A4_H);
ctPageSz.setOrient(STPageOrientation.PORTRAIT);
}
// 设置表格的标题
setText(tableName,document.createParagraph(),getKeyPointTextWordStyle());
XWPFTable infoTable = document.createTable();
infoTable.setWidthType(TableWidthType.PCT);
// 表格标题行
XWPFTableRow headers = infoTable.getRow(0);
if(headerData!=null && headerData.size()>=1){
XWPFTableCell cell = headers.getCell(0);
cell.setText(headerData.get(0).getLabel());
cell.setWidth(headerData.get(0).getColumnWidth());
}
for (int i = 1; i < headerData.size(); i++) {
XWPFTableCell cell = headers.addNewTableCell();
cell.setText(headerData.get(i).getLabel());
cell.setWidth(headerData.get(i).getColumnWidth());
}
// 表格的数据行
for (LinkedHashMap<String,Object> item : dataList){
XWPFTableRow row = infoTable.createRow();
for (int cellNum = 0; cellNum < headerData.size(); cellNum++) {
XWPFTableCell cell = row.getCell(cellNum);
cell.setText(item.get(headerData.get(cellNum).getCode())+"");
cell.setWidth(headerData.get(cellNum).getColumnWidth());
}
}
// 若是需要将纸张方向改变为横向,在这里设置,纸张的方向由分割后最后的段落指定
if(pageHorizontal){
XWPFParagraph paragraph = document.createParagraph();
CTSectPr ctSectPr = paragraph.getCTP().addNewPPr().addNewSectPr();
CTPageSz ctPageSz = ctSectPr.addNewPgSz();
// 必须要设置下面两个参数,否则整个的代码是无效的
// A3纸横向 宽度为A4纸宽度两倍,高度为A4纸高度
ctPageSz.setW(PAPER_A4_W.multiply(BigInteger.valueOf(2)));
ctPageSz.setH(PAPER_A4_H);
ctPageSz.setOrient(STPageOrientation.LANDSCAPE);
}
}
protected void setTable(List<HeaderCell> headers, List<LinkedHashMap<String,Object>> dataList, String tableName, XWPFDocument document){
setTable(headers,dataList,tableName,document,false);
}
public Date getExportDate() {
return exportDate;
}
public void setExportDate(Date exportDate) {
this.exportDate = exportDate;
}
}
转换纸张方向的关键代码
XWPFParagraph paragraph = document.createParagraph();
CTSectPr ctSectPr = paragraph.getCTP().addNewPPr().addNewSectPr();
CTPageSz ctPageSz = ctSectPr.addNewPgSz();
// 必须要设置下面两个参数,否则整个的代码是无效的
// A3纸横向 宽度为A4纸宽度两倍,高度为A4纸高度
ctPageSz.setW(PAPER_A4_W.multiply(BigInteger.valueOf(2)));
ctPageSz.setH(PAPER_A4_H);
ctPageSz.setOrient(STPageOrientation.LANDSCAPE);
假如想要在同一个文档中多次调整纸张的方向和大小,就要在需要调节的纸张的末尾添加一个额外的段落来修改 CTSectPr
对象,下面的代码会使整个文档都变成调整后的纸张样式。
CTDocument1 document1 = document.getDocument();
CTBody body = document1.getBody();
CTSectPr ctSectPr = body.addNewSectPr();
CTPageSz ctPageSz = ctSectPr.addNewPgSz();
ctPageSz.setW(PAPER_A4_W.multiply(BigInteger.valueOf(2)));
ctPageSz.setH(PAPER_A4_H);
ctPageSz.setOrient(STPageOrientation.LANDSCAPE);
另附上用到的两个实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HeaderCell {
private String code;
private String label;
private int span = 1;
private List<HeaderCell> children;
private String columnWidth = "300";
public HeaderCell(String code, String label) {
this.code = code;
this.label = label;
}
public HeaderCell(String code, String label, String columnWidth) {
this.code = code;
this.label = label;
this.columnWidth = columnWidth;
}
public void setChildren(List<HeaderCell> children) {
if(children!=null){
this.span = children.size();
this.children = children;
}
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WordStyle {
private String color = "000000";
private int fontSize = 16;
private boolean bold = false;
}