公司的日常事务中经常需要使用excel进行数据汇总,导入导出进行归类统计分析。

因为没有广泛流行的单元行到类转换/属性绑定工具,在功能开发之初或者很长一段时间内,

业务系统中我们处理普通excel数据的方法如下:

例如我们公司工程项目中需要到现场部署设备,

1、从问题域出发我们大概可以建立具有以下属性的类,用以描述每一行记录的所具有的属性以及性状特征

public class Device  {

    private String device_id; //设备编号

    private String name;     //设备名称

    private String model;   //设备型号

    private String location;   //存放位置

    private String serial;   //序列号

    private String ipv4;   //IP地址

    private String project_number;   //项目编号

    private String project_name;   //项目名称

    private String constructor_name;//建设人

    private String customer_name;   //客户单位名称

    private String project_manager_name;   //负责人

    private Date lastExamine;        //最后一次检查/巡查日期

}

通过对设备的基本特性、特征、用途分析,我们粗略地将他的属性分为3大类
抽取了一些代表性的属性,如下:

1、自有属性
通常是出厂设置或者与生俱来的:名称、型号、序列号等、
2、业务属性
项目编号、项目名称、建设人、客户单位名称
3、维保属性
巡检日期 等

当然比较合理的设计方法应该建立多个对象,用于描述业务对象(设备)在系统

功能中参与的一系列行为、事件等类。本文为了配合框架的使用,将属性糅合到一个类

当中,数据类型也只用了简单的字符串类型来阐述问题。

经过以上构造,一个崭新鲜活的类,如新生儿般,轻装上阵,便参与到OOP世界的业务系统中。

编写代码操作

...
public static Object getCellValue(Cell cell)
{
return getCellValue(cell,NULL);
} public static String getCellValue(Cell cell, Object defaultValue)
{
if(cell==null)
return defaultValue; cell.setCellType(CellType.STRING);
String value = cell.getStringCellValue();
if(StringUtils.isNotEmpty(value)) {
return value.trim().replaceAll("\\s+", "");
}
return defaultValue;
} ... List<Device> list = LinkedList<Device>(); for(int i = 1; i< iRowNums; i++)
{
Device dev = new Device(); //设备编号
Cell celldevice_id = row.getCell(0);
String device_id = getCellValue(celldevice_id);
dev.setDevice_di(device_id); //设备名称
... //项目编号
Cell cellproject_number = row.getCell(6);
String project_number = getCellValue(cellproject_number);
dev.setProject_number(project_number); list.add(dev); }

当然偷懒的方法也是有的,通过工具类来帮助我少写代码commons-beanutil.jar
中的属性工具类

 public static String  getProperty(Object bean,String propertyName)
{
try {
String value = (String)PropertyUtils.getSimpleProperty(bean,propertyName);
if(StringUtils.isEmpty(value))
return "";
return value;
}catch (Exception ex)
{
logger.error("getProperty failed:{}",ex);
return "";
}
} public Cell enumerateCell(Row row, Cell copyOfdev, int offet, int length,String []fields)
{
for(int i = offet; i <length;i++){
Cell cell = row.getCell(i);
String value = getCellValue(cell);
String propertyName = fields[i-(offet-1)];
setProperty(copyOfMessage,propertyName,value);
}
return copyOfMessage;
} String fields[] = {
"device_id", "name","model", "location","serial", "ipv4", "project_number",
"project_name","constructor_name","customer_name","project_manager_name","lastExamine"
};

我们给他列名对应的索引值让他去跑,也能拿到他的属性,这样的缺陷是要维护属性在String数组中的索引。

电子计算机是一个数字电路系统,按照数值进行计算是他的强项,对于开发人员来说,每次写类似的代码,都要锱铢必较的
计算每一个属性对应的位置,生怕写错了索引带来错误。

然而需求总是随着时间、政策法令、政治、宗教等客观因素,以及人的主管意愿在变化着。

----以下需求属于为了讲解需求变化场景,可能与事实需求有出入

需求情形1:公司要求,在模板上添加申请人、审核人
需求情形2:客户(公安等)要求每个设备的IP要记录备案
需求情形3:xxx设备需要符合国标(GBxxxx),需要添加属性 AAA

很显然,我的刚刚描述的类,他的业务属性和维保属性肯定会有需要变化的。

公司实际业务场景也可能遇到类似的需求变化,万一哪一天添加到字段对业务需求比较重要呢,需要提到前面几列,
或者列的顺序没有维护好,错乱了怎么办,偶然间闪过一个概念,能不能把Excel单元行绑定到JavaBean,偶然间就构思简单的
搜索关键字:how to binding excel row to javabean,Google一番找到了本文将要使用的框架Poiji

https://github.com/ozlerhakan/poiji
A tiny library converting excel rows to a list of Java objects based on Apache POI

