JAVA使用poi读取excel的工具类【通用】

使用读取excel工具类的例子,例子中,使用简单,对比灵活。代码简洁。

说明:这块代码是网上别人公开的,具体来源找不到了。我把它做了修改,抽离固定的实体,改成泛型,这样更加灵活。如果侵权,请通知博主。


一.编写工具类

工具类代码:

package com.system.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

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;

import freemarker.log.Logger;

/**
 * Author: laijieuan
 * Date: 2020-07-07
 * Description: 读取Excel内容 
 * T 泛型是接收每行数据的类名
 */
public abstract class ExcelReader<T> {

    private static Logger logger = Logger.getLogger(ExcelReader.class.getName()); // 日志打印类

    private static final String XLS = "xls";
    private static final String XLSX = "xlsx";

    /**
     * 根据文件后缀名类型获取对应的工作簿对象
     * @param inputStream 读取文件的输入流
     * @param fileType 文件后缀名类型(xls或xlsx)
     * @return 包含文件数据的工作簿对象
     * @throws IOException
     */
    public Workbook getWorkbook(InputStream inputStream, String fileName) throws IOException {
        Workbook workbook = null;
        if (fileName.endsWith(XLS)) {
            workbook = new HSSFWorkbook(inputStream);
        } else if (fileName.endsWith(XLSX)) {
            workbook = new XSSFWorkbook(inputStream);
        }
        return workbook;
    }

    /**
     * 读取Excel文件内容
     * @param fileName 要读取的Excel文件所在路径
     * @return 读取结果列表,读取失败时返回null
     */
    public List<T> readExcel(String fileName) {

        Workbook workbook = null;
    
        FileInputStream inputStream = null;

        try {
            // 获取Excel后缀名
            String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
            // 获取Excel文件
            File excelFile = new File(fileName);
            if (!excelFile.exists()) {
                logger.warn("指定的Excel文件不存在!");
                return null;
            }

            // 获取Excel工作簿
            inputStream = new FileInputStream(excelFile);
            workbook = getWorkbook(inputStream, fileType);

            // 读取excel中的数据
            List<T> resultDataList = parseExcel(workbook);

            return resultDataList;
        } catch (Exception e) {
            logger.warn("解析Excel失败,文件名:" + fileName + " 错误信息:" + e.getMessage());
            return null;
        } finally {
            try {
                
                if (null != inputStream) {
                    inputStream.close();
                }
            } catch (Exception e) {
                logger.warn("关闭数据流出错!错误信息:" + e.getMessage());
                return null;
            }
        }
    }

    /**
     * 解析Excel数据
     * @param workbook Excel工作簿对象 
     * @return 解析结果
     */
    public  List<T> parseExcel(Workbook workbook) {
       List<T> resultDataList = new ArrayList<>();
        // 解析sheet
        for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
            Sheet sheet = workbook.getSheetAt(sheetNum);

            // 校验sheet是否合法
            if (sheet == null) {
                continue;
            }

            // 获取第一行数据
            int firstRowNum = sheet.getFirstRowNum();
            Row firstRow = sheet.getRow(firstRowNum);
            if (null == firstRow) {
                logger.warn("解析Excel失败,在第一行没有读取到任何数据!");
            }

            // 解析每一行的数据,构造数据对象
            int rowStart = firstRowNum + 1;
            int rowEnd = sheet.getPhysicalNumberOfRows();
            for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
                Row row = sheet.getRow(rowNum);

                if (null == row) {
                    continue;
                }
				//读取当前行的数据,该方法需要重写
                T resultData = convertRowToData(row);
                if (null == resultData) {
                    logger.warn("第 " + row.getRowNum() + "行数据不合法,已忽略!");
                    continue;
                }
                resultDataList.add(resultData);
            }
        }

        return resultDataList;
    }

    /**
     * 将单元格内容转换为字符串
     * @param cell
     * @return
     */
    public static String convertCellValueToString(Cell cell) {
        if(cell==null){
            return null;
        }
        String returnValue = null;
        switch (cell.getCellType()) {
            case Cell.CELL_TYPE_NUMERIC:   //数字
                Double doubleValue = cell.getNumericCellValue();

                // 格式化科学计数法,取一位整数
                DecimalFormat df = new DecimalFormat("0");
                returnValue = df.format(doubleValue);
                break;
            case Cell.CELL_TYPE_STRING:    //字符串
                returnValue = cell.getStringCellValue();
                break;
            case Cell.CELL_TYPE_BOOLEAN:   //布尔
                Boolean booleanValue = cell.getBooleanCellValue();
                returnValue = booleanValue.toString();
                break;
            case Cell.CELL_TYPE_BLANK:     // 空值
                break;
            case Cell.CELL_TYPE_FORMULA:   // 公式
                returnValue = cell.getCellFormula();
                break;
            case Cell.CELL_TYPE_ERROR:     // 故障
                break;
            default:
                break;
        }
        return returnValue;
    }

    /**
     * 为了灵活使用该工具类,抽取泛型来完成
     * 提取每一行中需要的数据,构造成为一个结果数据对象
     * 当该行中有单元格的数据为空或不合法时,忽略该行的数据
     *
     * @param row 行数据
     * @return 解析后的行数据对象,行数据错误时返回null
     */
    public abstract T convertRowToData(Row row);
}

