java Excel導入導出,基於XML的實現,easy-excel使用

項目地址:http://git.oschina.net/lis1314/easy-exceljava

 

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

下面有以下的幾個模型spring

學生模型,圖書模型,做者模型數據庫

//學生模型
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文件格式,須要映射成學生實體類app

那麼使用easy-excel 如何導入呢?jvm

前兩行是屬於不規則的數據,從標題行之後纔是規則的數據,也就是從規則數據以後才能正常轉換成JavaBean。maven

下面使用easy-excel進行導入測試

一、下載easy-excel,引入到本身的工程,它是一個jar的maven工程,直接添加依賴便可字體

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

二、具體實現代碼,首先編寫配置文件: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包下的幾個類

相關文章
相關標籤/搜索