zhos0212的gravatar头像
zhos0212 2019-09-12 15:55:14
java报表开发框架jxls

关于java对于报表工具的应用开发,我们今天来了解一下jxls;

jxls是一个简单的、轻量级的excel导出库,使用特定的标记在excel模板文件中来定义输出格式和布局。

其实java中成熟的excel导出工具有pol、jxl,但他们都是使用java代码的方式来导出excel,编码效率很低且不方便维护。

jxls是通过预制excel模板,然后通过jxls相应API将我们应用程序的数据结合模板格式输出到相应的excel文件中,从而形成报表;

因此,我们首先需要了解jxls模板的相关使用标记;下面以jxls 2.4.0的示例来说明:

excel模板示例:

java报表开发框架jxls

Excel模板标记在jxls中的作用分为三部分:

  1. bean属性标记
  2. XLS Area定义标记
  3. XLS Command表示标记

bean属性标记

jxls使用 Apache JEXL表达式语言来解析定义在excel模板中的表达式。JEXL与JSTL相似,并对JSTL进行了扩展。eg:

${department.chief.age} //属性可以是无限深度

${utils:dateFmt(date,"yyyy-MM-dd")} //自定义工具函数

XLS Area定义标记

XLS Area 是JxlsPlus中的一个重要概念,它代表excel模板中需要被解析的矩形区域,由A1到最后一个单元格表示,有利于加快解析速度。

XLS Area 使用excel注释标注表示,它需要被定义在excel 模板的第一个单元格(A1):

jx:area(lastCell = "<AREA_LAST_CELL>")

这个标记定义了excel模板需要被解析的矩形区域为:A1到<AREA_LAST_CELL>。

XLS Command表示标记

XLS Command 使用excel注释标注表示,命令格式如下:

jx:<command_name>(attr1='val1' attr2='val2' ... attrN='valN' lastCell=<last_cell> areas=["<command_area1>", "<command_area2",

... "<command_areaN>"])

<command_name> 是库自带的命名或是用户自定义并注册到XlsCommentAreaBuilder的命令。

each 命令是最常用的XLS命令,形如:

jx:each(items="employees" var="employee" lastCell="D4")

each 可以有如下一些属性:

  • items 上下文中集合的变量名;
  • var 在遍历集合的时候每一条记录的变量名;
  • area 该XLS Command的解析区域;
  • direction 数据在excel中填充的方向,默认(DOWN)向下;
  • select 其值为一个表达式,用来过滤数据。

 

我们下面来看一个简单例子:

以下代码中,分别实现了通过设置excel模板,java后台处理数据对Map的加载、对List<javabean>的加载,闲话不多说,直接上示例代码

javabean Emp类

public class Emp {

	private String id;
	private String name;
	private String position;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPosition() {
		return position;
	}
	public void setPosition(String position) {
		this.position = position;
	}
	
}

Test测试类

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
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.transform.Transformer;
import org.jxls.util.TransformerFactory;

import java.io.*;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 简单示例
 */
public class Test {

    @SuppressWarnings({ "unchecked", "rawtypes" })
	public static void execute(FileOutputStream outputStream) throws IOException, InvalidFormatException, ParseException, SQLException {
        String template = "/xlstemplate/object_collection_template.xls";//报表模板
        InputStream is = Test.class.getResourceAsStream(template);
        OutputStream os = outputStream;
        Transformer transformer = TransformerFactory.createTransformer(is, os);
        AreaBuilder areaBuilder = new XlsCommentAreaBuilder(transformer);
        List<Area> xlsAreaList = areaBuilder.build();

        Area xlsArea = xlsAreaList.get(0);
        Context context = new Context();

        Calendar calendar = new GregorianCalendar();
		calendar.setTime(new Date());
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH) + 1;
		int day = calendar.get(Calendar.DAY_OF_MONTH);
		String monthStr = month < 10 ? ("0"+month) : month+"";
        String date = year + monthStr + day;
		
        //简单报表(Map);basicform也可以是javabean形式
        Map<String, Object> basicform = new HashMap();
        basicform.put("dwmc", "测试");
        basicform.put("zgbm", "测试11");
        basicform.put("yyzzh", "测试22");
        basicform.put("lxdh", "测试33");
        basicform.put("slsj1", "测试44");
        basicform.put("pdate", date);
        context.putVar("basicform", basicform);
        xlsArea.applyAt(new CellRef("封面!A1"), context);

        Area xlsArea1 = xlsAreaList.get(1);
        xlsArea1.applyAt(new CellRef("基本情况1!A1"), context);

        // List<Object>报表
        Area xlsArea2 = xlsAreaList.get(2);
        List<Emp> lisEmp = new ArrayList<Emp>();
        Emp e1 = new Emp();
        e1.setId("1");
        e1.setName("李X");
        e1.setPosition("施工员");
        lisEmp.add(e1);
        Emp e2 = new Emp();
        e2.setId("2");
        e2.setName("刘X");
        e2.setPosition("监理");
        lisEmp.add(e2);
        context.putVar("lisEmp", lisEmp);
//        Map<String, Object> emp = new HashMap();
//        emp.put("name", "李XX");
//        emp.put("id", "1");
//        emp.put("position", "施工员");
//        context.putVar("emp", emp);
        xlsArea2.applyAt(new CellRef("基本情况2!A1"), context);

