读取Excel工具类

ExcelPublic.java,其中包含读取Excel第一行(一般为标题行),读取所有Excel中所有数据(包括标题行),读取表头字段在excel中的位置(列值)等方法。

poi版本为3.15,数据库为MySQL

测试Excel和s数据库结果如下:

 

ExcelPublic.java

package com.alphajuns.ssm.util;

/**
 * ExcelPublic.java
 */
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * ClassName: excelPublic
 * </p>
 * <p>
 * Description: 负责excel的公共类
 * </p>
 * <p>
 * Author: Administrator
 * </p>
 * <p>
 * Date: 2015-6-28
 * </p>
 */
public class ExcelPublic {

    /**
     * <p>
     * Description: 一个提取excel文件内cell内容的方法
     * </p>
     * .
     *
     * @param cell
     *            一个单元格内的内容
     * @return 把cell转换成string
     */
    @SuppressWarnings("deprecation")
    public static String getCellValue(Cell cell) {
        String cellStr = null;
        DecimalFormat DF = new DecimalFormat("0");
        if (cell == null) {
            cellStr = "";
        } else {
            switch (cell.getCellType()) {
                //case Cell.CELL_TYPE_BOOLEAN:
                case BOOLEAN:
                    cellStr = String.valueOf(cell.getBooleanCellValue());
                    break;
                case NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell)) { // 日期
                        final DateFormat FORMATER = new SimpleDateFormat("dd.MM.yyyy");
                        cellStr = FORMATER.format(cell.getDateCellValue());
                    } else {
                        String number = String.valueOf(cell.getNumericCellValue());
                        if(number.indexOf(".") != -1){
                            DF = new DecimalFormat("#.###");
                        }
                        cellStr = DF.format(cell.getNumericCellValue());
                    }
                    break;
                case BLANK:
                    cellStr = "";
                    break;
                case ERROR:
                    cellStr = String.valueOf(cell.getErrorCellValue());
                    break;
                case FORMULA: // 首先判断一下是不是公式
                    cell.setCellType(CellType.NUMERIC); // 设置其单元格类型为数字
                    try {
                        cellStr = DF.format(cell.getNumericCellValue()); // 获取数字值
                    } catch (Exception e) {
                        throw new RuntimeException("行:" + (cell.getRowIndex() + 1) + ",列:" + (cell.getColumnIndex() + 1) + " 获取公式值失败," + e.toString());
                    }
                    break;
                default:
                    cellStr = cell.getStringCellValue();
                    break;
            }
        }
        return cellStr;
    }

    /**
     * <p>
     * Description: 一个检查excel的第一行是否有值的方法
     * </p>
     *
     * @param path
     *            path
     * @return boolean
     * @throws IOException
     *             IO异常
     */
    public static boolean checkArray(String path) throws IOException {
        final FileInputStream FS = new FileInputStream(path);
        final String TYPE = path.substring(path.lastIndexOf(".") + 1).toLowerCase();
        Workbook wb;
        if ("xlsx".equals(TYPE)) {
            wb = new XSSFWorkbook(FS);
        } else {
            wb = new HSSFWorkbook(FS);
        }
        Sheet sheet = wb.getSheetAt(0);
        boolean flag = sheet.getRow(0) != null ? true : false;

        // 添加一个检查表格第一行是否为正常数据的方法 gary 2016.9.19
        int cellNum = 0;
        if (sheet.getRow(0) != null) { // 检查第一行是不是为空
            cellNum = sheet.getRow(0).getPhysicalNumberOfCells();
        } else {
            cellNum = 0;
        }

        Row row = null;
        Cell cell = null;
        final String[] STR = new String[cellNum];
        if (flag) {
            row = sheet.getRow(0);
            for (int j = 1; j <= cellNum; j++) {
                cell = row.getCell(j - 1);
                if (cell == null) {
                    STR[j - 1] = "";
                } else {
                    STR[j - 1] = getCellValue(cell);
                }
            }
        }
        sheet = null;
        wb.close();
        wb = null;
        return flag;
    }

    public static String[][] dyadicArray(String path, int startNum, int endNum) throws IOException {
        String[][] str = null;
        FileInputStream fs = new FileInputStream(path);
        String type = path.substring(path.lastIndexOf(".") + 1).toLowerCase();
        Workbook wb;
        if ("xlsx".equals(type)) {
            wb = new XSSFWorkbook(fs);
        } else {
            wb = new HSSFWorkbook(fs);
        }
        try {
            Sheet sheet = wb.getSheetAt(0);

            final int A = sheet.getPhysicalNumberOfRows(); // 行数
            final int B;

            B = sheet.getRow(0).getPhysicalNumberOfCells(); // 列数

            if (endNum == 0 && startNum == 1) {
                endNum = A;
            } else if (startNum == 0) {
                startNum = 1;
            }

            int rowNumber = endNum - startNum + 1;
            str = new String[rowNumber][B];
            Row row = null;
            Cell cell = null;
            for (int i = 1; i <= rowNumber; i++) {
                row = sheet.getRow(startNum - 1);
                for (int j = 1; j <= B; j++) {
                    cell = row.getCell(j - 1);
                    if (cell == null) {
                        str[i - 1][j - 1] = "";
                    } else {
                        str[i - 1][j - 1] = getCellValue(cell);
                    }
                    cell = null;
                }
                startNum++;
                row = null;
            }
            sheet = null;
        } catch (Exception e) {
            throw new IOException(e);
        } finally {
            wb.close();
            wb = null;
            fs = null;
        }

        return str;
    }

    /**
     * <p>
     * Description: 得到excel行数的方法
     * </p>
     *
     * @param path
     *            path
     * @return int
     * @throws IOException
     */
    public static int getRowNumber(String path) throws IOException {
        final FileInputStream FS = new FileInputStream(path);
        final String TYPE = path.substring(path.lastIndexOf(".") + 1).toLowerCase();
        Workbook wb;
        if ("xlsx".equals(TYPE)) {
            wb = new XSSFWorkbook(FS);
        } else {
            wb = new HSSFWorkbook(FS);
        }
        final Sheet SHEET = wb.getSheetAt(0);

        int firstRowNumber = SHEET.getFirstRowNum();
        int lastRowNumber = SHEET.getLastRowNum();
        int rowNumber = lastRowNumber - firstRowNumber + 1; // 行数

        wb.close();

        return rowNumber;
    }

    public static ArrayList<String> readExcelFirstline(String path) throws IOException {
        final ArrayList<String> FIRSTLINE = new ArrayList<String>();
        if (checkArray(path)) {
            String[][] article = dyadicArray(path, 1, 1);
            final int LENGTH = article[0].length;
            for (int i = 0; i < LENGTH; i++) {
                FIRSTLINE.add(article[0][i]);
            }
            article = null;
        }
        return FIRSTLINE;
    }

    /**
     * <p>
     * Description: 将二维数组的每一行转成ArrayList
     * </p>
     * .
     *
     * @param path
     *            带文件名的路径
     * @param dyadic
     *            二维数组,也就是给定的原文,目前已经指定了行数范围
     * @return 返回该行
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static HashMap<Integer, ArrayList<String>> readExcelLine(String path, String[][] dyadic) throws IOException {

        final HashMap<Integer, ArrayList<String>> READEXCEL = new HashMap<Integer, ArrayList<String>>();
        final int LENGTH = dyadic.length;
        final int WIDTH = dyadic[0].length;
        String[][] article = null;
        article = dyadic;
        for (int i = 0; i < LENGTH; i++) {
            final ArrayList<String> ROW = new ArrayList<String>();
            for (int j = 0; j < WIDTH; j++) {
                ROW.add(article[i][j]);
            }
            READEXCEL.put(i, ROW);
        }
        return READEXCEL;
    }

    public static Integer findTheWord(String path, String word) throws IOException {
        int wordLocation = 0;
        ArrayList<String> arr = null;
        arr = readExcelFirstline(path);
        if (arr.contains(word)) {
            wordLocation = arr.indexOf(word);
        } else {
            wordLocation = -1;
        }
        return wordLocation;
    }

    // /**
    // * <p>
    // * Description: 根据不同文本来适配不同字符编码,针对txt文本使用
    // * </p>.
    // *
    // * @param fileName 带文件名的路径
    // * @return 文件编码
    // * @throws IOException Signals that an I/O exception has occurred.
    // */
    // public static String getCharset(String fileName) throws IOException {
    // final BufferedInputStream BIN = new BufferedInputStream(new
    // FileInputStream(fileName));
    // final int NUMBER = 8;
    // final int P = (BIN.read() << NUMBER) + BIN.read();
    // final int UTF8 = 0xefbb;
    // final int UNICODE = 0xfffe;
    // final int UTF16BE = 0xfeff;
    // String code = null;
    // switch (P) {
    // case UTF8:
    // code = "UTF-8";
    // break;
    // case UNICODE:
    // code = "Unicode";
    // break;
    // case UTF16BE:
    // code = "UTF-16BE";
    // break;
    // default:
    // code = "GBK";
    // }
    // BIN.close();
    // return code;
    // }

    /**
     * <p>
     * Description: 获取当前时间戳,格式到分
     * </p>
     * .
     *
     * @return 当前时间
     */
    public static String getTime() {
        final Date DATE = new Date(); // 创建一个时间对象,获取到当前的时间
        final SimpleDateFormat SDF = new SimpleDateFormat("yyyyMMddHHmm"); // 设置时间显示格式
        final String STR = SDF.format(DATE); // 将当前时间格式化为String
        return STR; // 输出结果
    }

    /**
     * <p>
     * Description: 在传入为list时的插入方法
     * </p>
     * .
     *
     * @param outList
     *            输出的字段
     * @param inList
     *            输入的字段
     * @param value
     *            值
     * @return outlist
     */
    public static List<String> addValueMethod(List<String> outList, List<String> inList, Integer value) {
        String word = null;
        if (value == -1) {
            outList.add("");
        } else if (value > inList.size()) {
            outList.add("");
        } else if (inList.get(value) != null) {
            if (inList.get(value).trim().length() > 250) {
                outList.add("");
            } else {
                if (inList.get(value).trim().contains("\'")) {
                    word = inList.get(value).trim().replace("\'", "’");
                } else if (inList.get(value).trim().contains("\"")) {
                    word = inList.get(value).trim().replace("\"", "”");
                } else {
                    word = inList.get(value).trim();
                }
                outList.add(word);

            }

        } else {
            outList.add("");
        }
        return outList;
    }

    /**
     * <p>
     * Description: 在插入值时去掉“.”的方法
     * </p>
     *
     * @param outList
     *            输出值
     * @param inList
     *            输出值
     * @param value
     *            位置
     * @return 输出结果
     */
    public static List<String> addValueMethodHavePoint(List<String> outList, List<String> inList, Integer value) {
        if (value == -1) {
            outList.add("");
        } else if (value > inList.size()) {
            outList.add("");
        } else if (inList.get(value) != null) {
            String newList;
            newList = inList.get(value).replace(".", "");
            outList.add(newList);
        } else {
            outList.add("");
        }
        return outList;
    }

    /**
     * <p>
     * Description: 生成当前时间,精确到毫秒,格式为年月日小时分钟秒毫秒,没有空格
     * </p>
     * .
     *
     * @return 时间string
     */
    public static String haveCurrentTime() {
        final long CURRENTTIME = System.currentTimeMillis();
        final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyyMMddHHmmssS");
        final Date DATE = new Date(CURRENTTIME);
        final String TIME = FORMATTER.format(DATE);
        return TIME;
    }

    /**
     * <p>
     * Description: 在需要提取文件名并将之插入时的方法
     * </p>
     * .
     *
     * @param outList
     *            输出数据
     * @param filepath
     *            带文件名的路径
     * @return 输出数据
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static List<String> addValueFileName(List<String> outList, String filepath) throws IOException {
        final String PATH1 = filepath.substring(0, filepath.lastIndexOf("_")); // 根据“_”之前的位置来获取文件名
        final String PATH = PATH1.substring(PATH1.lastIndexOf(File.separator) + 1).toUpperCase();
        outList.add(PATH);
        return outList;
    }

    /**
     * 根据文件路径读取列所在位置
     *
     * @param tempPath
     *            excel路径
     * @param columns
     *            列名数组
     * @return Map<String,Integer> key为列名,value为列在excel中的第几列
     * @throws IOException
     */
    public static Map<String, Integer> readLocation(String tempPath, String... columns) throws IOException {
        Map<String, Integer> locationMap = new HashMap<String, Integer>();
        for (String column : columns) {
            int location = ExcelPublic.findTheWord(tempPath, column);
            locationMap.put(column, location);
        }
        return locationMap;
    }
}