工具类就此写完了


二.例子说明

现在有一个类的实体是这样的:

package com.wl.differentCountries.entity;
/**
  *国别类
  */
public class Country {
    /**
     * 国别代码
     */
    private String countrycode;

    /**
     * 国别中文简称
     */
    private String countryname;

    /**
     * 国别英文简称
     */
    private String countryenname;

    /**
     * 国别英文缩写
     */
    private String countryenshort;

    /**
     * 优普税率
     */
    private String applytaxtype;

    /**
     * 国别描述
     */
    private String countrydesc;

    /**
     * 备注
     */
    private String comments;

    /**
     * 状态
     */
    private String states;

    /**
     * 最终目的国别代码
     */
    private String lastcountrycode;

    public String getCountrycode() {
        return countrycode;
    }
    public void setCountrycode(String countrycode) {
        this.countrycode = countrycode == null ? null : countrycode.trim();
    }
    public String getCountryname() {
        return countryname;
    }
    public void setCountryname(String countryname) {
        this.countryname = countryname == null ? null : countryname.trim();
    }
    public String getCountryenname() {
        return countryenname;
    }
    public void setCountryenname(String countryenname) {
        this.countryenname = countryenname == null ? null : countryenname.trim();
    }
    public String getCountryenshort() {
        return countryenshort;
    }
    public void setCountryenshort(String countryenshort) {
        this.countryenshort = countryenshort == null ? null : countryenshort.trim();
    }
    public String getApplytaxtype() {
        return applytaxtype;
    }
    public void setApplytaxtype(String applytaxtype) {
        this.applytaxtype = applytaxtype == null ? null : applytaxtype.trim();
    }
    public String getCountrydesc() {
        return countrydesc;
    }
    public void setCountrydesc(String countrydesc) {
        this.countrydesc = countrydesc == null ? null : countrydesc.trim();
    }
    public String getComments() {
        return comments;
    }
    public void setComments(String comments) {
        this.comments = comments == null ? null : comments.trim();
    }
    public String getStates() {
        return states;
    }  
    public void setStates(String states) {
        this.states = states == null ? null : states.trim();
    }
    public String getLastcountrycode() {
        return lastcountrycode;
    }
    public void setLastcountrycode(String lastcountrycode) {
        this.lastcountrycode = lastcountrycode == null ? null : lastcountrycode.trim();
    }
	@Override
	public String toString() {
		return "Country [countrycode=" + countrycode + ", countryname=" + countryname + ", countryenname="
				+ countryenname + ", countryenshort=" + countryenshort + ", applytaxtype=" + applytaxtype
				+ ", countrydesc=" + countrydesc + ", comments=" + comments + ", states=" + states
				+ ", lastcountrycode=" + lastcountrycode + "]";
	}
    
}

然后这个实体的数据基本都是由公司的人员从excel里的填写好后,上传到系统,系统读取excel并封装成的

excel模板:

国别代码国别中文简称国别英文简称国别英文缩写优普税率国别描述备注状态最终目的国别代码
502美国XXUAXXXXXXXXXYXXX

第一步:继承excelReader工具类并重写读取数据方法。

package com.wl.differentCountries.utils;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import com.system.util.ExcelReader;
import com.wl.differentCountries.entity.Country;

/**
 * 针对这个国别类封装一个工具
 * 必须继承ExcelReader<T>
 * T是自由的,当然,既然针对的是国别类,这里就是写国别类
 */
