JAVA根据模板生成WORD文件并导出

2023-10-29

实现功能
根据模板生成WORD文件,模板文件参数可配.
一 : WORD导出效果

先看一下导出的demo文件,具体参数可手动修改
下图为word_demo.docx导出的WORD文件
在这里插入图片描述
下图为word_list.docx导出的WORD文件
在这里插入图片描述

二 : 编写WORD模板
WORD文件模板,新建WORD文件,将所需参数用特殊符号 ${} 配置,如下图.

demo模板(数据替换模板中的配置参数) : word_demo.docx
在这里插入图片描述
demo模板(导出数据列表,数据表格在文件下方自动拼接) : word_list.docx
在这里插入图片描述

三 : 引入所需maven依赖

项目采用springboot框架

	<!--WORD导出POM-->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.8</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-scratchpad</artifactId>
        <version>3.8</version>
    </dependency>
四 : JAVA代码工具类

WORD导出接口类 WordController.java

package com.chang.word;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * WORD导出
 * @author message丶小和尚
 * @create 2020/01/10
 */
@Controller
public class WordController {

    @Resource
    private WordExportService wordExportService;//Word导出工具

    @RequestMapping("exportWordDemo")
    @ResponseBody
    public void exportWordDemo(HttpServletResponse response, @RequestParam("param")String param) throws Exception{
        WordResult wordResult = new WordResult();
        wordResult.setData(param);
        wordExportService.toWordDemo(response, wordResult);
    }

    @RequestMapping("exportWordList")
    @ResponseBody
    public void exportWordList(HttpServletResponse response, @RequestParam("param")String param) throws Exception{
        List<WordResult> wordResultList = new ArrayList<>();
        WordResult wordResult = new WordResult();
        wordResult.setData(param);
        wordResultList.add(wordResult);
        wordExportService.toWordList(response, wordResult, wordResultList);
    }
}

WORD导出工具类 WordExportService.java

package com.chang.word;

import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

/**
 * 模板文档下载
 * @author message丶小和尚
 * @create 2020/01/10
 */
@Service
public class WordExportService {
	//文件名
	private final static String DEMO_WORD_FILE="模板demo文件";
    private final static String DEMO_WORD_LIST="模板list文件";

    public void toWordDemo(HttpServletResponse response, WordResult wordResult)throws Exception{
        byte[]  bytes = WordBaseService.toWordDemo(wordResult);
        if(bytes != null){
            uploadWord(response,bytes,DEMO_WORD_FILE);
        }
    }

    public void toWordList(HttpServletResponse response, WordResult wordResult, List<WordResult> publicResultList)throws Exception{
        byte[]  bytes = WordBaseService.toWordList(wordResult,publicResultList);
        if(bytes != null){
            uploadWord(response,bytes,DEMO_WORD_LIST);
        }
    }

    /**
     * 下载模板
     * @param response 响应
     * @param bytes 字节
     * @param fileName 文件名
     * @throws Exception
     */
	private void uploadWord(HttpServletResponse response, byte[] bytes, String fileName) throws Exception{
		try {
			if(bytes != null){
//                OutputStream outputStream = new FileOutputStream("E:ceshi.docx");
				OutputStream outputStream = response.getOutputStream();
				response.setCharacterEncoding("utf-8");
				response.setContentType("application/x-download");  
				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
			    String userAgent = request.getHeader("User-Agent");  
			    byte[] byteName = userAgent.contains("MSIE") ? fileName.getBytes() : fileName.getBytes("UTF-8");//name.getBytes("UTF-8")处理safari的乱码问题
			    fileName = new String(byteName, "ISO-8859-1"); // 各浏览器基本都支持ISO编码  
			    response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", fileName+".docx"));//文件名外的双引号处理firefox的空格截断问题
				InputStream is = new ByteArrayInputStream(bytes);
				byte[] buff = new byte[1024];
				int len = 0;
				while ((len = is.read(buff)) != -1) {
                    outputStream.write(buff, 0, len);
				}
				is.close();
                outputStream.close();
			}
		} catch (Exception e) {
			throw(e);
		}
	}
}

