1.Poi-tl https://javajgs.com/archives/31475 官网 http://deepoove.com/poi-tl
    2.Apache POI https://blog.csdn.net/qq_42402854/article/details/105091121
    3.freemarker https://www.jianshu.com/p/956f56c2ddcf



    com.deepoove
    poi-tl
    1.10.3


    .js
    exportWord: function (xjNo){
    window.location = _basePath + “/xunjian/exportWord?xjNo=”+xjNo;
    }
    controller.java
    /*
    按模板导出word
    @param xjNo
    @return
    */
    @ResponseBody
    @GetMapping(“/exportWord”)
    public void exportWord(String xjNo, HttpServletResponse response){
    try{
    YwXunjianQueryModel ywXunjianQueryModel = new YwXunjianQueryModel();
    ywXunjianQueryModel.setXjNo(xjNo);
    ResultVo resultVo = findOne(ywXunjianQueryModel, null);
    Map data = (Map) resultVo.getData();
    XWPFTemplate template = ywXunjianService.createWord(data);
    if(template != null) {
    response.reset();
    response.setContentType(“application/octet-stream”);
    response.setHeader(“Content-disposition”, “attachment;filename=” + new String((“巡检记录表” + xjNo + “.docx”).getBytes(“gbk”), “ISO-8859-1”));

    1. OutputStream out = response.getOutputStream();<br /> BufferedOutputStream bos = new BufferedOutputStream(out);<br /> template.write(bos);<br /> bos.flush();<br /> out.flush();<br /> PoitlIOUtils.closeQuietlyMulti(template, bos, out);<br /> }else{<br /> response.setContentType("text/html; charset=UTF-8"); //转码<br /> PrintWriter out = response.getWriter();<br /> out.flush();<br /> out.println("<script defer='defer' type='text/javascript'>");<br /> out.println("alert('导出失败,生成word出错!');");<br /> out.println("</script>");<br /> }<br /> }catch (Exception e){<br /> e.printStackTrace();
    2. }<br /> }<br /> <br />/**<br /> * @ClassName ExportWordUtil<br /> * @Description 导出word工具类<br /> * @Author majk<br /> * @Date 2022/2/12 8:41<br /> * @Version 1.0<br /> **/<br />public class ExportWordUtil {
    3. //生成一个word复选框<br /> public static TextRenderData createCheckBoxTextRenderData(int flag) {<br /> if (flag == 1) {<br /> return Texts.of("R").fontFamily("Wingdings 2").create();<br /> } else {<br /> return Texts.of("□").fontFamily("仿宋").create();<br /> }<br /> }<br />}
    4. <br />@Override<br /> public XWPFTemplate createWord(Map data) {<br /> try {<br /> YwXunjianQueryModel ywXunjianModel = (YwXunjianQueryModel)data.get("ywXunJian");<br /> Map<String, Object> ywXunJian = BeanUtil.bean2map(data.get("ywXunJian"));<br /> //创建复选框数据<br /> createCheckBoxData(ywXunJian);<br /> Map<String, Object> map = new HashMap<>();<br /> map.put("xj", ywXunJian);<br /> map.put("lljLx", createListTextRenderDataForJlsb(ywXunJian, data, SmLiuliangjiLx.class));<br /> map.put("lsyLx", createListTextRenderDataForJlsb(ywXunJian, data, SmLiusuyiLx.class));<br /> map.put("swjLx", createListTextRenderDataForJlsb(ywXunJian, data, SmShuiweijiLx.class));<br /> /* map.put("lljTable", createTableRenderDataForJlsb(ywXunJian, data, SmLiuliangjiLx.class));<br /> map.put("lsyTable", createTableRenderDataForJlsb(ywXunJian, data, SmLiusuyiLx.class));<br /> map.put("swjTable", createTableRenderDataForJlsb(ywXunJian, data, SmShuiweijiLx.class));*/<br /> map.put("picTable", createPictureRenderData(ywXunjianModel));
    5. XWPFTemplate template = XWPFTemplate.compile(ApplicationConfig.getResourcesPath() + "docTemplate/巡检单模板.docx").render(map);<br /> return template;<br /> }<br /> catch (Exception e){<br /> e.printStackTrace();<br /> logger.error(e.getMessage());<br /> return null;<br /> }<br /> }<br /> <br /> //生成word 复选框data<br /> private void createCheckBoxData (Map ywXunJian){<br /> ywXunJian.put("xjDate",(ywXunJian.get("xjDate") == null ? "":ywXunJian.get("xjDate").toString().substring(0,10)));<br /> ywXunJian.put("jczj1",ywXunJian.get("jczj").toString().equals("1")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("jczj0",ywXunJian.get("jczj").toString().equals("0")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("zhanFang1",ywXunJian.get("zhanFang").toString().equals("1")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("zhanFang0",ywXunJian.get("zhanFang").toString().equals("0")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("ceJing1",ywXunJian.get("ceJing").toString().equals("1")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("ceJing0",ywXunJian.get("ceJing").toString().equals("0")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("biLei1",ywXunJian.get("biLei").toString().equals("1")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("biLei0",ywXunJian.get("biLei").toString().equals("0")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("ljxl1",ywXunJian.get("ljxl").toString().equals("1")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));<br /> ywXunJian.put("ljxl0",ywXunJian.get("ljxl").toString().equals("0")? ExportWordUtil.createCheckBoxTextRenderData(1) : ExportWordUtil.createCheckBoxTextRenderData(0));
    6. }<br /> //生成word list<br /> private <T> List<Map<String,Object>> createListTextRenderDataForJlsb (Map ywXunJian,Map<String,Object> data, Class<T> modelClass ){<br /> List<Map<String,Object>> listMap = new ArrayList();<br /> if(modelClass == SmLiuliangjiLx.class) {<br /> if (ywXunJian.get("lljLxCd") == null || data.get("lljLx") == null) {<br /> return null;<br /> }<br /> List<SmLiuliangjiLx> list = (List<SmLiuliangjiLx>) data.get("lljLx");<br /> for (int i = 0; i < list.size(); i++) {<br /> Map<String, Object> map = new HashMap();<br /> SmLiuliangjiLx item = list.get(i);<br /> if(item.getLxCd().equals(ywXunJian.get("lljLxCd"))){<br /> map.put("lxCd",ExportWordUtil.createCheckBoxTextRenderData(1));<br /> }else{<br /> map.put("lxCd",ExportWordUtil.createCheckBoxTextRenderData(0));<br /> }<br />//每3个节点换行,加入\n,最后一行不加<br /> map.put("lxNm",Texts.of(item.getLxNm() + ((i + 1) % 3 == 0 && i != list.size() - 1 ? "\n" : " ") ).fontFamily("仿宋").create());<br /> listMap.add(map);<br /> }<br /> }<br /> <br /> return listMap;<br /> }<br /> //生成word table<br /> private <T> TableRenderData createTableRenderDataForJlsb (Map ywXunJian,Map<String,Object> data, Class<T> modelClass ){<br /> List<RowRenderData> listRow = new ArrayList();<br /> List<CellRenderData> listCell = new ArrayList();<br /> int columnCount = 3;<br /> int tableWidth = 13;<br /> double[] arrColumnWidth = new double[columnCount];<br /> for(int i = 0 ;i < arrColumnWidth.length;i++ ){<br /> arrColumnWidth[i] = tableWidth * 1.0 / columnCount;<br /> }<br /> if(modelClass == SmLiuliangjiLx.class) {<br /> if (ywXunJian.get("lljLxCd") == null || data.get("lljLx") == null) {<br /> return null;<br /> }<br /> List<SmLiuliangjiLx> list = (List<SmLiuliangjiLx>) data.get("lljLx");<br /> for (int i = 0; i < list.size(); i++) {<br /> SmLiuliangjiLx item = list.get(i);<br /> ParagraphRenderData paragraph = new ParagraphRenderData();<br /> if (item.getLxCd().equals(ywXunJian.get("lljLxCd"))) {<br /> paragraph.addText(ExportWordUtil.createCheckBoxTextRenderData(1));<br /> paragraph.addText(Texts.of(item.getLxNm()).fontFamily("仿宋").create());<br /> listCell.add(Cells.of().create().addParagraph(paragraph));<br /> } else {<br /> paragraph.addText(ExportWordUtil.createCheckBoxTextRenderData(0));<br /> paragraph.addText(Texts.of(item.getLxNm()).fontFamily("仿宋").create());<br /> listCell.add(Cells.of().create().addParagraph(paragraph));<br /> }<br />//每columnCount 加入1行,并清除listCell<br /> if (listCell.size() % columnCount == 0) {<br /> listRow.add(Rows.of(listCell.toArray(new CellRenderData[listCell.size()])).create());<br /> listCell = new ArrayList();<br /> }
    7. }<br /> if (listCell.size() > 0) {<br /> //补齐剩余的单元格<br /> if (listCell.size() < columnCount) {<br /> for (int i = 0; i < columnCount - listCell.size(); i++) {<br /> listCell.add(Cells.of("").create());<br /> }<br /> }<br /> listRow.add(Rows.of(listCell.toArray(new CellRenderData[listCell.size()])).create());<br /> }<br /> }<br /> else if(modelClass == SmLiusuyiLx.class) {<br /> if (ywXunJian.get("lsyLxCd") == null || data.get("lsyLx") == null) {<br /> return null;<br /> }<br /> List<SmLiusuyiLx> list = (List<SmLiusuyiLx>) data.get("lsyLx");<br /> for (int i = 0; i < list.size(); i++) {<br /> Map<String, Object> map = new HashMap();<br /> SmLiusuyiLx item = list.get(i);<br /> ParagraphRenderData paragraph = new ParagraphRenderData();<br /> if (item.getLxCd().equals(ywXunJian.get("lsyLxCd"))) {<br /> paragraph.addText(ExportWordUtil.createCheckBoxTextRenderData(1));<br /> paragraph.addText(Texts.of(item.getLxNm()).fontFamily("仿宋").create());<br /> listCell.add(Cells.of().create().addParagraph(paragraph));<br /> } else {<br /> paragraph.addText(ExportWordUtil.createCheckBoxTextRenderData(0));<br /> paragraph.addText(Texts.of(item.getLxNm()).fontFamily("仿宋").create());<br /> listCell.add(Cells.of().create().addParagraph(paragraph));<br /> }<br /> if ((i + 1) % 3 == 0) { //listCell.size() % columnCount = 0 或者 listCell.size() == columnCount <br /> listRow.add(Rows.of(listCell.toArray(new CellRenderData[listCell.size()])).create());<br /> listCell = new ArrayList();<br /> }
    8. }<br /> if (listCell.size() > 0) {<br /> //补齐剩余的单元格<br /> if (listCell.size() < 3) {<br /> for (int i = 0; i < 3 - listCell.size(); i++) {<br /> listCell.add(Cells.of("").create());<br /> }<br /> }<br /> listRow.add(Rows.of(listCell.toArray(new CellRenderData[listCell.size()])).create());<br /> }<br /> }<br /> else if(modelClass == SmShuiweijiLx.class) {<br /> if (ywXunJian.get("swjLxCd") == null || data.get("swjLx") == null) {<br /> return null;<br /> }<br /> List<SmShuiweijiLx> list = (List<SmShuiweijiLx>) data.get("swjLx");<br /> for (int i = 0; i < list.size(); i++) {<br /> SmShuiweijiLx item = list.get(i);<br /> ParagraphRenderData paragraph = new ParagraphRenderData();<br /> if (item.getLxCd().equals(ywXunJian.get("swjLxCd"))) {<br /> paragraph.addText(ExportWordUtil.createCheckBoxTextRenderData(1));<br /> paragraph.addText(Texts.of(item.getLxNm()).fontFamily("仿宋").create());<br /> listCell.add(Cells.of().create().addParagraph(paragraph));<br /> } else {<br /> paragraph.addText(ExportWordUtil.createCheckBoxTextRenderData(0));<br /> paragraph.addText(Texts.of(item.getLxNm()).fontFamily("仿宋").create());<br /> listCell.add(Cells.of().create().addParagraph(paragraph));<br /> }<br /> if ((i + 1) % columnCount == 0) {<br /> listRow.add(Rows.of(listCell.toArray(new CellRenderData[listCell.size()])).create());<br /> listCell = new ArrayList();<br /> }
    9. }<br /> if (listCell.size() > 0) {<br /> //补齐剩余的单元格<br /> if (listCell.size() < columnCount) {<br /> for (int i = 0; i < columnCount - listCell.size(); i++) {<br /> listCell.add(Cells.of("").create());<br /> }<br /> }<br /> listRow.add(Rows.of(listCell.toArray(new CellRenderData[listCell.size()])).create());<br /> }<br /> }
    10. return Tables.of(listRow.toArray(new RowRenderData[listRow.size()])).width(tableWidth, arrColumnWidth).create();<br /> }<br /> //生成word 图片table<br /> private /*List<Map<String,Object>>*/ TableRenderData createPictureRenderData (YwXunjianQueryModel ywXunJian){<br /> if(ywXunJian == null) return null;<br /> List<Map<String,Object>> list = new ArrayList();<br /> Map<String,Object> map = new HashMap();<br /> List<RowRenderData> listRow = new ArrayList();<br /> List<CellRenderData> listCell = new ArrayList();
    11. if(StringUtils.isNotEmpty(ywXunJian.getXjImgDmk())){<br /> map = new HashMap();<br /> map.put("desc","用水单位大门口");<br /> map.put("picpath",ywXunJian.getXjImgDmk());<br /> list.add(map);<br /> }<br /> if(StringUtils.isNotEmpty(ywXunJian.getXjImgBfmk())){<br /> map = new HashMap();<br /> map.put("desc","泵房门口或渠道全景");<br /> map.put("picpath",ywXunJian.getXjImgBfmk());<br /> list.add(map);<br /> }<br /> if(StringUtils.isNotEmpty(ywXunJian.getXjImgJczqj())){<br /> map = new HashMap();<br /> map.put("desc","监测站全景");<br /> map.put("picpath",ywXunJian.getXjImgJczqj());<br /> list.add(map);<br /> }<br />

    return ExportWordUtil.listToTableRenderDataForPic(list,”picpath”,”desc”,18,3,200,200);
    }

    //========================================
    package com.hy.utils;

    import com.deepoove.poi.data.*;
    import com.deepoove.poi.data.style.BorderStyle;
    import com.hy.config.ApplicationConfig;
    import com.hy.model.YwQianyiMx;
    import org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator;
    import sun.java2d.pipe.AAShapePipe;

    import java.io.File;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    /
    @ClassName ExportWordUtil
    @Description 导出word工具类
    @Author majk
    @Date 2022/2/12 8:41
    * @Version 1.0
    /
    public class ExportWordUtil {

    1. //生成一个word复选框<br /> public static TextRenderData createCheckBoxTextRenderData(int flag) {<br /> if (flag == 1) {<br /> return Texts.of("R").fontFamily("Wingdings 2").create();<br /> } else {<br /> return Texts.of("□").fontFamily("仿宋").create();<br /> }<br /> }
    2. //================================================= 【whm】按模板导出公共方法 begin =================================<br /> // 字体Wingdings 2的符号<br /> static TextRenderData checked = Texts.of("R").fontFamily("Wingdings 2").create();;<br /> static TextRenderData unChecked = Texts.of("□").fontFamily("仿宋").create();<br /> /**<br /> * 设置是否选中<br /> * @param dataMap<br /> * @param sourceKey<br /> * @param options<br /> */<br /> public static void setChecked(Map dataMap, String sourceKey, String[] options){<br /> for(String option: options){<br /> if(dataMap.get(sourceKey) != null && option.equals(dataMap.get(sourceKey).toString())){<br /> dataMap.put(sourceKey+"_"+option, checked);<br /> }else{<br /> dataMap.put(sourceKey+"_"+option, unChecked);<br /> }<br /> }<br /> }<br /> /**<br /> * 集合生成表格信息<br /> * @param sourceList<br /> * @param checkFields<br /> * @param minRows<br /> */<br /> public static List<Map> listToMapData(List sourceList, List<Map<String, Object>> checkFields, int minRows){<br /> List<Map> resultList = new ArrayList<>();
    3. int i=0;<br /> //填充数据<br /> for(;i <sourceList.size(); i++){<br /> Map itemMap = BeanUtil.bean2map(sourceList.get(i));
    4. //遍历需要checkbox处理的字段<br /> for(Map itemCheckField: checkFields){<br /> setChecked(itemMap, itemCheckField.get("field").toString(), (String[]) itemCheckField.get("options"));<br /> }
    5. resultList.add(itemMap);<br /> }
    6. //如果数据行小于最小行数,以空填充<br /> for(; i<minRows; i++){<br /> Map itemMap = new HashMap();
    7. //遍历需要checkbox处理的字段<br /> for(Map itemCheckField: checkFields){<br /> setChecked(itemMap, itemCheckField.get("field").toString(), (String[]) itemCheckField.get("options"));<br /> }
    8. resultList.add(itemMap);<br /> }
    9. return resultList;<br /> }<br /> //================================================= 【whm】按模板导出公共方法 end =================================<br /> /**<br /> * @author: qzf<br /> * @date: 2022/2/14 9:01<br /> * @describe: 处理图片<br /> * @param:<br /> * @return:<br /> */<br /> public static void setImage(Map dataMap, String sourceKey,int picWidth,int picHeight){<br /> if(dataMap.get(sourceKey) != null && !dataMap.get(sourceKey).toString().equals("")){<br /> String fileName = ApplicationConfig.uploadPath + dataMap.get(sourceKey).toString();<br /> if(new File(fileName).exists()) {<br /> dataMap.put(sourceKey, Pictures.ofLocal(ApplicationConfig.uploadPath + dataMap.get(sourceKey).toString()).size(picWidth, picHeight).create());<br /> }<br /> }<br /> }<br /> /**<br /> * @author: qzf<br /> * @date: 2022/2/14 10:01<br /> * @describe: list转为图片table TableRenderData<br /> * @param: list 列表 tableWidth 表格宽度 columnCount 列数 relativePicPathKey 图片相对路径 picDescKey 图片描述<br /> * @return:<br /> */<br /> public static TableRenderData listToTableRenderDataForPic(List<Map<String,Object>> list,String relativePicPathKey,String picDescKey,double tableWidth,int columnCount,int picWidth,int picHeight){<br /> Map map = null;<br /> List<RowRenderData> listRow = new ArrayList();<br /> List<CellRenderData> listCell = new ArrayList();<br /> double[] arrColumnWidth = new double[columnCount];<br /> for(int i = 0 ;i < arrColumnWidth.length;i++ ){<br /> arrColumnWidth[i] = tableWidth * 1.0 / columnCount;<br /> }<br /> for (int i = 0; i < list.size(); i++) {<br /> map = list.get(i);<br /> ParagraphRenderData paragraph = new ParagraphRenderData();<br /> if(!StringUtil.isEmpty(map.get(picDescKey))){<br /> paragraph.addText(map.get(picDescKey).toString()+"\n");<br /> }<br /> String fileName = ApplicationConfig.uploadPath + map.get(relativePicPathKey);<br /> if(new File(fileName).exists() && !StringUtil.isEmpty(map.get(relativePicPathKey))) {<br /> paragraph.addPicture((Pictures.ofLocal(fileName)).size(picWidth, picHeight).create());<br /> listCell.add(Cells.of().create().addParagraph(paragraph));
    10. if (listCell.size() % columnCount == 0) {<br /> listRow.add(Rows.of(listCell.toArray(new CellRenderData[listCell.size()])).create());<br /> listCell = new ArrayList();<br /> }<br /> }<br /> }<br /> if (listCell.size() > 0) {<br /> //补齐剩余的单元格<br /> int listCellSize = listCell.size();<br />if (listCellSize < columnCount) {<br /> for (int i = 0; i < columnCount - listCellSize; i++) {<br /> listCell.add(Cells.of("").create());<br /> }<br />}<br /> listRow.add(Rows.of(listCell.toArray(new CellRenderData[listCell.size()])).create());<br /> }<br /> return Tables.of(listRow.toArray(new RowRenderData[listRow.size()])).border(new BorderStyle(){{setSize(0);}}).width(tableWidth, arrColumnWidth).create();<br /> }<br />}