何小豆儿在此 发表于 2023-6-14 05:23:43

springboot+JXLS+Jexl实现报表模版生成报表

前言

做这个项目的思路是由于公司基于自身发展,需要将之前的老项目平台拆解出来,由于之前的项目是所有的功能全部集中在一起,学习成本以及后续的扩展性来说,非常的不友好,并且由于之前设计人员的流失导致了项目无法进一步优化,所以想将其进行拆解,将单个功能模块进行拆分,形成微服务化,使每个功能的业务更加单一,也更加简单
经过使用了一段时间的老平台,发现目前公司的平台的一些设计确实非常的好,其中,报表的设计理念比市面上大多的报表工具设计都要好,为什么呢,因为我们公司是基于B to B的项目模式,所以,客户可能会经常临时性的提出一些报表需求,并且需要响应时间比较快速,所以我们需要一种基于模版即可生成报表的报表工具
报表工具的比对

基于模版形式的报表工具

目前市场上基于模版的是JXLS,他的优势是JXLS 是基于 Jakarta POI API 的 Excel 报表生成工具,可以生成精美的 Excel 格式报表。它采用标签的方式,类似 JSP 标签,写一个 Excel 模板,然后生成报表,非常灵活,简单!
缺点是它只可以导出03版本的excel
实现jxls

配置与使用


[*]引入依赖
                                <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls</artifactId>
            <version>2.8.0</version>
      </dependency>
      <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls-poi</artifactId>
            <version>1.0.15</version>
      </dependency>
      <dependency>
            <groupId>net.sf.jxls</groupId>
            <artifactId>jxls-core</artifactId>
            <version>1.0.5</version>
      </dependency>
[*]编写工具辅助类
研发一个execl生成的工具类,其中加入了自定义方法,这个思想与lims平台设计中的Alog类类似,采用Jexl来进行实现,本项目采用的是jexl3
package com.thyc.reportserver.utils;

import com.thyc.reportserver.excelCal.CalTime;
import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlEngine;
import org.jxls.area.Area;
import org.jxls.builder.AreaBuilder;
import org.jxls.builder.xls.XlsCommentAreaBuilder;
import org.jxls.common.CellRef;
import org.jxls.common.Context;
import org.jxls.expression.JexlExpressionEvaluator;
import org.jxls.transform.Transformer;
import org.jxls.util.TransformerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* @Description: excel辅助工具类
* @Author: wanping
* @Date: 6/13/23
**/
public class ExcelUtils {
    /***
   * excel导出到response
   * @param fileName   导出文件名
   * @param templateFile 模板文件地址
   * @param params   数据集合
   * @param response   response
   */
    public static void exportExcel(String fileName, InputStream templateFile, Map<String, Object> params,
                                 HttpServletResponse response) throws IOException {
      response.reset();
      response.setHeader("Accept-Ranges", "bytes");
      OutputStream os = null;
      response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", fileName));
      response.setContentType("application/octet-stream;charset=UTF-8");
      try {
            os = response.getOutputStream();
            exportExcel(templateFile, params, os);
      } catch (IOException e) {
            throw e;
      }
    }

    /**
   * 导出excel到输出流中
   * @param templateFile 模板文件
   * @param params 传入参数
   * @param os 输出流
   * @throws IOException
   */
    public static void exportExcel(InputStream templateFile, Map<String, Object> params, OutputStream os) throws IOException {
      try {
            Context context = new Context();
            Set<String> keySet = params.keySet();
            for (String key : keySet) {
                //设置参数变量
                context.putVar(key, params.get(key));
            }
            Map<String, Object> myFunction = new HashMap<>();
            myFunction.put("calTime", new CalTime());
            // 启动新的jxls-api 加载自定义方法
            Transformer trans = TransformerFactory.createTransformer(templateFile, os);
            JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator) trans.getTransformationConfig().getExpressionEvaluator();
//            evaluator.getJexlEngine().setFunctions(myFunction); 这个方法是2版本的
            JexlBuilder jb = new JexlBuilder();
            jb.namespaces(myFunction);
            JexlEngine je = jb.create();
            evaluator.setJexlEngine(je);

            // 载入模板、处理导出
            AreaBuilder areaBuilder = new XlsCommentAreaBuilder(trans);
            List<Area> areaList = areaBuilder.build();
            areaList.get(0).applyAt(new CellRef("sheet1!A1"), context);
            trans.write();
      } catch (IOException e) {
            throw e;
      } finally {
            try {
                if (os != null) {
                  os.flush();
                  os.close();
                }
                if (templateFile != null) {
                  templateFile.close();
                }
            } catch (IOException e) {
                throw e;
            }
      }
    }
}
[*]编写计算类
package com.thyc.reportserver.excelCal;

