概述
一、Excel基本概念
- Workbook:工作簿,代表一个Excel文件。Excel分为两种,后缀名为xls的HSSFWorkBook(2003版本及以前),和后缀名为xlsx的XSSFWorkBook(2007版本及以后)
- Sheet:表格,一个Workbook中可以有多个表格。
- Row:行(通过Sheet可以获取到某一行)
- Cell:单元格(通过Row可以获取到某个单元格,单元格中存放数据)
apache提供了poi可供我们操作Excel文件,需要引入依赖如下:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
<exclusions>
<exclusion>
<artifactId>poi-ooxml-schemas</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.0</version>
</dependency>
二、读取Excel
excel中的一行数据可以映射为一个JavaBean实例,而每行中的列就对应JavaBean的属性。由于poi提供的工具获取一行中具体某个单元格是通过下标(编号)来索引的,所以需要将JavaBean属性与excel中单元格的下标对应起来,为此可以先定义一个注解。
- 行编号的规则是从上到下顺序依次为0,1,2,……
- 列编号的规则是从左到右顺序一次为0,1,2,……
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelProperty {
int index(); //标注JavaBean属性对应的单元格的下标
}
public class Model {
@ExcelProperty(index = 0)
private String orderNo;
@ExcelProperty(index = 1)
private String modelName;
@ExcelProperty(index = 2)
private String phone;
//……
}
读取数据
读取数据的流程比较简单,大致如下:
- 获取WorkBook对象;
- 通过WorkBook对象获取Sheet页;
- 通过Sheet可以获取某一行Row;
- 通过Row可以获取具体单元格Cell;
- 通过Cell可以获取到数据。
public class ExcelUtils {
private static final String XLSX = ".xlsx";
private static final String XLS = ".xls";
//filePath:excel文件的路径,modelKlass为对应的JavaBean的字节码对象。我们需要将excel中的数据读取封装成对象。
private static <T> List<T> readExcel(String filePath, Class<T> modelKlass) throws Exception {
checkFilePath(filePath);
FileInputStream inputStream = new FileInputStream(filePath);
Workbook workbook = new XSSFWorkbook(inputStream);
if(filePath.endsWith(XLS)){
workbook = new HSSFWorkbook(inputStream);
}
//获取第一个sheet页
Sheet sheet = workbook.getSheetAt(0);
List<T> dataList = new ArrayList<>();
//getFirstRowNum返回的是excel中真实有数据的第一行下标
//getPhysicalNumberOfRows()返回的是excel物理第一行下标0
//第一行数据将其看作表头,所以从从第二行数据开始读取一直到最后一行有真实数据的位置,将数据加载到内存中。
for(int index = sheet.getFirstRowNum() + 1; index < sheet.getLastRowNum(); index++){
T data = modelKlass.newInstance();
//通过sheet.getRow(行下标)的方式获取一个Row对象
setRowValue(sheet.getRow(index),data);
dataList.add(data);
}
return dataList;
}
private static <T> void setRowValue(Row row, T data) throws Exception {
Class<?> klass = data.getClass();
Field[] fieldArray = klass.getDeclaredFields();
for(Field field : fieldArray){
if(field.isAnnotationPresent(ExcelProperty.class)){
int annonIndex = field.getAnnotation(ExcelProperty.class).index();
String fieldName = field.getName();
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String methodName = "set" + firstLetter + fieldName.substring(1);
Method method = klass.getMethod(methodName,new Class[]{field.getType()});
//获取一个单元格中的数据用反射的方式将其塞进JavaBean对应的属性中保存
method.invoke(data,new Object[]{getCellValue(row,annonIndex)});
}
}
}
/**
* 单元格中数据类型如下:
* Cell.CELL_TYPE_NUMERIC 数值型 0
* Cell.CELL_TYPE_STRING 字符串型 1
* Cell.CELL_TYPE_FORMULA 公式型 2
* Cell.CELL_TYPE_BLANK 空值 3
* Cell.CELL_TYPE_BOOLEAN 布尔型 4
* Cell.CELL_TYPE_ERROR 错误 5
*/
private static Object getCellValue(Row row, int columnIndex){
Cell cell = row.getCell(columnIndex);
if (cell == null) {
return null;
}
Object value = null;
switch (cell.getCellType()) {
//数字类型
case Cell.CELL_TYPE_NUMERIC: value = cell.getNumericCellValue();break;
//字符串类型
case Cell.CELL_TYPE_STRING: value = cell.getStringCellValue();break;
//布尔类型
case Cell.CELL_TYPE_BOOLEAN: value = cell.getBooleanCellValue();break;
default:break;
}
return value;
}
private static void checkFilePath(String filePath){
if(filePath == null || "".equals(filePath.trim())){
throw new IllegalArgumentException("excel路径不允许为空");
}
if(!filePath.endsWith(XLSX) && !filePath.endsWith(XLS)){
throw new IllegalArgumentException("非excel文件");
}
}
}
注意:通过getLastRowNum()这种方式获取的值很多时候也是不太准确的,这跟Excel的规则有关,可以阅读:https://www.jianshu.com/p/b36c9230089f
可以改成读取的行号由外部决定:
public static <T> List<T> readExcel(String filePath, Class<T> modelKlass, int startRowNo,int endRowNo) throws Exception {
checkFilePath(filePath);
FileInputStream inputStream = new FileInputStream(filePath);
Workbook workbook = new XSSFWorkbook(inputStream);
if(filePath.endsWith(XLS)){
workbook = new HSSFWorkbook(inputStream);
}
Sheet sheet = workbook.getSheetAt(0);
List<T> dataList = new ArrayList<>();
for(int index = startRowNo; index < endRowNo; index++){
T data = modelKlass.newInstance();
setRowValue(sheet.getRow(index),data);
dataList.add(data);
}
return dataList;
}
三、写入Excel
有时候需要将数据导出到Excel中。写入的流程也比较简单:
- 创建Excel对应的WorkBook对象;
- 利用WorkBook对象创建Sheet页;
- 利用Sheet创建行Row;
- 利用Row创建Cell单元格,将数据set进去就可以。
- 数据刷到Excel文件中。
private static <T> void checkWriteExcel(String sheetName, List<T> data, String[] header){
if(sheetName == null || "".equals(sheetName.trim())){
throw new IllegalArgumentException("请先定义SheetName");
}
if(data == null || data.size() == 0){
throw new IllegalArgumentException("写入的数据不允许为空");
}
if(header == null || header.length == 0){
throw new IllegalArgumentException("请定义表头格式");
}
}
public static <T> void writeExcel(String filePath, String sheetName, List<T> dataList,String[] header) throws IOException {
checkFilePath(filePath);
checkWriteExcel(sheetName,dataList,header);
//1.创建WorkBook对象
Workbook workbook = new XSSFWorkbook();
if(filePath.endsWith(XLS)){
workbook = new HSSFWorkbook();
}
//2.创建sheet页
Sheet sheet = workbook.createSheet(sheetName);
//初始化表头
createExcelHeader(sheet,header);
FileOutputStream fos = null;
try {
for (int index = 0; index < dataList.size(); index++) {
//3.创建行Row
Row row = sheet.createRow(index + 1);
T data = dataList.get(index);
writeRow(data,row);
}
fos = new FileOutputStream(filePath);
//5.数据刷到Excel文件中
workbook.write(fos);
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fos != null){
fos.close();
}
}
}
private static void createExcelHeader(Sheet sheet,String[] header){
Row headRow = sheet.createRow(0);
for (int index = 0; index < header.length; index++) {
headRow.createCell(index).setCellValue(header[index]);
}
}
private static void writeRow(Object data, Row row) throws Exception {
Class<?> klass = data.getClass();
Field[] fieldArray = klass.getDeclaredFields();
for(Field field : fieldArray){
if(field.isAnnotationPresent(ExcelProperty.class)){
int annonIndex = field.getAnnotation(ExcelProperty.class).index();
String fieldName = field.getName();
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String methodName = "get" + firstLetter + fieldName.substring(1);
Method method = klass.getMethod(methodName,new Class[]{});
Object value = method.invoke(data,new Object[]{});
//4.创建Cell单元格
Cell cell = row.createCell(annonIndex);
if(value == null){
cell.setCellValue("");
continue;
}
writeCell(value, cell);
}
}
}
private static void writeCell(Object value, Cell cell){
Class<?> klass = value.getClass();
if(klass == double.class || Double.class == klass){
cell.setCellValue((double) value);
}else if(boolean.class == klass ||Boolean.class == klass){
cell.setCellValue((boolean) value);
}else if(klass == Date.class){
cell.setCellValue((Date) value);
}else {
cell.setCellValue(String.valueOf(value));
}
}
最后
以上就是忧虑大门为你收集整理的Java读写Excel一、Excel基本概念二、读取Excel三、写入Excel的全部内容,希望文章能够帮你解决Java读写Excel一、Excel基本概念二、读取Excel三、写入Excel所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复