JXLS导出自定义EXCEL模板

105 阅读3分钟

 前言

还在为Java应用中复杂的Excel报表导出而头疼吗?是否厌倦了在代码里逐行逐单元格拼接数据的繁琐操作?如果你的答案是肯定的,那么这篇文章正是为你准备的!

作为开发者,高效、优雅地生成格式化的Excel报表是一项高频且关键的需求。手动操作POI API不仅代码冗长、维护困难,模板稍有变动就需要重新调整代码,灵活性极差。而 JXLS 正是为解决这一痛点而生的利器,它通过声明式的模板驱动方式,让Excel报表生成变得直观、简洁且易于维护。

在本文中,将聚焦于 JXLS最核心也最强大的功能之一:基于Excel批注的模板配置。

我的公众号(附有面试资料):Java乐享

一、引入依赖

        <dependency>
			<groupId>org.jxls</groupId>
			<artifactId>jxls</artifactId>
			<version>2.12.0</version>
		</dependency>
		<dependency>
			<groupId>org.jxls</groupId>
			<artifactId>jxls-poi</artifactId>
			<version>2.9.0</version>
		</dependency>
		<dependency>
			<groupId>org.jxls</groupId>
			<artifactId>jxls-jexcel</artifactId>
			<version>1.0.7</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.8.1</version>
		</dependency>

二、编写代码

实体类

package com.lexiang.demo.dto;

import lombok.Data;



/**
 * @author lexiang
 */
@Data
public class UserDTO {
    
    private Long id;

    private String username;

    private String phone;
}

工具类JxlsExcelUtil

package com.lexiang.demo.util;

import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.jxls.common.Context;
import org.jxls.transform.Transformer;
import org.jxls.transform.poi.PoiTransformer;
import org.jxls.util.JxlsHelper;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;

import java.io.*;
import java.net.URLEncoder;
import java.util.Map;

/**
 * @author lexiang
 */
public class JxlsExcelUtil {
    private static final String EXCEL_XLS = ".xls";
    private static final String EXCEL_XLSX = ".xlsx";

    /**
     * 导出工具类
     * @param response
     * @param input
     * @param data
     */
    public static void export(HttpServletResponse response, InputStream input, Map<String, Object> data, String importFileName) {
        OutputStream outStream = null;
        try {
            Context context = new Context();
            for (Map.Entry<String, Object> element : data.entrySet()) {
                context.putVar(element.getKey(), element.getValue());
            }
            outStream = response.getOutputStream();
            // 设置ContentType请求信息格式
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyExcel没有关系
            String fileName = URLEncoder.encode(importFileName, "UTF-8").replaceAll("\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=" + fileName + EXCEL_XLSX);
            Transformer transformer = PoiTransformer.createTransformer(input, outStream);
            JxlsHelper.getInstance().setEvaluateFormulas(true).processTemplate(context, transformer);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                assert outStream != null;
                outStream.flush();
                outStream.close();
            } catch (IOException e) {

            }
        }
    }

    /**
     * 获取模板文件流
     */
    public static InputStream getTplIs(String tpl) {
        InputStream is = null;
        try {
            String tplPath = "templates/" + tpl;
            is = ClassUtils.class.getClassLoader().getResourceAsStream(tplPath);
            if (is == null) {
                File file = ResourceUtils.getFile("classpath:" + tplPath);
                is = new FileInputStream(file);
            }
        } catch (Exception e) {
            String eMsg = StringUtils.isBlank(e.getMessage()) ? e.toString() : e.getMessage();
        }
        return is;
    }

}

测试类

package com.lexiang.demo.controller;

import com.lexiang.demo.dto.UserDTO;
import com.lexiang.demo.util.JxlsExcelUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.InputStream;
import java.util.*;

/**
 * jxls导出
 * @author lexiang
 */
@RestController
@RequestMapping("/jxls")
public class JxlsController {

    @GetMapping("export")
    public void export(HttpServletResponse response) {
        Map<String,Object> param = new HashMap<>(8);
        param.put("unitName", "学生状态表");
        param.put("className", "高一三班");
        param.put("people", "张三");
        param.put("phone", "13666666666");
        param.put("num", 30);
        param.put("gameNum", 12);
        param.put("bookNum", 10);
        param.put("musicNum", 8);

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
        InputStream inputStream = JxlsExcelUtil.getTplIs("people_report.xlsx");
        JxlsExcelUtil.export(response, inputStream, param, "学生状态表");
    }

    @GetMapping("exportList")
    public void exportList(HttpServletResponse response) {
        Map<String,Object> param = new HashMap<>(8);
        param.put("title", "标题");
        List<UserDTO> users = new ArrayList<>();
        UserDTO dto1 = new UserDTO();
        dto1.setId(1L);
        dto1.setUsername("张三");
        dto1.setPhone("13645634563");

        UserDTO dto2 = new UserDTO();
        dto2.setId(2L);
        dto2.setUsername("李思思");
        dto2.setPhone("13645634666");
        users.add(dto1);
        users.add(dto2);
        param.put("users", users);

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
        InputStream inputStream = JxlsExcelUtil.getTplIs("list_demo.xlsx");
        JxlsExcelUtil.export(response, inputStream, param, "用户信息表");
    }
}

三、在templates下创建excel模板

语法

jx:area 定义 Jxls 应处理的单元格区域。jx:area 通常位于单元格 A1 中,而 其 lastCell 属性定义所用工作表区域的右下角。

jx:each 主要用于创建行。一般用于循环列表。

jx:each(items=”users”,var=”use”,lastCell=”C3”)

说明: items: 返回 Iterable 或数组的表达式 ;var:保存每行对象的变量名称; lastCell:区域结束 

官方文档:jxls.sourceforge.net/commands.ht…

1.单个字段名称

创建people_report.xlsx

image

 选中unitName,右键插入批注jx:area(lastCell=D1),最后一列D结束,{unitName},右键插入批注jx:area(lastCell=”D1”),最后一列D结束,{people}和${num}同理设置

2.列表数据

创建list_demo.xl

image

 title批注设置的是jx:area(lastCell=”C3”)

${user.id}批注设置的是jx:each(items=”users”,var=”use”,lastCell=”C3”)

四、测试

启动项目后用apifox或者postman调用接口测试

接口地址:http://localhost:8080/jxls/export

image

 效果如下:

image

接口地址:http://localhost:8080/jxls/exportList

image

 效果如下:

image