POI工具操作excel(七)Excel文件导入
程序员文章站
2022-04-30 18:28:47
...
前面两篇讲的是excel的导出,在系统中,也会出现把excel表格中的数据导入到数据库的操作。那么这篇就简单的封装一个基于注解的工具类,可以利用POI技术方便的读取excel文件中的数据,把每一行数据封装成了一个我们的Java对象,然后存入到集合中。拿到集合数据就可以使用其他的持久化技术,把数据存储到数据库中了。
1、环境准备
本次使用的工程还是之前那篇文章的工程,具体创建请参照之。
准备一个excel的文件,内容如下:
2、自定义注解
自定义注解:@ExcelAnnotation,该注解只定义了一个sort属性,它的作用是:Java类的属性和excel文件中的列的属性一一对应。
package com.poi.imports.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelAnnotation {
int sort();//Java类的属性对应的列
}
3、定义Person类,添加注解
Person类的属性和excel文件中的列一一对应;
package com.poi.imports.pojo;
import com.poi.imports.annotation.ExcelAnnotation;
import java.util.Date;
public class Person {
@ExcelAnnotation(sort = 1)
private String pid;
@ExcelAnnotation(sort = 2)
private String name;
@ExcelAnnotation(sort = 3)
private String role;
@ExcelAnnotation(sort = 4)
private String job;
@ExcelAnnotation(sort = 5)
private String hobby;
@ExcelAnnotation(sort = 6)
private Date birthday;
@ExcelAnnotation(sort = 7)
private double money;
public Person() {//无参构造不能缺少
}
public Person(String pid, String name, String role, String job, String hobby, Date birthday, double money) {
this.pid = pid;
this.name = name;
this.role = role;
this.job = job;
this.hobby = hobby;
this.birthday = birthday;
this.money = money;
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
4、构建工具类
package com.poi.imports.util;
import com.poi.imports.annotation.ExcelAnnotation;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* excel文件导入,解析成对象的集合的工具类
* 该类的作用:把excel文件中的数据,每一行封装成一个对象,然后把对象封装成一个List集合
*/
public class ExcelImportUtil<T> {
private Class<T> clazz;//对应的对象的CLass对象
private Field[] fields;
/**
* 工具类的构造方法
* @param clazz 对应的对象的CLass对象
*/
public ExcelImportUtil(Class<T> clazz) {
this.clazz = clazz;
this.fields = clazz.getDeclaredFields();
}
/**
* 把excel数据封装到List集合中的方法
* @param inputStream excel文件流
* @param rowIndex 内容开始的行号,行号从0开始
* @param cellIndex 内容开始的列号,列号也是从0开始
* @param ext excel文件的后缀名,有xls和xlsx两种
* @return
* @throws Exception
*/
public List<T> readList(InputStream inputStream, int rowIndex, int cellIndex,String ext) throws Exception {
List<T> personList = new ArrayList<>();
T entity = null;
//根据文件流创建工作簿
Workbook workbook = null;
if ("xlsx".equals(ext)) {
workbook = new XSSFWorkbook(inputStream);
}else if("xls".equals(ext)){
workbook = new HSSFWorkbook(inputStream);
}
if(workbook == null){
return null;
}
Sheet sheet = workbook.getSheetAt(0);//得到第一个sheet,所以要求我们的内容要放到excel文件的第一个sheet中
int lastRowNum = sheet.getLastRowNum();//得到有内容的最大的行号
System.out.println("内容的最大行号:"+lastRowNum);
for(int rowNum = rowIndex; rowNum<lastRowNum; rowNum++){
Row row = sheet.getRow(rowNum);//获取行对象
entity = (T)clazz.newInstance();//通过反射创建实例
int lastCellNum = row.getLastCellNum();//得到该行内容的最大列号
for(int cellNum = cellIndex; cellNum<lastCellNum; cellNum++){
Cell cell = row.getCell(cellNum);//得到该单元格对象
for(Field field : fields){
if(field.isAnnotationPresent(ExcelAnnotation.class)){
field.setAccessible(true);
ExcelAnnotation excelAnnotation = field.getAnnotation(ExcelAnnotation.class);
int sort = excelAnnotation.sort();
if(cellNum == sort-1){
//调用方法,根据该列的数据类型获取对应的值
Object value = this.covertAttrType(field,cell);
field.set(entity,value);
}
}
}
}
personList.add(entity);
}
return personList;
}
/**
* 根据单元格的数据类型获取对应的数据值
* @param field 属性对象
* @param cell 单元格对象
* @return
*/
private Object covertAttrType(Field field, Cell cell) throws ParseException {
String fieldType = field.getType().getSimpleName();//得到单元格的数据类型名称
Object value = null;
if ("String".equals(fieldType)) {
value = getCellValue(cell);
}else if ("Date".equals(fieldType)) {
value = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(getCellValue(cell)) ;
}else if ("int".equals(fieldType) || "Integer".equals(fieldType)) {
value = Integer.parseInt(getCellValue(cell));
}else if ("double".equals(fieldType) || "Double".equals(fieldType)) {
value = Double.parseDouble(getCellValue(cell));
}
return value;
}
/**
* 根据单元格得到单元格的数据值,把内容格式化为字符串,单元格的数据类型如下:
* int CELL_TYPE_NUMERIC = 0;
* int CELL_TYPE_STRING = 1;
* int CELL_TYPE_FORMULA = 2;
* int CELL_TYPE_BLANK = 3;
* int CELL_TYPE_BOOLEAN = 4;
* int CELL_TYPE_ERROR = 5;
* @param cell 单元格对象
* @return
*/
private String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
switch (cell.getCellType()) {
case 1: //1表示字符串
return cell.getRichStringCellValue().getString().trim();
case 0: //0表示数字
if (DateUtil.isCellDateFormatted(cell)) {
Date date = DateUtil.getJavaDate(cell.getNumericCellValue());
return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(date);
} else {
// 防止数值变成科学计数法
String strCell = "";
Double num = cell.getNumericCellValue();
BigDecimal bd = new BigDecimal(num.toString());
if (bd != null) {
strCell = bd.toPlainString();
}
// 去除 浮点型 自动加的 .0
if (strCell.endsWith(".0")) {
strCell = strCell.substring(0, strCell.indexOf("."));
}
return strCell;
}
case 4://4表示boolean类型
return String.valueOf(cell.getBooleanCellValue());
default://其他类型没有处理都是返回空
return "";
}
}
}
5、控制器Controller
编写控制器,接收一个excel文件,返回我们从excel读取到的List<对象>的集合。
package com.poi.imports.controller;
import com.poi.imports.pojo.Person;
import com.poi.imports.util.ExcelImportUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.List;
/**
* 测试excel导入的控制器
*/
@Controller
@RequestMapping("/import")
public class ImportController {
@RequestMapping("/persons")
@ResponseBody
public List<Person> importPersons(@RequestParam("file") MultipartFile file){
List<Person> personList = null;
try {
InputStream inputStream = file.getInputStream();//得到上传的文件流
String originalFilename = file.getOriginalFilename();
String ext = originalFilename.substring(originalFilename.lastIndexOf(".")+1);
int rowIndex = 2;//内容开始的行
int cellIndex = 0;//内容开始的列
personList = new ExcelImportUtil<Person>(Person.class).readList(inputStream,rowIndex,cellIndex,ext);
} catch (Exception e) {
e.printStackTrace();
}
return personList;
}
}
6、测试
测试方式还是使用postman工具,
点击Send,可以看到返回结果:
[
{
"pid": "001",
"name": "王发财",
"role": "父亲",
"job": "设计师",
"hobby": "抽烟喝酒",
"birthday": "1968-01-01T16:00:00.000+0000",
"money": 100000.9
},
{
"pid": "002",
"name": "李华花",
"role": "母亲",
"job": "医生",
"hobby": "唱歌",
"birthday": "1969-03-02T16:00:00.000+0000",
"money": 200000.05
},
{
"pid": "003",
"name": "王有才",
"role": "哥哥",
"job": "船长",
"hobby": "打球",
"birthday": "1990-08-03T15:00:00.000+0000",
"money": 10000.8
},
{
"pid": "004",
"name": "王富贵",
"role": "弟弟",
"job": "售货员",
"hobby": "打牌",
"birthday": "1993-04-04T16:00:00.000+0000",
"money": 9000.5
}
]
拿到了这些数据,我们接下来就可以根据业务做相关的操作了。
推荐阅读
-
结合bootstrap fileinput插件和Bootstrap-table表格插件,实现文件上传、预览、提交的导入Excel数据操作流程
-
BootStrap Fileinput插件和Bootstrap table表格插件相结合实现文件上传、预览、提交的导入Excel数据操作步骤
-
java使用POI实现excel文件的导入和导出(通用方法)
-
使用POI同时对Excel文件进行读和写操作时避免Invalid header signatu
-
java中使用poi导入excel文件
-
使用POI导入和导出Excel文件
-
使用POI导入和导出Excel文件
-
thinkphp5.1 框架导入/导出excel文件操作示例
-
excel文件使用navicat工具导入mysql的方法
-
【Apache POI】Excel操作:Excel工具类的封装(最全版)