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依赖
 *      
 *          org.apache.poi
 *          poi
 *          4.1.1
 *      
 *      
 *          org.apache.poi
 *          poi-ooxml
 *          4.1.1
 *      
 **/
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类型
     *
     * 要求:
     *      1、excel第一行必须是标题
     *      2、excel所有单元格的格式必须是字符
     *
     * @param suffix excel文件后缀名
     * @param inputStream 文件输入流
     * @param clazz 类对象
     * @return List
     * @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;
    }
}

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

你可能感兴趣的:(Spring,excel,java,poi,反射)