千家信息网

Java怎么实现Excel导入导出操作

发表于:2024-11-28 作者:千家信息网编辑
千家信息网最后更新 2024年11月28日,今天小编给大家分享一下Java怎么实现Excel导入导出操作的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面
千家信息网最后更新 2024年11月28日Java怎么实现Excel导入导出操作

今天小编给大家分享一下Java怎么实现Excel导入导出操作的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

1. 功能测试

1.1 测试准备

在做测试前,我们需要將【2. 环境准备】中的四个文件拷贝在工程里(如:我这里均放在了com.zyq.util.excel 包下)。

1.2 数据导入

1.2.1 导入解析为JSON

比如,我们有下面一个表格:

Controller 代码:

@PostMapping("/import")public JSONArray importUser(@RequestPart("file")MultipartFile file) throws Exception {    JSONArray array = ExcelUtils.readMultipartFile(file);    System.out.println("导入数据为:" + array);    return array;}

测试效果:

1.2.2 导入解析为对象(基础)

首先,你需要创建一个与导入表格对应的Java实体对象,并打上对应的Excel解析的导入注解,@ExcelImport注解的value则为表头名称。

Controller 代码:

@PostMapping("/import")public void importUser(@RequestPart("file")MultipartFile file) throws Exception {    List users = ExcelUtils.readMultipartFile(file, User.class);    for (User user : users) {        System.out.println(user.toString());    }}

测试效果:

1.2.3 导入解析为对象(字段自动映射)

对于有的枚举数据,通常我们导入的时候,表格中的数据是值,而在数据保存时,往往用的是键,比如:我们用sex=1可以表示为男,sex=2表示为女,那么我们通过配置也可以达到导入时,数据的自动映射。

那么,我们只需要将Java实体中的对象sex字段的类型改为对应的数字类型Integer,然后再注解中配置好 kv 属性(属性格式为:键1-值1;键2-值2;键3-值3;.....)

Cotroller 代码略(和 1.2.2 完全一致)。

测试效果:可以看到已经自动映射成功了。

1.2.4 导入解析为对象(获取行号)

我们在做页面数据导入时,有时候可能需要获取行号,好追踪导入的数据。

那么,我们只需要在对应的实体中加入一个 int 类型的 rowNum 字段即可。

Cotroller 代码略(和 1.2.2 完全一致)。

测试效果:

1.2.5 导入解析为对象(获取原始数据)

在做页面数据导入的时候,如果某行存在错误,一般我们会将原始的数据拿出来分析,为什么会造成数据错误。那么,我们在实体类中,增加一个 String 类型的 rowData 字段即可。

Cotroller 代码略(和 1.2.2 完全一致)。

测试效果:

1.2.6 导入解析为对象(获取错误提示)

当我们在导入数据的时候,如果某行数据存在,字段类型不正确,长度超过最大限制(详见1.2.7),必填字段验证(1.2.8),数据唯一性验证(1.2.9)等一些错误时候,我们可以往对象中添加一个 String 类型的 rowTips 字段,则可以直接拿到对应的错误信息。

比如,我们将表格中赵子龙的性别改为F(F并不是映射数据),将大乔的性别改为二十八(不能转换为Integer类型数据)。

Cotroller 代码略(和 1.2.2 完全一致)。

测试效果:可以看到,我们可以通过 rowTips 直接拿到对应的错误数据提示。

1.2.7 导入解析为对象(限制字段长度)

比如,我们手机通常为11为长度,那么不妨限制电话的最大长度位数为11位。

对应的做法,就是在 @ExcelImport 注解中,设置 maxLength = 11 即可。

比如,我们将诸葛孔明的电话长度设置为超过11位数的一个字符串。

Cotroller 代码略(和 1.2.2 完全一致)。

测试效果:

1.2.8 导入解析为对象(必填字段验证)

我们在做数据导入的时候,往往还会有一些必填字段,比如用户的名称,电话。

那么,我们只需要在 @ExcelImport 注解属性中,加上 required = true 即可。

我们将诸葛孔明的电话,以及第4行的姓名去掉,进行测试。

Cotroller 代码略(和 1.2.2 完全一致)。

测试效果:

1.2.9 导入解析为对象(数据唯一性验证)

(1) 单字段唯一性验证

我们在导入数据的时候,某个字段是具有唯一性的,比如我们这里假设规定姓名不能重复,那么则可以在对应字段的 @ExcelImport 注解上加上 unique = true 属性。