WORD导出工具类 WordBaseService.java

package com.chang.word;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
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.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

/**
 * @author message丶小和尚
 * @create 2020/01/10
 * 模板下载
 */
@Slf4j
@Component
public class WordBaseService {

    private static String templateBasePath =  "/app/static/template/";
	private final static String WORD_DEMO = "word_demo.docx";
    private final static String WORD_LIST = "word_list.docx";

    //Word导出,参数配置
	public static byte[] toWordDemo(WordResult wordResult) throws Exception {
		return toWordObjectMap(wordResult,WORD_DEMO);
	}

    private static byte[] toWordObjectMap(Object obj,String filePath) throws Exception{
        byte[] bytes = null;
        if(obj != null ){
            bytes = toWordAllModelAnalysis(WordUtil.setMapObject(obj),templateBasePath + filePath);
        }
        return bytes;
    }

	private static byte[] toWordAllModelAnalysis(Map<String, Object> mapObject, String modelPath) throws Exception {
		byte[] bytes = null;
		if(mapObject != null && !StringUtils.isEmpty(modelPath)){
			File file = new File(modelPath);
			if(!file.exists()&&!file.isFile()){
				log.error("模板文件不存在");
				return null;
			}
	        try {
	        	XWPFDocument doc = WordUtil.generateWord(mapObject, modelPath);
	 	        ByteArrayOutputStream baos=new ByteArrayOutputStream();
				doc.write(baos);
                bytes =  baos.toByteArray();
				baos.close();
			} catch (Exception e) {
				log.error("文件处理异常",e);
			}
		}
		return bytes;
	}

    //Word导出,列表设置
    public static byte[] toWordList(WordResult wordResult, List<WordResult> publicResultList) throws Exception {
        return toWordObjectMapPublic(wordResult,publicResultList,WORD_LIST);
    }

    private static byte[] toWordObjectMapPublic(Object obj, List<WordResult> list, String filePath) throws Exception{
        byte[] bytes = null;
        if(obj != null ){
            bytes = toWordAllModelAnalysisPublic(WordUtil.setMapObject(obj),list,templateBasePath+filePath);
        }
        return bytes;
    }

    private static byte[] toWordAllModelAnalysisPublic(Map<String, Object> mapObject,List<WordResult> list, String modelPath) throws Exception {
        byte[] bytes = null;
        if(mapObject != null && !StringUtils.isEmpty(modelPath)){
            File file = new File(modelPath);
            if(!file.exists()&&!file.isFile()){
                log.error("模板文件不存在");
                return null;
            }
            try {
                XWPFDocument doc = WordUtil.generateWord(mapObject, modelPath);
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                //插入表格
                XWPFTable table = doc.createTable();
                table.getCTTbl().addNewTblPr().addNewJc().setVal(STJc.CENTER);//设置表格居中
                //设置表头
                XWPFTableRow tableRowOne = table.getRow(0);
                XWPFParagraph paragraph0 = getStyle(doc.createParagraph(),"序号");
                tableRowOne.getCell(0).setParagraph(paragraph0);
                paragraph0.removeRun(0);
                tableRowOne.getCell(0).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(1000));//设置宽度
                tableRowOne.getCell(0).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);//设置水平居中
//                tableRowOne.getCell(0).getCTTc().getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
                XWPFParagraph paragraph1 = getStyle(doc.createParagraph(),"数据");
                tableRowOne.addNewTableCell().setParagraph(paragraph1);
                paragraph1.removeRun(0);
                tableRowOne.getCell(1).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(1500));//设置宽度
                tableRowOne.getCell(1).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);//设置水平居中
