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

实现功能
根据模板生成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

  • 32
    点赞
  • 128
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论
Java可以使用第三方工具类库Hutool或者fr.opensagres.xdocreport来根据Word模板导出Word文档docx。其中,使用Hutool可以通过以下步骤实现: 1. 引入Hutool依赖: ``` <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.10</version> </dependency> ``` 2. 加载Word模板文件: ``` DocxWriter writer = new DocxWriter("template.docx"); ``` 3. 替换模板中的变量: ``` writer.replace("name", "张三"); ``` 4. 保存并关闭文件: ``` writer.flush(new FileOutputStream("output.docx")).close(); ``` 而使用fr.opensagres.xdocreport可以通过以下步骤实现: 1. 引入相关依赖: ``` <dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.xdocreport.document.docx</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> ``` 2. 加载Word模板文件: ``` InputStream in = new FileInputStream(new File("template.docx"));IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker); ``` 3. 创建数据模型并填充数据: ``` IContext context = report.createContext(); context.put("name", "张三"); ``` 4. 生成Word文档并保存: ``` OutputStream out = new FileOutputStream(new File("output.docx")); report.process(context, out); out.close(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

message丶小和尚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值