一个基于Apache POI轻量级工具库,将Excel行转换成Java对象列表

按照官方文档,我们把代码重构了一下

public class Device  {

    @ExcelCellName("设备编号")
private String device_id; //设备编号 @ExcelCellName("设备名称")
private String name; //设备名称 @ExcelCellName("设备型号")
private String model; //设备型号 @ExcelCellName("存放位置")
private String location; //存放位置 @ExcelCellName("序列号")
private String serial; //序列号 @ExcelCellName("IP地址")
private String ipv4; //IP地址 @ExcelCellName("项目编号")
private String project_number; //项目编号 @ExcelCellName("项目名称")
private String project_name; //项目名称 @ExcelCellName("建设人")
private String constructor_name;//建设人 @ExcelCellName("客户单位名称")
private String customer_name; //客户单位名称 @ExcelCellName("负责人")
private String project_manager_name; //负责人 @ExcelCellName("最后一次检查/巡查日期")
private Date lastExamine; //最后一次检查/巡查日期 }

在每个属性上使用注释,添加注解,把列名加上去,例如 设备名称列,写成

@ExcelCellName("设备名称")
private String name;

然后一行代码,我将获得批量的java对象

 List<Device> devs = Poiji.fromExcel(new File("g:\\device-import-template.xlsx"), Device.class);
System.out.println(devs);

笔者在实际开发测试过程中遇到一种情况,excel表头有空格的情况下无法绑定数值,日常工作过程中难免有人为
操作误差/失误,误输入空格,这种情况将有可能导致导入的业务数据就是错误的,数据在特定业务场景下运转起来,
因蝴蝶效应,有可能造成更深远的影响。
笔者已经修改源代码,默认去除行首行尾的空格。trimTagName方法

截至写本文章的时候,官方更新到1.18.1版本,由于1.18.1版本需要POI 4.0版本,现实中生产环境中使用的是3.1.6
笔者修改了一下源代码,目前兼容3.1.6,可以放到生产环境使用。

package com.poiji.deserialize;

import com.poiji.bind.Poiji;
import com.poiji.deserialize.model.byid.Employee;
import com.poiji.deserialize.model.byname.EmployeeByName;
import com.poiji.option.PoijiOptions;
import com.poiji.option.PoijiOptions.PoijiOptionsBuilder; import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import java.io.File;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List; import static com.poiji.util.Data.unmarshallingDeserialize;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail; /**
* Created by passedbylove@gmail.com on 2018-11-15.
*/
@RunWith(Parameterized.class)
public class DeserializersByNameTagWithWhiteSpaceTest { private String path;
private List<Employee> expectedEmployess;
private Class<?> expectedException; public DeserializersByNameTagWithWhiteSpaceTest(String path,
List<Employee> expectedEmployess,
Class<?> expectedException) {
this.path = path;
this.expectedEmployess = expectedEmployess;
this.expectedException = expectedException;
} @Parameterized.Parameters(name = "{index}: ({0})={1}")
public static Iterable<Object[]> queries() {
return Arrays.asList(new Object[][]{
{"src/test/resources/employees-tagwithwhitespace.xlsx", unmarshallingDeserialize(), null},
});
} @Test
public void shouldMapExcelToJava() { PoijiOptions options = PoijiOptionsBuilder.settings().datePattern("dd/MM/yyyy").dateTimeFormatter(DateTimeFormatter.ofPattern("yyyy-MM-dd")).trimCellValue(true).trimTagName(true).build();
try {
List<EmployeeByName> actualEmployees = Poiji.fromExcel(new File(path), EmployeeByName.class,options); assertThat(actualEmployees, notNullValue());
assertThat(actualEmployees.size(), not(0));
assertThat(actualEmployees.size(), is(expectedEmployess.size())); EmployeeByName actualEmployee1 = actualEmployees.get(0);
EmployeeByName actualEmployee2 = actualEmployees.get(1);
EmployeeByName actualEmployee3 = actualEmployees.get(2); Employee expectedEmployee1 = expectedEmployess.get(0);
Employee expectedEmployee2 = expectedEmployess.get(1);
Employee expectedEmployee3 = expectedEmployess.get(2); assertThat(actualEmployee1.toString(), is(expectedEmployee1.toString()));
assertThat(actualEmployee2.toString(), is(expectedEmployee2.toString()));
assertThat(actualEmployee3.toString(), is(expectedEmployee3.toString()));
} catch (Exception e) {
if (expectedException == null) {
fail(e.getMessage());
} else {
assertThat(e, instanceOf(expectedException));
}
}
} }

以下奉送上修改后的poiji 1.18.0源代码

平时空闲时间不多,如有疑问欢迎留言交流。

poi1.18.0修改版,兼容POI 3.1.x,自动去除表头输入的空格

Poiji:基于列名绑定方式将Excel单元行转换为JavaBean的开源框架的更多相关文章

