poi-tl,根据word模板导出word(表格行循环,表格无表头的情况)

 

最近项目里要做一个根据客户提供的word模板导出word的功能,方法有很多,比如easyPoi(对word的支持并不是很好),freeMark(太麻烦不想研究),以及poi-tl,

最后研究了半天发现也就只有poi-tl比较符合我的需求,特意记录下以防日后用到忘记了。

这是想要的word结果

这是我的word模板

代码如下:

 try {
            DecimalFormat df = new DecimalFormat("###################.###########");
            SettlementResponse.All settlement = getDetails(settlementId);
            Map<String, Object> params = new HashMap<>();
            params.put("guestName", settlement.getBase().getGuestName());
            String visitStart = DateUtil.timestamp2String(settlement.getBase().getVisitTimeStart(),"yyyy年MM月dd日");
            String visitEnd = DateUtil.timestamp2String(settlement.getBase().getVisitTimeStart(),"MM月dd日");
            params.put("visitDate", visitStart+ "-" + visitEnd);
            SettlementResponse.Detail detail = settlement.getDetail();
            double total = 0;
            //住宿费列表
            if (MyUtil.isNotBlank(detail.getAccomResponse())){
                SettlementAccomResponse accomResponse = detail.getAccomResponse();
                Map<String,Object> accomMap = getAccomdation(accomResponse);
                params.put("accomList", accomMap.get("accomList"));
                params.put("accomOwn", accomMap.get("accomOwn"));
                params.put("accomTotal", accomMap.get("accomTotal"));
                total = total + accomResponse.getSubtotal().doubleValue();
            }
            //会场费列表
            List<Map<String,Object>> meetList = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(detail.getMeetingResponseList())){
                Map<String,Object> meetingMap = getMeeting(detail.getMeetingResponseList());
                params.put("meetList", meetingMap.get("meetList"));
                params.put("meetTotal",meetingMap.get("meetTotal"));
                total = total + Double.parseDouble(meetingMap.get("meetTotal").toString());
            } else{
                meetList.add(new HashMap<String, Object>() {{
                    put("meetTime", "");
                    put("meetPlace", "");
                    put("roomName", "");
                    put("meetCost", "");
                }});
                params.put("meetList",meetList);
            }

            //餐饮费列表
            if (MyUtil.isNotBlank(detail.getMealsResponse())){
                List<SettlementMealsResponse.MealsDetail> mealsDetailList = detail.getMealsResponse().getMealsDetailList();
                Map<String,Object> mealsMap = getMeals(mealsDetailList);
                params.put("workMeal", mealsMap.get("workMeal"));
                params.put("dailMeal", mealsMap.get("dailMeal"));
                params.put("otheMeal", mealsMap.get("otheMeal"));
                params.put("mealsOwn", df.format(detail.getMealsResponse().getOwnExpense()));
                params.put("mealTotal", df.format(detail.getMealsResponse().getSubtotal()));
                total = total + detail.getMealsResponse().getSubtotal().doubleValue();
            }
            //其他费用列表
            List<Map<String,Object>> otherList = new ArrayList<Map<String,Object>>();
            if (CollectionUtil.isNotEmpty(detail.getOthersList())){
                Map<String,Object> otherMap = getOther(detail.getOthersList());
                params.put("otherList", otherMap.get("otherList"));
                params.put("otherTotal", otherMap.get("otherTotal"));
                total = total + Double.parseDouble(otherMap.get("otherTotal").toString());
            }else{
                otherList.add(new HashMap<String, Object>() {{
                    put("otherRemark", "");
                    put("otherCost", "");
                }});
                params.put("otherList", otherList);
            }
            //文印费
            params.put("printRemark", detail.getPrints().getDescription());
            params.put("printTotal",  df.format(detail.getPrints().getCost()));
            total = total + detail.getPrints().getCost().doubleValue();
            params.put("total", df.format(total));
            //word模板地址,如果项目需要部署在linux环境中,需要以流的方式读取文件否则会读取不到
            InputStream resource= this.getClass().getClassLoader().getResourceAsStream("static/template/settlement.docx");
            //渲染表格,new HackLoopTableRenderPolicy(true)即模板标签和循环行在同一行而不是在上一行
            HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy(true);
            Configure config = Configure.builder()
                    .bind("accomList", policy)
                    .bind("meetList", policy)
                    .bind("workMeal", policy)
                    .bind("dailMeal", policy)
                    .bind("otheMeal", policy)
                    .bind("otherList", policy)
                    .build();
            XWPFTemplate template = XWPFTemplate.compile(resource, config).render(params);
            String fileName = "接待任务费用结算表" + "-" + System.currentTimeMillis();
            ExportWordUtils.downloadWord(response, fileName, template);
        } catch (Exception e) {
            e.printStackTrace();
        }