public class CountryExcelReader extends ExcelReader<Country>{
	/*重写方法,读取每一行数据并封装成实体*/
	@Override
	public Country convertRowToData(Row row) {
        //先new一个国别实体
		Country resultData = new Country();
		//
		Cell cell;
        //当前列号,默认值0
		int cellNum = 0;
		//获取最大列号,
        row.getPhysicalNumberOfCells();
		//通过行获取列 获取第一列
        cell = row.getCell(cellNum++);
        
		// 获取国别代码 读取数据并装成String
		String countryCode = convertCellValueToString(cell);
        //封装至实体属性
		resultData.setCountrycode(countryCode);
        
		//通过行获取列 获取第二列 以下就以此类推,有多少列就读多少次,也可以通过最大的列数号遍历,通过反射完成封装,这里就不弄这么复杂的了。
		cell = row.getCell(cellNum++);
        // 获取国别中文简称 
		String countryname = convertCellValueToString(cell);
		resultData.setCountryname(countryname);
		// 获取国别英文简称
		cell = row.getCell(cellNum++);
		String countryenname = convertCellValueToString(cell);
		resultData.setCountryenname(countryenname);
		// 获取国别英文缩写
		cell = row.getCell(cellNum++);
		String countryenshort = convertCellValueToString(cell);
		resultData.setCountryenshort(countryenshort);
		// 获取优普税率
		cell = row.getCell(cellNum++);
		String applytaxtype = convertCellValueToString(cell);
		resultData.setApplytaxtype(applytaxtype);
		// 获取国别描述
		cell = row.getCell(cellNum++);
		String countrydesc = convertCellValueToString(cell);
		resultData.setCountrydesc(countrydesc);
		// 获取备注
		cell = row.getCell(cellNum++);
		String comments = convertCellValueToString(cell);
		resultData.setComments(comments);
		// 获取状态
		cell = row.getCell(cellNum++);
		String states = convertCellValueToString(cell);
		resultData.setComments(comments);
		// 获取最终目的国别代码
		cell = row.getCell(cellNum++);
		String lastcountrycode = convertCellValueToString(cell);
		resultData.setLastcountrycode(lastcountrycode);
		return resultData;
	}

}

Controller层:获取上传的excel文件

package com.wl.differentCountries.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.system.util.ResultUtils;
import com.system.vo.Result;
import com.wl.differentCountries.entity.Country;
import com.wl.differentCountries.service.WLCountryService;

/**
 * 
 * @author laijieguan
 * 2020-07-10
 */
@RestController
@RequestMapping("country")
public class CountryController {
	@Autowired
	private WLCountryService wlCountryService;
	/**
	 * 根据国别代码来查询
	 */
	@RequestMapping("selByCountryCode")
	private Result<Object> selByCountryCode(String countryCode){
		System.out.println(countryCode);
		Country country = wlCountryService.selectByPrimaryKey(countryCode);
		if(country != null) {
			return ResultUtils.data(country);
		}
		return ResultUtils.error("未查询到相关国别信息!");
	}
	
    /**
     *获取上传的文件
     */
	@RequestMapping("importCountryData")
	private Result<Object> importCountryData(@RequestParam(value = "file", required = false) MultipartFile mFile) {
        //这个地方应该对该文件的格式做判断,如果不是excel的话返回提示
		String type = "";
		try {
			Boolean importAddr = wlCountryService.importAddr(mFile, type);
			if (importAddr) {
				return ResultUtils.success("导入成功");
			} else {
				return ResultUtils.error("导入失败");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ResultUtils.error("导入失败");
		}
	}
}

Service层:读取数据,并对数据进行业务处理

package com.wl.differentCountries.service;

import java.io.InputStream;
import java.util.List;

import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.wl.differentCountries.dao.WLCountryMapper;
import com.wl.differentCountries.entity.Country;
import com.wl.differentCountries.utils.CountryExcelReader;

@Service
@Transactional
public class WLCountryServiceImpl implements WLCountryService{
	@Autowired
	private WLCountryMapper wlCountryMapper;
	
	@Override
	public Integer insert(Country country) {
		return wlCountryMapper.insert(country);
	}

	@Override
	public Country selectByPrimaryKey(String countryCode) {
		return wlCountryMapper.selectByPrimaryKey(countryCode);
	}

	@Override
	public Integer updateByPrimaryKeySelective(Country country) {
		return wlCountryMapper.updateByPrimaryKeySelective(country);
	}
	
    /**
     *读取excel数据
     */
	@Override
	public Boolean importAddr(MultipartFile mFile, String type) throws Exception {
        //获取流
		InputStream inputStream = mFile.getInputStream();
        //获取文件名
		String fileName = mFile.getOriginalFilename();
        //new 一个读取对应实体的excel读解器
		CountryExcelReader countryExcelReader = new CountryExcelReader();
		//通过流来获取workbook实体
        Workbook wb = countryExcelReader.getWorkbook(inputStream, fileName);
		//解析excel数据,封装后返回List集合
        List<Country> parseExcel = countryExcelReader.parseExcel(wb);
		int count = 0;
        //遍历每一实例,做对应的业务操作。
		for(int i = 0 ;i< parseExcel.size();i++) {
			System.out.println(parseExcel.get(i));
		}
		if(count == parseExcel.size()) { //这个是我的业务操作需要的,业务代码已经删除各位根据自己情况完成即可
			return true;
		}
		return false;
	}
	

在读取每列数据的时候,其实是不太灵活的,可以做成代理模式。具体的我就不详细说了,因为这块代码实现属于机密。哈哈哈哈哈。

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值