Excel导入导出功能

 

 

一、Excel基本导出

1、 默认模板目录的配置

可以通过配置文件配置一个模板的目录来获取目录中的模板,当然这不是必须的,只是为了统一代码管理。

1.1 非web工程配置

    在classpath:目录下smile.properties文件中配置 export.templateDir属可以是绝对路也可以是相对路径:

         例如:

         export.templateDir=${user.dir}/src/

        

         例如:

    export.templateDir=D:/template

1.2 Web项目配置

  web项目的时候除可在smile.properties中配置外,还实现了另一种可以在web.xml文件中的配置,此方法与其它使用listener加载配置的原理一致

         例如:

     <context-param>

        <param-name>xlsTemplateFileDir</param-name>

        <param-value>/WEB-INF/xlsTemplate</param-value>

    </context-param>

 

  也可以是classpath下

  <context-param>

        <param-name>xlsTemplateFileDir</param-name>

        <param-value>classpath:xlsTemplate</param-value>

    </context-param>

 

  再配置一个listener加载配置

<listener>

    <listener-class>org.smile.report.excel.XlsExportWebSupportListener</listener-class>

</listener>

1.3 配置信息使用

在配置的templateFileDir 目录下创建模板一个导出模板。

使用方法    XlsExportTemplate.getFilePath("/vmi/deliveryGoods.xls")  来获取模板的路径

 

代码样例:

XlsExportTemplate temp = new XlsExportTemplate();

        try {

    temp.loadXlsTemplate(XlsExportTemplate.getFilePath("/vmi/deliveryGoods.xls"));

            setReponseXls("VMI送货单_",".xls");

            List list=DeliveryQueryUtil.queryPageDeliery(vmiDeliveryService, query);

            temp.fillDataSource(list);

            BufferedOutputStream os = new BufferedOutputStream(getResponse().getOutputStream());

            temp.write(os);

            os.flush();

            os.close();

        } catch (Exception e) {

            e.printStackTrace();

        }

设置模板样例:

 

2、Excel模板

通用的模板样式为第一个sheet页中设置导出信息,第一行为导出信息的名称,第二行为导出信息对应导出对象的字段名。

2.1 对应字段名

如要显示名称 在单元格中 输入 name

如果属性是一个象则使用“ . ” 的方式调用,如 : id.name

属性可以支持 List     如  sublist.name  则会循环显示 对象sublist 中的对象的name 属性

2.2 转换函数

如果需要对对象属性进行转换,可以注册函数来处理 

实现 org.smile.report.excel.Function 接口 

 

package org.smile.report.excel;

 

public abstract class Function{

    /**

     * 转换对象值

     * @param oneData 行对象

     * @param exp 表达式

     * @param expValue 字段值

     * @return

     */

    public abstract Object convert(Object oneData,String exp,Object expValue);

    /**

     * 是否需要字段的值

     * 当返回false时 convert方法中expValue是不会有值的

     * 返回true时convert方法中expValue会根据exp表达式的值从oneData中获取值

     * @return

     */

    public boolean needFieldValue(){

        return true;

    }

}

 

注册后 ,模板中 使用 函数名{字段名} 方式调用。

 如:

