EasyExcel是一個基於Java的簡單、省內存的讀寫Excel的開源項目。在儘可能節約內存的情況下支持讀寫百M的Excel。 github地址:https://github.com/alibaba/easyexcel
https://www.yuque.com/easyexcel/doc/easyexcel
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
上傳下載示例:
/**
* 文件下載(失敗了會返回一個有部分數據的Excel)
* <p>1. 創建excel對應的實體對象 參照{@link DownloadData}
* <p>2. 設置返回的 參數
* <p>3. 直接寫,這裏注意,finish的時候會自動關閉OutputStream,當然你外面再關閉流問題不大
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
// 這裏注意 有同學反應使用swagger 會導致各種問題,請直接用瀏覽器或者用postman
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 這裏URLEncoder.encode可以防止中文亂碼 當然和easyexcel沒有關係
String fileName = URLEncoder.encode("測試", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}
/**
* 文件上傳
* <p>1. 創建excel對應的實體對象 參照{@link UploadData}
* <p>2. 由於默認一行行的讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link UploadDataListener}
* <p>3. 直接讀即可
*/
@PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
return "success";
}
動態單元格使合併
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import lombok.Data;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
/**
* 單元格合併
*
*/
@SuppressWarnings("rawtypes")
@Data
public class ExcelFillCellMergeStrategy implements CellWriteHandler {
/**
* 合併字段的下標
*/
private int[] mergeColumnIndex;
/**
* 合併幾行
*/
private int mergeRowIndex;
/**
* 作爲唯一的合併條件
*/
private Integer unqiueColumnIndex;
public ExcelFillCellMergeStrategy() {
}
public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
}
public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex,Integer unqiueColumnIndex) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
this.unqiueColumnIndex = unqiueColumnIndex;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
Head head, Integer integer, Integer integer1, Boolean aBoolean) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
Head head, Integer integer, Boolean aBoolean) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
//當前行
int curRowIndex = cell.getRowIndex();
//當前列
int curColIndex = cell.getColumnIndex();
if (curRowIndex > mergeRowIndex) {
for (int i = 0; i < mergeColumnIndex.length; i++) {
if (curColIndex == mergeColumnIndex[i]) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
}
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
String currentPrexValue ="";
String prexPrexValue ="";
if(this.unqiueColumnIndex!=null) {
Cell currentPrexCell=cell.getSheet().getRow(curRowIndex).getCell(unqiueColumnIndex);
if(currentPrexCell!=null) {
currentPrexValue= currentPrexCell.getCellTypeEnum() == CellType.STRING ?currentPrexCell.getStringCellValue():String.valueOf(currentPrexCell.getNumericCellValue());
}
Cell prexPrexCell=cell.getSheet().getRow(curRowIndex-1).getCell(unqiueColumnIndex);
prexPrexValue= prexPrexCell.getCellTypeEnum() == CellType.STRING ?prexPrexCell.getStringCellValue():String.valueOf(prexPrexCell.getNumericCellValue());
}
//獲取當前行的當前列的數據和上一行的當前列列數據,通過上一行數據是否相同進行合併
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() :
cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() :
preCell.getNumericCellValue();
// 比較當前行的第一列的單元格與上一行是否相同,相同合併當前單元格與上一行
//
if (curData.equals(preData) && currentPrexValue.equals(prexPrexValue)) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// 若上一個單元格已經被合併,則先移出原有的合併單元,再重新添加合併單元
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// 若上一個單元格未被合併,則新增合併單元
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex,
curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
}