文档章节

java Excel导入导出,基于XML的实现,easy-excel使用

lis1314
 lis1314
发布于 2016/06/19 01:05
字数 3267
阅读 6225
收藏 94

项目地址:http://git.oschina.net/lis1314/easy-excel

 

使用easy-excel 完成Excel导入导出功能

下面有如下的几个模型

学生模型,图书模型,作者模型

//学生模型
public class StudentModel {

	/** ID */
	protected String id;
	/** 创建时间 */
	protected Date createTime;
	/** 姓名 */
	private String name;
	/** 年龄 */
	private Integer age;
	/** 学号 */
	private String studentNo;
	/** 创建人 */
	private String createUser;
	/** 创建人ID */
	private String createUserId;
	/** 状态 */
	private Integer status;
	/** 图书信息 */
	private BookModel book;
        //略 getter setter...
}
//图书模型
public class BookModel {
	/** 图书名称 */
	private String bookName;
	/** 作者信息 */
	private AuthorModel author;
        //略 getter setter...
}
//作者模型
public class AuthorModel {
	/** 作者姓名 */
	private String authorName;
        //略 getter setter...
}

有如下的Excel文件格式,需要映射成学生实体类

那么使用easy-excel 如何导入呢?

前两行是属于不规则的数据,从标题行以后才是规则的数据,也就是从规则数据之后才能正常转换成JavaBean。

下面使用easy-excel进行导入

1、下载easy-excel,引入到自己的工程,它是一个jar的maven工程,直接添加依赖即可

http://git.oschina.net/lis1314/easy-excel

2、具体实现代码,首先编写配置文件:excel-config.xml

<excels>
<excel id="student" class="org.easy.excel.test.model.StudentModel">
	<field name="id" title="ID"/>
	<field name="name" title="学生姓名"/>
	<field name="age" title="年龄" isNull="false" regex="^[1-9]\d*$" regexErrMsg="必须是数字"/>
	<field name="studentNo" title="学号" isNull="false" />
	<field name="createTime" title="创建时间" pattern="yyyy-MM-dd,yyyy/MM/dd"/>
	<field name="status" title="状态" format="1:正常,0:禁用,-1:无效" />
	<field name="createUser" title="创建人"/>
	<!-- 复杂对象 -->
	<field name="book.bookName" title="图书名称" />
	<field name="book.author.authorName" title="作者名称"/>
</excel>
</excels>

解释,每个excel表示一种Excel文件到JavaBean的映射规则,该规则可以是导入和导出

标签解释

配置了一个id为student的映射,要映射对应的JavaBean实体为 StudentModel

<excel id="student" class="org.easy.excel.test.model.StudentModel">

excel文件中标题为ID的列,把它的值映射到 StudentModel .id属性上

<field name="id" title="ID"/>

isNull属性,表示在excel文件中标题为【年龄】的单元格的值不能为空,并且符合正则【 regex 】,当正则校验没有通过时,会提示【xxx行,[ 年龄 ]必须是数字,如果为空同理,xxx行[年龄]不能为空】

<field name="age" title="年龄" isNull="false" regex="^[1-9]\d*$" regexErrMsg="必须是数字"/>

pattern:不做过多解释,SimpleDateFormat(pattern),导入数据时字符串的值如何转换成日期

支持多种映射pattern,使用【英文逗号】进行分割

<field name="createTime" title="创建时间" pattern="yyyy-MM-dd,yyyy/MM/dd"/>

format属性,观察上面的excel文件结构会发现状态列是中文,那么导入时,可能javaBean中并不是中文,而是数字或其他,那么如何把它转换成数字呢?format就是做这个事情的。导入时它会以【,分割:前面的作为导入时使用的值,:后面的作为导出时使用的值】:后面值进行逆推,导出时同理。思考一个问题?如果这个值不确定如何解决,或者这个值需要到数据库校验?比如是个城市地址,这个时候是需要查询数据库进行比对的,如果地址不存在则抛出错误提示信息的,就说这么多,easy-excel已经做好了,支持自定义的转换器可以解决。

