SpringMVC Excel导入导出3.0升级版

本文在之前的Excel导入导出1.0版本Excel导入导出2.0版本基础上进一步改进,更新内容:
1、提供了公共的获取标题数组的方法。
2、提供了公共的获取数据总行数的方法(含标题)。
3、代码优化

package com.soft.util;

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

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Excel导入
 *
 * Maven依赖
 *      <dependency>
 *          <groupId>org.apache.poi</groupId>
 *          <artifactId>poi</artifactId>
 *          <version>4.1.1</version>
 *      </dependency>
 *      <dependency>
 *          <groupId>org.apache.poi</groupId>
 *          <artifactId>poi-ooxml</artifactId>
 *          <version>4.1.1</version>
 *      </dependency>
 **/
public class ExcelUtil {
    // Excel后缀
    public static final String SUFFIX_XLS = ".xls";
    public static final String SUFFIX_XLSX = ".xlsx";

    // 下载用:默认文件名
    private static String fileName_default = "excel_export";
    // 下载用:默认sheet名
    private static String sheetName_default = "sheet1";

    // 标题数组
    private static String[] title;
    // 数据总行数
    private static Integer rowCount;

    /**
     * 读取Excel文件的数据,可以把数据封装为List<T>类型
     *
     * 要求:
     *      1、excel第一行必须是标题
     *      2、excel所有单元格的格式必须是字符
     *
     * @param suffix excel文件后缀名
     * @param inputStream 文件输入流
     * @param clazz 类对象
     * @return List<T>
     * @throws IOException
     */
    public static <T> List<T> importExcel(String suffix, InputStream inputStream, Class<T> clazz) throws IOException,
            IllegalAccessException, InstantiationException, InvocationTargetException {

        // 判断后缀
        if(suffix == null || "".equalsIgnoreCase(suffix)){
            throw new RuntimeException("不能识别文件类型,支持.xls和.xlsx类型!");
        }

        // 判断输入流
        if(inputStream == null){
            throw new RuntimeException("文件解析失败,文件可能是空的!");
        }

        // 判断映射实体类类型
        if(clazz == null){
            throw new RuntimeException("对象映射错误!");
        }

        // Excel对象
        Workbook book = null;
        // 封装数据集合
        List<T> list = null;
        // 类对象生成的实例
        Object obj = null;

        // 2017以前版本
        if(SUFFIX_XLS.equalsIgnoreCase(suffix)){
            book = new HSSFWorkbook(inputStream);
            // 2017以后版本
        } else if(SUFFIX_XLSX.equalsIgnoreCase(suffix)){
            book = new XSSFWorkbook(inputStream);
        } else {
            throw new RuntimeException("不能识别文件类型,支持.xls和.xlsx类型!");
        }

        // 获取工作簿,默认获取第一个工作簿对象
        Sheet sheet = book.getSheetAt(0);

        // 获取工作簿共有多少行数据
        rowCount = sheet.getLastRowNum();

        // 遍历数据行,开始封装数据
        for(int i = 0; i <= rowCount; i++){
            /*
                由于要求第一行是标题,所以除了第一行不创建实体类对象以后每一行都创建
                这里利用了对象类型是值引用的特性,可以先把对象添加到List中
            */
            if(i > 0){
                obj = clazz.newInstance();
                if(list == null){
                    list = new ArrayList<T>();
                }
                list.add((T) obj);
            }

            // 获取行对象
            Row row = sheet.getRow(i);

            // 获取总有多少列数据
            short lastCellNum = row.getLastCellNum();

            // 遍历列
            for(int j = 0; j < lastCellNum; j++){
                // 单元格对象
                Cell cell = row.getCell(j);
                // 获取单元格数据
                String value = cell.getStringCellValue();

                // 第一行:标题
                if(i == 0){
                    // 存放标题
                    if(title == null){
                        title = new String[lastCellNum];
                    }
                    title[j] = value.toLowerCase();
                } else {

                    // 映射实体类set方法的集合
                    Map<String, Method> map = loadClass(clazz);

                    String methodName = "set" + title[j];
                    Method method = map.get(methodName);

                    if(method != null){
                        method.invoke(obj, value);
                    }
                }
            }
        }

        close(book, inputStream, null);
        return list;
    }