//                tableRowOne.getCell(1).getCTTc().getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
                //循环设置Word表格内容
                for (int i = 0; i < list.size(); i++) {
                    XWPFTableRow tableRow = table.createRow();
                    XWPFParagraph paragraph00 = getStyleNotBold(doc.createParagraph(),String.valueOf(i+1));
                    tableRow.getCell(0).setParagraph(paragraph00);
                    paragraph00.removeRun(0);
                    XWPFParagraph paragraph01 = getStyleNotBold(doc.createParagraph(),list.get(i).getData());
                    tableRow.getCell(1).setParagraph(paragraph01);
                    paragraph01.removeRun(0);

                    tableRow.getCell(0).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(1000));
                    tableRow.getCell(0).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);//设置水平居中
//                    tableRow.getCell(0).getCTTc().getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
                    tableRow.getCell(1).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(1500));
                    tableRow.getCell(1).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);//设置水平居中
//                    tableRow.getCell(1).getCTTc().getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
                }
                doc.write(byteArrayOutputStream);
                bytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();
            } catch (Exception e) {
                log.error("文件处理异常",e);
            }
        }
        return bytes;
    }

    //设置段落格式
    private static XWPFParagraph getStyle(XWPFParagraph paragraphX, String name){
        paragraphX.setAlignment(ParagraphAlignment.CENTER);//对齐方式
        XWPFRun runXOne = paragraphX.createRun();//创建文本对象
        runXOne.setText(name);
        runXOne.setFontSize(15);//字体大小
        runXOne.setFontFamily("黑体");//字体
        runXOne.setBold(true);//加粗
        runXOne.setTextPosition(10);//设置行间距
        return paragraphX;
    }

    //设置段落格式
    private static XWPFParagraph getStyleNotBold(XWPFParagraph paragraphX, String name){
        paragraphX.setAlignment(ParagraphAlignment.CENTER);//对齐方式
        XWPFRun runXOne = paragraphX.createRun();//创建文本对象
        runXOne.setText(name);
        runXOne.setFontSize(14);//字体大小
        runXOne.setBold(false);//加粗
        runXOne.setTextPosition(10);//设置行间距
        return paragraphX;
    }
}

WORD导出工具类 WordUtil.java

package com.chang.word;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
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.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author message丶小和尚
 * @create 2020/01/10
 * 模板的装载过程
 */
public class WordUtil {
	
	private static Log log = LogFactory.getLog(WordUtil.class);
	/**
	 * 装载模板所对应的对象
	 * @param object
	 * @return map
	 */
	public static Map<String,Object> setMapObject(Object object){
		Map<String,Object> mapObject = new HashMap<String,Object>();
		if(object != null){
			Field[] fields = object.getClass().getDeclaredFields();
            log.info("fields" + fields.length);
			for(Field field : fields){
				try {
                    field.setAccessible(true);
					String str = "${" + field.getName() + "}";
					Object objValue = field.get(object);
					if(objValue != null){
                        log.info(str + "----" + objValue.toString());
						mapObject.put(str, objValue);
					}else{
						mapObject.put(str, "");
					}
				} catch(Exception e) {
                    log.error("模板对象出现错误", e);
				}
			}
		} else {
            log.error("模板对象不是对应的一个类对象");
		}
		return mapObject;
	}

    /**
     * 根据指定的参数值、模板,生成 word 文档
     * @param param 需要替换的变量
     * @param template 模板
     * @return XWPFDocument
     * @throws IOException
     * @throws InvalidFormatException
     */
    public static XWPFDocument generateWord(Map<String, Object> param, String template) throws IOException, InvalidFormatException {
    	if(param == null || template == null){
    		return null ;
    	}
    	XWPFDocument xwpfDocument = null;
        log.info("解析的模版为:" + template);
    	try {
            OPCPackage pack = POIXMLDocument.openPackage(template);
            xwpfDocument = new XWPFDocument(pack);
            if (param.size() > 0) {
                //处理段落
                List<XWPFParagraph> paragraphList = xwpfDocument.getParagraphs();
				processParagraphs(paragraphList, param, xwpfDocument);
                //处理表格
                Iterator<XWPFTable> it = xwpfDocument.getTablesIterator();
                while (it.hasNext()) {
                    XWPFTable table = it.next();
                    List<XWPFTableRow> rows = table.getRows();
                    for (XWPFTableRow row : rows) {
                        List<XWPFTableCell> cells = row.getTableCells();
                        for (XWPFTableCell cell : cells) {
                            List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
                            processParagraphs(paragraphListTable, param, xwpfDocument);
                        }
                    }
                }
            }
    	} catch (IOException e) {
            log.error("文件处理异常", e);
			throw(e);
		}catch (InvalidFormatException e) {
            log.error("文档中内容处理异常", e);
			throw(e);
		}
        return xwpfDocument;
    }

