首页 > 其他分享 >poi导入工具类

poi导入工具类

时间:2023-12-25 11:55:41浏览次数:29  
标签:return String value cell 导入 clz poi 工具 class

前言

在工作中,尤其是对于经常操作数据的项目来说,可能会经常出现操作表格的需求,因为用户需要导出数据来查看汇报信息,这时就可以通过POI进行操作。

Apache POI 是用Java编写的免费开源的跨平台的Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能,其中使用最多的就是使用POI操作Excel文件

本篇文章并不是教大家了解学习POI,而是为大家介绍一个POI的工具类,方便大家开发节省时间。

首先简单来看下是如何通过POI操作导入Excel的,代码如下:

public boolean importExcel(MultipartFile file, HttpServletRequest request) throws Exception {
    log.info("开始导入");
  	// 解析文件获得workbook
    InputStream in = file.getInputStream();
    Workbook workbook = WorkbookFactory.create(in);
  	// 解析Excel第一sheet页
    Sheet sheet = workbook.getSheetAt(0);
    // 获取totalRows数据总行数
    int totalRows = sheet.getPhysicalNumberOfRows();
    if(totalRows <= 1){
        log.info("数据为空");
        return false;
    }
    for (int i = 1; i < totalRows; i++) {
      	// 获取第i行
        Row currentRow = sheet.getRow(i);
        // 获取第1列数据的值 [注意:poi解析中下标是从0开始的,也就是说第一行和第一列的下标为0]
        String str = currentRow.getCell(0).getStringCellValue();
      	// ...
    }
    log.info("导入结束");
    return true;
}

上面是粗略的展示了POI获取Excel中数据的写法,通过上面代码发现其实在解析Excel中有很多代码我们可以提取出来作为工具类来进行使用,下面展开工具类的介绍。

POI导入

前提介绍:POI导入工具类依据Swagger的一些注解进行编写,所以不了解Swagger的可以查看我之前的文章。

1.导入依赖

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>

2.工具类代码

  • ApiModelProperty注解工具
public class ApiModelPropertyUtils {

    /**
     * 获取参数名称与ApiModelProperty注解的值的对应关系
     *
     * @param clz 类的Class类型
     * @return
     */
    public static LinkedHashMap<String, String> getApiModelPropertyValueAndFieldName(Class<?> clz) {
        return getApiModelPropertyValueAndFieldName(clz, null);
    }

    /**
     * 获取参数名称与ApiModelProperty注解的值的对应关系
     *
     * @param clz 类的Class类型
     * @param replaceMap 需要进行替换的表头元素, key是原始值,value是新值
     * @return
     */
    public static LinkedHashMap<String, String> getApiModelPropertyValueAndFieldName(Class<?> clz, HashMap<String, String> replaceMap) {
        Field[] fields = clz.getDeclaredFields();
        LinkedHashMap<String, String> map = new LinkedHashMap<>(fields.length);
        for (Field field : fields) {
            if (field == null) {
                continue;
            }
            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
            if (apiModelProperty == null) {
                continue;
            }
            String apiModelPropertyValue = apiModelProperty.value();
            if(replaceMap != null && StringUtils.isNotBlank(replaceMap.get(apiModelPropertyValue))){
                apiModelPropertyValue = replaceMap.get(apiModelPropertyValue);
            }
            map.put(apiModelPropertyValue, field.getName());
        }
        return map;
    }

    /**
     * 获取参数名称与ApiModelProperty注解的值的对应关系
     *
     * @param variableObj
     * @return
     */
    public static LinkedHashMap<String, Object> getApiModelPropertyValueAndFieldValue(Object variableObj) throws IllegalAccessException {
        Field[] fields = variableObj.getClass().getDeclaredFields();
        LinkedHashMap<String, Object> map = new LinkedHashMap<>(fields.length);
        for (Field field : fields) {
            if (field == null) {
                continue;
            }
            field.setAccessible(true);
            Object value = field.get(variableObj);
            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
            if (apiModelProperty != null) {
                map.put(apiModelProperty.value(), value);
            }
        }
        return map;
    }
}
  • 导入excel工具类
@Slf4j
public class ImpExcelUtil {

    private static final int MAX_RANGE = 20;

    /**
     * 检查文件类型
     * @param file
     * @return
     */
    private static Workbook checkFileTypeAndGetWorkBook(MultipartFile file) throws Exception {
        // 解析文件
        String suffix = Objects.requireNonNull(file.getResource().getFilename()).substring(file.getResource().getFilename().indexOf(".") + 1);
        String xls = "xls";String xlsx = "xlsx";
        Workbook workbook;
        if (xls.equals(suffix)) {
            workbook = new HSSFWorkbook(file.getInputStream());
        } else if (xlsx.equals(suffix)) {
            workbook = new XSSFWorkbook(file.getInputStream());
        } else {
            throw new RuntimeException("文件类型不正确");
        }
        return workbook;
    }