import org.jxls.transform.poi.WritableCellValue;
import org.jxls.transform.poi.WritableHyperlink;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
* @Description: excel计算时间方法
* @Author: wanping
* @Date: 6/13/23
**/
public class CalTime {

    /**
   * 格式化时间
   */
    public Object formatDate(Date date) {
      if (date != null) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dateStr = sdf.format(date);
            return dateStr;
      }
      return "--";
    }

    /**
   * 设置超链接方法
   */
    public WritableCellValue getLink(String address, String title) {
      return new WritableHyperlink(address, title);
    }

}
[*]编写剩下的测试用例
service
package com.thyc.reportserver.service;

import javax.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.OutputStream;
import java.util.Map;

/**
* @Description: TODO
* @Author: wanping
* @Date: 6/13/23
**/
public interface ExcelService {

    /**
   * 导出excel,写入文件中
   * @param templateFile
   * @param params
   * @param outputFile
   * @return
   */
    boolean getExcel(String templateFile, Map<String,Object> params, File outputFile);
}impl
package com.thyc.reportserver.service.impl;

import com.thyc.reportserver.service.ExcelService;
import com.thyc.reportserver.utils.ExcelUtils;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

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

/**
* @Description: TODO
* @Author: wanping
* @Date: 6/13/23
**/
@Service
public class ExcelServiceImpl implements ExcelService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
   * 模板文件的基础路径
   */
    @Value("${jxls.template.path}")
    private String templatePath;

    @Override
    public boolean getExcel(String templateFile, Map<String, Object> params, File outputFile) {
      FileInputStream inputStream = null;
      try {
            //获取模板文件的输入流
            inputStream = new FileInputStream(ResourceUtils.getFile(templatePath + templateFile));
            File dFile = outputFile.getParentFile();
            //文件夹不存在时创建文件夹
            if(dFile.isDirectory()){
                if(!dFile.exists()){
                  dFile.mkdir();
                }
            }
            //文件不存在时创建文件
            if(!outputFile.exists()){
                outputFile.createNewFile();
            }
            //导出excel文件
            ExcelUtils.exportExcel(inputStream, params, new FileOutputStream(outputFile));
      } catch (IOException e) {
            logger.error("excel export has error" + e);
            return false;
      }
      return true;
    }
}编写测试用例
package com.thyc.reportserver;

import com.thyc.reportserver.excelModel.UserModel;
import com.thyc.reportserver.service.ExcelService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.File;
import java.util.*;

@SpringBootTest
class ReportServerApplicationTests {

    @Autowired
    ExcelService excelService;

    @Test
    void contextLoads() {
      Map<String, Object> params = new HashMap();
      List<UserModel> list = new ArrayList<>();
      for (int i = 0; i < 10; i++) {
            int i1 = i + 1;
            list.add(new UserModel(i1, "test" + i1, "男", 25 + i, "tttttttttt" + i1, new Date(), "htpp://wwww.baidu.com"));
      }
      params.put("list", list);
      excelService.getExcel("user1.xlsx", params, new File("/Users/wanping/IdeaProjects/ddd/report-server/excel/test01.xlsx"));
    }

}
[*]结果展示
导入模版

https://img2023.cnblogs.com/blog/2783853/202306/2783853-20230613182222773-1487029110.png
结果
https://img2023.cnblogs.com/blog/2783853/202306/2783853-20230613182235075-613742207.png
参考:https://www.jb51.net/article/195015.htm

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: springboot+JXLS+Jexl实现报表模版生成报表