<field name="status" title="状态" format="1:正常,0:禁用,-1:无效" />

把excel文件标题为【图书名称】的值映射到 StudentModel 类中的book类中的bookName属性上

<field name="book.bookName" title="图书名称" />

-----------不每条配置都解释了,明白标签的作用我想大家能看懂。下面展示Java代码

public class ImportTest {
	public static void main(String[] args) throws Exception {
		//准备excel文件流
		InputStream excelStream = new FileInputStream("C:/Users/Administrator/Desktop/stu.xlsx");
		//创建excel上下文实例,它的构成需要配置文件的路径
		ExcelContext context = new ExcelContext("excel-config.xml");
		//按照xml配置中id为student的配置形式读取excel文件,并转换成StudentModel
		//这里的第二个参数是值,标题是第几行开始,之前也说了标题之前的数据并不是规则的数据
		ExcelImportResult result = context.readExcel("student", 2,excelStream);
		//打印导入结果,查看标题之前不规则的数据
		List<List<Object>> header = result.getHeader();
		System.out.println(header.get(0));
		System.out.println(header.get(1));
		//查看学生集合导入结果
		List<StudentModel> students = result.getListBean();
		for(StudentModel stu:students){
			System.out.println(stu);
		}
	}
}

运行结果:

[共导出【10】条数据]
[本次批次号为:XXX]
StudentModel [id=1, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三0, age=20, studentNo=Stu_0, createUser=王五0, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]]
StudentModel [id=2, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三1, age=21, studentNo=Stu_1, createUser=王五1, createUserId=null, status=0, book=null]
StudentModel [id=3, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三2, age=22, studentNo=Stu_2, createUser=王五2, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]]
StudentModel [id=4, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三3, age=23, studentNo=Stu_3, createUser=王五3, createUserId=null, status=0, book=null]
StudentModel [id=5, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三4, age=24, studentNo=Stu_4, createUser=王五4, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]]
StudentModel [id=6, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三5, age=25, studentNo=Stu_5, createUser=王五5, createUserId=null, status=0, book=null]
StudentModel [id=7, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三6, age=26, studentNo=Stu_6, createUser=王五6, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]]
StudentModel [id=8, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三7, age=27, studentNo=Stu_7, createUser=王五7, createUserId=null, status=0, book=null]
StudentModel [id=9, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三8, age=28, studentNo=Stu_8, createUser=王五8, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]]
StudentModel [id=10, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=张三9, age=29, studentNo=Stu_9, createUser=王五9, createUserId=null, status=0, book=null]

导入结束,完美导入,其实上面的代码有些都很多余,那么核心的代码是哪几行?

//准备excel文件流
InputStream excelStream = new FileInputStream("C:/Users/Administrator/Desktop/stu.xlsx");
//创建excel上下文实例,它的构成需要配置文件的路径
ExcelContext context = new ExcelContext("excel-config.xml");
//按照xml配置中id为student的配置形式读取excel文件,并转换成StudentModel
//这里的第二个参数是值,标题是第几行开始,之前也说了标题之前的数据并不是规则的数据
ExcelImportResult result = context.readExcel("student", 2,excelStream);

只有准备数据、创建上下文、读取excel。。通常在真实的常见创建上下文都可以省略了,因为它会交给spring容器管理,整个jvm中,只保持一个实例就够了。

 

关于导入配置的一个很重要的属性:cellValueConverter

在上面并没有配置它,这个属性就是可以解决之前我标记为红色的问题。那么它是什么?

它是一个CellValueConverter接口的实现类:假设我们的Excel中有地址,或者结合业务中可能是其他,都是需要查询数据库,或者经过更复杂的业务逻辑进行校验的,那么我们可以配置它。我们来观察这个接口做了什么事?

/**
 * CellValue转换器,用于解析cell值的规则
 * @author lisuo
 *
 */
public interface CellValueConverter {
	
	/**
	 * 操作类型,导入或导出
	 */
	enum Type {
		EXPORT, IMPORT
	}
	
