poi根据word/excel模板(书签)创建导出word/excel文档
首先poi
需要的jar
包全部导入工程
温馨提示:千万要注意xmlbeans
的版本号,最好使用2.6.0以上的版本,否则poi
会报错的噢!
一,poi根据excel模板,修改内容导出新excel 文档(只支持HSSF)
excel
模板就存放在了静态文件夹下,然后拿到这个文档之后,通过poi
对单元格的赋值进行创建。
public class CreateExcel {
public static void main(String[] args) throws IOException {
//拿到excel模板的输入流
InputStream inputStream = this.getClass().getResourceAsStream("/static/attachments/03-企业认证产品技术信息表V1.0.xls");
POIFSFileSystem fs = new POIFSFileSystem(inputStream);
//读取excel模板
HSSFWorkbook wb = new HSSFWorkbook(fs);
//读取了模板内所有sheet内容
HSSFSheet sheet = wb.getSheetAt(0);
//在相应的单元格进行赋值
HSSFCell cell = sheet.getRow(1).getCell(3);
cell.setCellValue("测试");
HSSFCell cell2 = sheet.getRow(3).getCell(3);
cell2.setCellValue("数据");
HSSFCell cell3 = sheet.getRow(0).getCell(0);
cell3.setCellValue("大标题");
//修改模板内容导出新模板(导出到了本地磁盘)
FileOutputStream out = new FileOutputStream("D:/export.xls");
wb.write(out);
out.close();
}
}
二,poi导出excel文档输出到浏览器下载
上面的导出只是导出到了本地磁盘,正常业务应该是输出到浏览器下载。
输出到浏览器下载的根本原因就是把输出流交给Response
对象,然后超链接访问并接收Response
对象。
因此按钮应该是超链接形式的跳转,跳转到导出的后台方法(不是用不了ajax
,老是因为类型问题出错,索性废弃)
function jsxx_export() {
location.href = "/export/jsxx?pk="+pk;
}
后台导出方法(参数要加上HttpServletResponse
)
@RequestMapping("/jsxx")
@ResponseBody
public void jsxxExport(String pk,HttpServletResponse response) throws Exception{
KpFileTechnicalMessage message = (KpFileTechnicalMessage) this.getLightServiceUtil().callServiceWithParam("TechMessageSc_getById", pk);
//操作系统类型及版本
String operateSystemKind = message.getOperateSystemKind();
//###################这里从数据库查询到数据(中间省略)#####################
//其他商业闭源软件
String otherClosedSoftware = message.getOtherClosedSoftware();
InputStream inputStream = this.getClass().getResourceAsStream("/static/attachments/03-企业认证产品技术信息表V1.0.xls");
POIFSFileSystem fs=new POIFSFileSystem(inputStream);
HSSFWorkbook wb=new HSSFWorkbook(fs);
HSSFSheet sheet = wb.getSheet("产品技术信息表");
sheet.getRow(1).getCell(3).setCellValue(operateSystemKind);
//#################给excel单元格赋值(中间省略)####################
sheet.getRow(18).getCell(3).setCellValue(otherClosedSoftware);
//调用下面的输入到浏览器下载的方法
exportExcelByDownload(wb,response,"技术信息表导出");
}
excel表格直接浏览器下载的通用方法
//excel表格直接浏览器下载
public void exportExcelByDownload(HSSFWorkbook wb, HttpServletResponse httpServletResponse, String fileName) throws Exception {
//响应类型为application/octet- stream情况下使用了这个头信息的话,那就意味着不想直接显示内容
//httpServletResponse.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
//attachment为以附件方式下载
httpServletResponse.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(
fileName + ".xls",
"utf-8"));
/**
* 代码里面使用Content-Disposition来确保浏览器弹出下载对话框的时候。
* response.addHeader("Content-Disposition","attachment");一定要确保没有做过关于禁止浏览器缓存的操作
*/
httpServletResponse.setHeader("Cache-Control", "No-cache");
httpServletResponse.flushBuffer();
wb.write(httpServletResponse.getOutputStream());
wb.close();
}
这样点击按钮进行导出就直接在浏览器左下角进行下载了!
三,poi根据excel模板,修改内容导出新excel 文档(支持XSSF)
HSSF
是xls
格式的excel
文档,而XSSH
则是xlsx
格式的excel
文档,上面的导出excel
是支持HSSF
的,想要支持XSSH
格式的话,其实具体过程还是和上面的导出过程一样,只不过在创建Workbook
对象的时候有所区别。
创建.xls
的workbook对象
InputStream inputStream = this.getClass().getResourceAsStream("/static/attachments/03-企业认证产品技术信息表V1.0.xls");
POIFSFileSystem fs=new POIFSFileSystem(inputStream);
HSSFWorkbook wb=new HSSFWorkbook(fs);
创建.xlsx
的workbook
对象
InputStream inputStream = this.getClass().getResourceAsStream("/static/attachments/07-适配认证资料checklist.xlsx");
//下面的两行(XSSH)就用不了了,因为下面的是HSSF,注掉
// POIFSFileSystem fs=new POIFSFileSystem(inputStream);
// HSSFWorkbook wb=new HSSFWorkbook(fs);
//使用workbook工厂创建workbook文档对象
Workbook wb = WorkbookFactory.create(inputStream);
其他的用法都一样!
四,poi根据word模板(书签)创建导出word文档
创建一个要导出固定格式的word
模板。
写测试类并运行
package com.ftx.word;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WordTest {
public static void main(String[] args) {
//测试数据准备
//1.标题
String title = "t1heluosh1-使用POI导出Word";
//2.段落数据
String font_song_four_red = "这里是宋体四号红色字体";
String font_black_three_black = "这里是黑体三号号黑色字体";
String font_micro_five_red = "这里是微软雅黑五号红色字体";
//存放段落数据
Map<String,Object> map = new HashMap<String,Object>();
map.put("title", title);
map.put("font_song_four_red", font_song_four_red);
map.put("font_black_three_black", font_black_three_black);
map.put("font_micro_five_red", font_micro_five_red);
//3.表格数据
List<Map<String,String>> excelMapList = new ArrayList<Map<String,String>>();
Map<String,String> excelMapTemp = null;
for (int i=1;i<11;i++) {
excelMapTemp = new HashMap<String,String>();
excelMapTemp.put("excel.no1", "one-"+i);
excelMapTemp.put("excel.no2", "two-"+i);
excelMapTemp.put("excel.no3", "three-"+i);
excelMapTemp.put("excel.no4", "four-"+i);
excelMapTemp.put("excel.no5", "five-"+i);
excelMapList.add(excelMapTemp);
}
//模板存放位置
String demoTemplate = "D:/template.docx";
//生成文档存放位置
String targetPath = "D:/target.doc";
//初始化导出
WordExport export = new WordExport(demoTemplate);
try {
export.init();
} catch (IOException e) {
e.printStackTrace();
}
try {
export.export(map);
//0为表格的下标,第一个表格下标为0,以此类推
export.export(excelMapList, 0);
export.generate(targetPath);
} catch (Exception e) {
e.printStackTrace();
}
}
}
加入poi
导出word
的工具类(即插即用)
package com.ftx.word;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
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.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSpacing;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @Title: WordExport.java
* @Description: 导出word文档
* @author xuyong
* @version 1.0
*/
public class WordExport {
private static final Logger logger = LoggerFactory.getLogger(WordExport.class);
private String templatePath;
private XWPFDocument doc = null;
private FileInputStream is = null;
private OutputStream os = null;
public WordExport(String templatePath) {
this.templatePath = templatePath;
}
public void init() throws IOException {
is = new FileInputStream(new File(this.templatePath));
doc = new XWPFDocument(is);
}
/**
* 替换掉占位符
* @param params
* @return
* @throws Exception
*/
public boolean export(Map<String,Object> params) throws Exception{
this.replaceInPara(doc, params);
return true;
}
/**
* 替换掉表格中的占位符
* @param params
* @param tableIndex
* @return
* @throws Exception
*/
public boolean export(Map<String,Object> params,int tableIndex) throws Exception{
this.replaceInTable(doc, params,tableIndex);
return true;
}
/**
* 循环生成表格
* @param params
* @param tableIndex
* @return
* @throws Exception
*/
public boolean export(List<Map<String,String>> params,int tableIndex) throws Exception{
return export(params,tableIndex,false);
}
public boolean export(List<Map<String,String>> params,int tableIndex,Boolean hasTotalRow) throws Exception{
this.insertValueToTable(doc, params, tableIndex,hasTotalRow);
return true;
}
/**
* 导出图片
* @param params
* @return
* @throws Exception
*/
public boolean exportImg(Map<String,Object> params) throws Exception{
/*List<XWPFParagraph> list = doc.getParagraphs();
for(XWPFParagraph para : list){
logger.info(para.getText());
}*/
List<XWPFTable> list = doc.getTables();
System.out.print(list.size());
return true;
}
/**
* 生成word文档
* @param outDocPath
* @return
* @throws IOException
*/
public boolean generate(String outDocPath) throws IOException{
os = new FileOutputStream(outDocPath);
doc.write(os);
this.close(os);
this.close(is);
return true;
}
/**
* 替换表格里面的变量
*
* @param doc
* 要替换的文档
* @param params
* 参数
* @throws Exception
*/
private void replaceInTable(XWPFDocument doc, Map<String, Object> params,int tableIndex) throws Exception {
List<XWPFTable> tableList = doc.getTables();
if(tableList.size()<=tableIndex){
throw new Exception("tableIndex对应的表格不存在");
}
XWPFTable table = tableList.get(tableIndex);
List<XWPFTableRow> rows;
List<XWPFTableCell> cells;
List<XWPFParagraph> paras;
rows = table.getRows();
for (XWPFTableRow row : rows) {
cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
paras = cell.getParagraphs();
for (XWPFParagraph para : paras) {
this.replaceInPara(para, params);
}
}
}
}
/**
* 替换段落里面的变量
*
* @param doc
* 要替换的文档
* @param params
* 参数
* @throws Exception
*/
private void replaceInPara(XWPFDocument doc, Map<String, Object> params) throws Exception {
Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
XWPFParagraph para;
while (iterator.hasNext()) {
para = iterator.next();
this.replaceInPara(para, params);
}
}
/**
* 替换段落里面的变量
*
* @param para
* 要替换的段落
* @param params
* 参数
* @throws Exception
* @throws IOException
* @throws InvalidFormatException
*/
private boolean replaceInPara(XWPFParagraph para, Map<String, Object> params) throws Exception {
boolean data = false;
List<XWPFRun> runs;
//有符合条件的占位符
if (this.matcher(para.getParagraphText()).find()) {
runs = para.getRuns();
data = true;
Map<Integer,String> tempMap = new HashMap<Integer,String>();
for (int i = 0; i < runs.size(); i++) {
XWPFRun run = runs.get(i);
String runText = run.toString();
//以"$"开头
boolean begin = runText.indexOf("$")>-1;
boolean end = runText.indexOf("}")>-1;
if(begin && end){
tempMap.put(i, runText);
fillBlock(para, params, tempMap, i);
continue;
}else if(begin && !end){
tempMap.put(i, runText);
continue;
}else if(!begin && end){
tempMap.put(i, runText);
fillBlock(para, params, tempMap, i);
continue;
}else{
if(tempMap.size()>0){
tempMap.put(i, runText);
continue;
}
continue;
}
}
} else if (this.matcherRow(para.getParagraphText())) {
runs = para.getRuns();
data = true;
}
return data;
}
/**
* 填充run内容
* @param para
* @param params
* @param tempMap
* @param i
* @param runText
* @throws InvalidFormatException
* @throws IOException
* @throws Exception
*/
@SuppressWarnings("rawtypes")
private void fillBlock(XWPFParagraph para, Map<String, Object> params,
Map<Integer, String> tempMap, int index)
throws InvalidFormatException, IOException, Exception {
Matcher matcher;
if(tempMap!=null&&tempMap.size()>0){
String wholeText = "";
List<Integer> tempIndexList = new ArrayList<Integer>();
for(Map.Entry<Integer, String> entry :tempMap.entrySet()){
tempIndexList.add(entry.getKey());
wholeText+=entry.getValue();
}
if(wholeText.equals("")){
return;
}
matcher = this.matcher(wholeText);
if (matcher.find()) {
boolean isPic = false;
int width = 0;
int height = 0;
int picType = 0;
String path = null;
String keyText = matcher.group().substring(2,matcher.group().length()-1);
Object value = params.get(keyText);
String newRunText = "";
if(value instanceof String){
newRunText = matcher.replaceFirst(String.valueOf(value));
}else if(value instanceof Map){//插入图片
isPic = true;
Map pic = (Map)value;
width = Integer.parseInt(pic.get("width").toString());
height = Integer.parseInt(pic.get("height").toString());
picType = getPictureType(pic.get("type").toString());
path = pic.get("path").toString();
}
//模板样式
XWPFRun tempRun = null;
// 直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面,
// 所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。
for(Integer pos : tempIndexList){
tempRun = para.getRuns().get(pos);
tempRun.setText("", 0);
}
if(isPic){
//addPicture方法的最后两个参数必须用Units.toEMU转化一下
//para.insertNewRun(index).addPicture(getPicStream(path), picType, "测试",Units.toEMU(width), Units.toEMU(height));
tempRun.addPicture(getPicStream(path), picType, "测试",Units.toEMU(width), Units.toEMU(height));
}else{
//样式继承
if(newRunText.indexOf("\n")>-1){
String[] textArr = newRunText.split("\n");
if(textArr.length>0){
//设置字体信息
String fontFamily = tempRun.getFontFamily();
int fontSize = tempRun.getFontSize();
//logger.info("------------------"+fontSize);
for(int i=0;i<textArr.length;i++){
if(i==0){
tempRun.setText(textArr[0],0);
}else{
if(StringUtils.isNotEmpty(textArr[i])){
XWPFRun newRun=para.createRun();
//设置新的run的字体信息
newRun.setFontFamily(fontFamily);
if(fontSize==-1){
newRun.setFontSize(10);
}else{
newRun.setFontSize(fontSize);
}
newRun.addBreak();
newRun.setText(textArr[i], 0);
}
}
}
}
}else{
tempRun.setText(newRunText,0);
}
}
}
tempMap.clear();
}
}
/**
* Clone Object
* @param obj
* @return
* @throws Exception
*/
@SuppressWarnings("unused")
private Object cloneObject(Object obj) throws Exception{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(obj);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in =new ObjectInputStream(byteIn);
return in.readObject();
}
@SuppressWarnings("unused")
private void insertValueToTable(XWPFDocument doc,List<Map<String, String>> params,int tableIndex) throws Exception {
insertValueToTable(doc,params,tableIndex,false);
}
private void insertValueToTable(XWPFDocument doc,List<Map<String, String>> params,int tableIndex,Boolean hasTotalRow) throws Exception {
List<XWPFTable> tableList = doc.getTables();
if(tableList.size()<=tableIndex){
throw new Exception("tableIndex对应的表格不存在");
}
XWPFTable table = tableList.get(tableIndex);
List<XWPFTableRow> rows = table.getRows();
if(rows.size()<2){
throw new Exception("tableIndex对应表格应该为2行");
}
//模板行
XWPFTableRow tmpRow = rows.get(1);
List<XWPFTableCell> tmpCells = null;
List<XWPFTableCell> cells = null;
XWPFTableCell tmpCell = null;
tmpCells = tmpRow.getTableCells();
String cellText = null;
String cellTextKey = null;
Map<String,Object> totalMap = null;
for (int i = 0, len = params.size(); i < len; i++) {
Map<String,String> map = params.get(i);
if(map.containsKey("total")){
totalMap = new HashMap<String,Object>();
totalMap.put("total", map.get("total"));
continue;
}
XWPFTableRow row = table.createRow();
row.setHeight(tmpRow.getHeight());
cells = row.getTableCells();
// 插入的行会填充与表格第一行相同的列数
for (int k = 0, klen = cells.size(); k < klen; k++) {
tmpCell = tmpCells.get(k);
XWPFTableCell cell = cells.get(k);
cellText = tmpCell.getText();
if(StringUtils.isNotBlank(cellText)){
//转换为mapkey对应的字段
cellTextKey = cellText.replace("$", "").replace("{", "").replace("}","");
if(map.containsKey(cellTextKey)){
setCellText(tmpCell, cell, map.get(cellTextKey));
}
}
}
}
// 删除模版行
table.removeRow(1);
if(hasTotalRow && totalMap!=null){
XWPFTableRow row = table.getRow(1);
//cell.setText("11111");
XWPFTableCell cell = row.getCell(0);
replaceInPara(cell.getParagraphs().get(0),totalMap);
/*String wholeText = cell.getText();
Matcher matcher = this.matcher(wholeText);
if(matcher.find()){*/
/*List<XWPFParagraph> paras = cell.getParagraphs();
for (XWPFParagraph para : paras) {
this.replaceInPara(para, totalMap);
}*/
//}
table.addRow(row);
table.removeRow(1);
}
}
private void setCellText(XWPFTableCell tmpCell, XWPFTableCell cell,
String text) throws Exception {
CTTc cttc2 = tmpCell.getCTTc();
CTTcPr ctPr2 = cttc2.getTcPr();
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
//cell.setColor(tmpCell.getColor());
// cell.setVerticalAlignment(tmpCell.getVerticalAlignment());
if (ctPr2.getTcW() != null) {
ctPr.addNewTcW().setW(ctPr2.getTcW().getW());
}
if (ctPr2.getVAlign() != null) {
ctPr.addNewVAlign().setVal(ctPr2.getVAlign().getVal());
}
if (cttc2.getPList().size() > 0) {
CTP ctp = cttc2.getPList().get(0);
if (ctp.getPPr() != null) {
if (ctp.getPPr().getJc() != null) {
cttc.getPList().get(0).addNewPPr().addNewJc()
.setVal(ctp.getPPr().getJc().getVal());
}
}
}
if (ctPr2.getTcBorders() != null) {
ctPr.setTcBorders(ctPr2.getTcBorders());
}
XWPFParagraph tmpP = tmpCell.getParagraphs().get(0);
XWPFParagraph cellP = cell.getParagraphs().get(0);
XWPFRun tmpR = null;
if (tmpP.getRuns() != null && tmpP.getRuns().size() > 0) {
tmpR = tmpP.getRuns().get(0);
}
List<XWPFRun> runList = new ArrayList<XWPFRun>();
if(text==null){
XWPFRun cellR = cellP.createRun();
runList.add(cellR);
cellR.setText("");
}else{
//这里的处理思路是:$b认为是段落的分隔符,分隔后第一个段落认为是要加粗的
if(text.indexOf("\b") > -1){//段落,加粗,主要用于产品行程
String[] bArr = text.split("\b");
for(int b=0;b<bArr.length;b++){
XWPFRun cellR = cellP.createRun();
runList.add(cellR);
if(b==0){//默认第一个段落加粗
cellR.setBold(true);
}
if(bArr[b].indexOf("\n") > -1){
String[] arr = bArr[b].split("\n");
for(int i = 0; i < arr.length; i++){
if(i > 0){
cellR.addBreak();
}
cellR.setText(arr[i]);
}
}else{
cellR.setText(bArr[b]);
}
}
}else{
XWPFRun cellR = cellP.createRun();
runList.add(cellR);
if(text.indexOf("\n") > -1){
String[] arr = text.split("\n");
for(int i = 0; i < arr.length; i++){
if(i > 0){
cellR.addBreak();
}
cellR.setText(arr[i]);
}
}else{
cellR.setText(text);
}
}
}
// 复制字体信息
if (tmpR != null) {
//cellR.setBold(tmpR.isBold());
//cellR.setBold(true);
for(XWPFRun cellR : runList){
if(!cellR.isBold()){
cellR.setBold(tmpR.isBold());
}
cellR.setItalic(tmpR.isItalic());
cellR.setStrike(tmpR.isStrike());
cellR.setUnderline(tmpR.getUnderline());
cellR.setColor(tmpR.getColor());
cellR.setTextPosition(tmpR.getTextPosition());
if (tmpR.getFontSize() != -1) {
cellR.setFontSize(tmpR.getFontSize());
}
if (tmpR.getFontFamily() != null) {
cellR.setFontFamily(tmpR.getFontFamily());
}
if (tmpR.getCTR() != null) {
if (tmpR.getCTR().isSetRPr()) {
CTRPr tmpRPr = tmpR.getCTR().getRPr();
if (tmpRPr.isSetRFonts()) {
CTFonts tmpFonts = tmpRPr.getRFonts();
CTRPr cellRPr = cellR.getCTR().isSetRPr() ? cellR
.getCTR().getRPr() : cellR.getCTR().addNewRPr();
CTFonts cellFonts = cellRPr.isSetRFonts() ? cellRPr
.getRFonts() : cellRPr.addNewRFonts();
cellFonts.setAscii(tmpFonts.getAscii());
cellFonts.setAsciiTheme(tmpFonts.getAsciiTheme());
cellFonts.setCs(tmpFonts.getCs());
cellFonts.setCstheme(tmpFonts.getCstheme());
cellFonts.setEastAsia(tmpFonts.getEastAsia());
cellFonts.setEastAsiaTheme(tmpFonts.getEastAsiaTheme());
cellFonts.setHAnsi(tmpFonts.getHAnsi());
cellFonts.setHAnsiTheme(tmpFonts.getHAnsiTheme());
}
}
}
}
}
// 复制段落信息
cellP.setAlignment(tmpP.getAlignment());
cellP.setVerticalAlignment(tmpP.getVerticalAlignment());
cellP.setBorderBetween(tmpP.getBorderBetween());
cellP.setBorderBottom(tmpP.getBorderBottom());
cellP.setBorderLeft(tmpP.getBorderLeft());
cellP.setBorderRight(tmpP.getBorderRight());
cellP.setBorderTop(tmpP.getBorderTop());
cellP.setPageBreak(tmpP.isPageBreak());
if (tmpP.getCTP() != null) {
if (tmpP.getCTP().getPPr() != null) {
CTPPr tmpPPr = tmpP.getCTP().getPPr();
CTPPr cellPPr = cellP.getCTP().getPPr() != null ? cellP
.getCTP().getPPr() : cellP.getCTP().addNewPPr();
// 复制段落间距信息
CTSpacing tmpSpacing = tmpPPr.getSpacing();
if (tmpSpacing != null) {
CTSpacing cellSpacing = cellPPr.getSpacing() != null ? cellPPr
.getSpacing() : cellPPr.addNewSpacing();
if (tmpSpacing.getAfter() != null) {
cellSpacing.setAfter(tmpSpacing.getAfter());
}
if (tmpSpacing.getAfterAutospacing() != null) {
cellSpacing.setAfterAutospacing(tmpSpacing
.getAfterAutospacing());
}
if (tmpSpacing.getAfterLines() != null) {
cellSpacing.setAfterLines(tmpSpacing.getAfterLines());
}
if (tmpSpacing.getBefore() != null) {
cellSpacing.setBefore(tmpSpacing.getBefore());
}
if (tmpSpacing.getBeforeAutospacing() != null) {
cellSpacing.setBeforeAutospacing(tmpSpacing
.getBeforeAutospacing());
}
if (tmpSpacing.getBeforeLines() != null) {
cellSpacing.setBeforeLines(tmpSpacing.getBeforeLines());
}
if (tmpSpacing.getLine() != null) {
cellSpacing.setLine(tmpSpacing.getLine());
}
if (tmpSpacing.getLineRule() != null) {
cellSpacing.setLineRule(tmpSpacing.getLineRule());
}
}
// 复制段落缩进信息
CTInd tmpInd = tmpPPr.getInd();
if (tmpInd != null) {
CTInd cellInd = cellPPr.getInd() != null ? cellPPr.getInd()
: cellPPr.addNewInd();
if (tmpInd.getFirstLine() != null) {
cellInd.setFirstLine(tmpInd.getFirstLine());
}
if (tmpInd.getFirstLineChars() != null) {
cellInd.setFirstLineChars(tmpInd.getFirstLineChars());
}
if (tmpInd.getHanging() != null) {
cellInd.setHanging(tmpInd.getHanging());
}
if (tmpInd.getHangingChars() != null) {
cellInd.setHangingChars(tmpInd.getHangingChars());
}
if (tmpInd.getLeft() != null) {
cellInd.setLeft(tmpInd.getLeft());
}
if (tmpInd.getLeftChars() != null) {
cellInd.setLeftChars(tmpInd.getLeftChars());
}
if (tmpInd.getRight() != null) {
cellInd.setRight(tmpInd.getRight());
}
if (tmpInd.getRightChars() != null) {
cellInd.setRightChars(tmpInd.getRightChars());
}
}
}
}
}
/**
* 删除表中的行
* @param tableAndRowsIdxMap 表的索引和行索引集合
*/
public void deleteRow(Map<Integer,List<Integer>> tableAndRowsIdxMap){
if(tableAndRowsIdxMap!=null && !tableAndRowsIdxMap.isEmpty()){
List<XWPFTable> tableList = doc.getTables();
for(Map.Entry<Integer, List<Integer>> map : tableAndRowsIdxMap.entrySet()){
Integer tableIdx = map.getKey();
List<Integer> rowIdxList = map.getValue();
if(rowIdxList!=null && rowIdxList.size()>0){
if(tableList.size()<=tableIdx){
logger.error("表格"+tableIdx+"不存在");
continue;
}
XWPFTable table = tableList.get(tableIdx);
List<XWPFTableRow> rowList = table.getRows();
for(int i=rowList.size()-1;i>=0;i--){
if(rowIdxList.contains(i)){
table.removeRow(i);
}
}
}
}
}
}
/**
* 正则匹配字符串
*
* @param str
* @return
*/
private Matcher matcher(String str) {
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}",
Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher;
}
/**
* 正则匹配字符串
*
* @param str
* @return
*/
private boolean matcherRow(String str) {
Pattern pattern = Pattern.compile("\\$\\[(.+?)\\]",
Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher.find();
}
/**
* 根据图片类型,取得对应的图片类型代码
* @param picType
* @return int
*/
private int getPictureType(String picType){
int res = XWPFDocument.PICTURE_TYPE_PICT;
if(picType != null){
if(picType.equalsIgnoreCase("png")){
res = XWPFDocument.PICTURE_TYPE_PNG;
}else if(picType.equalsIgnoreCase("dib")){
res = XWPFDocument.PICTURE_TYPE_DIB;
}else if(picType.equalsIgnoreCase("emf")){
res = XWPFDocument.PICTURE_TYPE_EMF;
}else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){
res = XWPFDocument.PICTURE_TYPE_JPEG;
}else if(picType.equalsIgnoreCase("wmf")){
res = XWPFDocument.PICTURE_TYPE_WMF;
}
}
return res;
}
private InputStream getPicStream(String picPath) throws Exception{
URL url = new URL(picPath);
//打开链接
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//设置请求方式为"GET"
conn.setRequestMethod("GET");
//超时响应时间为5秒
conn.setConnectTimeout(5 * 1000);
//通过输入流获取图片数据
InputStream is = conn.getInputStream();
return is;
}
/**
* 关闭输入流
*
* @param is
*/
private void close(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 关闭输出流
*
* @param os
*/
private void close(OutputStream os) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 保留小数点后两位
* @param d
* @return
*/
public static String getPoint2(Double d){
DecimalFormat df =new DecimalFormat("0.00");
return df.format(d);
}
/**
* 判断字符串是否都为数字
* @param str
* @return
*/
public static boolean isNumeric(String str){
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNum = pattern.matcher(str);
if( !isNum.matches() ){
return false;
}
return true;
}
/**
* 数字转换为汉语中人民币的大写<br>
*
* @author hongten
* @contact hongtenzone@foxmail.com
* @create 2013-08-13
*/
public static class NumberToCN {
/**
* 汉语中数字大写
*/
private static final String[] CN_UPPER_NUMBER = { "零", "壹", "贰", "叁", "肆",
"伍", "陆", "柒", "捌", "玖" };
/**
* 汉语中货币单位大写,这样的设计类似于占位符
*/
private static final String[] CN_UPPER_MONETRAY_UNIT = { "分", "角", "元",
"拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆", "拾",
"佰", "仟" };
/**
* 特殊字符:整
*/
private static final String CN_FULL = "整";
/**
* 特殊字符:负
*/
private static final String CN_NEGATIVE = "负";
/**
* 金额的精度,默认值为2
*/
private static final int MONEY_PRECISION = 2;
/**
* 特殊字符:零元整
*/
private static final String CN_ZEOR_FULL = "零元" + CN_FULL;
/**
* 把输入的金额转换为汉语中人民币的大写
*
* @param numberOfMoney
* 输入的金额
* @return 对应的汉语大写
*/
public static String number2CNMontrayUnit(BigDecimal numberOfMoney) {
StringBuffer sb = new StringBuffer();
// -1, 0, or 1 as the value of this BigDecimal is negative, zero, or
// positive.
int signum = numberOfMoney.signum();
// 零元整的情况
if (signum == 0) {
return CN_ZEOR_FULL;
}
//这里会进行金额的四舍五入
long number = numberOfMoney.movePointRight(MONEY_PRECISION)
.setScale(0, 4).abs().longValue();
// 得到小数点后两位值
long scale = number % 100;
int numUnit = 0;
int numIndex = 0;
boolean getZero = false;
// 判断最后两位数,一共有四中情况:00 = 0, 01 = 1, 10, 11
if (!(scale > 0)) {
numIndex = 2;
number = number / 100;
getZero = true;
}
if ((scale > 0) && (!(scale % 10 > 0))) {
numIndex = 1;
number = number / 10;
getZero = true;
}
int zeroSize = 0;
while (true) {
if (number <= 0) {
break;
}
// 每次获取到最后一个数
numUnit = (int) (number % 10);
if (numUnit > 0) {
if ((numIndex == 9) && (zeroSize >= 3)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[6]);
}
if ((numIndex == 13) && (zeroSize >= 3)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[10]);
}
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
sb.insert(0, CN_UPPER_NUMBER[numUnit]);
getZero = false;
zeroSize = 0;
} else {
++zeroSize;
if (!(getZero)) {
sb.insert(0, CN_UPPER_NUMBER[numUnit]);
}
if (numIndex == 2) {
if (number > 0) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
}
} else if (((numIndex - 2) % 4 == 0) && (number % 1000 > 0)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
}
getZero = true;
}
// 让number每次都去掉最后一个数
number = number / 10;
++numIndex;
}
// 如果signum == -1,则说明输入的数字为负数,就在最前面追加特殊字符:负
if (signum == -1) {
sb.insert(0, CN_NEGATIVE);
}
// 输入的数字小数点后两位为"00"的情况,则要在最后追加特殊字符:整
if (!(scale > 0)) {
sb.append(CN_FULL);
}
return sb.toString();
}
}
}
然后就生成了指定模板的word
文档,如下图。
上面的表格是特别规则的表格,但是如果有特殊的需求,比如说,一个表格内有一个单元格,这个单元格是不确定的多个行的数据,例如下图,其他的都是唯一的,而申请服务内容是不固定的多条数据,这就难搞了,不过也没什么难的,就上面的WordExport
工具类是写死的,可以根据不同的使用场景去改写工具类的代码。
如果使用上面的工具类实现上图这样的效果,只需要改工具类的insertValueToTable
方法中的内容,我只是改了其中一部分就完成了上述的效果。
for (int i = 0, len = params.size(); i < len; i++) {
Map<String,String> map = params.get(i);
if(map.containsKey("total")){
totalMap = new HashMap<String,Object>();
totalMap.put("total", map.get("total"));
continue;
}
//########################修改内容开始#########################
//在第6行的位置插入一行
XWPFTableRow row = table.insertNewTableRow(6);
//拿到第5行
XWPFTableRow row5 = table.getRow(5);
//复制行属性(复制属性的目的是为了插入的行要和上面的行的宽高等样式相同)
row.getCtRow().setTrPr(row5.getCtRow().getTrPr());
//复制列属性
//得到第5行所有的列
List<XWPFTableCell> tableCells = row5.getTableCells();
XWPFTableCell targetCell = null;
//对第5行所有的列遍历
for (XWPFTableCell cell:tableCells){
//给插入的新行增加列
targetCell=row.addNewTableCell();
//把第五行对应的列的属性复制给该新加列
targetCell.getCTTc().setTcPr(cell.getCTTc().getTcPr());
}
//########################修改内容开始#########################
row.setHeight(tmpRow.getHeight());
cells = row.getTableCells();
效果如下图
完美谢幕!
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)