java poi导入Excel通用工具类

问题引入和分析

提示:如果不想看罗嗦的文章,可以直接到最后点击源码下载运行即可


最近在做一个导入Excel的功能,在做之前在百度上面查找“java通用导入Excel工具类”,没有查到,大多数都是java通用导出Excel。后来仔细想想,导出可以利用java的反射,做成通用的,放进相应的实体成员变量中,导入为什么不可以呢?也是可以的,不过在做之前我们要解决如下两个问题:

1.表格中的列数和顺序要和实体类中的成员变量个数和顺序一致。

2.表格中的列的类型要和成员变量的类型一致。


第一个问题:

列数一致可以做到,但是我们最后都是要插入数据库的。那么id是必不可少的,或者良好的习惯可能还有创建时间,创建人等信息。

所以我想到了两个办法:

1.封装一个Vo,只将需要的字段封装进去,并且字段顺序和表格列的顺序一致,再将vo与实体类po转化(用PropertyUtil.copy方法);

2.在需要的成员变量上注入自定义注解,并且加入注解的这些字段顺序和表格列的顺序一致,利用反射得到这些字段。

这里主要利用第二个方法,因为扩展性更好


第二个问题:

获取表格数据的时候,我们要判断类型,并取得相应值,全部转化为String类型,当我们给实体类赋值的时候,利用反射获取需要的成员变量的类型,并赋值。


需求

假设我们需求的excel如下:



我们可以看做两部分:

第一部分:

第2行到第11行,为一个列表数据,共有字段5个,分别为:学号,姓名,身份证号码,性别,分数


第二部分:

第12行第5列,第13行第5列,共有字段2个,分别为:总计,平均



项目

需要导入的jar包

1.poi的相关jar包,主要用来处理excel
2.beanutils 利用反射为成员变量赋值
3.commons-lang String判断非空的方法,可以不用自己判断


如若maven项目导入下面的jar包

<!-- poi操作excel -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>3.8</version>
		</dependency>
<!-- beanutils -->
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.8.3</version>
		</dependency>
<!-- commons-lang-->
		<dependency>
    			<groupId>commons-lang</groupId>
    			<artifactId>commons-lang</artifactId>
    			<version>2.6</version>
		</dependency>

非maven项目导入下面的jar(下面例子当中用到的jar,有些没用到,可自行处理)

commons-beanutils-1.8.3.jar
commons-lang-2.6.jar
commons-logging-1.1.jar
dom4j-1.6.1.jar
log4j-1.2.13.jar
poi-3.8-20120326.jar
poi-excelant-3.8-20120326.jar
poi-ooxml-3.8-20120326.jar
poi-ooxml-schemas-3.8-20120326.jar
poi-scratchpad-3.8-20120326.jar
stax-api-1.0.1.jar
xmlbeans-2.3.0.jar


项目结构