        transformer.write();
        is.close();
    }

    public static void main(String[] args) throws IOException, SQLException, InvalidFormatException, ParseException {
        execute(new FileOutputStream(new File("d:/xxx.xls")));
    }
}

 

 

jexl自定义工具函数

如果你需要自定jexl来处理数据,你可以从Transformer对象获取JexlEngine引用,并对其配置。

下面的例子实现了将一个自定义jexl函数注册到utils命名空间下:

JxlsHelper jxlsHelper = JxlsHelper.getInstance();
Transformer transformer = jxlsHelper.createTransformer(is, os);
JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator)transformer.getTransformationConfig().getExpressionEvaluator();
Map<String, Object> funcs = new HashMap<String, Object>();
funcs.put("utils", new JxlsUtils()); //添加自定义功能
evaluator.getJexlEngine().setFunctions(funcs);

demo 

Employee.java 

 private String id;
    private String name;
    private Integer age;
    public Person(String id, String name, Integer age) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public Person() {
    }
....set,get 省略

建立excel模板:

java报表开发框架jxls

JxlsUtils工具类: 

package test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


import org.jxls.common.Context;
import org.jxls.expression.JexlExpressionEvaluator;
import org.jxls.transform.Transformer;
import org.jxls.transform.poi.PoiTransformer;
import org.jxls.util.JxlsHelper;

public class JxlsUtils{
	
	public static void exportExcel(InputStream is, OutputStream os, Map<String, Object> model) throws IOException{
        Context context = PoiTransformer.createInitialContext();
        if (model != null) {
            for (String key : model.keySet()) {
                context.putVar(key, model.get(key));
            }
        }
        JxlsHelper jxlsHelper = JxlsHelper.getInstance();
        Transformer transformer  = jxlsHelper.createTransformer(is, os);
        //获得配置
        JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator)transformer.getTransformationConfig().getExpressionEvaluator();
        //设置静默模式,不报警告
        evaluator.getJexlEngine().setSilent(true);
        //函数强制,自定义功能
        Map<String, Object> funcs = new HashMap<String, Object>();
        funcs.put("utils", new JxlsUtils());    //添加自定义功能
        evaluator.getJexlEngine().setFunctions(funcs);
        //必须要这个,否者表格函数统计会错乱
        jxlsHelper.setUseFastFormulaProcessor(false).processTemplate(context, transformer);
        //并没什么卵用
        //jxlsHelper.setDeleteTemplateSheet(true);
	}

    public static void exportExcel(File xls, File out, Map<String, Object> model) throws FileNotFoundException, IOException {
            exportExcel(new FileInputStream(xls), new FileOutputStream(out), model);
    }
    
    public static void exportExcel(String templatePath, OutputStream os, Map<String, Object> model) throws Exception {
    	File template = getTemplate(templatePath);
    	if(template != null){
        	exportExcel(new FileInputStream(template), os, model);	
    	} else {
    		throw new Exception("Excel 模板未找到。");
    	}
    }
    
    //获取jxls模版文件
    public static File getTemplate(String path){
        File template = new File(path);
        if(template.exists()){
            return template;
        }
        return null;
    }	
	
    // 日期格式化
    public String dateFmt(Date date, String fmt) {
        if (date == null) {
            return "";
        }
        try {
            SimpleDateFormat dateFmt = new SimpleDateFormat(fmt);
            return dateFmt.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
    
    // if判断
    public Object ifelse(boolean b, Object o1, Object o2) {
        return b ? o1 : o2;
    }
    
}

Test测试类:

// 模板位置,输出流
String templatePath = "/xlstemplate/template_2.xls";// /xlstemplate/template2.xls
templatePath = TestMain.class.getResource(templatePath).getPath();
OutputStream os = new FileOutputStream("E:/out.xls");
 
// 一个装有对象数据的链表
List<Person> persons = new ArrayList<Person>();
Person p1 = new Person("001", "张三", 18);
Person p2 = new Person("002", "李四", 19);
Person p3 = new Person("003", "王五", 20);
persons.add(p1);
persons.add(p2);
persons.add(p3);
 
Map<String, Object> model = new HashMap<String, Object>();
model.put("person", persons);    // 把链表放进model中
 
JxlsUtils.exportExcel(templatePath, os, model);
os.close();
System.out.println("完成");

运行截图: 

java报表开发框架jxls


打赏
最近浏览
王涛的1  LV1 2023年8月5日
panda1509 2023年4月17日
暂无贡献等级
anzai123  LV3 2022年1月14日
1326081564  LV1 2021年11月15日
gong001002003  LV2 2021年11月11日
小翊杭宝  LV2 2021年11月8日
heshiyang  LV1 2021年9月27日
weijianguo  LV7 2021年8月14日
小胖胖2019  LV2 2021年7月19日
lxfhi6  LV7 2021年6月25日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友