    /**
     * 处理段落
     * @param paragraphList
     * @param param
     * @param doc
     * @throws InvalidFormatException
     * @throws FileNotFoundException
     */
    public static void processParagraphs(List<XWPFParagraph> paragraphList, Map<String, Object> param, XWPFDocument doc) throws InvalidFormatException, FileNotFoundException{
        if(paragraphList != null && paragraphList.size() > 0){
            for(XWPFParagraph paragraph : paragraphList){
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    String text = run.getText(0);
                    if(text != null){
                        boolean isSetText = false;
                        for (Map.Entry<String, Object> entry : param.entrySet()) {
                            String key = entry.getKey();
                            if(text.indexOf(key) != -1){
                                isSetText = true;
                                Object value = entry.getValue();
                                if (value instanceof String) {//文本替换
                                    log.info(key + "模板中模要转化属性对应的值:" + value);
                                    text = text.replace(key, value.toString());
                                } else if (value instanceof Map) {//图片替换
                                    text = text.replace(key, "");
                                    Map pic = (Map)value;
                                    int width = Integer.parseInt(pic.get("width").toString());
                                    int height = Integer.parseInt(pic.get("height").toString());
                                    int picType = getPictureType(pic.get("type").toString());
                                    String byteArray = (String) pic.get("imgPath");
                                    log.info("模板中模要转化的图片" + byteArray);
                                    CTInline inline = run.getCTR().addNewDrawing().addNewInline();
                                    insertPicture(doc,byteArray,inline, width, height);
                                }
                            }
                        }
                        if(isSetText){
                            run.setText(text,0);
                        }
                    }
                }
            }
        }
    }

    /**
     * 根据图片类型,取得对应的图片类型代码
     * @param picType
     * @return int
     */
    private static 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;
    }

    /**
     * 将输入流中的数据写入字节数组
     * @param inputStream
     * @param isClose
     * @return
     */
    public static byte[] inputStream2ByteArray(InputStream inputStream,boolean isClose){
        byte[] byteArray = null;
        try {
            int total = inputStream.available();
            byteArray = new byte[total];
            inputStream.read(byteArray);
        } catch (IOException e) {
            log.error("IO异常",e);
        } finally {
            if(isClose){
                try {
                    inputStream.close();
                } catch (Exception e2) {
                    log.debug("关闭流失败");
                }
            }
        }
        return byteArray;
    }

    /**
     *
     * @param document
     * @param filePath
     * @param inline
     * @param width
     * @param height
     * @throws InvalidFormatException
     * @throws FileNotFoundException
     */
    private static void insertPicture(XWPFDocument document, String filePath, CTInline inline, int width, int height) throws InvalidFormatException, FileNotFoundException {
        document.addPictureData(new FileInputStream(filePath), XWPFDocument.PICTURE_TYPE_PNG);
        int id = document.getAllPictures().size() - 1;
        final int EMU = 9525;
        width *= EMU;
        height *= EMU;
//        String blipId = document.getAllPictures().get(id).getPackageRelationship().getId();
        Integer blipIdString = document.getAllPictures().get(id).getPictureType();
        String blipId = blipIdString.toString();
        String picXml = getPicXml(blipId, width, height);
        XmlToken xmlToken = null;
        try {
            xmlToken = XmlToken.Factory.parse(picXml);
        } catch (XmlException xe) {
            log.error("XmlException",xe);
        }
        inline.set(xmlToken);
        inline.setDistT(0);
        inline.setDistB(0);
        inline.setDistL(0);
        inline.setDistR(0);
        CTPositiveSize2D extent = inline.addNewExtent();
        extent.setCx(width);
        extent.setCy(height);
        CTNonVisualDrawingProps docPr = inline.addNewDocPr();
        docPr.setId(id);
        docPr.setName("IMG_" + id);
        docPr.setDescr("IMG_" + id);
    }

    /**
     * get the xml of the picture
     * @param blipId
     * @param width
     * @param height
     * @return
     */
    private static String getPicXml(String blipId, int width, int height) {
        String picXml =
            "" + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
            "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
            "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
            "         <pic:nvPicPr>" + "            <pic:cNvPr id=\"" + 0 +
            "\" name=\"Generated\"/>" + "            <pic:cNvPicPr/>" +
            "         </pic:nvPicPr>" + "         <pic:blipFill>" +
            "            <a:blip r:embed=\"" + blipId +
            "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
            "            <a:stretch>" + "               <a:fillRect/>" +
            "            </a:stretch>" + "         </pic:blipFill>" +
            "         <pic:spPr>" + "            <a:xfrm>" +
            "               <a:off x=\"0\" y=\"0\"/>" +
            "               <a:ext cx=\"" + width + "\" cy=\"" + height +
            "\"/>" + "            </a:xfrm>" +
            "            <a:prstGeom prst=\"rect\">" +
            "               <a:avLst/>" + "            </a:prstGeom>" +
            "         </pic:spPr>" + "      </pic:pic>" +
            "   </a:graphicData>" + "</a:graphic>";
        return picXml;
    }
}