工具类
package com.dao.chu.excel;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * 
 * excel读取工具类
 * 
 * @author daochuwenziyao
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class ImportExeclUtil
{
    
    private static int totalRows = 0;// 总行数
    
    private static int totalCells = 0;// 总列数
    
    private static String errorInfo;// 错误信息
    
    /** 无参构造方法 */
    public ImportExeclUtil()
    {
    }
    
    public static int getTotalRows()
    {
        return totalRows;
    }
    
    public static int getTotalCells()
    {
        return totalCells;
    }
    
    public static String getErrorInfo()
    {
        return errorInfo;
    }
    
    /**
     * 
     * 根据流读取Excel文件
     * 
     * 
     * @param inputStream
     * @param isExcel2003
     * @return
     * @see [类、类#方法、类#成员]
     */
    public List<List<String>> read(InputStream inputStream, boolean isExcel2003)
        throws IOException
    {
        
        List<List<String>> dataLst = null;
        
        /** 根据版本选择创建Workbook的方式 */
        Workbook wb = null;
        
        if (isExcel2003)
        {
            wb = new HSSFWorkbook(inputStream);
        }
        else
        {
            wb = new XSSFWorkbook(inputStream);
        }
        dataLst = readDate(wb);
        
        return dataLst;
    }
    
    /**
     * 
     * 读取数据
     * 
     * @param wb
     * @return
     * @see [类、类#方法、类#成员]
     */
    private List<List<String>> readDate(Workbook wb)
    {
        
        List<List<String>> dataLst = new ArrayList<List<String>>();
        
        /** 得到第一个shell */
        Sheet sheet = wb.getSheetAt(0);
        
        /** 得到Excel的行数 */
        totalRows = sheet.getPhysicalNumberOfRows();
        
        /** 得到Excel的列数 */
        if (totalRows >= 1 && sheet.getRow(0) != null)
        {
            totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
        }
        
        /** 循环Excel的行 */
        for (int r = 0; r < totalRows; r++)
        {
            Row row = sheet.getRow(r);
            if (row == null)
            {
                continue;
            }
            
            List<String> rowLst = new ArrayList<String>();
            
            /** 循环Excel的列 */
            for (int c = 0; c < getTotalCells(); c++)
            {
                
                Cell cell = row.getCell(c);
                String cellValue = "";
                
                if (null != cell)
                {
                    // 以下是判断数据的类型
                    switch (cell.getCellType())
                    {
                        case HSSFCell.CELL_TYPE_NUMERIC: // 数字
                            cellValue = cell.getNumericCellValue() + "";
                            break;
                        
                        case HSSFCell.CELL_TYPE_STRING: // 字符串
                            cellValue = cell.getStringCellValue();
                            break;
                        
                        case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
                            cellValue = cell.getBooleanCellValue() + "";
                            break;
                        
                        case HSSFCell.CELL_TYPE_FORMULA: // 公式
                            cellValue = cell.getCellFormula() + "";
                            break;
                        
                        case HSSFCell.CELL_TYPE_BLANK: // 空值
                            cellValue = "";
                            break;
                        
                        case HSSFCell.CELL_TYPE_ERROR: // 故障
                            cellValue = "非法字符";
                            break;
                        
                        default:
                            cellValue = "未知类型";
                            break;
                    }
                }
                
                rowLst.add(cellValue);
            }
            
            /** 保存第r行的第c列 */
            dataLst.add(rowLst);
        }
        
        return dataLst;
    }
    
    /**
     * 
     * 按指定坐标读取实体数据
     * <按顺序放入带有注解的实体成员变量中>
     * 
     * @param wb 工作簿
     * @param t 实体
     * @param in 输入流
     * @param integers 指定需要解析的坐标
     * @return T 相应实体
     * @throws IOException
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings("unused")
    public static <T> T readDateT(Workbook wb, T t, InputStream in, Integer[]... integers)
        throws IOException, Exception
    {
        // 获取该工作表中的第一个工作表
        Sheet sheet = wb.getSheetAt(0);
        
        // 成员变量的值
        Object entityMemberValue = "";
        
        // 所有成员变量
        Field[] fields = t.getClass().getDeclaredFields();
        // 列开始下标
        int startCell = 0;
        
        /** 循环出需要的成员 */
        for (int f = 0; f < fields.length; f++)
        {
            
            fields[f].setAccessible(true);
            String fieldName = fields[f].getName();
            boolean fieldHasAnno = fields[f].isAnnotationPresent(IsNeeded.class);
            // 有注解
            if (fieldHasAnno)
            {
                IsNeeded annotation = fields[f].getAnnotation(IsNeeded.class);
                boolean isNeeded = annotation.isNeeded();
                
                // Excel需要赋值的列
                if (isNeeded)
                {
                    
                    // 获取行和列
                    int x = integers[startCell][0] - 1;
                    int y = integers[startCell][1] - 1;
                    
                    Row row = sheet.getRow(x);
                    Cell cell = row.getCell(y);
                    
                    if (row == null)
                    {
                        continue;
                    }
                    
                    // Excel中解析的值
                    String cellValue = getCellValue(cell);
                    // 需要赋给成员变量的值
                    entityMemberValue = getEntityMemberValue(entityMemberValue, fields, f, cellValue);
                    // 赋值
                    PropertyUtils.setProperty(t, fieldName, entityMemberValue);
                    // 列的下标加1
                    startCell++;
                }
            }
            
        }
        
        return t;
    }
    
    /**
     * 
     * 读取列表数据 
     * <按顺序放入带有注解的实体成员变量中>
     * 
     * @param wb 工作簿
     * @param t 实体
     * @param beginLine 开始行数
     * @param totalcut 结束行数减去相应行数
     * @return List<T> 实体列表
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> readDateListT(Workbook wb, T t, int beginLine, int totalcut)
        throws Exception
    {
        List<T> listt = new ArrayList<T>();
        
        /** 得到第一个shell */
        Sheet sheet = wb.getSheetAt(0);
        
        /** 得到Excel的行数 */
        totalRows = sheet.getPhysicalNumberOfRows();
        
        /** 得到Excel的列数 */
        if (totalRows >= 1 && sheet.getRow(0) != null)
        {
            totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
        }
        
        /** 循环Excel的行 */
        for (int r = beginLine - 1; r < totalRows - totalcut; r++)
        {
            Object newInstance = t.getClass().newInstance();
            Row row = sheet.getRow(r);
            if (row == null)
            {
                continue;
            }
            
            // 成员变量的值
            Object entityMemberValue = "";
            
            // 所有成员变量
            Field[] fields = t.getClass().getDeclaredFields();
            // 列开始下标
            int startCell = 0;
            
            for (int f = 0; f < fields.length; f++)
            {
                
                fields[f].setAccessible(true);
                String fieldName = fields[f].getName();
                boolean fieldHasAnno = fields[f].isAnnotationPresent(IsNeeded.class);
                // 有注解
                if (fieldHasAnno)
                {
                    IsNeeded annotation = fields[f].getAnnotation(IsNeeded.class);
                    boolean isNeeded = annotation.isNeeded();
                    // Excel需要赋值的列
                    if (isNeeded)
                    {
                        Cell cell = row.getCell(startCell);
                        String cellValue = getCellValue(cell);
                        entityMemberValue = getEntityMemberValue(entityMemberValue, fields, f, cellValue);
                        // 赋值
                        PropertyUtils.setProperty(newInstance, fieldName, entityMemberValue);
                        // 列的下标加1
                        startCell++;
                    }
                }
                
            }
            
            listt.add((T)newInstance);
        }
        
        return listt;
    }
    
    /**
     * 
     * 根据Excel表格中的数据判断类型得到值
     * 
     * @param cell
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static String getCellValue(Cell cell)
    {
        String cellValue = "";
        
        if (null != cell)
        {
            // 以下是判断数据的类型
            switch (cell.getCellType())
            {
                case HSSFCell.CELL_TYPE_NUMERIC: // 数字
                    if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell))
                    {
                        Date theDate = cell.getDateCellValue();
                        SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd");
                        cellValue = dff.format(theDate);
                    }
                    else
                    {
                        DecimalFormat df = new DecimalFormat("0");
                        cellValue = df.format(cell.getNumericCellValue());
                    }
                    break;
                case HSSFCell.CELL_TYPE_STRING: // 字符串
                    cellValue = cell.getStringCellValue();
                    break;
                
                case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
                    cellValue = cell.getBooleanCellValue() + "";
                    break;
                
                case HSSFCell.CELL_TYPE_FORMULA: // 公式
                    cellValue = cell.getCellFormula() + "";
                    break;
                
                case HSSFCell.CELL_TYPE_BLANK: // 空值
                    cellValue = "";
                    break;
                
                case HSSFCell.CELL_TYPE_ERROR: // 故障
                    cellValue = "非法字符";
                    break;
                
                default:
                    cellValue = "未知类型";
                    break;
            }
            
        }
        return cellValue;
    }
    
    /**
     * 
     * 根据实体成员变量的类型得到成员变量的值
     * 
     * @param realValue
     * @param fields
     * @param f
     * @param cellValue
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static Object getEntityMemberValue(Object realValue, Field[] fields, int f, String cellValue)
    {
        String type = fields[f].getType().getName();
        switch (type)
        {
            case "char":
            case "java.lang.Character":
            case "java.lang.String":
                realValue = cellValue;
                break;
            case "java.util.Date":
                realValue = StringUtils.isBlank(cellValue) ? null : DateUtil.strToDate(cellValue, DateUtil.YYYY_MM_DD);
                break;
            case "java.lang.Integer":
                realValue = StringUtils.isBlank(cellValue) ? null : Integer.valueOf(cellValue);
                break;
            case "int":
            case "float":
            case "double":
            case "java.lang.Double":
            case "java.lang.Float":
            case "java.lang.Long":
            case "java.lang.Short":
            case "java.math.BigDecimal":
                realValue = StringUtils.isBlank(cellValue) ? null : new BigDecimal(cellValue);
                break;
            default:
                break;
        }
        return realValue;
    }
    
    /**
     * 
     * 根据路径或文件名选择Excel版本
     * 
     * 
     * @param filePathOrName
     * @param in
     * @return
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    public static Workbook chooseWorkbook(String filePathOrName, InputStream in)
        throws IOException
    {
        /** 根据版本选择创建Workbook的方式 */
        Workbook wb = null;
        boolean isExcel2003 = ExcelVersionUtil.isExcel2003(filePathOrName);
        
        if (isExcel2003)
        {
            wb = new HSSFWorkbook(in);
        }
        else
        {
            wb = new XSSFWorkbook(in);
        }
        
        return wb;
    }
    
    static class ExcelVersionUtil
    {
        
        /**
         * 
         * 是否是2003的excel,返回true是2003
         * 
         * 
         * @param filePath
         * @return
         * @see [类、类#方法、类#成员]
         */
        public static boolean isExcel2003(String filePath)
        {
            return filePath.matches("^.+\\.(?i)(xls)$");
            
        }
        
        /**
         * 
         * 是否是2007的excel,返回true是2007
         * 
         * 
         * @param filePath
         * @return
         * @see [类、类#方法、类#成员]
         */
        public static boolean isExcel2007(String filePath)
        {
            return filePath.matches("^.+\\.(?i)(xlsx)$");
            
        }
        
    }
    
    public static class DateUtil
    {
        
        // ======================日期格式化常量=====================//
        
        public static final String YYYY_MM_DDHHMMSS = "yyyy-MM-dd HH:mm:ss";
        
        public static final String YYYY_MM_DD = "yyyy-MM-dd";
        
        public static final String YYYY_MM = "yyyy-MM";
        
        public static final String YYYY = "yyyy";
        
        public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
        
        public static final String YYYYMMDD = "yyyyMMdd";
        
        public static final String YYYYMM = "yyyyMM";
        
        public static final String YYYYMMDDHHMMSS_1 = "yyyy/MM/dd HH:mm:ss";
        
        public static final String YYYY_MM_DD_1 = "yyyy/MM/dd";
        
        public static final String YYYY_MM_1 = "yyyy/MM";
        
        /**
         * 
         * 自定义取值,Date类型转为String类型
         * 
         * @param date 日期
         * @param pattern 格式化常量
         * @return
         * @see [类、类#方法、类#成员]
         */
        public static String dateToStr(Date date, String pattern)
        {
            SimpleDateFormat format = null;
            
            if (null == date)
                return null;
            format = new SimpleDateFormat(pattern, Locale.getDefault());
            
            return format.format(date);
        }
        
        /**
         * 将字符串转换成Date类型的时间
         * <hr>
         * 
         * @param s 日期类型的字符串<br>
         *            datePattern :YYYY_MM_DD<br>
         * @return java.util.Date
         */
        public static Date strToDate(String s, String pattern)
        {
            if (s == null)
            {
                return null;
            }
            Date date = null;
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            try
            {
                date = sdf.parse(s);
            }
            catch (ParseException e)
            {
                e.printStackTrace();
            }
            return date;
        }
    }
    
}