	/**
	 * 转换cell的值
	 * @param bean Excel配置的JavaBean对象
	 * @param value Excel原值
	 * @param fieldValue FieldValue信息
	 * @param type 导入或导出
	 * @param rowNum 行号
	 * @return 解析结果对应的value
	 * @throws Exception
	 */
	public Object convert(Object bean,Object value, FieldValue fieldValue, Type type,int rowNum) throws Exception;
}

核心只有一个方法convert

我们可以自定义它的实现类,然后把全类名注册到 cellValueConverter属性上

如:假设创建人是需要查询用户表进行校验,如果没有则不允许导入,我们则可以在自定义的实现类抛出一个异常, 可以精准的提示用户多少行,哪一个字段【标题】的值错误了。

这里不在展示代码了,具体查看http://git.oschina.net/lis1314/easy-excel中的源代码

<field name="createUser" title="创建人" 
		cellValueConverter="org.easy.excel.test.converter.CreateUserCellValueConverter"/>

如何使用easy-excel 进行导出?

之前的配置信息完全不变,直接上java代码

public class ExportTest {
	public static void main(String[] args) throws Exception {
		//准备excel输出流
		OutputStream ops = new FileOutputStream("C:/Users/Administrator/Desktop/exportStudent.xlsx");
		//创建excel上下文实例,它的构成需要配置文件的路径
		ExcelContext context = new ExcelContext("excel-config.xml");
		//获取POI创建结果
		Workbook workbook = context.createExcel("student",getStudents());
		workbook.write(ops);
		ops.close();
		workbook.close();
	}
	
	//获取模拟数据,数据库数据...
	public static List<StudentModel> getStudents(){
		int size = 10;
		List<StudentModel> students = new ArrayList<>(size);
		for(int i=0;i<size;i++){
			StudentModel stu = new StudentModel();
			stu.setId(""+(i+1));
			stu.setName("张三"+i);
			stu.setAge(20+i);
			stu.setStudentNo("Stu_"+i);
			stu.setCreateTime(new Date());
			stu.setStatus(i%2==0?1:0);
			stu.setCreateUser("王五"+i);
			
			//创建复杂对象
			if(i % 2==0){
				BookModel book = new BookModel();
				book.setBookName("Thinking in java");
				AuthorModel author = new AuthorModel();
				author.setAuthorName("Bruce Eckel");
				book.setAuthor(author);
				stu.setBook(book);
			}
			
			students.add(stu);
		}
		return students;
	}
}

运行结果生成文件:

其他更多导出示例参看http://http://git.oschina.net/lis1314/easy-excel中的源代码

导出的一些疑问?支持样式么?支持在标题之前创建点其他的信息么?

目前支持cell宽度设置,sheet名称自定义,标题背景颜色,标题字体颜色,标题对齐方式,单元格样式是否与标题统一样式,默认cell对齐方式

对应相关标签

columnWidth,sheetname,titleBgColor,titleFountColor,align,enableStyle,defaultAlign。

支持导出前自定义头信息。

--上面红色标签部分为最新加入标签

 

补充:如何在自己工程中与spring无缝集成以及使用?

在你的spring.xml配置文件中加入

<!-- Excel上下文  -->
<bean id="excelContext" class="org.easy.excel.ExcelContext">
	<constructor-arg>
		<!--你自己的excel配置文件路径,支持classpath前缀,如果不写前缀,默认为classpath:-->
                <value>excel-config.xml</value>
	</constructor-arg>
</bean>
<!-- 初始化SpringUtil -->
<bean id="springUtil" class="org.easy.util.SpringUtil"/>

关于海量数据导出问题,看如下代码,非常easy

/***
* 导出测试,分多次导出
* @throws Exception
*/
@Test
public void testExporPart()throws Exception{
	//需求概述.数据量较大,可能大批量数据导出,会对DB造成压力,这里分批次检索数据,一部分一部分向Excel中写
	OutputStream ops = new FileOutputStream(path);
	ExcelExportResult exportResult = context.createExcelForPart(excelId,getStudents());
	//假设这是第二次从数据库或其他平台查询到到数据
	exportResult.append(getStudents());
	//第n次....
	exportResult.append(getStudents());
	exportResult.append(getStudents());
	exportResult.append(getStudents());
	exportResult.append(getStudents());
	Workbook workbook = exportResult.build();
	workbook.write(ops);
	ops.close();
	workbook.close();
}