WORD导出实体类(模板所需参数) WordResult.java

package com.chang.word;

import java.io.Serializable;
/**
 * WORD导出参数类
 * @author message丶小和尚
 * @create 2020/01/10
 */
public class WordResult implements Serializable {

    private static final long serialVersionUID = 1L;
    public String data;

    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
}
五 : 配置信息说明

在WordExportService中,可设置导出的Word文件名.
在这里插入图片描述
在WordBaseService中,可设置Word模板配置的地址,以及配置模板名称
在这里插入图片描述

六 : 在固定位置插入表格
6.1 : 情况说明

在真实的业务场景中,可能会涉及Word中表格的导出。表格并不是拼接在文档末尾,而是设置在文档中,即某个段落与段落之间,类似下图这种情况。
在这里插入图片描述
对于这种在固定位置插入表格的情况,我们可采用同样的占位符的方式来实现。
如图所示,定义一个占位符 ${make_newTable},当然里面的内容可以自己定义,需注意不能与文档中其他占位符同名即可。
在这里插入图片描述

6.2 : 编码实现

前提是前面的架子已经搭好。
这里的实现结果为标准表格导出,如果需要特殊表格,即合并单元格等,可改造该方法,对cell做特殊处理即可。
在WordTempleCommonService.java文件中增加方法如下:

	//通用导出WORD 包含list
    public static byte[] toWordCommonIndexList(Object obj,List<String> head,List<List<String>> list,String filePath) throws Exception{
        byte[] bytes = null;
        if(obj != null ){
            bytes = toWordAllModelAnalysisCommonIndexList(WordUtil.setMapObject(obj),head,list,WordConstant.TEMPLATE_BASE_PATH + filePath);
        }
        return bytes;
    }
	private static byte[] toWordAllModelAnalysisCommonIndexList(Map<String, Object> mapObject,List<String> head,List<List<String>> stringList, String modelPath) throws Exception {
        byte[] bytes = null;
        if(mapObject != null && !StringUtils.isEmpty(modelPath)){
            File file = new File(modelPath);
            if(!file.exists() && !file.isFile()){
                return null;
            }
            try {
                XWPFDocument doc = WordUtil.generateWord(mapObject, modelPath);
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                List<XWPFParagraph> xwpfParagraphList = doc.getParagraphs();
                for(int s = 0; s < xwpfParagraphList.size(); s++){
                    XWPFParagraph xwpfParagraphIndex = xwpfParagraphList.get(s);
                    if("${make_newTable}".equals(xwpfParagraphIndex.getText())){
                        XmlCursor cursor = xwpfParagraphIndex.getCTP().newCursor();
                        XWPFTable table = doc.insertNewTbl(cursor);
                        //插入表格
                        table.getCTTbl().addNewTblPr().addNewJc().setVal(STJc.CENTER);//设置表格居中
                        //定义map
                        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
                        //设置表头
                        XWPFTableRow tableRowOne = table.getRow(0);
                        for(String string:head){
                            Integer index = head.indexOf(string);//当前所处序号
                            Integer width = string.length() * 350 + 200;
                            if(0 == index && "序号".equals(string)){
                                width = 800;
                            }
                            map.put(index,width);
                            XWPFParagraph paragraph = getCommonIndexStyle(doc.createParagraph(), string, true);
                            if(0 == index){
                                tableRowOne.getCell(0).setParagraph(paragraph);
                                paragraph.removeRun(0);
                                tableRowOne.getCell(index).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(width));//设置宽度
                                tableRowOne.getCell(0).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);//设置水平居中
                                tableRowOne.getCtRow().addNewTrPr().addNewTrHeight().setVal(BigInteger.valueOf(600));
                            } else {
                                tableRowOne.addNewTableCell().setParagraph(paragraph);
                                paragraph.removeRun(0);
                                tableRowOne.getCell(index).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(width));//设置宽度
                                tableRowOne.getCell(index).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);//设置水平居中
                                tableRowOne.getCtRow().addNewTrPr().addNewTrHeight().setVal(BigInteger.valueOf(600));
                            }
                            doc.removeBodyElement(doc.getPosOfParagraph(paragraph));
                        }
                        //循环设置Word表格内容
                        for(List<String> list : stringList){
                            XWPFTableRow tableRow = table.createRow();
                            for(int i = 0; i < list.size(); i++){
                                CTTcPr tcpr = tableRow.getCell(i).getCTTc().addNewTcPr();
                                XWPFParagraph paragraph = getCommonIndexStyle(doc.createParagraph(), list.get(i), false);
                                tableRow.getCell(i).setParagraph(paragraph);
                                paragraph.removeRun(0);
                                tcpr.addNewTcW().setW(BigInteger.valueOf(map.get(i)));//设置宽度,表头设置了宽度,此处设置表头的宽度
                                tcpr.addNewVAlign().setVal(STVerticalJc.CENTER);//设置水平居中
                                tableRow.getCtRow().addNewTrPr().addNewTrHeight().setVal(BigInteger.valueOf(500));
                                doc.removeBodyElement(doc.getPosOfParagraph(paragraph));
                            }
                        }
                        doc.removeBodyElement(doc.getPosOfParagraph(xwpfParagraphIndex));
                    }
                }
                doc.write(byteArrayOutputStream);
                bytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();
            } catch (Exception e) {
                log.error("文件处理异常,Exception:", e);
            }
        }
        return bytes;
    }
    //设置通用段落格式
    private static XWPFParagraph getCommonIndexStyle(XWPFParagraph paragraphX, String name, boolean flag){
        paragraphX.setAlignment(ParagraphAlignment.CENTER);//对齐方式
        paragraphX.setVerticalAlignment(TextAlignment.CENTER);//对齐方式

        XWPFRun runXOne = paragraphX.createRun();//创建文本对象
        runXOne.setText(name);
        if(null == name){
            runXOne.setText("");
        }
        runXOne.setFontSize(12);//字体大小
        runXOne.setFontFamily("Calibri (正文)");//字体
        if(flag){
            runXOne.setBold(true);//加粗
        }
        runXOne.setTextPosition(10);//设置行间距
        return paragraphX;
    }