这里我们构建2条姓名一样的数据进行测试。

Cotroller 代码略(和 1.2.2 完全一致)。

测试效果:

(2)多字段唯一性验证

如果你导入的数据存在多字段唯一性验证这种情况,只需要将每个对应字段的 @ExcelImport 注解属性中,都加上 required = true 即可。

比如:我们将姓名和电话两个字段进行联合唯一性验证(即不能存在有名称和电话都一样的数据,单个字段属性重复允许)。

首先,我们将刚刚(1)的数据进行导入。

测试效果:可以看到,虽然名称有相同,但电话不相同,所以这里并没有提示唯一性验证错误。

现在,我们将最后一行的电话也改为和第1行一样的,于是,现在就存在了违背唯一性的两条数据。

测试效果:可以看到,我们的联合唯一性验证生效了。

1.3 数据导出

1.3.1 动态导出(基础)

这种方式十分灵活,表中的数据,完全自定义设置。

Controller 代码:

@GetMapping("/export")public void export(HttpServletResponse response) {    // 表头数据    List head = Arrays.asList("姓名","年龄","性别","头像");    // 用户1数据    List user1 = new ArrayList<>();    user1.add("诸葛亮");    user1.add(60);    user1.add("男");    user1.add("https://profile.csdnimg.cn/A/7/3/3_sunnyzyq");    // 用户2数据    List user2 = new ArrayList<>();    user2.add("大乔");    user2.add(28);    user2.add("女");    user2.add("https://profile.csdnimg.cn/6/1/9/0_m0_48717371");    // 将数据汇总    List> sheetDataList = new ArrayList<>();    sheetDataList.add(head);    sheetDataList.add(user1);    sheetDataList.add(user2);    // 导出数据    ExcelUtils.export(response,"用户表", sheetDataList);}

代码截图:

由于是 get 请求,我们直接在浏览器上输入请求地址即可触发下载。

打开下载表格,我们可以看到,表中的数据和我们代码组装的顺序一致。

1.3.2 动态导出(导出图片)

如果你的导出中,需要将对应图片链接直接显示为图片的话,那么,这里也是可以的,只需要将对应的类型转为 java.net.URL 类型即可(注意:转的时候有异常处理,为了方便演示,我这里直接抛出)

测试效果:

1.3.3 动态导出(实现下拉列表)

我们在做一些数据导出的时候,可能要对某一行的下拉数据进行约束限制。

比如,当我们下载一个导入模版的时候,我们可以将性别,城市对应的列设置为下拉选择。

测试效果:

1.3.4 动态导出(横向合并)

比如,我们将表头横向合并,只需要将合并的单元格设置为 ExcelUtils.COLUMN_MERGE 即可。

测试效果:可以看到表头的地址已经被合并了。

1.3.5 动态导出(纵向合并)

除了横向合并,我们还可以进行纵向合并,只需要将合并的单元格设置为 ExcelUtils.ROW_MERGE 即可。

测试效果:

1.3.6 导出模板(基础)

我们在做数据导入的时候,往往首先会提供一个模版供其下载,这样用户在导入的时候才知道如何去填写数据。导出模板除了可以用上面的动态导出,这里还提供了一种更加便捷的写法。只需要创建一个类,然后再对应字段上打上 @ExcelExport 注解类即可。

Controller 代码:

@GetMapping("/export")public void export(HttpServletResponse response) {    ExcelUtils.exportTemplate(response, "用户表", User.class);}

代码截图:

测试效果:

1.3.7 导出模板(附示例数据)

我们在做模版下载时候,有时往往会携带一条样本数据,好提示用户数据格式是什么,那么我们只需要在对应字段上进行配置即可。

Controller代码:

测试效果:

1.3.8 按对象导出(基础)

我们还可以通过 List 对象,对数据直接进行导出。首先,同样需要在对应类的字段上,设置导出名称。

Controller 代码:

测试效果:

1.3.9 按对象导出(数据映射)

在上面 1.3.8 的导出中,我们可以看到,性别数据导出来是1和2,这个不利于用户体验,应该需要转换为对应的中文,我们可以在字段注解上进行对应的配置。

Controller 代码略(和1.3.8完全一致)

测试效果:可以看到1和2显示为了对应的男和女

1.3.10 按对象导出(调整表头顺序)

如果你需要对表头字段进行排序,有两种方式:

第一种:按照表格的顺序,排列Java类中的字段;

第二种:在 @ExcelExport 注解中,指定 sort 属性,其值越少,排名越靠前。

Controller 代码略(和1.3.8完全一致)

测试效果:可以看到,此时导出数据的表头顺序,和我们指定的顺序完全一致。

2. 环境准备

2.1 Maven 依赖

本次工具类的封装主要依赖于阿里巴巴的JSON包,以及表格处理的POI包,所以我们需要导入这两个库的依赖包,另外,我们还需要文件上传的相关包,毕竟我们在浏览器页面,做Excel导入时,是上传的Excel文件。

    org.apache.httpcomponents    httpmime        4.5.7    com.alibaba    fastjson    1.2.41    org.apache.poi    poi-ooxml    3.16

2.2 类文件

ExcelUtils
package com.zyq.util.excel; import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Field;import java.math.BigDecimal;import java.math.RoundingMode;import java.net.URL;import java.text.NumberFormat;import java.text.SimpleDateFormat;import java.util.*;import java.util.Map.Entry; import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletResponse; import com.zyq.entity.User;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.Cell;import org.apache.poi.ss.usermodel.CellStyle;import org.apache.poi.ss.usermodel.CellType;import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;import org.apache.poi.ss.usermodel.DataValidation;import org.apache.poi.ss.usermodel.DataValidationConstraint;import org.apache.poi.ss.usermodel.DataValidationHelper;import org.apache.poi.ss.usermodel.Drawing;import org.apache.poi.ss.usermodel.FillPatternType;import org.apache.poi.ss.usermodel.HorizontalAlignment;import org.apache.poi.ss.usermodel.IndexedColors;import org.apache.poi.ss.usermodel.Row;import org.apache.poi.ss.usermodel.Sheet;import org.apache.poi.ss.usermodel.VerticalAlignment;import org.apache.poi.ss.usermodel.Workbook;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.multipart.MultipartFile; import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject; /** * Excel导入导出工具类 * * @author sunnyzyq * @date 2021/12/17 */public class ExcelUtils {     private static final String XLSX = ".xlsx";    private static final String XLS = ".xls";    public static final String ROW_MERGE = "row_merge";    public static final String COLUMN_MERGE = "column_merge";    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);    }     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)) {                field.set(t, new BigDecimal(val));            }        } catch (Exception e) {            e.printStackTrace();        }    }     private static JSONArray readExcel(MultipartFile mFile, File file) throws IOException {        boolean fileNotExist = (file == null || !file.exists());        if (mFile == null && fileNotExist) {            return new JSONArray();        }        // 解析表格数据        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 new JSONArray();        }        JSONArray array = read(book);        book.close();        in.close();        return array;    }     private static JSONArray read(Workbook book) {        // 获取 Excel 文件第一个 Sheet 页面        Sheet sheet = book.getSheetAt(0);        return readSheet(sheet);    }     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.getCellTypeEnum() == CellType.BLANK) {            return "";        }        // String类型        if (cell.getCellTypeEnum() == CellType.STRING) {            String val = cell.getStringCellValue();            if (val == null || val.trim().length() == 0) {                return "";            }            return val.trim();        }        // 数字类型        if (cell.getCellTypeEnum() == CellType.NUMERIC) {            // 科学计数法类型            return NUMBER_FORMAT.format(cell.getNumericCellValue()) + "";        }        // 布尔值类型        if (cell.getCellTypeEnum() == CellType.BOOLEAN) {            return cell.getBooleanCellValue() + "";        }        // 错误类型        return cell.getCellFormula();    }     public static  void exportTemplate(HttpServletResponse response, String fileName, Class clazz) {        exportTemplate(response, fileName, fileName, clazz, false);    }     public static  void exportTemplate(HttpServletResponse response, String fileName, String sheetName,                                          Class clazz) {        exportTemplate(response, fileName, sheetName, clazz, false);    }     public static  void exportTemplate(HttpServletResponse response, String fileName, Class clazz,                                          boolean isContainExample) {        exportTemplate(response, fileName, fileName, clazz, isContainExample);    }     public static  void exportTemplate(HttpServletResponse response, String fileName, String sheetName,                                          Class clazz, boolean isContainExample) {        // 获取表头字段        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);    }     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) {        if (file == null) {            System.out.println("文件创建失败");            return;        }        if (sheetData == null) {            sheetData = new ArrayList<>();        }        export(null, file, file.getName(), file.getName(), sheetData, null);    }     /**     * 导出表格到本地     *     * @param       导出数据类似,和K类型保持一致     * @param filePath 文件父路径(如:D:/doc/excel/)     * @param fileName 文件名称(不带尾缀,如:学生表)     * @param list     导出数据     * @throws IOException IO异常     */    public static  File exportFile(String filePath, String fileName, List list) throws IOException {        File file = getFile(filePath, fileName);        List> sheetData = getSheetData(list);        exportFile(file, sheetData);        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;                }                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 (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) {        List> sheetDataList = new ArrayList<>();        List headList = new ArrayList<>();        headList.add("导出无数据");        sheetDataList.add(headList);        export(response, fileName, sheetDataList);    }     public static void export(HttpServletResponse response, String fileName, List> sheetDataList) {        export(response, fileName, fileName, sheetDataList, null);    }     public static void export(HttpServletResponse response, String fileName, String sheetName,                              List> sheetDataList) {        export(response, fileName, sheetName, sheetDataList, null);    }     public static void export(HttpServletResponse response, String fileName, String sheetName,                              List> sheetDataList, Map> selectMap) {        export(response, null, fileName, sheetName, sheetDataList, selectMap);    }     public static  void export(HttpServletResponse response, String fileName, List list, Class template) {        // list 是否为空        boolean lisIsEmpty = list == null || list.isEmpty();        // 如果模板数据为空,且导入的数据为空,则导出空文件        if (template == null && lisIsEmpty) {            exportEmpty(response, fileName);            return;        }        // 如果 list 数据,则导出模板数据        if (lisIsEmpty) {            exportTemplate(response, fileName, template);            return;        }        // 导出数据        List> sheetDataList = getSheetData(list);        export(response, fileName, sheetDataList);    }     public static void export(HttpServletResponse response, String fileName, List> sheetDataList, Map> selectMap) {        export(response, fileName, fileName, sheetDataList, selectMap);    }     private static void export(HttpServletResponse response, File file, String fileName, String sheetName,                               List> sheetDataList, Map> selectMap) {        // 整个 Excel 表格 book 对象        SXSSFWorkbook book = new SXSSFWorkbook();        // 每个 Sheet 页        Sheet sheet = book.createSheet(sheetName);        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);        // 设置表格列宽度(默认为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);                    } else {                        // 其他行为数据行,默认白底色                        v = setCellValue(cell, o, rowStyle);                    }                }                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);        ServletOutputStream out = response.getOutputStream();        book.write(out);        out.flush();        out.close();    }     private static int setCellValue(Cell cell, Object o, CellStyle style) {        // 设置样式        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)) {                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));            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) {        if (date == null) {            return "";        }        SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);        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;        }        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();    } }
ExcelImport
package com.zyq.util.excel; import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; /** * @author sunnyzyq * @date 2021/12/17 */@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; }
ExcelExport
package com.zyq.util.excel; import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; /** * @author sunnyzyq * @date 2021/12/17 */@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 ""; }
ExcelClassField
package com.zyq.util.excel; import java.util.LinkedHashMap; /** * @author sunnyzyq * @date 2021/12/17 */public class ExcelClassField {     /** 字段名称 */    private String fieldName;     /** 表头名称 */    private String name;     /** 映射关系 */    private LinkedHashMap kvMap;     /** 示例值 */    private Object example;     /** 排序 */    private int sort;     /** 是否为注解字段:0-否,1-是 */    private int hasAnnotation;     public String getFieldName() {        return fieldName;    }     public void setFieldName(String fieldName) {        this.fieldName = fieldName;    }     public String getName() {        return name;    }     public void setName(String name) {        this.name = name;    }     public LinkedHashMap getKvMap() {        return kvMap;    }     public void setKvMap(LinkedHashMap kvMap) {        this.kvMap = kvMap;    }     public Object getExample() {        return example;    }     public void setExample(Object example) {        this.example = example;    }     public int getSort() {        return sort;    }     public void setSort(int sort) {        this.sort = sort;    }     public int getHasAnnotation() {        return hasAnnotation;    }     public void setHasAnnotation(int hasAnnotation) {        this.hasAnnotation = hasAnnotation;    } }

以上就是"Java怎么实现Excel导入导出操作"这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注行业资讯频道。

0