2016-09-02加入一下4个标签:

otherConfig:如下面XML注释,我遇到额需求是处理字典,只有Key不同,其他逻辑一模一样。那么我通过otherConfig达到动态传参的功能。

<!-- 当一个转换器处理多个字段时,可能逻辑一样,只有个别的参数不一样,那么可以使用otherConfig,动态传递 -->
<field name="createUser" title="创建人" cellValueConverter="org.easy.excel.test.converter.CreateUserFieldValueConverter" otherConfig="Test动态传递的一个变量"/>

defaultValue:无论是导入还是导出都给一个默认值

<!-- defaultValue,无论是导入还是导出当值为空给一个默认值 -->
<field name="book.price" title="图书价格" columnWidth="6000" defaultValue="0.00"/>

decimalFormatPattern:Number格式处理

<!-- 对Number类型进行处理,比如(12345.12),转换成(123,45.12),导入的规则是从字符到Number,导出是从Number到字符,基于标准的java.text.DecimalFormat -->
<field name="book.price" title="图书价格" columnWidth="6000" decimalFormatPattern="###,##0.00" defaultValue="0.00"/>

roundingMode:结合上么的decimalFormatPattern标签,对于小数位数处理方案进行配置,默认向下取整

<!-- 当处理字符时,假设保留2位小数,那么遇到3位甚至更多的位数如何处理?通过该配置可以指定处理方式,默认向下取整 -->
<field name="book.price" title="图书价格" columnWidth="6000" decimalFormatPattern="###,##0.00" roundingMode="up" defaultValue="0.00"/>

2017-03-21 变更:

主要对工程进行了重构,对一些包重新进行了划分以及命名

重命名resolveFieldValueConverterName配置为cellValueConverter

在ExcelDefinition中增加了

sheetIndex属性,支持指定sheet形式读取内容

增加了

ExcelUtil ,用于读取没有规则的Excel文件

ExcelDownLoadUtil,用于WEB环境Excel文件的下载

SpringMvcExcelView,用于WEB环境使用SpringMvc轻松实现下载

与SpringMvc整合

正常整合,把org.easy.util.view.SpringMvcExcelView添加到SpringMvc容器中,使用标准的Spring自定义视图跳转即可,参看org.easy.util.view.SpringMvcExcelView这个类的注释部分

2017-03-30 变更:支持多行导入校验

例子代码

//具体参看 ImportMultiValidateTest 测试类
ExcelImportResult result = context.readExcel(excelId, titleIndex, excelStream,true);
//通过导入结果集的hasErrors方法判断
if(result.hasErrors()){
	System.out.println("导入包含错误,下面是错误信息:");
	for (ExcelError err:result.getErrors()) {
		System.out.println(err.getErrorMsg());
	}
}

//运行结果
导入包含错误,下面是错误信息:
第[1行],[创建时间][D]不能转换成日期,正确的格式应该是:[yyyy-MM-dd]
第[1行],[状态][不正常]取值错误
第[2行],[作者名称]不能为空
第[4行],[作者名称]不能为空

更多信息请参考源代码工程中的org.easy.excel.test包下的几个类

技术交流群:489137933

© 著作权归作者所有

lis1314
粉丝 12
博文 28
码字总数 26773
作品 0
丰台
高级程序员
私信 提问
加载中

评论(18)

lis1314
lis1314 博主

引用来自“护士的小黄瓜”的评论

当没有数据的时候导出的不是空Excel,而是报错了,是不是要修改一下
报什么错?日期格式化的异常么?
护士的小黄瓜
护士的小黄瓜
当没有数据的时候导出的不是空Excel,而是报错了,是不是要修改一下
护士的小黄瓜
护士的小黄瓜
创建时间,MySQL数据库是datetime,xml配置是<field name="addTime" title="其他" pattern="yyyy-MM-dd HH:mm"/>,为什么报错,最新版自己打包编译的
1363435084
1363435084
合并单元格后的导入支持不?形成一对多的关系那种
lis1314
lis1314 博主

