SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格)

Poi-tl官方文档:http://deepoove.com/poi-tl/

一、实现过程

1.添加必要依赖

    <!-- word导出 -->
    <dependency>
       <groupId>com.deepoove</groupId>
        <artifactId>poi-tl</artifactId>
        <version>1.7.3</version>
    </dependency>
    <!--  上面需要的依赖-->
     <dependency>
         <groupId>org.apache.poi</groupId>
         <artifactId>poi-ooxml</artifactId>
         <version>4.1.2</version>
     </dependency>
    <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.1.2</version>
        </dependency>
    <dependency>
         <groupId>org.apache.poi</groupId>
         <artifactId>poi</artifactId>
         <version>4.1.2</version>
     </dependency>

    <!-- 对JSP的支持 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
    </dependency>

2.新建一个word,编写word模板:

 

 

把该模板放到项目中的static/template/文件夹下:

 

 3.编写一个controller 类,导出销售订单信息的接口类,供页面请求

package com.example.word.controller;


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.policy.HackLoopTableRenderPolicy;
import com.example.word.common.MoneyUtils;

/**
 * 导出Word
 * @author Administrator
 *
 */
@RequestMapping("/auth/exportWord/")
@RestController
public class ExportWordController {

        /**
     * 销售订单信息导出word --- poi-tl(包含动态表格)
     * @throws IOException 
     */
    @RequestMapping("/exportDataWord3")
    public void exportDataWord3(HttpServletRequest request,HttpServletResponse response) throws IOException{
        try {
            Map<String, Object> params = new HashMap<>();
    
            // TODO 渲染其他类型的数据请参考官方文档
            DecimalFormat df = new DecimalFormat("######0.00");   
            Calendar now = Calendar.getInstance(); 
            double money = 0;//总金额
            //组装表格列表数据
            List<Map<String,Object>> detailList=new ArrayList<Map<String,Object>>();
            for (int i = 0; i < 6; i++) {
                 Map<String,Object> detailMap = new HashMap<String, Object>();
                 detailMap.put("index", i+1);//序号
                 detailMap.put("title", "商品"+i);//商品名称
                 detailMap.put("product_description", "套");//商品规格
                 detailMap.put("buy_num", 3+i);//销售数量
                 detailMap.put("saleprice", 100+i);//销售价格
                
                 double saleprice=Double.valueOf(String.valueOf(100+i));
                 Integer buy_num=Integer.valueOf(String.valueOf(3+i));
                 String buy_price=df.format(saleprice*buy_num);
                 detailMap.put("buy_price", buy_price);//单个商品总价格
                 money=money+Double.valueOf(buy_price);
                 
                 detailList.add(detailMap);
            }
            //总金额
            String order_money=String.valueOf(money);
            //金额中文大写
            String money_total = MoneyUtils.change(money);
              
              //word模板地址获取方式一:缺点---打jar包获取不到该路径
//              String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
//              String resource =basePath+"order1.docx";//word模板地址
            //word模板地址获取方式二:优点---相比上一种方式,这种方法不会在linux或者jar上失效
              ClassPathResource classPathResource = new ClassPathResource("static/template/order1.docx");
            String resource = classPathResource.getURL().getPath();
            //渲染表格
            HackLoopTableRenderPolicy  policy = new HackLoopTableRenderPolicy();
            Configure config = Configure.newBuilder().bind("detailList", policy).build();
            XWPFTemplate template = XWPFTemplate.compile(resource, config).render(
                    new HashMap<String, Object>() {{
                    put("detailList", detailList);
                    put("order_number", "2356346346645");
                    put("y", now.get(Calendar.YEAR));//当前年
                    put("m", (now.get(Calendar.MONTH) + 1));//当前月
                    put("d", now.get(Calendar.DAY_OF_MONTH));//当前日
                    put("order_money",order_money);//总金额
                    put("money_total",money_total);//金额中文大写
                }}
            );
            //=================生成文件保存在本地D盘某目录下=================
            String temDir="D:/mimi/"+File.separator+"file/word/"; ;//生成临时文件存放地址
            //生成文件名
            Long time = new Date().getTime();
            // 生成的word格式
            String formatSuffix = ".docx";
            // 拼接后的文件名
            String fileName = time + formatSuffix;//文件名  带后缀
            
            FileOutputStream fos = new FileOutputStream(temDir+fileName);
            template.write(fos);
            //=================生成word到设置浏览默认下载地址=================
            // 设置强制下载不打开
            response.setContentType("application/force-download");
            // 设置文件名
            response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
            OutputStream out = response.getOutputStream();
            template.write(out);
            out.flush();
            out.close();
            template.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

 

需要注意的是:
方法中的代码:

 FileOutputStream fos = new FileOutputStream(temDir+fileName);//输出路径(下载到指定路径)

exportDataWord3方法中的两行代码:

//浏览器下载
response.setContentType("application/force-download");
response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);

如果想要显示浏览器下载exportDataWord3方法中的这两行代码必须显示

5.MoneyUtils 工具类

package com.example.word.common;


/**
 * 金额转换工具类
 */
public class MoneyUtils {
    private static final String UNIT = "万千佰拾亿千佰拾万千佰拾元角分";
    private static final String DIGIT = "零壹贰叁肆伍陆柒捌玖";
    private static final double MAX_VALUE = 9999999999999.99D;
    public static String change(double v) {
        if (v < 0 || v > MAX_VALUE){
            return "参数非法!";
        }
        long l = Math.round(v * 100);
        if (l == 0){
            return "零元整";
        }
        String strValue = l + "";
        // i用来控制数
        int i = 0;
        // j用来控制单位
        int j = UNIT.length() - strValue.length();
        String rs = "";
        boolean isZero = false;
        for (; i < strValue.length(); i++, j++) {
            char ch = strValue.charAt(i);
            if (ch == '0') {
                isZero = true;
                if (UNIT.charAt(j) == '亿' || UNIT.charAt(j) == '万' || UNIT.charAt(j) == '元') {
                    rs = rs + UNIT.charAt(j);
                    isZero = false;
                }
            } else {
                if (isZero) {
                    rs = rs + "零";
                    isZero = false;
                }
                rs = rs + DIGIT.charAt(ch - '0') + UNIT.charAt(j);
            }
        }
        if (!rs.endsWith("分")) {
            rs = rs + "整";
        }
        rs = rs.replaceAll("亿万", "亿");
        return rs;
    }
 
    public static void main(String[] args){
        System.out.println(MoneyUtils.change(12356789.9845));
    }
}

5.jsp部分代码:

<a href="#" class="easyui-linkbutton" onclick="doExportWord3();" data-options="iconCls:'icon-save'">导出word(包含动态表格)</a>
function doExportWord3(){
  window.location.href="<%=basePath%>/auth/exportWord/exportDataWord3";
}


---------------------------------
解决ajax下载乱码:

let uri = '/live/sum/exportExcel'
let xhr = new XMLHttpRequest()
xhr.onload = function(e) {
if (this.status == 200) {
/* 文件下载 */
let blob = new Blob([this.response], {
type: "application/vnd.ms-excel;charset=UTF-8"
})
let downloadUrl = window.URL.createObjectURL(blob)
let link = document.createElement('a')
link.href = downloadUrl
link.download = '统计.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(downloadUrl)
}
hideLoading_dialog()
}
xhr.open("POST", uri, true)
/* 重点:后端返回的响应类型为 arraybuffer,不是常用的 blob */
xhr.responseType = "arraybuffer"
/* 此处为后端接受请求数据的 MIME 类型 */
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
let param = new URLSearchParams()
param.append("queryDate", queryDate)
xhr.send(param)

 

6.导出结果:

 

 

 

 

功能延伸

SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)

 

转载https://blog.csdn.net/qq_26383975/article/details/111561540

 

posted @ 2022-03-08 15:11  joel1889  阅读(740)  评论(0编辑  收藏  举报