上述代码中需要注意的是:doc.removeBodyElement(doc.getPosOfParagraph(xwpfParagraphIndex));
这是由于我们在生成表格的时候,会去调用 doc.createParagraph(),创建段落,如果不去remove的话,会导致文档产生非常多的空白页。
方法getCommonIndexStyle,其主要作用即设置样式,如果想设置不同样式,可以自行设置即可。

然后在WordTempleService.java文件中增加方法如下:

	//指定位置插入表格 ${make_newTable}
    public void toWordCommonIndexList(HttpServletResponse response, Object object,List<String> head,List<List<String>> list,String wordTemplate,String fileName)throws Exception{
        byte[]  bytes = WordTempleCommonService.toWordCommonIndexList(object,head,list,wordTemplate);
        if(bytes != null){
            uploadWord(response,bytes,fileName);
        }
    }

上述代码的 uploadWord方法,可在文中找到。

至此方法已经搭建完成,下面是模拟调用。

wordTempleService.toWordCommonIndexList(response, templateDate, tableHead, tableData, wordTemplate, fileName);

参数说明:
response:响应头。
templateDate:Word模板导出的其他匹配数据。
tableHead:表格的表头。可使用Arrays.asList(“序号”, “姓名”)
tableData:表格的内容。
wordTemplate:模板的名称,需要注意路径问题。
fileName:导出的文件对应的文件名。