引用来自“向北勿忘”的评论

文件加密呢?有解密的方法没,博主
这个没有哦。不过可以获取到workbook,你可以看下poi的API,关于workbook的
向北勿忘
向北勿忘
文件加密呢?有解密的方法没,博主
lis1314
lis1314 博主

引用来自“heyman3”的评论

AbstractExcelResolver中自定义转换的值是否忘记return了?

value = conv.convert(bean,value, fieldValue, type, rowNum);
十分感谢。确实是个问题,之前可能是没有默认值,代码一直没注意到。
heyman3
heyman3
AbstractExcelResolver中自定义转换的值是否忘记return了?

value = conv.convert(bean,value, fieldValue, type, rowNum);
lis1314
lis1314 博主

引用来自“eggbucket”的评论

是否有maven版本呢!不想下载源码
这个没有哦。需要下源码自己install到私服
eggbucket
eggbucket
是否有maven版本呢!不想下载源码
Java对象和Excel转换工具XXL-EXCEL

《Java对象和Excel转换工具XXL-EXCEL》 ![donate](http://

许雪里
2017/09/13
690
0
Java程序员从笨鸟到菜鸟之(一百零四)java操作office和pdf文件(二)利用POI实现数据导出excel报表

在上一篇博客中,我们简单介绍了java读取word,excel和pdf文档内容 ,但在实际开发中,我们用到最多的是把数据库中数据导出excel报表形式。不仅仅简单的读取office中的数据.尤其是在生产管理...

长平狐
2012/11/12
1K
0
XXL-EXCEL v1.1.1 发布,Java 对象和 Excel 转换工具

v1.1.1 新特性 1、支持设置Field水平位置,如居中、居左; 2、底层API优化,预约多Sheet操作支持; 3、空Cell导入抛错问题修复; 4、Cell数据类型识别优化,全类型支持; 5、导入时支持空Exc...

许雪里
2018/10/24
1K
9
GrapeCity Documents for Excel 文档 API 组件 V2.2 版本发布

GrapeCity Documents for Excel 文档 API 组件 V2.2 正式发布,本次新版本包含诸多重量级产品功能,如:将带有形状的电子表格导出为 PDF、控制分页和电子表格内容、将 Excel 电子表格的特定页...

葡萄城技术团队
07/16
577
0
GrapeCity Documents for Excel 文档API组件 V2.2 新特性介绍

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/powertoolsteam/article/details/96150843 GrapeCity Documents for ...

powertoolsteam
07/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

vue 2打包注意点

使用npm run build打包之后往往直接本地运行,路径类似这样:http://127.0.0.1:5500/xa/dist/index.html 或者http://127.0.0.1:5500/dist/index.html。然后页面打开是空白的,打开控制台查看...

牧云橙
14分钟前
4
0
归并排序

1.原理图 2.代码 public static void merge(int []a,int left,int mid,int right){ int []tmp=new int[a.length];//辅助数组 int p1=left,p2=mid+1,k=left;//p1、p2是检测......

wen123
18分钟前
4
0
css实现透明的两种方法

一、opacity:0~1 值越高,透明度越低: div{opacity:0.5 } 选择器匹配到的节点们,包括节点们的孩子节点,都会实现%50透明,另 0.5 可直接写成 .5 二、rgba(0~255,0~255,0~255,0~1) r...

Bing309
21分钟前
4
0
Tomcat 配置访问路径

此处只是部署完成后idea打开的默认路径,并非项目部署路径, 此处才是项目实际部署路径,可以有多个项目部署路径,idea可以配置默认打开一个

Aeroever
24分钟前
4
0
将ApiBoot Logging采集的日志上报到Admin

通过ApiBoot Logging可以将每一条请求的详细信息获取到,在分布式部署方式中,一个请求可能会经过多个服务,如果是每个服务都独立保存请求日志信息,我们没有办法做到统一的控制,而且还会存...

恒宇少年
24分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部