欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

POI工具操作excel(七)Excel文件导入

程序员文章站 2022-04-30 18:28:47
...

       前面两篇讲的是excel的导出,在系统中,也会出现把excel表格中的数据导入到数据库的操作。那么这篇就简单的封装一个基于注解的工具类,可以利用POI技术方便的读取excel文件中的数据,把每一行数据封装成了一个我们的Java对象,然后存入到集合中。拿到集合数据就可以使用其他的持久化技术,把数据存储到数据库中了。

1、环境准备

本次使用的工程还是之前那篇文章的工程,具体创建请参照之。

准备一个excel的文件,内容如下:

POI工具操作excel(七)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工具,

POI工具操作excel(七)Excel文件导入

POI工具操作excel(七)Excel文件导入

 

点击Send,可以看到返回结果:

POI工具操作excel(七)Excel文件导入

[
    {
        "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
    }
]

拿到了这些数据,我们接下来就可以根据业务做相关的操作了。

相关标签: POI