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>
&lt;!-- 对JSP的支持 --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
    &lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;
    &lt;artifactId&gt;tomcat-embed-jasper&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
    &lt;artifactId&gt;jstl&lt;/artifactId&gt;
&lt;/dependency&gt;</pre>
复制代码

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 {

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 销售订单信息导出word --- poi-tl(包含动态表格)
 * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> IOException 
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@RequestMapping(</span>"/exportDataWord3"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> exportDataWord3(HttpServletRequest request,HttpServletResponse response) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException{
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        Map</span>&lt;String, Object&gt; params = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO 渲染其他类型的数据请参考官方文档</span>
        DecimalFormat df = <span style="color: rgba(0, 0, 255, 1)">new</span> DecimalFormat("######0.00"<span style="color: rgba(0, 0, 0, 1)">);   
        Calendar now </span>=<span style="color: rgba(0, 0, 0, 1)"> Calendar.getInstance(); 
        </span><span style="color: rgba(0, 0, 255, 1)">double</span> money = 0;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">总金额
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">组装表格列表数据</span>
        List&lt;Map&lt;String,Object&gt;&gt; detailList=<span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList&lt;Map&lt;String,Object&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
        </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; 6; i++<span style="color: rgba(0, 0, 0, 1)">) {
             Map</span>&lt;String,Object&gt; detailMap = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;String, Object&gt;<span style="color: rgba(0, 0, 0, 1)">();
             detailMap.put(</span>"index", i+1);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">序号</span>
             detailMap.put("title", "商品"+i);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">商品名称</span>
             detailMap.put("product_description", "套");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">商品规格</span>
             detailMap.put("buy_num", 3+i);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">销售数量</span>
             detailMap.put("saleprice", 100+i);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">销售价格</span>
            
             <span style="color: rgba(0, 0, 255, 1)">double</span> saleprice=Double.valueOf(String.valueOf(100+<span style="color: rgba(0, 0, 0, 1)">i));
             Integer buy_num</span>=Integer.valueOf(String.valueOf(3+<span style="color: rgba(0, 0, 0, 1)">i));
             String buy_price</span>=df.format(saleprice*<span style="color: rgba(0, 0, 0, 1)">buy_num);
             detailMap.put(</span>"buy_price", buy_price);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">单个商品总价格</span>
             money=money+<span style="color: rgba(0, 0, 0, 1)">Double.valueOf(buy_price);
             
             detailList.add(detailMap);
        }
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">总金额</span>
        String order_money=<span style="color: rgba(0, 0, 0, 1)">String.valueOf(money);
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">金额中文大写</span>
        String money_total =<span style="color: rgba(0, 0, 0, 1)"> MoneyUtils.change(money);
          
          </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">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" οnclick="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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当使用Poi-tl库根据Word模板填充内容生成Word文档时,可以使用Poi-tl提供的模板语法来处理空值。以下是一个示例代码: ```java import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.ParagraphAlignment; import org.apache.poi.xwpf.usermodel.TextAlignment; import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter; import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions; import org.apache.poi.util.Units; import org.apache.poi.xwpf.usermodel.Document; import org.apache.poi.xwpf.usermodel.HeaderFooterType; import org.apache.poi.xwpf.usermodel.IBodyElement; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class WordTemplateFiller { public static void main(String[] args) { try { // 加载Word模板文件 FileInputStream templateStream = new FileInputStream("template.docx"); XWPFDocument document = new XWPFDocument(templateStream); // 填充内容 Map<String, Object> placeholders = new HashMap<>(); placeholders.put("name", "John Doe"); placeholders.put("age", "30"); placeholders.put("address", ""); replacePlaceholders(document, placeholders); // 保存填充后的文档 FileOutputStream outputStream = new FileOutputStream("filled_template.docx"); document.write(outputStream); outputStream.close(); System.out.println("Word文档生成成功!"); } catch (IOException e) { e.printStackTrace(); } } private static void replacePlaceholders(XWPFDocument document, Map<String, Object> placeholders) { for (XWPFParagraph paragraph : document.getParagraphs()) { for (XWPFRun run : paragraph.getRuns()) { String text = run.getText(0); if (text != null) { for (Map.Entry<String, Object> entry : placeholders.entrySet()) { String placeholder = "${" + entry.getKey() + "}"; if (text.contains(placeholder)) { Object value = entry.getValue(); if (value != null && !value.toString().isEmpty()) { text = text.replace(placeholder, value.toString()); } else { text = text.replace(placeholder, ""); // 替换为空字符串 } run.setText(text, 0); } } } } } } } ``` 在上述代码中,我们首先加载Word模板文件,然后定义了一个`placeholders`的映射,其中包了要替换的占位符和对应的值。接下来,我们调用`replacePlaceholders`方法来替换文档中的占位符。 在`replacePlaceholders`方法中,我们遍历文档中的每个段落和文本运,通过检查文本内容中是否包占位符来确定是否需要替换。如果找到了匹配的占位符,则根据占位符对应的值来进替换。如果值不为空且非空字符串,则将占位符替换为对应的值;如果值为空或空字符串,则将占位符替换为空字符串。 请注意,上述代码中使用的占位符格式为`${placeholder}`,你可以根据实际情况修改为其他格式。 以上是一个基本示例,你可以根据自己的需求进修改和扩展。同时,需要确保在项目中添加了Poi-tl的依赖库。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值