  1. Java 设置Excel单元格格式—基于Spire.Cloud.SDK for Java

    本文介绍使用Spire.Cloud.SDK for Java来设置Excel单元格格式,包括字体.字号.单元格背景.字体下滑线.字体加粗.字体倾斜.字体颜色.单元格对齐方式.单元格边框等 一.下载SD ...

  2. SNF快速开发平台MVC-各种级联绑定方式,演示样例程序(包含表单和表格控件)

    做了这么多项目,经常会使用到级联.联动的情况. 如:省.市.县.区.一级分类.二级分类.三级分类.仓库.货位. 方式:有表单需要做级联的,还是表格行上需要做级联操作的. 实现:实现方法也有很多种方式. ...

  3. 基于jdk1.7实现的excel导出工具类

    通用excel导出工具类,基于泛型.反射.hashmap 以及基于泛型.反射.bean两种方式 import java.io.*;import java.lang.reflect.Field;impo ...

  4. springMVC中使用POI方式导出excel至客户端、服务器实例

    Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. 这里的方法支持导出excel至项目所在服务器,或导 ...

  5. C# Aspose.Cells方式导入Excel文件

    读取Excel 类 我返回的是DataTable 类型 也可以返回DataSet类型 public class XlsFileHelper { public DataTable ImportExcel ...

  6. C# ASP.NET 读取EXCEL 单元格 读取 空值 不显示

    跟大家分享一下,[摘自]:http://blog.csdn.net/li185416672/article/details/8213729 读取excel时,某些单元格为空值 原来如此: 当我们用ol ...

  7. Excel 单元格自定义格式技巧总结

    第一部分 Excel 中的单元格格式是一个最基本但是又很高级的技能,说它基本是因为我们几乎天天都会用到它,会用它来设置一些简单的格式,比如日期,文本等等:高级是因为利用 Excel 单元格的自定义格式 ...

  8. C# 对Excel 单元格格式, 及行高、 列宽、 单元格边框线、 冻结设置

    一.对行高,列宽.单元格边框等的设置 这篇简短的文字对单元格的操作总结的比较全面,特此转载过来. private _Workbook _workBook = null; private Workshe ...

  9. C#使用oledb方式将excel数据导入到datagridview后数据被截断为 255 个字符

    问题描述:在使用oledb方式将excel数据导入到datagridview中,在datagridview单元格中的数据没有显示全,似乎只截取了数据源中的一段 解决方案:1.关于该问题,微软官方答案: ...

随机推荐

  1. Docker入门与实战讲解

    转载自:http://blog.csdn.net/relax_hb/article/details/69668815 简述 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包 ...

  2. [zz]LyX中文问题

    http://www.cnblogs.com/biaoyu/archive/2012/04/28/2475318.html LyX是一款极为优秀的所见即所得的文档处理软件,与MS Word相比,其排版 ...

  3. string formating字符串格式化,function函数,group组,recursion递归,练习

    # -*- coding: UTF-8 -*- msg = 'i am {} my hobby is {}'.format('lhf',18) print(msg) msg1 = 'i am %s m ...

  4. element-ui的不稳定性

    伤脑筋的版本升级 element-ui升级到2.0版本了! element-ui作为比较成熟的广为人知的前端框架,原本满怀热情的去学习,也基于element-ui搭建出了一套系统,可是它居然升级了! ...

  5. redis高可用(哨兵机制)

    redis哨兵机制:redis的哨兵系统用于管理多个reids服务器,该系统主要有三个作用: 监控:哨兵 会不断地检查你的主服务(Master)和从服务器(Slave)是否运作正常. 提醒:当被监控的 ...

  6. PowerDesiger 生成C#实体类,字段转变成大小写方法

    1.打开编辑生成C#实体类的PD脚本 2..L:  表示全部转小写,.U: 表示全部转成大写.

  7. spring mvc 注解整理(一)

    @Controller和@RestController: RestController = @ResponseBody + @Controller  所有返回都是json类型,无法跳转到jsp页面,但 ...

  8. 根据url路径获取图片并显示到ListView中

    项目开发中我们需要从网络获取图片显示到控件中,很多开源框架如Picasso可以实现图片下载和缓存功能.这里介绍的是一种简易的网络图片获取方式并把它显示到ListView中. 本案例实现的效果如下: 项 ...

  9. Web App Checklist

    Mobile Web App checklist 目标: 高性能Mobile Web App 一.UX和UI 操作节目与边框之间留空隙: 防止操作过程中,触发系统缺省行为,有些是无法disable的. ...

  10. 关于PHP代码复用‘traits’的一段代码

    附:代码摘自菜鸟教程 <?php// 定义一个类名Base对象,并带有公共函数sayHello class Base { public function sayHello() { echo 'H ...