    /**
     * 拿到不同类型单元格中的值
     * 1. 字符串: 字符串
     * 2. 布尔: toString
     * 3. 数值(double): 格式化后的字符串
     * @param cell 获取的单元格
     * @return 单元格中的值
     */
    public static String getCellValue(Cell cell) {
        String resultValue = "";
        // 判空
        if (Objects.isNull(cell)) {
            return resultValue;
        }

        // 拿到单元格类型
        CellType cellType = cell.getCellType();
        switch (cellType) {
            // 字符串类型
            case STRING:
                resultValue = StringUtils.isEmpty(cell.getStringCellValue()) ? "" : cell.getStringCellValue().trim();
                break;
            // 布尔类型
            case BOOLEAN:
                resultValue = String.valueOf(cell.getBooleanCellValue());
                break;
            // 数值类型
            case NUMERIC:
                resultValue = new DecimalFormat("#.######").format(cell.getNumericCellValue());
                break;
            // 取空串
            default:
                break;
        }
        return resultValue;
    }


    /**
     * 通过excel生成数据
     *
     * @param workbook excel
     * @param sheetNum sheet页数
     * @param tClass T的class类型
     * @param map 参数名称与Excel表中的列头的对应关系
     * @param <T> 需要返回的对象类型
     * @return 需要返回的对象类型的列表
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws InvocationTargetException
     */
    public static <T> List<T> buildDataListByExcel(Workbook workbook, int sheetNum,  Class<T> tClass, Map<String, String> map) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        List<T> list = new ArrayList<>();
        Sheet sheet = workbook.getSheetAt(sheetNum);
        Map<Integer, Method> columnNumMethodNameMap = new HashMap<>(16);
        for (int i = 0; i < sheet.getPhysicalNumberOfRows(); i++) {
            // 获取工作表中的某一行,通过下标获取
            Row row = sheet.getRow(i);
            // 跳过空行
            if (row == null) { continue;}
            // 对第一行进行处理,获取参数方法与列顺序的对应
            if (i == 0) {
                for (int j = 0; j < MAX_RANGE; j++) {
                    Cell cell = row.getCell(j);
                    // 跳过空数据
                    if (cell == null) {
                        continue;
                    }
                    String cellStr = getCellValue(cell);
                    Method[] methods =  tClass.getMethods();
                    for (int m = 0; m < methods.length - 1; m++) {
                        Method method = methods[m];
                        String fieldName = map.get(cellStr);
                        // 跳过没有对应关系的列
                        if (StringUtils.isBlank(fieldName)) {
                            continue;
                        }
                        // 拼装为set方法的名称,获取set方法,如果匹配,放入
                        String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                        if (method.getName().equals(methodName)) {
                            columnNumMethodNameMap.put(j, methods[m]);
                        }
                    }
                }
                continue;
            }
            // 遍历一个行中的所有列
            T t = tClass.newInstance();
            boolean isNullFlag = false;
            for (int j = 0; j < MAX_RANGE; j++) {
                // 获取一行中的某个单元格,通过下标获取
                Cell cell = row.getCell(j);
                if (cell == null) {
                    continue;
                }
                // 获取单元格中的内容
                String value = ImpExcelUtil.getCellValue(cell);
                // 获取方法
                Method method = columnNumMethodNameMap.get(j);
                // 如果方法、方法的参数为空,直接跳过
                if (method == null || method.getParameters() == null || method.getParameters().length <= 0
                        || method.getParameters()[0] == null || StringUtils.isBlank(value)) {
                    continue;
                }
                Class<?> clz = method.getParameters()[0].getType();

                    // 对类型进行匹配,然后执行方法,进行数据插入
                    try {
                        if (BigDecimal.class.equals(clz)) {
                            method.invoke(t, new BigDecimal(value));
                        }
                    } catch (Exception e) {
                        throw new RuntimeException("传入的'"+ value +"'类型不符合,请检查!!!");
                    }
                    if (Long.class.equals(clz)) {
                        method.invoke(t, Long.parseLong(value));
                    } else if (String.class.equals(clz)) {
                        method.invoke(t, value);
                    } else if (Double.class.equals(clz)) {
                        method.invoke(t, Double.parseDouble(value));
                    } else if (Integer.class.equals(clz)) {
                        method.invoke(t, Integer.parseInt( value));
                    } else if (Boolean.class.equals(clz)) {
                        method.invoke(t, Boolean.parseBoolean(value));
                    } else {
                        continue;
                    }

                isNullFlag = true;
            }
            if (isNullFlag) {
                list.add(t);
            }
        }
        return list;
    }
}

3.使用

  • 首先创建接收的实体类,图下:
@Data
public class UserVo {

    @ApiModelProperty(value = "账号", dataType = "String")
    private String account;

    @ApiModelProperty(value = "密码", dataType = "String")
    private String userPassword;
}
  • 然后创建一个模板,如下图

注意:第一行的表头要和@ApiModelProperty中的value值相同

  • 编写导入接口及方法实现