自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 
 * 是否需要从解析excel赋值
 * @author daochuwenziyao
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD})
public @interface IsNeeded
{
    
    /**
     * 是否需要从解析excel赋值
     * @return
     *         true:需要  false:不需要
     * @see [类、类#方法、类#成员]
     */
    boolean isNeeded() default true;
}


学生基本信息


import java.math.BigDecimal;

/**
 * 
 * 学生基本信息
 * @author daochuwenziyao
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class StudentBaseInfo
{
    private Integer id;
    @IsNeeded
    private String no;
    @IsNeeded
    private String name;
    @IsNeeded
    private String idnum;
    @IsNeeded
    private String sex;
    @IsNeeded
    private BigDecimal grade;
    
    
    @Override
    public String toString()
    {
        return "StudentBaseInfo [id=" + id + ", no=" + no + ", name=" + name + ", idnum=" + idnum + ", sex=" + sex
            + ", grade=" + grade + "]";
    }
    public Integer getId()
    {
        return id;
    }
    public void setId(Integer id)
    {
        this.id = id;
    }
    public String getNo()
    {
        return no;
    }
    public void setNo(String no)
    {
        this.no = no;
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public String getSex()
    {
        return sex;
    }
    public void setSex(String sex)
    {
        this.sex = sex;
    }
    public String getIdnum()
    {
        return idnum;
    }
    public void setIdnum(String idnum)
    {
        this.idnum = idnum;
    }
    public BigDecimal getGrade()
    {
        return grade;
    }
    public void setGrade(BigDecimal grade)
    {
        this.grade = grade;
    }
    
}


学生统计信息

/**
 * 
 * 学生统计信息
 * @author daochuwenziyao
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class StudentStatistics
{
    private Integer id;
    @IsNeeded
    private BigDecimal totalGrade;
    @IsNeeded
    private BigDecimal avgGrade;
    
    @Override
    public String toString()
    {
        return "StudentStatistics [id=" + id + ", totalGrade=" + totalGrade + ", avgGrade=" + avgGrade + "]";
    }
    public Integer getId()
    {
        return id;
    }
    public void setId(Integer id)
    {
        this.id = id;
    }
    public BigDecimal getTotalGrade()
    {
        return totalGrade;
    }
    public void setTotalGrade(BigDecimal totalGrade)
    {
        this.totalGrade = totalGrade;
    }
    public BigDecimal getAvgGrade()
    {
        return avgGrade;
    }
    public void setAvgGrade(BigDecimal avgGrade)
    {
        this.avgGrade = avgGrade;
    }
    
}


测试类


package com.dao.chu.excel;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;


import org.apache.poi.ss.usermodel.Workbook;


public class TestImportExcel
{
    
    public static void main(String[] args) throws IOException, Exception
    {
        
        String fileName="student.xlsx";
        InputStream in = new FileInputStream(new File("excelfile\\student.xlsx"));
        Workbook wb = ImportExeclUtil.chooseWorkbook(fileName, in);
        StudentStatistics studentStatistics = new StudentStatistics();
        
        //读取一个对象的信息
        StudentStatistics readDateT =
            ImportExeclUtil.readDateT(wb, studentStatistics, in, new Integer[] {12, 5}, new Integer[] {13, 5});
        System.out.println(readDateT);
        
        //读取对象列表的信息
        StudentBaseInfo studentBaseInfo = new StudentBaseInfo();
        //第二行开始,到倒数第三行结束(总数减去两行)
        List<StudentBaseInfo> readDateListT = ImportExeclUtil.readDateListT(wb, studentBaseInfo, 2, 2);
        System.out.println(readDateListT);
        
    }
}


输出结果

StudentStatistics [id=null, totalGrade=845, avgGrade=84]
[StudentBaseInfo [id=null, no=2012240001, name=张三1, idnum=233314199009062304, sex=男, grade=80], StudentBaseInfo [id=null, no=2012240002, name=张三2, idnum=233314199009062304, sex=男, grade=81], StudentBaseInfo [id=null, no=2012240003, name=张三3, idnum=233314199009062304, sex=男, grade=82], StudentBaseInfo [id=null, no=2012240004, name=张三4, idnum=233314199009062304, sex=男, grade=83], StudentBaseInfo [id=null, no=2012240005, name=张三5, idnum=233314199009062304, sex=男, grade=84], StudentBaseInfo [id=null, no=2012240006, name=张三6, idnum=233314199009062304, sex=男, grade=85], StudentBaseInfo [id=null, no=2012240007, name=张三7, idnum=233314199009062304, sex=男, grade=86], StudentBaseInfo [id=null, no=2012240008, name=张三8, idnum=233314199009062304, sex=男, grade=87], StudentBaseInfo [id=null, no=2012240009, name=张三9, idnum=233314199009062304, sex=男, grade=88], StudentBaseInfo [id=null, no=2012240010, name=张三10, idnum=233314199009062304, sex=男, grade=89]]


源码下载

源码分享给大家,上面提到的都在这里,由于很多的数据类型没有试验到,可能会有些类型有问题,所以希望大家如果遇到问题回复我,我会将其完善。谢谢

http://download.csdn.net/download/daochuwenziyao/9971228



版本修改


V20170915_解决不能导入带有公式计算的excel



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值