Excel表的导入、导出

文章目录

  • 一、Excel表的两种导入导出方式(POI和JXL)
  • 二、使用两种不同方式的概念和Excel的关系
  • 三、实现两种不同方式的简单实例

一、Excel表的两种导入导出方式(POI和JXL)

注:网上找的资料

JXL:支持比较低版本的excel,比如Excel 95 ,97 ,2000,2003
由于Excel版本比较低,导致最大行有限制,无法导出65535以上量级的数据
对于内存,和时间的花费也比POI基于内存+磁盘的方式高。

网友技术说明
1. 读取Excel公式(可以读取Excel 97以后的公式)
2. 生成Excel数据表(格式为Excel 97)
3. 支持字体、数字、日期的格式化
4. 支持单元格的阴影操作,以及颜色操作
5. 修改已经存在的数据表
6. 是最基础的excel api
7. 小文件读取效率比较高
8. 跨平台
POI技术说明

  1. 能保持Excel里原有的宏(但不能用它写新的宏)。
  2. 不支持跨平台(主要就是Java语言)
  3. 在一些业务场景中代码相对复杂,但是API丰富,支持多种模式的读写。
  4. 支持比较新版本的excel.
  5. 读写的时候比较占内存。
  6. 读写的时候比较占内存。
  7. 支持大数量大文件的读写操作。但是需要熟悉API。

总体来说,对于简单的单表excel导入导出的需求,建议使用JXL。数据量稍微小点,占用内存少,速度快。
对于报表类的,涉及月份数据量,多表数据聚合在一起建议使用POI。

二、使用两种不同方式的概念和Excel的关系

poi的几个概念和Excel的关系

WorkBook:一个excel文件

XSSFWorkbook

SXSSFWorkbook

HSSFWorkbook


Sheet:页签,工作表,代表一个excel文件的一张表

HSSFSheet

SXSSFSheet

XSSFChartSheet

XSSFDialogsheet


Cell:一张表中的一个单元格

XSSFCell

SXSSFCell

HSSFCell


CellStyle:单元格的样式

XSSFCell:基于内存
SXSSFCell:基于内存+磁盘的写入方式
HSSFCell:高水平的写入方式,对于单元格的数据类型有很高的限制,比如:字符串格式只有字符,不能有数字


Row:excel表中的一行

HSSFRow

SXSSFRow

XSSFRow
上面的每个抽象出来的对象都被POI封装好了,声明了接口,有不同的实现方式。

jxl的几个概念和Excel的关系

三、实现两种不同方式的简单实例

Poi导入excel

实体类GoodsInfoDto

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class GoodsInfoDto {

    private static final long serialVersionUID = 1L;

    /**
     * 所属分类
     */
    private String categoryId;

    /**
     * 物品名称
     */
    private String goodsName;

    /**
     * 物品编码(手工对物品编码)
     */
    private String goodsNo;

    /**
     * 条码(物品出厂时的条形码编号)
     */
    private String barcode;

    /**
     * 单位(如:个、本等)
     */
    private String unit;

    /**
     * 规格/型号(如:30cm*40cm,A4等)
     */
    private String specification;

    /**
     * 单价(单位:分,使用时的单位是元,存储时乘以100,取出使用时除以100)
     */
    private Integer price;

    /**
     * 存储位置
     */
    private String storeLocation;

    /**
     * 品牌
     */
    private String brand;

    /**
     * 颜色
     */
    private String colour;

    /**
     * 当前库存数量
     */
    private Integer pcs;

    /**
     * 分类对象
     */
    private GoodsCategoryDto categoryDto;

    /**
     * 入库数
     */
    private Integer addNumber;

    /**
     * 价格字符串
     */
    private String priceStr;

    /**
     * 种类名称
     */
    private String categoryName;

    /**
     * 备注
     */

    // convert方法是在反射的类中的静态方法.也防止Excel中的表头
    //和反射的类的字段顺序不一致,导致数据读取在不正确的属性上
    public static String convert(String str){
        switch (str){
            case "物品分类": return  "categoryName";
            case "物品名称":  return "goodsName";
            case "物品编号":  return "goodsNo";
            case "条码":  return "barcode";
            case "单位":  return "unit";
            case "规格/型号":  return "specification";
            case "单价":  return "priceStr";
            case "品牌":  return "brand";
            case "颜色":  return "colour";
            case "当前库存数量":  return "pcs";
            case "储存位置":  return "storeLocation";
            case "备注":  return "remarks";
            default: return  str;
        }
    }
}

 导入的工具方法


import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 导入excel文件
 */
public class ReadExcel {
    private static final Logger logger = LoggerFactory.getLogger(ReadExcel.class);