@PostMapping("/importExcelTest")
@ResponseBody
Boolean importExcelTest(@RequestBody MultipartFile file, HttpServletRequest request) throws Exception {
    return service.importExcelTest(file, request);
}

public Boolean importExcelTest(MultipartFile file, HttpServletRequest request) throws Exception {
    //检查文件类型
    Workbook workbook = ImpExcelUtil.checkFileTypeAndGetWorkBook(file);
    //获取参数名称与ApiModelProperty注解的值的对应关系
    LinkedHashMap<String, String> map = ApiModelPropertyUtils.getApiModelPropertyValueAndFieldName(UserVo.class);
    List<UserVo> importList = ImpExcelUtil.buildDataListByExcel(workbook, 0, UserVo.class, map);
    // ...
    return true;
}
  • 通过debug查看最后获取的importList的值

通过上面的工具类可以很好的获得Excel表格中导入的数据,之后开发人员直接操作获取到的数据就可以了,很是方便。

微信搜索【君耀软件设计】了解更多

标签:return,String,value,cell,导入,clz,poi,工具,class
From: https://www.cnblogs.com/jyblogs/p/17925811.html

相关文章

  • 数据映射优秀实践:类型、方法和工具的简要指南
    在软件应用程序之间映射数据是一个耗时的过程,这需要进行深入的准备,对数据源和目标有较好的理解,并要根据方法进行实际开发。在任何应用程序集成、数据迁移以及一般的数据管理计划中,数据映射都是最关键的步骤之一。甚至可以这么认为:集成项目的成功在很大程度上取决于源数据到目标数......
  • 日期时间处理工具怎么选?看这篇就够啦!
    哈喽!大家好!我是程序视点的小二哥。一直以来,处理时间和日期的JavaScript库,选用的都是Momment.js。它的API清晰简单,使用方便灵巧,功能还特别齐全。我自己也是是Moment.js的重度使用者。凡是遇到时间和日期的操作,就把Moment.js引用上。moment.js在功能上最为丰富,但体积较大,加载的m......
  • Wireshark网络工具来了
    Wireshark是网络包分析工具。网络包分析工具的主要作用是尝试捕获网络包,并尝试显示包的尽可能详细的情况。Wireshark是一个免费开源软件,不需要付费,免费使用,可以直接登陆到Wireshark的官网下载安装。在windows环境中,Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换,这个工具......
  • 谷歌搜索引擎数据采集工具
    谷歌搜索引擎数据采集工具(“大镜山谷歌搜索数据采集器”,官网168318.com),基于谷歌搜索引擎的数据采集软件。根据用户输入的关键词,实时采集采集谷歌的搜索结果。其智能挖掘功能非常强大,采集的数据包括网站、标题、描述、邮件地址、手机或电话号码、facebook、linkin、twitter、youtube......
  • Spring 自带的常用工具包
    在SpringFramework里的spring-core包里面,有个org.springframework.util里面;另一个工具包是commons-lang3参考:https://mp.weixin.qq.com/s/ZalSIQMRXJ0edhJUaw7oxw                 ......
  • postman越来越不好用,有没有其他的替代工具?答案是postwoman(不是恶搞哦)
    chrome扩展https://chromewebstore.google.com/detail/ieoejemkppmjcdfbnfphhpbfmallhfnc?utm_source=app-launcher界面预览https://postwoman.com.cn/......
  • apache poi读取各种文件的方式以及优劣分析
     文章摘要        安卓平台上的ApachePOI库用于读取和写入MicrosoftOffice格式的文件,如Excel、Word和PowerPoint。这个库非常强大,因为它允许开发者在安卓应用程序中直接处理这些常见的文件格式。下面是对ApachePOI在安卓平台上读取不同文件的方式的分析,包括其优势和劣......
  • 9.k star,推荐一款实用ping工具
    1简介是ping,但是带图的,你见过吗?来看下今天推荐这款小工具,是用rust写的ping工具,可以在ping的同时看到响应的时间折线图。2安装github可以访问的直接到如下链接去下载就可以,目前支持windows、mac、linux等版本https://github.com/orf/gpinggithub如果无法访问的话,可以后台直......
  • 十五.JAVA.MAP.工具类,泛型
    嵌套类/内置类/内部类/内部接口K:keyV:valueE:elementR:ReturnTypeT:typeMap<K,V>:存储的是键值对。每个键值对成为映射项(Entry);键唯一,值是可重复的;每个键最多只能映射到一个值。HashMap:键采用哈希表结构,允许null键null值,线程不安全Like......
  • MySQL导入导出 —— mysqldump 简介及常见用法
    一、导出导出用户需要有导出对象的权限,例如导出表要有select权限、导出视图要有showview权限、导出触发器要有trigger权限、需要锁表时要有locktables权限等。如果dump文件中包含了GTID信息,则无法导入到未启用GTID的数据库(低于5.6.9版本的数据库不支持GTID,因此也无法导入到这......