• Java之POI导出Excel(一):单sheet


    相信在大部分的web项目中都会有导出导入Excel的需求,今天我们就来看看如何用Java代码去实现 用POI导出Excel表格。

    一、pom引用

    pom文件中,添加以下依赖

    查看代码
     
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poiartifactId>
                <version>5.2.2version>
                <scope>compilescope>
            dependency>
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poi-ooxmlartifactId>
                <version>5.2.2version>
                <scope>compilescope>
            dependency>

    二、工具类util

    1.ExcelClassField

    查看代码
     package com.***;
     
    import lombok.Data;
     
    import java.util.LinkedHashMap;
     
    /**
     * @description: excel字段
     * @author: ***
     * @date: 2022/6/21
     */
    @Data
    public class ExcelClassField {
        /**
         * 字段名称
         */
        private String fieldName;
     
        /**
         * 表头名称
         */
        private String name;
     
        /**
         * 映射关系
         */
        private LinkedHashMap kvMap;
     
        /**
         * 示例值
         */
        private Object example;
     
        /**
         * 排序
         */
        private int sort;
     
        /**
         * 是否为注解字段:0-否,1-是
         */
        private int hasAnnotation;
     
    }

     2.ExcelExport(导出Excel用)

    查看代码
     package com.***;
     
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    /**
     * @description: excel导出
     * @author: ***
     * @date: 2022/6/21
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExcelExport {
        /**
         * 字段名称
         */
        String value();
     
        /**
         * 导出排序先后: 数字越小越靠前(默认按Java类字段顺序导出)
         */
        int sort() default 0;
     
        /**
         * 导出映射,格式如:0-未知;1-男;2-女
         */
        String kv() default "";
     
        /**
         * 导出模板示例值(有值的话,直接取该值,不做映射)
         */
        String example() default "";
     
    }

    3.ExcelImport(导入Excel用)

    查看代码
     package com.***;
     
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    /**
     * @description: excel导入
     * @author: ***
     * @date: 2022/6/21
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExcelImport {
        /**
         * 字段名称
         */
        String value();
     
        /**
         * 导出映射,格式如:0-未知;1-男;2-女
         */
        String kv() default "";
     
        /**
         * 是否为必填字段(默认为非必填)
         */
        boolean required() default false;
     
        /**
         * 最大长度(默认255)
         */
        int maxLength() default 255;
     
        /**
         * 导入唯一性验证(多个字段则取联合验证)
         */
        boolean unique() default false;
     
    }

    4.ExcelUtils

    查看代码
     package com.***;
    import com.***.utils.DateUtil;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import com.***.uitl.StringUtils;
    import org.apache.poi.hssf.usermodel.HSSFDataValidation;
    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.apache.poi.ss.util.CellRangeAddressList;
    import org.apache.poi.xssf.streaming.SXSSFWorkbook;
    import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.multipart.MultipartFile;
     
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.math.BigDecimal;
    import java.math.RoundingMode;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.text.NumberFormat;
    import java.text.SimpleDateFormat;
    import java.util.*;
    import java.util.Map.Entry;
    import java.util.regex.Pattern;
     
     
    /**
     * @description: 导出报表util
     * @author: ***
     * @date: 2022/6/21
     */
    public class ExcelUtils {
        public static final String ROW_MERGE = "row_merge";
        public static final String COLUMN_MERGE = "column_merge";
        private static final String XLSX = ".xlsx";
        private static final String XLS = ".xls";
        private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
        private static final String ROW_NUM = "rowNum";
        private static final String ROW_DATA = "rowData";
        private static final String ROW_TIPS = "rowTips";
        private static final int CELL_OTHER = 0;
        private static final int CELL_ROW_MERGE = 1;
        private static final int CELL_COLUMN_MERGE = 2;
        private static final int IMG_HEIGHT = 30;
        private static final int IMG_WIDTH = 30;
        private static final char LEAN_LINE = '/';
        private static final int BYTES_DEFAULT_LENGTH = 10240;
        private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance();
     
        public static  List readFile(File file, Class clazz) throws Exception {
            JSONArray array = readFile(file);
            return getBeanList(array, clazz);
        }
     
        public static  List readMultipartFile(MultipartFile mFile, Class clazz) throws Exception {
            JSONArray array = readMultipartFile(mFile);
            return getBeanList(array, clazz);
        }
     
        public static JSONArray readFile(File file) throws Exception {
            return readExcel(null, file);
        }
     
        public static JSONArray readMultipartFile(MultipartFile mFile) throws Exception {
            return readExcel(mFile, null);
        }
     
        public static Map readFileManySheet(File file) throws Exception {
            return readExcelManySheet(null, file);
        }
     
        public static Map readFileManySheet(MultipartFile file) throws Exception {
            return readExcelManySheet(file, null);
        }
     
        private static  List getBeanList(JSONArray array, Class clazz) throws Exception {
            List list = new ArrayList<>();
            Map uniqueMap = new HashMap<>(16);
            for (int i = 0; i < array.size(); i++) {
                list.add(getBean(clazz, array.getJSONObject(i), uniqueMap));
            }
            return list;
        }
     
        /**
         * 获取每个对象的数据
         */
        private static  T getBean(Class c, JSONObject obj, Map uniqueMap) throws Exception {
            T t = c.newInstance();
            Field[] fields = c.getDeclaredFields();
            List errMsgList = new ArrayList<>();
            boolean hasRowTipsField = false;
            StringBuilder uniqueBuilder = new StringBuilder();
            int rowNum = 0;
            for (Field field : fields) {
                // 行号
                if (field.getName().equals(ROW_NUM)) {
                    rowNum = obj.getInteger(ROW_NUM);
                    field.setAccessible(true);
                    field.set(t, rowNum);
                    continue;
                }
                // 是否需要设置异常信息
                if (field.getName().equals(ROW_TIPS)) {
                    hasRowTipsField = true;
                    continue;
                }
                // 原始数据
                if (field.getName().equals(ROW_DATA)) {
                    field.setAccessible(true);
                    field.set(t, obj.toString());
                    continue;
                }
                // 设置对应属性值
                setFieldValue(t, field, obj, uniqueBuilder, errMsgList);
            }
            // 数据唯一性校验
            if (uniqueBuilder.length() > 0) {
                if (uniqueMap.containsValue(uniqueBuilder.toString())) {
                    Set rowNumKeys = uniqueMap.keySet();
                    for (Integer num : rowNumKeys) {
                        if (uniqueMap.get(num).equals(uniqueBuilder.toString())) {
                            errMsgList.add(String.format("数据唯一性校验失败,(%s)与第%s行重复)", uniqueBuilder, num));
                        }
                    }
                } else {
                    uniqueMap.put(rowNum, uniqueBuilder.toString());
                }
            }
            // 失败处理
            if (errMsgList.isEmpty() && !hasRowTipsField) {
                return t;
            }
            StringBuilder sb = new StringBuilder();
            int size = errMsgList.size();
            for (int i = 0; i < size; i++) {
                if (i == size - 1) {
                    sb.append(errMsgList.get(i));
                } else {
                    sb.append(errMsgList.get(i)).append(";");
                }
            }
            // 设置错误信息
            for (Field field : fields) {
                if (field.getName().equals(ROW_TIPS)) {
                    field.setAccessible(true);
                    field.set(t, sb.toString());
                }
            }
            return t;
        }
     
        private static  void setFieldValue(T t, Field field, JSONObject obj, StringBuilder uniqueBuilder, List errMsgList) {
            // 获取 ExcelImport 注解属性
            ExcelImport annotation = field.getAnnotation(ExcelImport.class);
            if (annotation == null) {
                return;
            }
            String cname = annotation.value();
            if (cname.trim().length() == 0) {
                return;
            }
            // 获取具体值
            String val = null;
            if (obj.containsKey(cname)) {
                val = getString(obj.getString(cname));
            }
            if (val == null) {
                return;
            }
            field.setAccessible(true);
            // 判断是否必填
            boolean require = annotation.required();
            if (require && val.isEmpty()) {
                errMsgList.add(String.format("[%s]不能为空", cname));
                return;
            }
            // 数据唯一性获取
            boolean unique = annotation.unique();
            if (unique) {
                if (uniqueBuilder.length() > 0) {
                    uniqueBuilder.append("--").append(val);
                } else {
                    uniqueBuilder.append(val);
                }
            }
            // 判断是否超过最大长度
            int maxLength = annotation.maxLength();
            if (maxLength > 0 && val.length() > maxLength) {
                errMsgList.add(String.format("[%s]长度不能超过%s个字符(当前%s个字符)", cname, maxLength, val.length()));
            }
            // 判断当前属性是否有映射关系
            LinkedHashMap kvMap = getKvMap(annotation.kv());
            if (!kvMap.isEmpty()) {
                boolean isMatch = false;
                for (String key : kvMap.keySet()) {
                    if (kvMap.get(key).equals(val)) {
                        val = key;
                        isMatch = true;
                        break;
                    }
                }
                if (!isMatch) {
                    errMsgList.add(String.format("[%s]的值不正确(当前值为%s)", cname, val));
                    return;
                }
            }
            // 其余情况根据类型赋值
            String fieldClassName = field.getType().getSimpleName();
            try {
                if ("String".equalsIgnoreCase(fieldClassName)) {
                    field.set(t, val);
                } else if ("boolean".equalsIgnoreCase(fieldClassName)) {
                    field.set(t, Boolean.valueOf(val));
                } else if ("int".equalsIgnoreCase(fieldClassName) || "Integer".equals(fieldClassName)) {
                    try {
                        field.set(t, Integer.valueOf(val));
                    } catch (NumberFormatException e) {
                        errMsgList.add(String.format("[%s]的值格式不正确(当前值为%s)", cname, val));
                    }
                } else if ("double".equalsIgnoreCase(fieldClassName)) {
                    field.set(t, Double.valueOf(val));
                } else if ("long".equalsIgnoreCase(fieldClassName)) {
                    field.set(t, Long.valueOf(val));
                } else if ("BigDecimal".equalsIgnoreCase(fieldClassName)) {
                    if (StringUtils.isEmpty(val)) {
                        field.set(t, new BigDecimal(0));
                    } else {
                        field.set(t, new BigDecimal(val));
                    }
                } else if ("Date".equalsIgnoreCase(fieldClassName)) {
                    field.set(t, DateUtil.getDate(val, DateUtil.YYYYMMDDHHMMSS));
                } else {
                    field.set(t, val);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
     
        private static Map readExcelManySheet(MultipartFile mFile, File file) throws IOException {
            Workbook book = getWorkbook(mFile, file);
            if (book == null) {
                return Collections.emptyMap();
            }
            Map map = new LinkedHashMap<>();
            for (int i = 0; i < book.getNumberOfSheets(); i++) {
                Sheet sheet = book.getSheetAt(i);
                JSONArray arr = readSheet(sheet);
                map.put(sheet.getSheetName(), arr);
            }
            book.close();
            return map;
        }
     
        private static JSONArray readExcel(MultipartFile mFile, File file) throws IOException {
            Workbook book = getWorkbook(mFile, file);
            if (book == null) {
                return new JSONArray();
            }
            JSONArray array = readSheet(book.getSheetAt(0));
            book.close();
            return array;
        }
     
        private static Workbook getWorkbook(MultipartFile mFile, File file) throws IOException {
            boolean fileNotExist = (file == null || !file.exists());
            if (mFile == null && fileNotExist) {
                return null;
            }
            // 解析表格数据
            InputStream in;
            String fileName;
            if (mFile != null) {
                // 上传文件解析
                in = mFile.getInputStream();
                fileName = getString(mFile.getOriginalFilename()).toLowerCase();
            } else {
                // 本地文件解析
                in = new FileInputStream(file);
                fileName = file.getName().toLowerCase();
            }
            Workbook book;
            if (fileName.endsWith(XLSX)) {
                book = new XSSFWorkbook(in);
            } else if (fileName.endsWith(XLS)) {
                POIFSFileSystem poifsFileSystem = new POIFSFileSystem(in);
                book = new HSSFWorkbook(poifsFileSystem);
            } else {
                return null;
            }
            in.close();
            return book;
        }
     
        private static JSONArray readSheet(Sheet sheet) {
            // 首行下标
            int rowStart = sheet.getFirstRowNum();
            // 尾行下标
            int rowEnd = sheet.getLastRowNum();
            // 获取表头行
            Row headRow = sheet.getRow(rowStart);
            if (headRow == null) {
                return new JSONArray();
            }
            int cellStart = headRow.getFirstCellNum();
            int cellEnd = headRow.getLastCellNum();
            Map keyMap = new HashMap<>();
            for (int j = cellStart; j < cellEnd; j++) {
                // 获取表头数据
                String val = getCellValue(headRow.getCell(j));
                if (val != null && val.trim().length() != 0) {
                    keyMap.put(j, val);
                }
            }
            // 如果表头没有数据则不进行解析
            if (keyMap.isEmpty()) {
                return (JSONArray) Collections.emptyList();
            }
            // 获取每行JSON对象的值
            JSONArray array = new JSONArray();
            // 如果首行与尾行相同,表明只有一行,返回表头数据
            if (rowStart == rowEnd) {
                JSONObject obj = new JSONObject();
                // 添加行号
                obj.put(ROW_NUM, 1);
                for (int i : keyMap.keySet()) {
                    obj.put(keyMap.get(i), "");
                }
                array.add(obj);
                return array;
            }
            for (int i = rowStart + 1; i <= rowEnd; i++) {
                Row eachRow = sheet.getRow(i);
                JSONObject obj = new JSONObject();
                // 添加行号
                obj.put(ROW_NUM, i + 1);
                StringBuilder sb = new StringBuilder();
                for (int k = cellStart; k < cellEnd; k++) {
                    if (eachRow != null) {
                        String val = getCellValue(eachRow.getCell(k));
                        // 所有数据添加到里面,用于判断该行是否为空
                        sb.append(val);
                        obj.put(keyMap.get(k), val);
                    }
                }
                if (sb.length() > 0) {
                    array.add(obj);
                }
            }
            return array;
        }
     
        private static String getCellValue(Cell cell) {
            // 空白或空
            if (cell == null || cell.getCellType() == CellType.BLANK) {
                return "";
            }
            // String类型
            if (cell.getCellType() == CellType.STRING) {
                String val = cell.getStringCellValue();
                if (val == null || val.trim().length() == 0) {
                    return "";
                }
                return val.trim();
            }
            // 数字类型
            if (cell.getCellType() == CellType.NUMERIC) {
                String s = cell.getNumericCellValue() + "";
                // 去掉尾巴上的小数点0
                if (Pattern.matches(".*\\.0*", s)) {
                    return s.split("\\.")[0];
                } else {
                    return s.trim();
                }
            }
            // 布尔值类型
            if (cell.getCellType() == CellType.BOOLEAN) {
                return cell.getBooleanCellValue() + "";
            }
            // 错误类型
            return cell.getCellFormula();
        }
     
        public static  void exportTemplate(HttpServletResponse response, String fileName, Class clazz, String dateFormat) {
            exportTemplate(response, fileName, fileName, clazz, false, dateFormat);
        }
     
        public static  void exportTemplate(HttpServletResponse response, String fileName, String sheetName,
                                              Class clazz, String dateFormat) {
            exportTemplate(response, fileName, sheetName, clazz, false, dateFormat);
        }
     
        public static  void exportTemplate(HttpServletResponse response, String fileName, Class clazz,
                                              boolean isContainExample, String dateFormat) {
            exportTemplate(response, fileName, fileName, clazz, isContainExample, dateFormat);
        }
     
        public static  void exportTemplate(HttpServletResponse response, String fileName, String sheetName,
                                              Class clazz, boolean isContainExample, String dateFormat) {
            // 获取表头字段
            List headFieldList = getExcelClassFieldList(clazz);
            // 获取表头数据和示例数据
            List> sheetDataList = new ArrayList<>();
            List headList = new ArrayList<>();
            List exampleList = new ArrayList<>();
            Map> selectMap = new LinkedHashMap<>();
            for (int i = 0; i < headFieldList.size(); i++) {
                ExcelClassField each = headFieldList.get(i);
                headList.add(each.getName());
                exampleList.add(each.getExample());
                LinkedHashMap kvMap = each.getKvMap();
                if (kvMap != null && kvMap.size() > 0) {
                    selectMap.put(i, new ArrayList<>(kvMap.values()));
                }
            }
            sheetDataList.add(headList);
            if (isContainExample) {
                sheetDataList.add(exampleList);
            }
            // 导出数据
            export(response, fileName, sheetName, sheetDataList, selectMap, dateFormat);
        }
     
        private static  List getExcelClassFieldList(Class clazz) {
            // 解析所有字段
            Field[] fields = clazz.getDeclaredFields();
            boolean hasExportAnnotation = false;
            Map> map = new LinkedHashMap<>();
            List sortList = new ArrayList<>();
            for (Field field : fields) {
                ExcelClassField cf = getExcelClassField(field);
                if (cf.getHasAnnotation() == 1) {
                    hasExportAnnotation = true;
                }
                int sort = cf.getSort();
                if (map.containsKey(sort)) {
                    map.get(sort).add(cf);
                } else {
                    List list = new ArrayList<>();
                    list.add(cf);
                    sortList.add(sort);
                    map.put(sort, list);
                }
            }
            Collections.sort(sortList);
            // 获取表头
            List headFieldList = new ArrayList<>();
            if (hasExportAnnotation) {
                for (Integer sort : sortList) {
                    for (ExcelClassField cf : map.get(sort)) {
                        if (cf.getHasAnnotation() == 1) {
                            headFieldList.add(cf);
                        }
                    }
                }
            } else {
                headFieldList.addAll(map.get(0));
            }
            return headFieldList;
        }
     
        private static  ExcelClassField getExcelClassField(Field field) {
            ExcelClassField cf = new ExcelClassField();
            String fieldName = field.getName();
            cf.setFieldName(fieldName);
            ExcelExport annotation = field.getAnnotation(ExcelExport.class);
            // 无 ExcelExport 注解情况
            if (annotation == null) {
                cf.setHasAnnotation(0);
                cf.setName(fieldName);
                cf.setSort(0);
                return cf;
            }
            // 有 ExcelExport 注解情况
            cf.setHasAnnotation(1);
            cf.setName(annotation.value());
            String example = getString(annotation.example());
            if (!example.isEmpty()) {
                if (isNumeric(example)) {
                    cf.setExample(Double.valueOf(example));
                } else {
                    cf.setExample(example);
                }
            } else {
                cf.setExample("");
            }
            cf.setSort(annotation.sort());
            // 解析映射
            String kv = getString(annotation.kv());
            cf.setKvMap(getKvMap(kv));
            return cf;
        }
     
        private static LinkedHashMap getKvMap(String kv) {
            LinkedHashMap kvMap = new LinkedHashMap<>();
            if (kv.isEmpty()) {
                return kvMap;
            }
            String[] kvs = kv.split(";");
            if (kvs.length == 0) {
                return kvMap;
            }
            for (String each : kvs) {
                String[] eachKv = getString(each).split("-");
                if (eachKv.length != 2) {
                    continue;
                }
                String k = eachKv[0];
                String v = eachKv[1];
                if (k.isEmpty() || v.isEmpty()) {
                    continue;
                }
                kvMap.put(k, v);
            }
            return kvMap;
        }
     
        /**
         * 导出表格到本地
         *
         * @param file      本地文件对象
         * @param sheetData 导出数据
         */
        public static void exportFile(File file, List> sheetData, String dateFormat) {
            if (file == null) {
                System.out.println("文件创建失败");
                return;
            }
            if (sheetData == null) {
                sheetData = new ArrayList<>();
            }
            Map>> map = new HashMap<>();
            map.put(file.getName(), sheetData);
            export(null, file, file.getName(), map, null, dateFormat);
        }
     
        /**
         * 导出表格到本地
         *
         * @param       导出数据类似,和K类型保持一致
         * @param filePath 文件父路径(如:D:/doc/excel/)
         * @param fileName 文件名称(不带尾缀,如:学生表)
         * @param list     导出数据
         * @throws IOException IO异常
         */
        public static  File exportFile(String filePath, String fileName, List list, String dateFormat) throws IOException {
            File file = getFile(filePath, fileName);
            List> sheetData = getSheetData(list);
            exportFile(file, sheetData, dateFormat);
            return file;
        }
     
        /**
         * 获取文件
         *
         * @param filePath filePath 文件父路径(如:D:/doc/excel/)
         * @param fileName 文件名称(不带尾缀,如:用户表)
         * @return 本地File文件对象
         */
        private static File getFile(String filePath, String fileName) throws IOException {
            String dirPath = getString(filePath);
            String fileFullPath;
            if (dirPath.isEmpty()) {
                fileFullPath = fileName;
            } else {
                // 判定文件夹是否存在,如果不存在,则级联创建
                File dirFile = new File(dirPath);
                if (!dirFile.exists()) {
                    dirFile.mkdirs();
                }
                // 获取文件夹全名
                if (dirPath.endsWith(String.valueOf(LEAN_LINE))) {
                    fileFullPath = dirPath + fileName + XLSX;
                } else {
                    fileFullPath = dirPath + LEAN_LINE + fileName + XLSX;
                }
            }
            System.out.println(fileFullPath);
            File file = new File(fileFullPath);
            if (!file.exists()) {
                file.createNewFile();
            }
            return file;
        }
     
        private static  List> getSheetData(List list) {
            // 获取表头字段
            List excelClassFieldList = getExcelClassFieldList(list.get(0).getClass());
            List headFieldList = new ArrayList<>();
            List headList = new ArrayList<>();
            Map headFieldMap = new HashMap<>();
            for (ExcelClassField each : excelClassFieldList) {
                String fieldName = each.getFieldName();
                headFieldList.add(fieldName);
                headFieldMap.put(fieldName, each);
                headList.add(each.getName());
            }
            // 添加表头名称
            List> sheetDataList = new ArrayList<>();
            sheetDataList.add(headList);
            // 获取表数据
            for (T t : list) {
                Map fieldDataMap = getFieldDataMap(t);
                Set fieldDataKeys = fieldDataMap.keySet();
                List rowList = new ArrayList<>();
                for (String headField : headFieldList) {
                    if (!fieldDataKeys.contains(headField)) {
                        continue;
                    }
                    Object data = fieldDataMap.get(headField);
                    if (data == null) {
                        rowList.add("");
                        continue;
                    }
                    // 超防止过11位的数字自动转换为科学计数法
                    String string = data.toString();
                    if (isNumeric(string) && string.length() > 11) {
                        data = new BigDecimal(string).toPlainString();
                    }
     
                    ExcelClassField cf = headFieldMap.get(headField);
                    // 判断是否有映射关系
                    LinkedHashMap kvMap = cf.getKvMap();
                    if (kvMap == null || kvMap.isEmpty()) {
                        rowList.add(data);
                        continue;
                    }
                    String val = kvMap.get(data.toString());
                    if (val == null) {
                        rowList.add(data);
                        continue;
                    }
                    if (isNumeric(val)) {
                        rowList.add(Double.valueOf(val));
                    } else {
                        rowList.add(val);
                    }
                }
                sheetDataList.add(rowList);
            }
            return sheetDataList;
        }
     
        private static  Map getFieldDataMap(T t) {
            Map map = new HashMap<>();
            Field[] fields = t.getClass().getDeclaredFields();
            try {
                for (Field field : fields) {
                    String fieldName = field.getName();
                    field.setAccessible(true);
                    Object object = field.get(t);
                    map.put(fieldName, object);
                }
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
            }
            return map;
        }
     
        public static void exportEmpty(HttpServletResponse response, String fileName, String dateFormat) {
            List> sheetDataList = new ArrayList<>();
            List headList = new ArrayList<>();
            headList.add("导出无数据");
            sheetDataList.add(headList);
            export(response, fileName, sheetDataList, dateFormat);
        }
     
        public static void export(HttpServletResponse response, String fileName, List> sheetDataList, String dateFormat) {
            export(response, fileName, fileName, sheetDataList, null, dateFormat);
        }
     
        public static void exportManySheet(HttpServletResponse response, String fileName, Map>> sheetMap, String dateFormat) {
            export(response, null, fileName, sheetMap, null, dateFormat);
        }
     
     
        public static void export(HttpServletResponse response, String fileName, String sheetName,
                                  List> sheetDataList, String dateFormat) {
            export(response, fileName, sheetName, sheetDataList, null, dateFormat);
        }
     
        public static void export(HttpServletResponse response, String fileName, String sheetName,
                                  List> sheetDataList, Map> selectMap, String dateFormat) {
     
            Map>> map = new HashMap<>();
            map.put(sheetName, sheetDataList);
            export(response, null, fileName, map, selectMap, dateFormat);
        }
     
        public static  void export(HttpServletResponse response, String fileName, List list, Class template) {
            String dateFormat = DATE_FORMAT;
            // list 是否为空
            boolean lisIsEmpty = list == null || list.isEmpty();
            // 如果模板数据为空,且导入的数据为空,则导出空文件
            if (template == null && lisIsEmpty) {
                exportEmpty(response, fileName, dateFormat);
                return;
            }
            // 如果 list 数据,则导出模板数据
            if (lisIsEmpty) {
                exportTemplate(response, fileName, template, dateFormat);
                return;
            }
            // 导出数据
            List> sheetDataList = getSheetData(list);
            export(response, fileName, sheetDataList, dateFormat);
        }
     
        public static  void export(HttpServletResponse response, String fileName, List list, Class template, String dateFormat) {
            // list 是否为空
            boolean lisIsEmpty = list == null || list.isEmpty();
            // 如果模板数据为空,且导入的数据为空,则导出空文件
            if (template == null && lisIsEmpty) {
                exportEmpty(response, fileName, dateFormat);
                return;
            }
            // 如果 list 数据,则导出模板数据
            if (lisIsEmpty) {
                exportTemplate(response, fileName, template, dateFormat);
                return;
            }
            // 导出数据
            List> sheetDataList = getSheetData(list);
            export(response, fileName, sheetDataList, dateFormat);
        }
     
        public static void export(HttpServletResponse response, String fileName, List> sheetDataList, Map> selectMap, String dateFormat) {
            export(response, fileName, fileName, sheetDataList, selectMap, dateFormat);
        }
     
        private static void export(HttpServletResponse response, File file, String fileName,
                                   Map>> sheetMap, Map> selectMap, String dateFormat) {
            // 整个 Excel 表格 book 对象
            SXSSFWorkbook book = new SXSSFWorkbook();
            // 每个 Sheet 页
            Set>>> entries = sheetMap.entrySet();
            for (Entry>> entry : entries) {
                List> sheetDataList = entry.getValue();
                Sheet sheet = book.createSheet(entry.getKey());
                Drawing patriarch = sheet.createDrawingPatriarch();
                // 设置表头背景色(灰色)
                CellStyle headStyle = book.createCellStyle();
                headStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.index);
                headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                headStyle.setAlignment(HorizontalAlignment.CENTER);
                headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index);
                // 设置表身背景色(默认色)
                CellStyle rowStyle = book.createCellStyle();
                rowStyle.setAlignment(HorizontalAlignment.CENTER);
                rowStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                //创建一个DataFormat对象
                DataFormat format = book.createDataFormat();
                rowStyle.setDataFormat(format.getFormat("@"));
                // 设置表格列宽度(默认为15个字节)
                sheet.setDefaultColumnWidth(15);
                // 创建合并算法数组
                int rowLength = sheetDataList.size();
                int columnLength = sheetDataList.get(0).size();
                int[][] mergeArray = new int[rowLength][columnLength];
                for (int i = 0; i < sheetDataList.size(); i++) {
                    // 每个 Sheet 页中的行数据
                    Row row = sheet.createRow(i);
                    List rowList = sheetDataList.get(i);
                    for (int j = 0; j < rowList.size(); j++) {
                        // 每个行数据中的单元格数据
                        Object o = rowList.get(j);
                        int v = 0;
                        if (o instanceof URL) {
                            // 如果要导出图片的话, 链接需要传递 URL 对象
                            setCellPicture(book, row, patriarch, i, j, (URL) o);
                        } else {
                            Cell cell = row.createCell(j);
                            if (i == 0) {
                                // 第一行为表头行,采用灰色底背景
                                v = setCellValue(cell, o, headStyle, dateFormat);
                            } else {
                                // 其他行为数据行,默认白底色
                                v = setCellValue(cell, o, rowStyle, dateFormat);
                            }
                        }
                        mergeArray[i][j] = v;
                    }
                }
                // 合并单元格
                mergeCells(sheet, mergeArray);
                // 设置下拉列表
                setSelect(sheet, selectMap);
            }
            // 写数据
            if (response != null) {
                // 前端导出
                try {
                    write(response, book, fileName);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                // 本地导出
                FileOutputStream fos;
                try {
                    fos = new FileOutputStream(file);
                    ByteArrayOutputStream ops = new ByteArrayOutputStream();
                    book.write(ops);
                    fos.write(ops.toByteArray());
                    fos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
     
        /**
         * 合并当前Sheet页的单元格
         *
         * @param sheet      当前 sheet 页
         * @param mergeArray 合并单元格算法
         */
        private static void mergeCells(Sheet sheet, int[][] mergeArray) {
            // 横向合并
            for (int x = 0; x < mergeArray.length; x++) {
                int[] arr = mergeArray[x];
                boolean merge = false;
                int y1 = 0;
                int y2 = 0;
                for (int y = 0; y < arr.length; y++) {
                    int value = arr[y];
                    if (value == CELL_COLUMN_MERGE) {
                        if (!merge) {
                            y1 = y;
                        }
                        y2 = y;
                        merge = true;
                    } else {
                        merge = false;
                        if (y1 > 0) {
                            sheet.addMergedRegion(new CellRangeAddress(x, x, (y1 - 1), y2));
                        }
                        y1 = 0;
                        y2 = 0;
                    }
                }
                if (y1 > 0) {
                    sheet.addMergedRegion(new CellRangeAddress(x, x, (y1 - 1), y2));
                }
            }
            // 纵向合并
            int xLen = mergeArray.length;
            int yLen = mergeArray[0].length;
            for (int y = 0; y < yLen; y++) {
                boolean merge = false;
                int x1 = 0;
                int x2 = 0;
                for (int x = 0; x < xLen; x++) {
                    int value = mergeArray[x][y];
                    if (value == CELL_ROW_MERGE) {
                        if (!merge) {
                            x1 = x;
                        }
                        x2 = x;
                        merge = true;
                    } else {
                        merge = false;
                        if (x1 > 0) {
                            sheet.addMergedRegion(new CellRangeAddress((x1 - 1), x2, y, y));
                        }
                        x1 = 0;
                        x2 = 0;
                    }
                }
                if (x1 > 0) {
                    sheet.addMergedRegion(new CellRangeAddress((x1 - 1), x2, y, y));
                }
            }
        }
     
        private static void write(HttpServletResponse response, SXSSFWorkbook book, String fileName) throws IOException {
            /*response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String name = new String(fileName.getBytes("GBK"), "ISO8859_1") + XLSX;
            response.addHeader("Content-Disposition", "attachment;filename=" + name);*/
            /*String formFileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\";", formFileName));
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("UTF-8");*/
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            assert attributes != null;
            HttpServletRequest request = attributes.getRequest();
            response.setContentType("multipart/form-data;charset=UTF-8");
            String userAgent = request.getHeader("USER-AGENT");
            try {
                if (userAgent.contains("MSIE") || userAgent.contains("Edge")) {// IE浏览器
                    fileName = URLEncoder.encode(fileName, "UTF8");
                } else if (userAgent.contains("Mozilla")) {// google,火狐浏览器
                    fileName = new String(fileName.getBytes(), "ISO8859-1");
                } else {
                    fileName = URLEncoder.encode(fileName, "UTF8");// 其他浏览器
                }
                response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            ServletOutputStream out = response.getOutputStream();
            book.write(out);
            out.flush();
            out.close();
        }
     
        private static int setCellValue(Cell cell, Object o, CellStyle style, String dateFormat) {
            // 设置样式
            cell.setCellStyle(style);
            // 数据为空时
            if (o == null) {
                cell.setCellType(CellType.STRING);
                cell.setCellValue("");
                return CELL_OTHER;
            }
            // 是否为字符串
            if (o instanceof String) {
                String s = o.toString();
                if (isNumeric(s)) {
                    if (s.length() > 11) {
                        cell.setCellType(CellType.STRING);
                        cell.setCellValue(s);
                        return CELL_OTHER;
                    } else {
                        cell.setCellType(CellType.NUMERIC);
                        cell.setCellValue(Double.parseDouble(s));
                        return CELL_OTHER;
                    }
                } else {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(s);
                }
                if (s.equals(ROW_MERGE)) {
                    return CELL_ROW_MERGE;
                } else if (s.equals(COLUMN_MERGE)) {
                    return CELL_COLUMN_MERGE;
                } else {
                    return CELL_OTHER;
                }
            }
            // 是否为字符串
            if (o instanceof Integer || o instanceof Long || o instanceof Double || o instanceof Float) {
                cell.setCellType(CellType.NUMERIC);
                cell.setCellValue(Double.parseDouble(o.toString()));
                return CELL_OTHER;
            }
            // 是否为Boolean
            if (o instanceof Boolean) {
                cell.setCellType(CellType.BOOLEAN);
                cell.setCellValue((Boolean) o);
                return CELL_OTHER;
            }
            // 如果是BigDecimal,则默认3位小数
            if (o instanceof BigDecimal) {
                cell.setCellType(CellType.NUMERIC);
                cell.setCellValue(((BigDecimal) o).setScale(3, RoundingMode.HALF_UP).doubleValue());
                return CELL_OTHER;
            }
            // 如果是Date数据,则显示格式化数据
            if (o instanceof Date) {
                cell.setCellType(CellType.STRING);
                cell.setCellValue(formatDate((Date) o, dateFormat));
                return CELL_OTHER;
            }
            // 如果是其他,则默认字符串类型
            cell.setCellType(CellType.STRING);
            cell.setCellValue(o.toString());
            return CELL_OTHER;
        }
     
        private static void setCellPicture(SXSSFWorkbook wb, Row sr, Drawing patriarch, int x, int y, URL url) {
            // 设置图片宽高
            sr.setHeight((short) (IMG_WIDTH * IMG_HEIGHT));
            // (jdk1.7版本try中定义流可自动关闭)
            try (InputStream is = url.openStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                byte[] buff = new byte[BYTES_DEFAULT_LENGTH];
                int rc;
                while ((rc = is.read(buff, 0, BYTES_DEFAULT_LENGTH)) > 0) {
                    outputStream.write(buff, 0, rc);
                }
                // 设置图片位置
                XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, y, x, y + 1, x + 1);
                // 设置这个,图片会自动填满单元格的长宽
                anchor.setAnchorType(AnchorType.MOVE_AND_RESIZE);
                patriarch.createPicture(anchor, wb.addPicture(outputStream.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
     
        private static String formatDate(Date date, String dateFormat) {
            if (date == null) {
                return "";
            }
            if (dateFormat == null) {
                dateFormat = DATE_FORMAT;
            }
            SimpleDateFormat format = new SimpleDateFormat(dateFormat);
            return format.format(date);
        }
     
        private static void setSelect(Sheet sheet, Map> selectMap) {
            if (selectMap == null || selectMap.isEmpty()) {
                return;
            }
            Set>> entrySet = selectMap.entrySet();
            for (Entry> entry : entrySet) {
                int y = entry.getKey();
                List list = entry.getValue();
                if (list == null || list.isEmpty()) {
                    continue;
                }
                String[] arr = new String[list.size()];
                for (int i = 0; i < list.size(); i++) {
                    arr[i] = list.get(i);
                }
                DataValidationHelper helper = sheet.getDataValidationHelper();
                CellRangeAddressList addressList = new CellRangeAddressList(1, 65000, y, y);
                DataValidationConstraint dvc = helper.createExplicitListConstraint(arr);
                DataValidation dv = helper.createValidation(dvc, addressList);
                if (dv instanceof HSSFDataValidation) {
                    dv.setSuppressDropDownArrow(false);
                } else {
                    dv.setSuppressDropDownArrow(true);
                    dv.setShowErrorBox(true);
                }
                sheet.addValidationData(dv);
            }
        }
     
        private static boolean isNumeric(String str) {
            if ("0.0".equals(str)) {
                return true;
            }
            if ("".equals(str)) {
                return false;
            }
     
            for (int i = str.length(); --i >= 0; ) {
                if (!Character.isDigit(str.charAt(i))) {
                    return false;
                }
            }
            return true;
        }
     
        private static String getString(String s) {
            if (s == null) {
                return "";
            }
            if (s.isEmpty()) {
                return s;
            }
            return s.trim();
        }
     
    }
    
    

    三、相关业务代码

    1.service层

        /*** 车运运单信息导出*/
        List exportBillInfo(List billIdList);

    2.impl实现类

            实现类里的代码,需求各位根据自己的业务场景进行改动,将需要导出的数据查询出来

    查看代码
         @Override
        public List exportBillInfo(List billIdList) {
            if (StringUtils.isEmpty(billIdList)) {
                throw new ServiceException("车辆运单ID不能为空");
            }
            BillDto billDto = new BillDto();
            billDto.setBillIdList(billIdList);
            List billList = billFacadeService.queryBillList(billDto);
            if (StringUtils.isEmpty(billList)) {
                billList = new ArrayList<>();
            }
            return InvoiceWrapper.instance.convertTo(billList);
        }

    3.controller层

            controller层的代码需要注意的是:

    1.因为导出Excel一般都是通过浏览器进行下载的,所以入参中需要加入HttpServletResponse

    2.调用封装的工具类ExcelUtils中的export方法就可以了

    查看代码
         /**
         * 车运运单信息导出
         */
        @Log
        @PostMapping("/exportBillInfo")
        public void exportBillInfo(@RequestBody @Valid BillListDto dto, HttpServletResponse response) {
            List list = invoiceFacadeService.exportBillInfo(dto.getBillIdList());
            ExcelUtils.export(response, "车运运单信息", list, ExportBillVo.class);
        }

    最终导出的Excel文件:

  • 相关阅读:
    leetcode 1921. 消灭怪物的最大数量(每日一题)
    图学习笔记
    Java获取客户端操作系统类型-HTTP请求头User-Agent
    新手小白前端学习艰辛之路
    Pinia不就是Vuex5?
    学会和自己相处
    RabbitMQ的高可用方案
    Java项目:JSP会议-会议室管理系统
    关起门来搞开源,做不了开源世界的Leader
    教你在HbuilderX上使用模拟器运行uni-app,良心教学!!!
  • 原文地址:https://www.cnblogs.com/wyj-java/p/16747200.html