6.3 : 导出效果

在这里插入图片描述

七 : 可能出现的问题

在模板中配置参数 ${data} 时,可能会出现配置了参数,但是导出的时候赋值不了的情况,生成的Word中仍是 ${data} .
这种情况需要在代码中debug,找到对应的map,从代码中把对应的key复制到Word模板上.
如图所示复制一下,问题就可以解决了
在这里插入图片描述

附上材料下载地址
链接:https://pan.baidu.com/s/1jL1UpQatLVIjx0iBXIOMeg 提取码: ga1a
CSDN资源,0积分下载:https://download.csdn.net/download/qq_38254635/12099599

八 : 相关链接

JAVA生成Zip文件并导出:
https://blog.csdn.net/qq_38254635/article/details/127364398

JAVA导出Excel文件:
https://blog.csdn.net/qq_38254635/article/details/126691175

JAVA根据PDF文件生成图片:
https://blog.csdn.net/qq_38254635/article/details/112029941

JAVA根据模板生成PDF文件并导出:
https://blog.csdn.net/qq_38254635/article/details/103919024

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA根据模板生成WORD文件并导出 的相关文章

随机推荐

  • 机器学习 —— 朴素贝叶斯

    朴素贝叶斯 贝叶斯公式 P A B P A P B A P B 一个例子 现分别有 A B 两个容器 在容器 A 里分别有 7 个红球和 3 个白球 在容器 B 里有 1 个红球和 9 个白球 现已知从这两个容器里任意抽出了一个球 且是红球
  • JVM-垃圾回收

    目录 1 如何判断对象可以回收 1 1引用计数法 1 3四种引用 1 3 1强引用 1 3 2软引用 1 3 3弱引用 1 3 4虚引用 1 3 5终结器引用 2 垃圾回收算法 2 1标记清除 2 2标记整理 2 3复制 3 分代垃圾回收
  • unity游戏关卡解锁和未解锁时的不同图片以及可或不可按下

    若想让按钮不可按只要将interactable的勾勾关掉就可以了 一般用做未解锁的关卡 public void UpdateOnce 用于更新过关数 没解锁的抑制 for int i 0 i
  • 分享web前端七款HTML5 Loading动画特效集锦

    以前我们大部分的Loading动画都是利用gif图片实现的 这种图片实现Loading动画的方法虽然也很不错 但是作为HTML5开发者来说 如果能利用HTML5和CSS3实现这些超酷的Loading动画 那将是一件非常痛快的事情 1 HTM
  • 生产环境elasticsearch的配置建议

    以下主要来自官方文档 主要分为几块 硬件方面 内存 CPU 硬盘 网络 其他 操作系统 较大的文件描述符 设置MMap 管理工具 JVM虚拟机 请不要调整JVM设置 请不要修改垃圾收集器 给lucene留下一半的内存空间 不要超过32G 避
  • CentOS7安装Oracle数据库的全流程

    一 准备工作 1 下载Oracle的安装介质 Oracle 11g R2 Linux版本有两个压缩文件包 都需下载安装才会完整 linux x64 11gR2 database 1of2 zip linux x64 11gR2 databa
  • ip 和 iphdr

    1 struct ip 和struct iphdr struct ip if BYTE ORDER LITTLE ENDIAN u char ip hl 4 header length ip v 4 version endif if BYT
  • 数组也是对象

    一个对象中的属性名不仅仅是字符串格式 还有可能是数字格式的 当我们存储的属性名不是字符串也不是数字的时候 浏览器会把这个值转换为字符串 toString 然后在进行存储 obj 300 gt 先把 toString 后的结果作为对象的属性名
  • 处理递归数据的键名

    tortoise data 使用递归函数 if data data length lt 0 递归的出口 return null return data map e gt 循环数据 const model name e label id e
  • 剑指offer 学习笔记 圆圈中最后剩下的数字

    面试题62 圆圈中最后剩下的数字 0 1 n 1这n个数字排成一个圆圈 从数字0开始 每次从这个圆圈里删除第m个数字 求出这个圆圈里剩下的最后一个数字 本题就是约瑟夫环问题 法一 用环形链表模拟圆圈 我们可以直接用标准库的list模拟环形链
  • [转]怎样在systemverilog DPI中调用SV,C与C++(二)

    有的时候需要交互struct union数据类型 下面举个简单例子 在SV里定义这个一个结构体 typedef struct int id string name xaction 同样的 在C里定义同样的结构体 结构体名可以不一致 type
  • Android 数据库框架GreenDao

    参考详情网站 Android 数据库框架 GreenDao org greenrobot greendao 起航 当风起时的博客 CSDN博客
  • java的string常用方法_java中String类的常用方法

    public class HelloWorld public static void main String args Java文件名 String fileName HelloWorld java 邮箱 String email laur
  • Pandas分组、聚合、过滤操作全面解析!

    gt gt gt import numpy as np gt gt gt import pandas as pd gt gt gt df pd read csv data table csv index col ID gt gt gt df
  • Redisson-分布式锁-闭锁

    Redisson 分布式锁 闭锁 引入必要依赖
  • 以色列技术!Amimon无线WHDI技术解析

    转自 http www pcpop com doc 0 579 579310 all shtml Amimon WHDI技术独家解析 泡泡网高清频道9月23日 今年年初 本站独家撰写有关无线技术的展望性文章 Intel Android 天幕
  • 慢~再听我讲一遍Activity的启动流程

    前言 activity启动的流程分为两部分 一是在activity中通过startActivity Intent intent 方法启动一个Activity 二是我们在桌面通过点击应用图标启动一个App然后显示Activity 第二种方式相
  • 5个可以激发设计灵感的AI工具推荐

    当设计灵感耗尽 陷入创作瓶颈时 人工智能艺术生成器可能会为您提供新的启示 这些基于深度学习和发展 神经网络 的工具可以将输入的文本描述或图像转换成各种风格的艺术作品 并提供丰富的风格参数和材料库 让您可以自由调整和创作 无论是专业设计师还是
  • R语言中读取和处理文件的常用方法

    测试文件放在rawdata 目录下 包含以下内容 我在rawdata下存放了以上文件 目录 1 dir 2 list files 3 dir ls 4 整理文件下的内容 重要 获得包含特定字符串的文件 获得文件绝对路径 将文件粘贴至另一个文
  • JAVA根据模板生成WORD文件并导出

    JAVA根据模板生成WORD并导出 实现功能 一 WORD导出效果 二 编写WORD模板 三 引入所需maven依赖 四 JAVA代码工具类 五 配置信息说明 六 在固定位置插入表格 6 1 情况说明 6 2 编码实现 6 3 导出效果 七