junit测试类

package com.alphajuns.junit;

import com.alphajuns.ssm.util.ExcelPublic;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @ClassName ExcelTest
 * @Description TODO
 * @Author AlphaJunS
 * @Date 2020/4/18 22:24
 * @Version 1.0
 */
public class ExcelTest extends SuperJunitTest {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Test
    public void readExcel() {
        String result = null;
        String filePath = "C:\\TempFile\\temp\\导入商品信息.xlsx";
        File file = new File(filePath);
        try {
            // 判断第一行是否有值
            if (ExcelPublic.checkArray(filePath)) {
                // 读取第一行
                List<String> firstLine = new ArrayList<>();
                firstLine = ExcelPublic.readExcelFirstline(filePath);
                // 读取excel文件中的所有内容
                String[][] content = ExcelPublic.dyadicArray(filePath, 1, 0);
                // 存放需要插入的数据的位置
                Map<String, Integer> locationMap = new HashMap<String, Integer>(); // 存放需要插入的数据的位置
                String[] finalFieldArr = { "商品ID", "商品标题", "商品卖点", "商品价格"};
                // 读取标题字段及其所在列位置
                locationMap = readLocation(filePath, finalFieldArr);
                if (locationMap.containsValue(-1)) {
                    result = "表头不正确,正确表头为:" + Arrays.asList(finalFieldArr);
                    throw new Exception(result);
                }
                // 模拟调用service方法
                result = serviceHandleMethod(firstLine, content, locationMap);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @Description 模拟service层方法
     * @param firstLine
     * @param content
     * @param locationMap
     * @return java.lang.String
     */
    private String serviceHandleMethod(List<String> firstLine, String[][] content, Map<String, Integer> locationMap) {
        // 保存指定字段,可用于检查数据库中是否已经存在,检验导入数据该字段是否重复等
        List<String> itemIdList = new ArrayList<>();
        // map中保存了所有excel中的数据,不含表头字段
        Map<String, String[]> itemMap = new HashMap<>();
        // excel中content下表从1开始到末尾
        for (int i = 1; i < content.length; i++) {
            // 获取指定列的的值
            String itemId = content[i][locationMap.get("商品ID")];
            // 以指定列为键,该行数据作为值保存在map中
            itemMap.put(itemId, content[i]);
            itemIdList.add(itemId);
        }
        
        // 校验数据库是否已经存在,校验重复等操作
        
        // 批量操作,插入数据库等,可采用spring JdbcTemplate的批量更新操作
        // 生成时间
        String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        // sql
        String sql = "insert into tb_item (id, title, sell_point, price, num , cid, status, created, updated) values(?, ?, ?, ?, 500, 560, 1, '"
                + date +"','" + date + "')";
        List<Object[]> batchArgs = new ArrayList<Object[]>();
        // 遍历,封装参数
        /*for (int i = 0; i < itemIdList.size(); i++) {
            String itemId = itemIdList.get(i);
            String[] itemArray = itemMap.get(itemId);
            Object[] batchArg = new Object[]{};
            for (int j = 0; j < itemArray.length; j++) {
                batchArg[j] = itemArray[j];
            }
            batchArgs.add(batchArg);
        }*/
        for (int i = 1; i < content.length; i++) {
            String[] itemArray = content[i];
            Object[] batchArg = new Object[itemArray.length];
            for (int j = 0; j < itemArray.length; j++) {
                batchArg[j] = itemArray[j];
            }
            batchArgs.add(batchArg);
        }
        // 执行sql
        String result = "";
        try {
            jdbcTemplate.batchUpdate(sql, batchArgs);
            result = "success";
        } catch (DataAccessException e) {
            e.printStackTrace();
        }
        
        return result;
    }
    
    /**
     * 读取字段位置
     * @param tempPath
     * @param columns
     * @return
     * @throws IOException
     */
    private Map<String,Integer> readLocation(String tempPath,String... columns) throws IOException {
        Map<String,Integer> locationMap = new HashMap<String,Integer>();
        for(String column : columns){
            int location = ExcelPublic.findTheWord(tempPath, column);
            locationMap.put(column,location);
        }
        return locationMap;
    }

}

猜你喜欢

转载自www.cnblogs.com/alphajuns/p/12729060.html