JAVA连接Excel最好用的开源项目EasyExcel,官方使用文档及.jar包下载
EasyExcel是一個(gè)基于Java的簡(jiǎn)單、省內(nèi)存的讀寫(xiě)Excel的開(kāi)源項(xiàng)目。在盡可能節(jié)約內(nèi)存的情況下支持讀寫(xiě)百M(fèi)的Excel。
github地址:https://github.com/alibaba/easyexcel
開(kāi)源項(xiàng)目不容易,如果覺(jué)得本項(xiàng)目對(duì)您的工作還是有幫助的話,請(qǐng)?jiān)趲兔υ趃ithub star點(diǎn)個(gè)★Star。
我使用后,覺(jué)得阿里確實(shí)很用心,使用簡(jiǎn)單,速度還快,這個(gè)?可以給。
如果以下內(nèi)容還是看不懂,給他們點(diǎn)個(gè)小星星,然后我教你,嘻嘻。
jar下載地址:https://share.weiyun.com/5ADw1oz
讀excel的DEMO文檔
package com.alibaba.easyexcel.test.demo.read;import java.io.File; import java.util.List; import java.util.Map;import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelReader; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.converters.DefaultConverterLoader; import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.fastjson.JSON;/*** 讀的常見(jiàn)寫(xiě)法** @author Jiaju Zhuang*/ @Ignore public class ReadTest {private static final Logger LOGGER = LoggerFactory.getLogger(ReadTest.class);/*** 最簡(jiǎn)單的讀* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 由于默認(rèn)一行行的讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link DemoDataListener}* <p>* 3. 直接讀即可*/@Testpublic void simpleRead() {// 有個(gè)很重要的點(diǎn) DemoDataListener 不能被spring管理,要每次讀取excel都要new,然后里面用到spring可以構(gòu)造方法傳進(jìn)去// 寫(xiě)法1:String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheet 文件流會(huì)自動(dòng)關(guān)閉EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();// 寫(xiě)法2:fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();ReadSheet readSheet = EasyExcel.readSheet(0).build();excelReader.read(readSheet);// 這里千萬(wàn)別忘記關(guān)閉,讀的時(shí)候會(huì)創(chuàng)建臨時(shí)文件,到時(shí)磁盤(pán)會(huì)崩的excelReader.finish();}/*** 指定列的下標(biāo)或者列名** <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象,并使用{@link ExcelProperty}注解. 參照{(diào)@link IndexOrNameData}* <p>* 2. 由于默認(rèn)一行行的讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link IndexOrNameDataListener}* <p>* 3. 直接讀即可*/@Testpublic void indexOrNameRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 這里默認(rèn)讀取第一個(gè)sheetEasyExcel.read(fileName, IndexOrNameData.class, new IndexOrNameDataListener()).sheet().doRead();}/*** 讀多個(gè)或者全部sheet,這里注意一個(gè)sheet不能讀取多次,多次讀取需要重新讀取文件* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 由于默認(rèn)一行行的讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link DemoDataListener}* <p>* 3. 直接讀即可*/@Testpublic void repeatedRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 讀取全部sheet// 這里需要注意 DemoDataListener的doAfterAllAnalysed 會(huì)在每個(gè)sheet讀取完畢后調(diào)用一次。然后所有sheet都會(huì)往同一個(gè)DemoDataListener里面寫(xiě)EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();// 讀取部分sheetfileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";ExcelReader excelReader = EasyExcel.read(fileName).build();// 這里為了簡(jiǎn)單 所以注冊(cè)了 同樣的head 和Listener 自己使用功能必須不同的ListenerReadSheet readSheet1 =EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();ReadSheet readSheet2 =EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();// 這里注意 一定要把sheet1 sheet2 一起傳進(jìn)去,不然有個(gè)問(wèn)題就是03版的excel 會(huì)讀取多次,浪費(fèi)性能excelReader.read(readSheet1, readSheet2);// 這里千萬(wàn)別忘記關(guān)閉,讀的時(shí)候會(huì)創(chuàng)建臨時(shí)文件,到時(shí)磁盤(pán)會(huì)崩的excelReader.finish();}/*** 日期、數(shù)字或者自定義格式轉(zhuǎn)換* <p>* 默認(rèn)讀的轉(zhuǎn)換器{@link DefaultConverterLoader#loadDefaultReadConverter()}* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link ConverterData}.里面可以使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定義注解* <p>* 2. 由于默認(rèn)一行行的讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link ConverterDataListener}* <p>* 3. 直接讀即可*/@Testpublic void converterRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheetEasyExcel.read(fileName, ConverterData.class, new ConverterDataListener())// 這里注意 我們也可以registerConverter來(lái)指定自定義轉(zhuǎn)換器, 但是這個(gè)轉(zhuǎn)換變成全局了, 所有java為string,excel為string的都會(huì)用這個(gè)轉(zhuǎn)換器。// 如果就想單個(gè)字段使用請(qǐng)使用@ExcelProperty 指定converter// .registerConverter(new CustomStringStringConverter())// 讀取sheet.sheet().doRead();}/*** 多行頭** <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 由于默認(rèn)一行行的讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link DemoDataListener}* <p>* 3. 設(shè)置headRowNumber參數(shù),然后讀。 這里要注意headRowNumber如果不指定, 會(huì)根據(jù)你傳入的class的{@link ExcelProperty#value()}里面的表頭的數(shù)量來(lái)決定行數(shù),* 如果不傳入class則默認(rèn)為1.當(dāng)然你指定了headRowNumber不管是否傳入class都是以你傳入的為準(zhǔn)。*/@Testpublic void complexHeaderRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheetEasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet()// 這里可以設(shè)置1,因?yàn)轭^就是一行。如果多行頭,可以設(shè)置其他值。不傳入也可以,因?yàn)槟J(rèn)會(huì)根據(jù)DemoData 來(lái)解析,他沒(méi)有指定頭,也就是默認(rèn)1行.headRowNumber(1).doRead();}/*** 讀取表頭數(shù)據(jù)** <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 由于默認(rèn)一行行的讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link DemoHeadDataListener}* <p>* 3. 直接讀即可*/@Testpublic void headerRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheetEasyExcel.read(fileName, DemoData.class, new DemoHeadDataListener()).sheet().doRead();}/*** 額外信息(批注、超鏈接、合并單元格信息讀取)* <p>* 由于是流式讀取,沒(méi)法在讀取到單元格數(shù)據(jù)的時(shí)候直接讀取到額外信息,所以只能最后通知哪些單元格有哪些額外信息** <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoExtraData}* <p>* 2. 由于默認(rèn)異步讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link DemoExtraListener}* <p>* 3. 直接讀即可** @since 2.2.0-beat1*/@Testpublic void extraRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "extra.xlsx";// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheetEasyExcel.read(fileName, DemoExtraData.class, new DemoExtraListener())// 需要讀取批注 默認(rèn)不讀取.extraRead(CellExtraTypeEnum.COMMENT)// 需要讀取超鏈接 默認(rèn)不讀取.extraRead(CellExtraTypeEnum.HYPERLINK)// 需要讀取合并單元格信息 默認(rèn)不讀取.extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();}/*** 讀取公式和單元格類型** <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link CellDataReadDemoData}* <p>* 2. 由于默認(rèn)一行行的讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link DemoHeadDataListener}* <p>* 3. 直接讀即可** @since 2.2.0-beat1*/@Testpublic void cellDataRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "cellDataDemo.xlsx";// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheetEasyExcel.read(fileName, CellDataReadDemoData.class, new CellDataDemoHeadDataListener()).sheet().doRead();}/*** 數(shù)據(jù)轉(zhuǎn)換等異常處理** <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link ExceptionDemoData}* <p>* 2. 由于默認(rèn)一行行的讀取excel,所以需要?jiǎng)?chuàng)建excel一行一行的回調(diào)監(jiān)聽(tīng)器,參照{(diào)@link DemoExceptionListener}* <p>* 3. 直接讀即可*/@Testpublic void exceptionRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheetEasyExcel.read(fileName, ExceptionDemoData.class, new DemoExceptionListener()).sheet().doRead();}/*** 同步的返回,不推薦使用,如果數(shù)據(jù)量大會(huì)把數(shù)據(jù)放到內(nèi)存里面*/@Testpublic void synchronousRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheet 同步讀取會(huì)自動(dòng)finishList<DemoData> list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync();for (DemoData data : list) {LOGGER.info("讀取到數(shù)據(jù):{}", JSON.toJSONString(data));}// 這里 也可以不指定class,返回一個(gè)list,然后讀取第一個(gè)sheet 同步讀取會(huì)自動(dòng)finishList<Map<Integer, String>> listMap = EasyExcel.read(fileName).sheet().doReadSync();for (Map<Integer, String> data : listMap) {// 返回每條數(shù)據(jù)的鍵值對(duì) 表示所在的列 和所在列的值LOGGER.info("讀取到數(shù)據(jù):{}", JSON.toJSONString(data));}}/*** 不創(chuàng)建對(duì)象的讀*/@Testpublic void noModelRead() {String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";// 這里 只要,然后讀取第一個(gè)sheet 同步讀取會(huì)自動(dòng)finishEasyExcel.read(fileName, new NoModelDataListener()).sheet().doRead();} }寫(xiě)excel的DEMO文檔
package com.alibaba.easyexcel.test.demo.write;import java.io.File; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set;import org.apache.poi.ss.usermodel.FillPatternType; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.junit.Ignore; import org.junit.Test;import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight; import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.write.merge.LoopMergeStrategy; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteTable; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;/*** 寫(xiě)的常見(jiàn)寫(xiě)法** @author Jiaju Zhuang*/ @Ignore public class WriteTest {/*** 最簡(jiǎn)單的寫(xiě)* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 直接寫(xiě)即可*/@Testpublic void simpleWrite() {// 寫(xiě)法1String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉// 如果這里想使用03 則 傳入excelType參數(shù)即可EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());// 寫(xiě)法2fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě)ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();excelWriter.write(data(), writeSheet);/// 千萬(wàn)別忘記finish 會(huì)幫忙關(guān)閉流excelWriter.finish();}/*** 根據(jù)參數(shù)只導(dǎo)出指定列* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 根據(jù)自己或者排除自己需要的列* <p>* 3. 直接寫(xiě)即可** @since 2.1.1*/@Testpublic void excludeOrIncludeWrite() {String fileName = TestFileUtil.getPath() + "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";// 根據(jù)用戶傳入字段 假設(shè)我們要忽略 dateSet<String> excludeColumnFiledNames = new HashSet<String>();excludeColumnFiledNames.add("date");// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板").doWrite(data());fileName = TestFileUtil.getPath() + "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";// 根據(jù)用戶傳入字段 假設(shè)我們只要導(dǎo)出 dateSet<String> includeColumnFiledNames = new HashSet<String>();includeColumnFiledNames.add("date");// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("模板").doWrite(data());}/*** 指定寫(xiě)入的列* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link IndexData}* <p>* 2. 使用{@link ExcelProperty}注解指定寫(xiě)入的列* <p>* 3. 直接寫(xiě)即可*/@Testpublic void indexWrite() {String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, IndexData.class).sheet("模板").doWrite(data());}/*** 復(fù)雜頭寫(xiě)入* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link ComplexHeadData}* <p>* 2. 使用{@link ExcelProperty}注解指定復(fù)雜的頭* <p>* 3. 直接寫(xiě)即可*/@Testpublic void complexHeadWrite() {String fileName = TestFileUtil.getPath() + "complexHeadWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, ComplexHeadData.class).sheet("模板").doWrite(data());}/*** 重復(fù)多次寫(xiě)入* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link ComplexHeadData}* <p>* 2. 使用{@link ExcelProperty}注解指定復(fù)雜的頭* <p>* 3. 直接調(diào)用二次寫(xiě)入即可*/@Testpublic void repeatedWrite() {// 方法1 如果寫(xiě)到同一個(gè)sheetString fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě)ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();// 這里注意 如果同一個(gè)sheet只要?jiǎng)?chuàng)建一次WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();// 去調(diào)用寫(xiě)入,這里我調(diào)用了五次,實(shí)際使用時(shí)根據(jù)數(shù)據(jù)庫(kù)分頁(yè)的總的頁(yè)數(shù)來(lái)for (int i = 0; i < 5; i++) {// 分頁(yè)去數(shù)據(jù)庫(kù)查詢數(shù)據(jù) 這里可以去數(shù)據(jù)庫(kù)查詢每一頁(yè)的數(shù)據(jù)List<DemoData> data = data();excelWriter.write(data, writeSheet);}/// 千萬(wàn)別忘記finish 會(huì)幫忙關(guān)閉流excelWriter.finish();// 方法2 如果寫(xiě)到不同的sheet 同一個(gè)對(duì)象fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";// 這里 指定文件excelWriter = EasyExcel.write(fileName, DemoData.class).build();// 去調(diào)用寫(xiě)入,這里我調(diào)用了五次,實(shí)際使用時(shí)根據(jù)數(shù)據(jù)庫(kù)分頁(yè)的總的頁(yè)數(shù)來(lái)。這里最終會(huì)寫(xiě)到5個(gè)sheet里面for (int i = 0; i < 5; i++) {// 每次都要?jiǎng)?chuàng)建writeSheet 這里注意必須指定sheetNo 而且sheetName必須不一樣writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();// 分頁(yè)去數(shù)據(jù)庫(kù)查詢數(shù)據(jù) 這里可以去數(shù)據(jù)庫(kù)查詢每一頁(yè)的數(shù)據(jù)List<DemoData> data = data();excelWriter.write(data, writeSheet);}/// 千萬(wàn)別忘記finish 會(huì)幫忙關(guān)閉流excelWriter.finish();// 方法3 如果寫(xiě)到不同的sheet 不同的對(duì)象fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";// 這里 指定文件excelWriter = EasyExcel.write(fileName).build();// 去調(diào)用寫(xiě)入,這里我調(diào)用了五次,實(shí)際使用時(shí)根據(jù)數(shù)據(jù)庫(kù)分頁(yè)的總的頁(yè)數(shù)來(lái)。這里最終會(huì)寫(xiě)到5個(gè)sheet里面for (int i = 0; i < 5; i++) {// 每次都要?jiǎng)?chuàng)建writeSheet 這里注意必須指定sheetNo 而且sheetName必須不一樣。這里注意DemoData.class 可以每次都變,我這里為了方便 所以用的同一個(gè)class 實(shí)際上可以一直變writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build();// 分頁(yè)去數(shù)據(jù)庫(kù)查詢數(shù)據(jù) 這里可以去數(shù)據(jù)庫(kù)查詢每一頁(yè)的數(shù)據(jù)List<DemoData> data = data();excelWriter.write(data, writeSheet);}/// 千萬(wàn)別忘記finish 會(huì)幫忙關(guān)閉流excelWriter.finish();}/*** 日期、數(shù)字或者自定義格式轉(zhuǎn)換* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link ConverterData}* <p>* 2. 使用{@link ExcelProperty}配合使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定義注解* <p>* 3. 直接寫(xiě)即可*/@Testpublic void converterWrite() {String fileName = TestFileUtil.getPath() + "converterWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, ConverterData.class).sheet("模板").doWrite(data());}/*** 圖片導(dǎo)出* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link ImageData}* <p>* 2. 直接寫(xiě)即可*/@Testpublic void imageWrite() throws Exception {String fileName = TestFileUtil.getPath() + "imageWrite" + System.currentTimeMillis() + ".xlsx";// 如果使用流 記得關(guān)閉InputStream inputStream = null;try {List<ImageData> list = new ArrayList<ImageData>();ImageData imageData = new ImageData();list.add(imageData);String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg";// 放入五種類型的圖片 實(shí)際使用只要選一種即可imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));imageData.setFile(new File(imagePath));imageData.setString(imagePath);inputStream = FileUtils.openInputStream(new File(imagePath));imageData.setInputStream(inputStream);imageData.setUrl(new URL("https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg"));EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list);} finally {if (inputStream != null) {inputStream.close();}}}/*** 根據(jù)模板寫(xiě)入* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link IndexData}* <p>* 2. 使用{@link ExcelProperty}注解指定寫(xiě)入的列* <p>* 3. 使用withTemplate 寫(xiě)取模板* <p>* 4. 直接寫(xiě)即可*/@Testpublic void templateWrite() {String templateFileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";String fileName = TestFileUtil.getPath() + "templateWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, DemoData.class).withTemplate(templateFileName).sheet().doWrite(data());}/*** 列寬、行高* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link WidthAndHeightData}* <p>* 2. 使用注解{@link ColumnWidth}、{@link HeadRowHeight}、{@link ContentRowHeight}指定寬度或高度* <p>* 3. 直接寫(xiě)即可*/@Testpublic void widthAndHeightWrite() {String fileName = TestFileUtil.getPath() + "widthAndHeightWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, WidthAndHeightData.class).sheet("模板").doWrite(data());}/*** 注解形式自定義樣式* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoStyleData}* <p>* 3. 直接寫(xiě)即可** @since 2.2.0-beta1*/@Testpublic void annotationStyleWrite() {String fileName = TestFileUtil.getPath() + "annotationStyleWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, DemoStyleData.class).sheet("模板").doWrite(data());}/*** 攔截器形式自定義樣式* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 創(chuàng)建一個(gè)style策略 并注冊(cè)* <p>* 3. 直接寫(xiě)即可*/@Testpublic void handlerStyleWrite() {String fileName = TestFileUtil.getPath() + "handlerStyleWrite" + System.currentTimeMillis() + ".xlsx";// 頭的策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景設(shè)置為紅色headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short)20);headWriteCellStyle.setWriteFont(headWriteFont);// 內(nèi)容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 這里需要指定 FillPatternType 為FillPatternType.SOLID_FOREGROUND 不然無(wú)法顯示背景顏色.頭默認(rèn)了 FillPatternType所以可以不指定contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);// 背景綠色contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());WriteFont contentWriteFont = new WriteFont();// 字體大小contentWriteFont.setFontHeightInPoints((short)20);contentWriteCellStyle.setWriteFont(contentWriteFont);// 這個(gè)策略是 頭是頭的樣式 內(nèi)容是內(nèi)容的樣式 其他的策略可以自己實(shí)現(xiàn)HorizontalCellStyleStrategy horizontalCellStyleStrategy =new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板").doWrite(data());}/*** 合并單元格* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData} {@link DemoMergeData}* <p>* 2. 創(chuàng)建一個(gè)merge策略 并注冊(cè)* <p>* 3. 直接寫(xiě)即可** @since 2.2.0-beta1*/@Testpublic void mergeWrite() {// 方法1 注解String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";// 在DemoStyleData里面加上ContentLoopMerge注解// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, DemoMergeData.class).sheet("模板").doWrite(data());// 方法2 自定義合并單元格策略fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";// 每隔2行會(huì)合并 把eachColumn 設(shè)置成 3 也就是我們數(shù)據(jù)的長(zhǎng)度,所以就第一列會(huì)合并。當(dāng)然其他合并策略也可以自己寫(xiě)LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data());}/*** 使用table去寫(xiě)入* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 然后寫(xiě)入table即可*/@Testpublic void tableWrite() {String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx";// 這里直接寫(xiě)多個(gè)table的案例了,如果只有一個(gè) 也可以直一行代碼搞定,參照其他案例// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě)ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();// 把sheet設(shè)置為不需要頭 不然會(huì)輸出sheet的頭 這樣看起來(lái)第一個(gè)table 就有2個(gè)頭了WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build();// 這里必須指定需要頭,table 會(huì)繼承sheet的配置,sheet配置了不需要,table 默認(rèn)也是不需要WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build();WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build();// 第一次寫(xiě)入會(huì)創(chuàng)建頭excelWriter.write(data(), writeSheet, writeTable0);// 第二次寫(xiě)如也會(huì)創(chuàng)建頭,然后在第一次的后面寫(xiě)入數(shù)據(jù)excelWriter.write(data(), writeSheet, writeTable1);/// 千萬(wàn)別忘記finish 會(huì)幫忙關(guān)閉流excelWriter.finish();}/*** 動(dòng)態(tài)頭,實(shí)時(shí)生成頭寫(xiě)入* <p>* 思路是這樣子的,先創(chuàng)建List<String>頭格式的sheet僅僅寫(xiě)入頭,然后通過(guò)table 不寫(xiě)入頭的方式 去寫(xiě)入數(shù)據(jù)** <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 然后寫(xiě)入table即可*/@Testpublic void dynamicHeadWrite() {String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";EasyExcel.write(fileName)// 這里放入動(dòng)態(tài)頭.head(head()).sheet("模板")// 當(dāng)然這里數(shù)據(jù)也可以用 List<List<String>> 去傳入.doWrite(data());}/*** 自動(dòng)列寬(不太精確)* <p>* 這個(gè)目前不是很好用,比如有數(shù)字就會(huì)導(dǎo)致?lián)Q行。而且長(zhǎng)度也不是剛好和實(shí)際長(zhǎng)度一致。 所以需要精確到剛好列寬的慎用。 當(dāng)然也可以自己參照* {@link LongestMatchColumnWidthStyleStrategy}重新實(shí)現(xiàn).* <p>* poi 自帶{@link SXSSFSheet#autoSizeColumn(int)} 對(duì)中文支持也不太好。目前沒(méi)找到很好的算法。 有的話可以推薦下。** <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link LongestMatchColumnWidthData}* <p>* 2. 注冊(cè)策略{@link LongestMatchColumnWidthStyleStrategy}* <p>* 3. 直接寫(xiě)即可*/@Testpublic void longestMatchColumnWidthWrite() {String fileName =TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, LongestMatchColumnWidthData.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong());}/*** 下拉,超鏈接等自定義攔截器(上面幾點(diǎn)都不符合但是要對(duì)單元格進(jìn)行操作的參照這個(gè))* <p>* demo這里實(shí)現(xiàn)2點(diǎn)。1. 對(duì)第一行第一列的頭超鏈接到:https://github.com/alibaba/easyexcel 2. 對(duì)第一列第一行和第二行的數(shù)據(jù)新增下拉框,顯示 測(cè)試1 測(cè)試2* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 注冊(cè)攔截器 {@link CustomCellWriteHandler} {@link CustomSheetWriteHandler}* <p>* 2. 直接寫(xiě)即可*/@Testpublic void customHandlerWrite() {String fileName = TestFileUtil.getPath() + "customHandlerWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, DemoData.class).registerWriteHandler(new CustomSheetWriteHandler()).registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data());}/*** 插入批注* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}* <p>* 2. 注冊(cè)攔截器 {@link CommentWriteHandler}* <p>* 2. 直接寫(xiě)即可*/@Testpublic void commentWrite() {String fileName = TestFileUtil.getPath() + "commentWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉// 這里要注意inMemory 要設(shè)置為true,才能支持批注。目前沒(méi)有好的辦法解決 不在內(nèi)存處理批注。這個(gè)需要自己選擇。EasyExcel.write(fileName, DemoData.class).inMemory(Boolean.TRUE).registerWriteHandler(new CommentWriteHandler()).sheet("模板").doWrite(data());}/*** 可變標(biāo)題處理(包括標(biāo)題國(guó)際化等)* <p>* 簡(jiǎn)單的說(shuō)用List<List<String>>的標(biāo)題 但是還支持注解* <p>* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link ConverterData}* <p>* 2. 直接寫(xiě)即可*/@Testpublic void variableTitleWrite() {// 寫(xiě)法1String fileName = TestFileUtil.getPath() + "variableTitleWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName, ConverterData.class).head(variableTitleHead()).sheet("模板").doWrite(data());}/*** 不創(chuàng)建對(duì)象的寫(xiě)*/@Testpublic void noModelWrite() {// 寫(xiě)法1String fileName = TestFileUtil.getPath() + "noModelWrite" + System.currentTimeMillis() + ".xlsx";// 這里 需要指定寫(xiě)用哪個(gè)class去寫(xiě),然后寫(xiě)到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉EasyExcel.write(fileName).head(head()).sheet("模板").doWrite(dataList());}private List<LongestMatchColumnWidthData> dataLong() {List<LongestMatchColumnWidthData> list = new ArrayList<LongestMatchColumnWidthData>();for (int i = 0; i < 10; i++) {LongestMatchColumnWidthData data = new LongestMatchColumnWidthData();data.setString("測(cè)試很長(zhǎng)的字符串測(cè)試很長(zhǎng)的字符串測(cè)試很長(zhǎng)的字符串" + i);data.setDate(new Date());data.setDoubleData(1000000000000.0);list.add(data);}return list;}private List<List<String>> variableTitleHead() {List<List<String>> list = new ArrayList<List<String>>();List<String> head0 = new ArrayList<String>();head0.add("string" + System.currentTimeMillis());List<String> head1 = new ArrayList<String>();head1.add("number" + System.currentTimeMillis());List<String> head2 = new ArrayList<String>();head2.add("date" + System.currentTimeMillis());list.add(head0);list.add(head1);list.add(head2);return list;}private List<List<String>> head() {List<List<String>> list = new ArrayList<List<String>>();List<String> head0 = new ArrayList<String>();head0.add("字符串" + System.currentTimeMillis());List<String> head1 = new ArrayList<String>();head1.add("數(shù)字" + System.currentTimeMillis());List<String> head2 = new ArrayList<String>();head2.add("日期" + System.currentTimeMillis());list.add(head0);list.add(head1);list.add(head2);return list;}private List<List<Object>> dataList() {List<List<Object>> list = new ArrayList<List<Object>>();for (int i = 0; i < 10; i++) {List<Object> data = new ArrayList<Object>();data.add("字符串" + i);data.add(new Date());data.add(0.56);list.add(data);}return list;}private List<DemoData> data() {List<DemoData> list = new ArrayList<DemoData>();for (int i = 0; i < 10; i++) {DemoData data = new DemoData();data.setString("字符串" + i);data.setDate(new Date());data.setDoubleData(0.56);list.add(data);}return list;}}寫(xiě)在最后:
我叫風(fēng)骨散人,名字的意思是我多想可以不低頭的自由生活,可現(xiàn)實(shí)卻不是這樣。家境貧寒,總得向這個(gè)世界低頭,所以我一直在奮斗,想改變我的命運(yùn)給親人好的生活,希望同樣被生活綁架的你可以通過(guò)自己的努力改變現(xiàn)狀,深知成年人的世界里沒(méi)有容易二字。目前是一名在校大學(xué)生,預(yù)計(jì)考研,熱愛(ài)編程,熱愛(ài)技術(shù),喜歡分享,知識(shí)無(wú)界,希望我的分享可以幫到你!
如果有什么想看的,可以私信我,如果在能力范圍內(nèi),我會(huì)發(fā)布相應(yīng)的博文!
感謝大家的閱讀!😘你的點(diǎn)贊、收藏、關(guān)注是對(duì)我最大的鼓勵(lì)!
總結(jié)
以上是生活随笔為你收集整理的JAVA连接Excel最好用的开源项目EasyExcel,官方使用文档及.jar包下载的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 银行利润计算公式
- 下一篇: DFS--POJ 1190 生日蛋糕