    /**
     * Excel导出,导出xlsx版本,支持2017以上版本
     * 使用默认文件名:excel_export.xlsx
     *
     * @param list 结果集合,封装实体类
     * @param clazz 实体类对象
     * @param resp  response
     * @throws IOException InvocationTargetException IllegalAccessException
     */
    public static <T> void exportExcel(List<T> list, Class<T> clazz, HttpServletResponse resp) throws IOException, InvocationTargetException, IllegalAccessException {
        exportExcel(null, list, clazz, resp);
    }

    /**
     * Excel导出,导出xlsx版本,支持2017以上版本
     * 自定义文件名
     *
     * @param fileName 文件名
     * @param list 结果集合,封装实体类
     * @param clazz 实体类对象
     * @param resp  response
     * @throws IOException InvocationTargetException IllegalAccessException
     */
    public static <T> void exportExcel(String fileName, List<T> list, Class<T> clazz, HttpServletResponse resp) throws IOException, InvocationTargetException, IllegalAccessException {

        // 判断文件名
        if(fileName == null || "".equals(fileName)){
            fileName = fileName_default;
        }

        // 创建Excel对象
        Workbook book = new XSSFWorkbook();

        // 创建工作簿
        Sheet sheet = book.createSheet(sheetName_default);

        // 获取对象中所有的公共属性
        Field[] fields = clazz.getDeclaredFields();

        // 行数
        int r = 0;

        // 遍历数据结果集
        for(int i = 0; i < list.size();){
            // 创建行对象
            Row row = sheet.createRow(r);

            // 遍历对象中的属性
            for (int j = 0; j < fields.length; j++) {
                // 获取属性名
                String fieldName = fields[j].getName().toLowerCase();
                String value = "";

                // 标题
                if(r == 0) {
                    // 标题数组
                    if (title == null) {
                        title = new String[fields.length];
                    }
                    title[j] = fieldName;

                    // 标题
                    value = fieldName;
                } else {
                    // list集合中的单个对象
                    T t = list.get(i);

                    // 获取类对象中所有公共的方法
                    Map<String, Method> map = loadClass(clazz);
                    Method method = map.get("get" + fieldName);

                    if(method != null){
                        value = (String)method.invoke(t);
                    }
                }

                // 单元格对象
                Cell cell = row.createCell(j);
                // 单元格赋值
                cell.setCellValue(value);
                // 单元格样式
                CellStyle cellStyle = book.createCellStyle();
                // 四面边框实线
                cellStyle.setBorderTop(BorderStyle.THIN);
                cellStyle.setBorderRight(BorderStyle.THIN);
                cellStyle.setBorderBottom(BorderStyle.THIN);
                cellStyle.setBorderLeft(BorderStyle.THIN);
                // 设置单元格样式
                cell.setCellStyle(cellStyle);
            }
            // 判断行数,如果行数大于1,读取的数据下标才开始累加
            if(r > 0){
                i++;
            }
            // 行累加
            r++;
        }

        // 设置响应头信息
        resp.setHeader("content-disposition","attachement;filename=" + fileName + SUFFIX_XLSX);
        // 把Excel响应到页面
        ServletOutputStream outputStream = resp.getOutputStream();
        book.write(resp.getOutputStream());
        // 释放资源
        close(book, null, outputStream);
    }

    /**
     * 释放资源
     * @param book
     * @param inputStream
     */
    private static void close(Workbook book, InputStream inputStream, OutputStream outputStream) {
        try {
            if(book != null){
                book.close();
            }

            if(inputStream != null){
                inputStream.close();
            }

            if(outputStream != null){
                outputStream.close();
            }
        } catch (IOException e) {
            throw new RuntimeException("资源释放失败!");
        }
    }

    /**
     * 解析类对象,返回set方法的Map映射集合
     * @param clazz
     * @return
     */
    private static <T> Map<String, Method> loadClass(Class<T> clazz){
        // 判断类对象是否为空
        if(clazz == null){
            throw new RuntimeException("对象映射错误!");
        }

        // 存储方法的Map集合
        Map<String, Method> map = new HashMap<String, Method>();

        // 获取类中所有的方法对象
        Method[] methods = clazz.getMethods();

        // 遍历
        for (Method method : methods) {
            String name = method.getName().toLowerCase();
            map.put(name, method);
        }

        return map;
    }

    /**
     * 获取Excel标题数组
     * @return
     */
    public static String[] getTitle() {
        return title;
    }

    /**
     * 获取Excel总数据行数
     * @return
     */
    public static Integer getRowCount() {
        return rowCount;
    }
}

更多技术分享请到个人主页查看。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值