    /**
     * @param file
     * @param clazz
     * @return java.util.List
     * @author 86135
     * @createTime 2021/9/7 15:27
     * @description 读取excel文件的值
     */
    public static List readExcel(MultipartFile file, Class clazz) {
        List objectList = new ArrayList<>();

        Workbook workbook = null;
        InputStream inputStream = null;

        try {
            inputStream = file.getInputStream();
            String originalFilename = file.getOriginalFilename();
            String substring = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
            //判断后缀是否为excel文件
            if (substring.equals("xls") || substring.equals("xlsx")) {
                //创建文本簿
                workbook = WorkbookFactory.create(inputStream);
            }

            //获取第一个工作表
            Sheet sheetAt = workbook.getSheetAt(0);

            //获取数据的总行数
            int lastRowNum = sheetAt.getLastRowNum();

            //获取数据的总列数
            int numberOfCells = sheetAt.getRow(0).getPhysicalNumberOfCells();

            //获取表头
            Row headRow = sheetAt.getRow(0);

            //获取反射类的所有字段
            Field[] declaredFields = getAllFields(clazz);

            //创建一个字段数组,用于和excel执行顺序一致
            Field[] fields = new Field[numberOfCells];

            //获取静态方法,该方法适用于把excel表头映射成对应的实体类属性
            Method covert = clazz.getDeclaredMethod("convert", String.class);

            T t = clazz.newInstance();

            for (int i = 0; i < numberOfCells; i++) {
                for (Field field : declaredFields) {
                    Cell cell = headRow.getCell(i);
                    //按照excel中的存储存放数组,以便后面遍历excel表格,数据一一对应.
                    if (covert.invoke(t, getXCellVal(cell)).equals(field.getName())) {
                        fields[i] = field;
                        continue;
                    }
                }
            }

            for (int x = 1; x < lastRowNum; x++) {
                T object = clazz.newInstance();
                //获得第i行对象
                Row row = sheetAt.getRow(x);
                //如果一行里的所有单元格都为空则不放进list里面
                int a = 0;
                for (int y = 0; y < numberOfCells; y++) {
                    if (!(row == null)) {
                        Cell cell = row.getCell(y);
                        if (cell == null) {
                            a++;
                        } else {
                            Field field = fields[y];
                            String value = getXCellVal(cell);
                            if (value != null && !value.equals("") && field != null) {
                                //给字段设置值.
                                setValue(field, value, object);
                            }
                        }
                    }
                }

                if (a != numberOfCells && row != null) {
                    objectList.add(object);
                }
            }

        } catch (Exception e) {
            logger.debug(e.getMessage(), e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    logger.debug(e.getMessage(), e);
                }
            }
        }
        return objectList;
    }

    /**
     * 获取本类及其父类的属性的方法
     * @param clazz 当前类对象
     * @return 字段数组
     */
    private static Field[] getAllFields(Class clazz) {
        List fieldList = new ArrayList<>();
        while (clazz != null){
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        return fieldList.toArray(fields);
    }

    /**
     * @param field
     * @param value
     * @param object
     * @return void
     * @author 86135
     * @createTime 2021/9/7 11:20
     * @description 给字段赋值,判断值的类型,然后转换成实体类需要的类型
     */
    private static void setValue(Field field, String value, Object object) {
        try {
            field.setAccessible(true);
            DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
            if (field.getGenericType().toString().contains("Integer")) {
                field.set(object, Integer.valueOf(value));
            } else if (field.getGenericType().toString().contains("String")) {
                field.set(object, value);
            } else if (field.getGenericType().toString().contains("Date")) {
                field.set(object, fmt.parse(value));
            }
            field.setAccessible(false);
        } catch (ParseException e) {
            logger.debug(e.getMessage(), e);
        } catch (IllegalAccessException e) {
            logger.debug(e.getMessage(), e);
        }
    }

    /**
     * @param cell
     * @return java.lang.String
     * @author 86135
     * @createTime 2021/9/7 11:03
     * @description 获取单元格中的值
     */
    private static String getXCellVal(Cell cell) {
        DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        DecimalFormat df = new DecimalFormat("0.0000");
        String val = "";
        switch (cell.getCellType()) {
            case XSSFCell.CELL_TYPE_NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    val = fmt.format(cell.getDateCellValue()); //日期型
                } else {
                    val = df.format(cell.getNumericCellValue()); //数字型
                    // 去掉多余的0,如最后一位是.则去掉
                    val = val.replaceAll("0+?$", "").replaceAll("[.]$", "");
                }
                break;
            case XSSFCell.CELL_TYPE_STRING: //文本类型
                val = cell.getStringCellValue();
                break;
            case XSSFCell.CELL_TYPE_BOOLEAN: //布尔型
                val = String.valueOf(cell.getBooleanCellValue());
                break;
            case XSSFCell.CELL_TYPE_BLANK: //空白
                val = cell.getStringCellValue();
                break;
            case XSSFCell.CELL_TYPE_ERROR: //错误
                val = "";
                break;
            case XSSFCell.CELL_TYPE_FORMULA: //公式
                try {
                    val = String.valueOf(cell.getStringCellValue());
                } catch (IllegalStateException e) {
                    val = String.valueOf(cell.getNumericCellValue());
                }
                break;
            default:
                val = cell.getRichStringCellValue() == null ? null : cell.getRichStringCellValue().toString();
        }
        return val;
    }
}

 在service层调用

List ts = ReadExcel.readExcel(file, GoodsInfoDto.class);

前端页面使用ajax请求传递参数




var upload = function () {
        $.ajax({
            url: "",
            data: new FormData(document.getElementById('search_form')),
            processData: false, // 告诉jquery要传输data对象
            contentType: false,   // 告诉jquery不需要增加请求头对于contentType的设置
            dataType: 'json',
            success : function(data) {
                Dialog.msg("数据上传成功");
                $("#searchlist").click();
            }
        });
    }


    // 文件上传
    $("#file").on('change', function () {
        var f = $("#file").val();
        if (f === null || f === "") {
            return Dialog.msg("上传文件不能为空")
        } else {
            var extname = f.substring(f.lastIndexOf(".") + 1, f.length);
            extname = extname.toLowerCase();//处理了大小写
            if (extname !== "xlsx" && extname !== "xls") {
                return Dialog.msg("上传的文件后缀为xlsx或者xls");
            }
        }
        upload();
    });

你可能感兴趣的:(#,java工具类,java)