temp.registerFunction("f", new Function() {

              @Override

              public Object convert(Object oneData, String exp,

                     Object expValue) {

                  ReportQuery reportData=(ReportQuery)oneData;

                  String status=reportData.getVstatus();

                  if(StringUtils.isEmpty(status)){

                     return "未确认";

                  }else if("5".equals(status)){

                     return "待采购确认";

                  }else if("0".equals(status)){

                     return "已确认";

                  }

           });

 

在excel单元格中填写 f{status} 就会调用转换函数进行显示转换

 

 

2.3显示常量

如需在xls中显示常量 可以通过 /**增加一个参数*/

public void addParam(String name,Object value)

方法添加常量  在模板中 以#name 方式调用

 

例如:

XlsExportTemplate temp=new XlsExportTemplate();

temp.addParam("china", "中华人民共和国");

 

在单元格中输入#china   输出的内容为中华人民共和国

2.4 Ognl表达式支持

导出模板中还可以对ongl表达式支持,只需要将ognl.jar加载到classpath中,在单元格中使用${exp} 或 ognl{exp} 方式对ognl表达式支持输出

例${state==1?'成功':'失败'}    对ognl的使用请参考网上的资料

 

2.5 内部变量

导出模板中还支持对 XlsExportTemplate 的成员变量进行输出显示,使用##fieldName 方式进行输出显示

 

/** 当前数据填充到的序号 */

protected int dataRowNumber = 1;

 

##dataRowNumber 可会输出当前填充到的数据行号

 

/** 数据的长度 */

protected int dataSize;

二、Excel导出高级特性

1、数据填充行

数据填充行是可以设置的,只是在默认情况下是行二行,第一行为描述,当不是第二行的时候需要在代码中设置。

   /**

     * 设置 数据填充名称行号

     * @param dataNameRowIndex

     */

    public void setDataNameRowIndex(int dataNameRowIndex) {

       this.dataNameRowIndex = dataNameRowIndex;

    }

 

例如:

XlsExportTemplate temp = new XlsExportTemplate();

temp.setDataNameRowIndex(4); temp.loadXlsTemplate(temp.getFilePath("/vmi/deliveryGoodsNo.xls"));

此模板就是以第5行做为填充数据行,所以设置索引的时候是4

2、填充数据行后的内容

有的时候在填充数据行后面的行还需要固定内空的行的时候,现要在代码中设置模板底部的索引和底部行数。

/**

     * 设置页脚信息

     * @param bottomRowIndex 页脚开始行索引

     * @param rowCount 页脚行数

     */

    public void setBottomRowIndex(int bottomRowIndex, int rowCount) {

       this.bottomRowIndex = bottomRowIndex;

       this.bottomRowEnd = bottomRowIndex + rowCount-1;

}

 

使用代码如下:

XlsExportTemplate temp = new XlsExportTemplate();

       setReponseXls("机加工送货单_",".xls");

           temp.loadXlsTemplate(temp.getFilePath("/auinf/auinfDeliveryNote.xls"));

           temp.setDataNameRowIndex(8);

           temp.setBottomRowIndex(28, 7);


模板:

 

3、存在头信息和尾信息

需要导出的模板存在头信息和尾信息的情况

3.1例子

 

           XlsExportTemplate template=new XlsExportTemplate();

        try {

            List list=new LinkedList();

            for(int i=0;i<2;i++){

                for(int j=0;j<2;j++){

                    for(int k=0;k<2;k++){

                        Map map=new HashMap();

                        map.put("a", "A"+i);

                        map.put("b", "B"+i);

                        map.put("c", "C"+j);

                        map.put("d", k);

                        list.add(map);

                    }

                }

            }

           

            template.setMergeConfig(new MergeConfig(new String[]{"a"}, new String[]{"a","${b+1}","b"}));

            template.addMergeConfig(new MergeConfig(new String[]{"a","c"}, new String[]{"c"}));

            Map context=new HashMap();

           

            context.put("dataSource", list);

            template.setDataNameRowIndex(5);

            template.setBottomRowIndex(6, 3);

            context.put("name", "广东迈瑞");

            context.put("date", DateUtils.parseDate("2017-09-08"));

            CellImage image= new CellImage(new FileInputStream("D:/temp/test.jpg"),Workbook.PICTURE_TYPE_JPEG);

            image.setWidth(3.5F);

            image.setHeight(1f);

            image.setLeft(10);

            image.setTop(20);

            context.put("image",image);

           

            template.loadXlsTemplate("d:/temp/test.xls");

            template.addParam("ttt", "胡真山");

            template.registerFunction("ff", new Function(){

                @Override

                public Object convert(Object oneData, String exp, Object expValue) {

                    return "测试";

                }

               

            });

            template.fillDataSource(context);

3.2模板

 

3.3输出

4、插入图片

通过代码在要输出的对象中加入图片对象,在模板中跟输出普通字段属性一个设置即可

代码:

CellImage image= new CellImage(new FileInputStream("D:/temp/test.jpg"),Workbook.PICTURE_TYPE_JPEG);

           image.setWidth(3.5F);

           image.setHeight(1f);

           image.setLeft(10);

           image.setTop(20);

           context.put("image",image);

 

在模板中只要设置 ${image} 就会输出为图片

 

5、单元格合并

在template中添加合并配置即会对单元格行进行合并

template.addMergeConfig(new MergeConfig(new String[]{"a","c"}, new String[]{"c"}));

上面的代码实现了:a 和 c 的值相同的行 对 c 列进行合并

 

5.1 MergeConfig 类的代码

package org.smile.report.excel;

 

import java.util.HashMap;

import java.util.Map;

 

import org.smile.report.poi.ObjectMergeSet;

 

/**

 * 设置要合并的列

 * @author 胡真山

 */

public class MergeConfig extends ObjectMergeSet{

    /***

     * 要合并的列名

     */

    protected String[] mergeName;

   

    protected Map<String,Integer> nameIndex=new HashMap<String,Integer>();

    /**

     * @param keyName

     * @param mergeColumn 要合并的列的索引

     */

    public MergeConfig(String keyPropertyName, Integer[] mergeColumn){

        this.propertyName=new String[]{keyPropertyName};

        this.mergeColumn=mergeColumn;

    }

   

    /**

     * 以标题名称来标记合并

     * @param keyName

     * @param mergeName

     */

    public MergeConfig(String keyPropertyName, String[] mergeName){

        this.propertyName=new String[]{keyPropertyName};

        this.mergeName=mergeName;

    }

   

    /**

     * @param keyName

     * @param mergeColumn 要合并的列的索引

     */

    public MergeConfig(String[] keyPropertyName, Integer[] mergeColumn){

        this.propertyName=keyPropertyName;

        this.mergeColumn=mergeColumn;

    }

   

    /**

     * 以标题名称来标记合并

     * @param keyName

     * @param mergeName

     */

    public MergeConfig(String[] keyPropertyName, String[] mergeName){

        this.propertyName=keyPropertyName;

        this.mergeName=mergeName;

    }

    /**

     * 从xls的标题初始化出要合并的列的索引

     * @param names

     */

    protected void initMerge(String[] names,int firstCellNum){

        initNameIndex(names);

        if(mergeColumn==null){

            initMergeColumn(names,firstCellNum);

        }

    }

   

    public Integer getColumnIndex(String name){

        return nameIndex.get(name);

    }

   

    protected void initNameIndex(String[] names){

        int i=0;

        for(String n:names){

            nameIndex.put(n, i++);

        }

    }

   

    protected void initMergeColumn(String[] names,int firstCellNum){

        mergeColumn=new Integer[mergeName.length];

        int i=firstCellNum;

        for(String n:mergeName){

            Integer idx=nameIndex.get(n);

            if(idx==null){

                throw new NullPointerException("不存在的数据名称列:"+n);

            }

            mergeColumn[i]=idx;

            i++;

        }

    }

 

}

 

6、自定义行的高度

通过方法重写实现高度的自定义。

例子:

/**

     * 通过一定策略对行高度进行控制

     * @author 胡真山

     *

     */

    protected class ExportContractTemplete extends XlsExportTemplate{

        private float keyRowHeight;

        private float rate;

        private float height;

        @Override

        protected Row onCreateDataRow(Sheet sheet, Row keyRow, Object rowData, int rowIndex) {

            Row row=super.onCreateDataRow(sheet, keyRow, rowData, rowIndex);

            if(rowIndex==dataNameRowIndex){

                keyRowHeight=keyRow.getHeightInPoints();

                rate=40f/dataSize;

                if(rate>2.5){

                    rate=2.5f;

                }else if(rate<0.8){

                    rate=0.8f;

                }

                height=keyRowHeight*rate;

            }

            if(dataSize<20){

                TDacContractDetail obj=(TDacContractDetail)rowData;

                int length=obj.getMaktx().length();

                if(obj.getMaktx().length()>20){

                    float nrate=(length/10)*0.8f;

                    if(nrate>5){

                        nrate=5;

                    }else if(nrate<2.5){

                        nrate=2.5f;

                    }

                    row.setHeightInPoints(keyRowHeight*nrate);

                }else{

                    row.setHeightInPoints(height);

                }

            }else{

                row.setHeightInPoints(height);

            }

            return row;

        }

    }

 

 

7、多sheet页填充

org.smile.report.excel .XlsExportTemplateUtils中定义了一个多sheet页填充数据,从第一个sheet页复制模板,进行数据填充。

/**

     * 一次填充多页数据

     * @param template

     * @param contexts

     * @param nameHandler

     */

    public static void fillDataSource(XlsExportTemplate template,Map<String,Object>[] contexts,SheetNameHandler nameHandler){

       int index=0;

       int sheetIndex=1;

       for(Map<String,Object> context :contexts){

           if(index>1){

              template.copySheet(0, nameHandler);

              template.setSheetIndex(sheetIndex++);

              template.fillDataSource(context);

           }

           index++;

       }

       //填充第一个sheet

       template.setSheetIndex(0);

       template.fillDataSource(contexts[0]);

    }

 

8、在模板中配置属性

可以在第一行第一列单元格中配置模板表头和表尾信息,配置了之后在代码中就不需要使用代码对这几个属性进行设置了。

如下图:

 

9、动态模板

在代码中使用setDynamic 方法设置动态列,在模板中使用 %[name] 的方式设置动态列

 

代码示例:

XlsExportDynamicTemplate template=new XlsExportDynamicTemplate();

try {

    template.loadXlsTemplate("d:/temp/dynamic.xls");

    template.setDynamic("names", new String[]{"二月","三月","四月"});

    template.setDynamic("ms", new String[]{"m2","m3","m4"});

    template.setDynamic("names2", new String[]{"五月","六月","七月"});

    template.setDynamic("ms2", new String[]{"m5","m6","m7"});

    List list=new LinkedList();

    for(int i=0;i<10;i++){

        Map map=new HashMap();

        map.put("m1", 10);

        map.put("m2", 20);

        map.put("m3", 30);

        map.put("m4", 40);

        map.put("m5", 50);

        map.put("m6", 60);

        map.put("m7", 70);

        map.put("total", 8000);

        list.add(map);

    }

    template.fillDataSource(list);

    template.write(new FileOutputStream(new File("d:/temp/dynameic_out.xls")));

} catch (IOException e) {

        e.printStackTrace();

}

 

 

模板样例:

 

输出结果:

三、Excel导入

1、基本导入

1.1代码样例

      final String batchFlag=UUIDGenerator.uuid();

            XlsImportTemplete template=new XlsImportTemplete(upload){

                @Override

                protected Object newTargetInstanse() {

                    TDacDelayPaymentTemp obj=new TDacDelayPaymentTemp();

                    obj.setBatchFlag(batchFlag);

                    return obj;

                }

                @Override

                protected void onAfterReadRow(Object targetObject, Row currentRow) {

                    TDacDelayPaymentTemp obj=(TDacDelayPaymentTemp)targetObject;

                    Date date=DateUtils.parseDate(obj.getImportDate());

                    Date latestFeedbackDate=DateUtils.getBeforeDay(date, -29);

                    obj.setLatestFeedbackDate(DateUtils.formatOnlyDate(latestFeedbackDate));

                    obj.setImportDate(DateUtils.formatOnlyDate(date));

                }

                @Override

                protected boolean validateTitles() throws ExcelException{

                    String[] t=new String[]{"月份","序号","报关单号","报关合同号","币种","进口金额","进口日期"};

                    if(ArrayUtils.check(getTitles(), new int[]{0,1,2,3,4,5,6}, t)){

                        return true;

                    }else{

                        throw new ExcelException("请选择正确的模板"+(titleRowIndex+1)+"行必须为标题:"+JSONValue.toJSONString(t));

                    }

                }

               

            };

            template.initTargetClass(TDacDelayPaymentTemp.class);

            List<TDacDelayPaymentTemp> list=template.readDataToList(CollectionUtils.newLinkedHashMap(new Integer[]{0,1,2,3,4,5,6},

                    new String[]{"month","serialNum","customsNo","contractNo","currency","importMoney","importDate"}));

 

 

模板样例

 

1.2 简单样例

XlsImportTemplete importTemplate=new XlsImportTemplete(upload);

importTemplate.initTargetClass(TDacHkStockDetail.class);

List<TDacHkStockDetail> dataList=importTemplate.readDataToList(CollectionUtils.newLinkedHashMap(

                new Integer[]{6,1,2,3,4,5,8,9,10,11,12,13,14,15},

                new String[]{"quantity","lifnr","matnr","model","brand","producePlace","grossWeight","netWeight","boxNum","batchNo","checkindate","deliveryNo","unit","remark"}));

       

1.3 List 属性支持

可以对导入类有list属性支持 ,list属性必须有getter setter 和泛型。xls属性以第一列做为是否是同一个对象的区分 ,就是说第一列同一个对象第二行只能为空,合并后不影响

 

public List<TestVo> getSubList();

 

这们就可以在xls中设置 subList.name   这样就会把单元格的值导入到subList 属性中的对象的name 属性中

 

四、其它Excel操作工具

1、PoiSupport

org.smile.report.poi.PoiSupport 类是一个poi库操作的工具类,提供了一此方便的功能。

转载于:https://my.oschina.net/huzhsh/blog/1816768

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值