在实际开发中,我们可能会遇到比较复杂的导出word的业务场景,比如添加段落,添加图片,添加表格,有时候表格还有特定的样式,比如单元格水平居中,垂直居中,有背景颜色等等,或者同一个表格在一份word文件里出现在不同的地方,这个时候我们通常不能用简答版的word去开发了。虽然步骤是一样的,但是开发难度明显加大。
1. 设置模板(一般在这样的场景中,首页一般都是定制的,用java去实现出来比较费劲,所以我建议建立两份模板文件,第一份用来保存首页,第二份用来保存word文件里导出需要用到的表格或图片。)
2. 编写代码
2.1 添加依赖
<!-- Excel = EasyPoi -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.0.0</version>
<exclusions>
<exclusion>
<artifactId>commons-lang3</artifactId>
<groupId>org.apache.commons</groupId>
</exclusion>
</exclusions>
</dependency>
2.2 编写controller
package com.mayi1203.myproject.controller;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.LineSpacingRule;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.TableRowAlign;
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.XWPFTableCell.XWPFVertAlign;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mayi1203.myproject.entity.Entity;
import cn.afterturn.easypoi.cache.WordCache;
import cn.afterturn.easypoi.word.WordExportUtil;
@RestController
@RequestMapping(value = "/v1/test")
public class TestController {
private static final String TEMPLATE_FILE_NAME = "word/template.docx";
private static final String HELPER_TEMPLATE_FILE_NAME = "word/templateHelper.docx";
private static final String IMAGE_FILE_NAME = "img/template.png";
public static final DecimalFormat PERCENTAGE_DECIMAL_FORMAT = new DecimalFormat("0.00%");
@GetMapping("exportWord")
public void exportWord(HttpServletResponse response) throws Exception {
// 填充参数
Map<String, Object> map = new HashMap<>(9);
map.put("0", "one");
map.put("1", "two");
map.put("2", "three");
map.put("3", "four");
map.put("4", "five");
map.put("5", "six");
XWPFDocument document = WordExportUtil.exportWord07(TEMPLATE_FILE_NAME, map);
// 添加段落
XWPFParagraph paragraph = document.createParagraph();
// 设置段前间距,120是6磅
paragraph.setSpacingBefore(120);
// 设置段后间距,120是6磅
paragraph.setSpacingAfter(120);
// 设置行距,固定值25磅
paragraph.setSpacingBetween(30, LineSpacingRule.EXACT);
// 设置水平对齐方式
// paragraph.setAlignment(ParagraphAlignment.CENTER);
// 设置首行缩进建议用4个空格代替,代码里的单位是毫米
// paragraph.setBorderBottom(Borders.THICK_THIN_SMALL_GAP);
// 设置缩进文本之前,单位是毫米。
// paragraph.setIndentationLeft(400);
// 设置缩进文本之后,单位是毫米。
// paragraph.setIndentFromRight(400);
// 设置段落底纹
CTPPr ppr = paragraph.getCTP().getPPr();
CTShd shd = ppr.addNewShd();
shd.setVal(STShd.CLEAR);
// 设置段落底纹颜色
shd.setFill("D9D9D9");
// 添加字体
XWPFRun run = paragraph.createRun();
// 设置加粗
run.setBold(true);
// 设置字体大小,16是三号
run.setFontSize(16);
// 设置字符间距
run.setCharacterSpacing(20);
// 设置字体
run.setFontFamily("宋体");
// 设置文本
run.setText("这是测试段落-------------------,昨天是520,没有情人,只能敲代码。难受想哭!!!!!!!!");
// 设置字体颜色
run.setColor("FF0000");
// 设置大写,比如my name is zhangsan,会变成MY NAME IS ZHANGSAN。
// run.setCapitalized(true);
// 设置双删除线
// run.setDoubleStrikethrough(true);
// 设置着重号
// run.setEmphasisMark("dot");
// 设置斜体
// run.setItalic(true);
// 设置小型大写字母
// run.setSmallCaps(true);
// 设置删除线
// run.setStrikeThrough(true);
// 设置下划线
// run.setUnderline(UnderlinePatterns.DASH);
// 设置下划线颜色
// run.setUnderlineColor("FF0000");
// 设置消失
// run.setVanish(true);
// XWPFRun secondRun = paragraph.createRun();
// // 设置上标
// secondRun.setSubscript(VerticalAlign.SUPERSCRIPT);
// secondRun.setText("2");
// XWPFRun thirdRun = paragraph.createRun();
// // 设置下标
// thirdRun.setSubscript(VerticalAlign.SUBSCRIPT);
// thirdRun.setText("3");
// 换行
// run.addBreak();
// 添加回车
// run.addCarriageReturn();
// 添加图片,有时候图片展示不全,可以提高行距来使图片展示完整。
// InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(IMAGE_FILE_NAME);
// int pictureType = Document.PICTURE_TYPE_PNG;
// width = 360000 * 效果图的宽度(单位厘米)/12700
// int width = Units.toEMU(183.685);
// height = 360000 * 效果图的高度(单位厘米)/12700
// int height = Units.toEMU(26.646);
// run.addPicture(inputStream, pictureType, IMAGE_FILE_NAME, width, height);
// 换页
// paragraph.setPageBreak(true);
document.createParagraph();
XWPFDocument helperDocument = WordCache.getXWPFDocumen(HELPER_TEMPLATE_FILE_NAME);
XWPFTable sourceTable = helperDocument.getTableArray(1);
XWPFTableRow sourceRow = sourceTable.getRow(0);
XWPFTable table = document.createTable(1, sourceRow.getTableCells().size());
this.copyFirstRow(table, sourceRow);
this.copyTableStyle(table, sourceTable);
List<Entity> list = new ArrayList<>(10);
this.addData(list);
final int size = list.size();
for(int i = 0; i < size; i++) {
XWPFTableRow row = table.createRow();
// 设置行高
row.setHeight(600);
List<XWPFTableCell> cellList = row.getTableCells();
Entity entity = list.get(i);
final int cellSize = cellList.size();
for(int j = 0; j < cellSize; j++) {
XWPFTableCell cell = cellList.get(j);
// 设置列宽
cell.setWidth(String.valueOf(sourceRow.getCell(j).getWidth()));
cell.setWidthType(sourceRow.getCell(j).getWidthType());
// 设置垂直对齐方式
cell.setVerticalAlignment(XWPFVertAlign.CENTER);
XWPFParagraph cellPara = cell.getParagraphArray(0);
// 设置水平对齐方式
cellPara.setAlignment(ParagraphAlignment.CENTER);
XWPFRun cellRun = cellPara.createRun();
cellRun.setFontFamily("宋体");
cellRun.setFontSize(11);
// 隔行换色
if(i % 2 != 0) {
CTShd ctshd = cell.getCTTc().addNewTcPr().addNewShd();
ctshd.setVal(STShd.CLEAR);
// 设置底纹颜色
ctshd.setFill("D9D9D9");
}
if(j == 0) {
cellRun.setBold(true);
cellRun.setText(entity.getName());
}else if(j == 1) {
cellRun.setText(entity.getPrice().toString());
}else if(j == 2) {
cellRun.setText(PERCENTAGE_DECIMAL_FORMAT.format(entity.getMonthLimit()));
}else if(j == 3) {
cellRun.setText(PERCENTAGE_DECIMAL_FORMAT.format(entity.getYearLimit()));
}
}
}
String fileName = System.currentTimeMillis() + ".docx";
response.reset();
response.setContentType("application/msword");
String dispositionValue = "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-disposition", dispositionValue);
response.setCharacterEncoding("UTF-8");
OutputStream output = response.getOutputStream();
document.write(output);
document.close();
output.close();
}
private void addData(List<Entity> list) {
Entity entity = new Entity("深证100", new BigDecimal("4658.12"), new BigDecimal("0.0791"), new BigDecimal("0.0160"));
list.add(entity);
entity = new Entity("深圳成指", new BigDecimal("10430.77"), new BigDecimal("0.0762"), new BigDecimal("0.0279"));
list.add(entity);
entity = new Entity("沪深300", new BigDecimal("4096.58"), new BigDecimal("0.0614"), new BigDecimal("0.0449"));
list.add(entity);
entity = new Entity("上证指数", new BigDecimal("3050.12"), new BigDecimal("0.0399"), new BigDecimal("0.0623"));
list.add(entity);
entity = new Entity("上证50", new BigDecimal("3063.22"), new BigDecimal("0.0642"), new BigDecimal("0.0657"));
list.add(entity);
entity = new Entity("恒生指数", new BigDecimal("28189.75"), new BigDecimal("0.0441"), new BigDecimal("0.1258"));
list.add(entity);
entity = new Entity("道琼斯指数", new BigDecimal("28538.44"), new BigDecimal("0.1108"), new BigDecimal("0.1469"));
list.add(entity);
}
public void copyTableStyle(XWPFTable targetTable, XWPFTable sourceTable) {
// 设置表格对齐方式
targetTable.setTableAlignment(TableRowAlign.CENTER);
// 设置底部边框
targetTable.setBottomBorder(sourceTable.getBottomBorderType(), sourceTable.getBottomBorderSize(), sourceTable.getBottomBorderSpace(), sourceTable.getBottomBorderColor());
targetTable.setInsideHBorder(sourceTable.getInsideHBorderType(), sourceTable.getInsideHBorderSize(), sourceTable.getInsideHBorderSpace(), sourceTable.getInsideHBorderColor());
targetTable.setInsideVBorder(sourceTable.getInsideVBorderType(), sourceTable.getInsideVBorderSize(), sourceTable.getInsideVBorderSpace(), sourceTable.getInsideVBorderColor());
targetTable.setLeftBorder(sourceTable.getLeftBorderType(), sourceTable.getLeftBorderSize(), sourceTable.getLeftBorderSpace(), sourceTable.getLeftBorderColor());
targetTable.setRightBorder(sourceTable.getRightBorderType(), sourceTable.getRightBorderSize(), sourceTable.getRightBorderSpace(), sourceTable.getRightBorderColor());
targetTable.setTopBorder(sourceTable.getTopBorderType(), sourceTable.getTopBorderSize(), sourceTable.getTopBorderSpace(), sourceTable.getTopBorderColor());
}
private void copyFirstRow(XWPFTable targetTable, XWPFTableRow sourceRow) {
XWPFTableRow targetRow = targetTable.getRow(0);
targetRow.setHeight(sourceRow.getHeight());
for(int i = 0; i < targetRow.getTableCells().size(); i++) {
XWPFTableCell targetCell = targetRow.getCell(i);
XWPFTableCell sourceCell = sourceRow.getCell(i);
targetCell.setWidth(String.valueOf(sourceCell.getWidth()));
targetCell.setWidthType(sourceCell.getWidthType());
// 单元格垂直对齐方式
targetCell.setVerticalAlignment(sourceCell.getVerticalAlignment());
if(null != sourceCell.getCTTc() && null != sourceCell.getCTTc().getTcPr()) {
targetCell.getCTTc().addNewTcPr().setShd(sourceCell.getCTTc().getTcPr().getShd());
}
if(CollectionUtils.isNotEmpty(targetCell.getParagraphs())) {
targetCell.removeParagraph(0);
}
if(CollectionUtils.isNotEmpty(sourceCell.getParagraphs())) {
sourceCell.getParagraphs().stream().forEach(sourcePara -> {
XWPFParagraph targetPara = targetCell.addParagraph();
targetPara.setSpacingAfter(sourcePara.getSpacingAfter());
targetPara.setSpacingBefore(sourcePara.getSpacingBefore());
targetPara.setSpacingBetween(sourcePara.getSpacingBetween(), sourcePara.getSpacingLineRule());
targetPara.setAlignment(sourcePara.getAlignment());
targetPara.setIndentFromLeft(sourcePara.getIndentFromLeft());
targetPara.setIndentFromRight(sourcePara.getIndentFromRight());
sourcePara.getRuns().stream().forEach(sourceRun -> {
XWPFRun targetRun = targetPara.createRun();
targetRun.setBold(sourceRun.isBold());
targetRun.setText(sourceRun.getText(0));
targetRun.setFontSize(sourceRun.getFontSize());
targetRun.setFontFamily(sourceRun.getFontFamily());
targetRun.setColor(sourceRun.getColor());
targetRun.setItalic(sourceRun.isItalic());
});
});
}
}
}
}
2.3 模板文件
3 运行效果