public class ExportWordUtils {

    /**
     * 根据模板填充内容生成word,并下载
     * @param templatePath word模板文件路径
     * @param paramMap     替换的参数集合
     */
    public static void compileWord(HttpServletResponse response, InputStream templatePath, Map<String, Object> paramMap, String fileName) throws UnsupportedEncodingException {
        // 读取模板templatePath并将paramMap的内容填充进模板,即编辑模板(compile)+渲染数据(render)
        XWPFTemplate template = XWPFTemplate.compile(templatePath).render(paramMap);
        downloadWord(response, fileName, template);
    }


    public static void downloadWord(HttpServletResponse response, String fileName, XWPFTemplate template) throws UnsupportedEncodingException {
        response.setContentType("application/octet-stream");
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".docx");
        //设置生成的文件临时存放路径
        String rootPath="./wordTemplate";
        String filePath = rootPath + fileName;
        File newFile = new File(filePath);
        if(!newFile.getParentFile().exists()){
            newFile.getParentFile().mkdirs();
        }
        try {
            OutputStream out = response.getOutputStream();
            // 将填充之后的模板写入filePath
            template.write(out);
            out.flush();
            out.close();
            template.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

最后附上poi-tl的文档地址: http://deepoove.com/poi-tl/#hack-loop-table

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot中使用poi-tl库来导出带有合并列的Word表格并下载,您可以按照以下步骤操作: 1. 首先,确保您的Spring Boot项目中已经添加了poi-tl的依赖。您可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.6.0</version> </dependency> ``` 2. 创建一个Controller来处理导出请求。例如,创建一个名为WordExportController的类,并添加一个处理导出请求的方法。 ```java import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.data.*; import com.deepoove.poi.util.BytePictureUtils; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; @Controller public class WordExportController { @GetMapping("/export") public ResponseEntity<InputStreamResource> exportWord() throws IOException { // 创建一个数据模型 List<List<String>> tableData = new ArrayList<>(); tableData.add(createRow("Merged Cells", "Cell 3")); tableData.add(createRow("Cell 4", "Cell 6")); // 使用poi-tl的XWPFTemplate来生成Word文档 XWPFTemplate template = XWPFTemplate.compile("templates/template.docx").render( new DataTable(tableData) .setHeader(createRow("Header 1", "Header 2")) .setCellWidth(2000) // 设置单元格宽度 .setHeaderCellStyle(new CellStyle().setBold(true).setColor("FFFFFF").setBgColor("336699")) .setOddRowCellStyle(new CellStyle().setColor("FFFFFF").setBgColor("99CCFF")) .setEvenRowCellStyle(new CellStyle().setColor("FFFFFF").setBgColor("CCEEFF")) ); // 将生成的Word文档转换为字节数组 ByteArrayOutputStream out = new ByteArrayOutputStream(); template.write(out); byte[] documentBytes = out.toByteArray(); // 设置下载响应的头信息 HttpHeaders headers = new HttpHeaders(); headers.setContentDispositionFormData("attachment", "merged_table.docx"); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 创建一个包含Word文档字节数组的InputStreamResource InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(documentBytes)); // 返回响应实体 return ResponseEntity.ok() .headers(headers) .body(resource); } private List<String> createRow(String cell1, String cell2) { List<String> row = new ArrayList<>(); row.add(cell1); row.add(cell2); return row; } } ``` 3. 在resources目录下创建一个名为template.docx的Word模板文件。在模板文件中,您可以根据自己的需求设置表格样式和内容。 4. 启动您的Spring Boot应用程序,并访问导出请求的URL(例如:http://localhost:8080/export)。将会自动下载名为merged_table.docx的Word文档,其中包含合并列的表格。 请确保按照您的需求修改代码,并根据模板文件的位置进相应的调整。 希望对您有所帮助!如果您有任何其他问题,请随时提问。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值