springboot导入excel(POI)

POI官方文档

引入依赖

        <!--POI-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</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-ooxml-schemas</artifactId>
            <version>4.1.2</version>
        </dependency>

编写导入工具类

结合springboot导出(POI)用到的自定义注解,让导入使用起来更方便简洁且更容易扩展。

java 复制代码
public class ExcelImportUtil {

    /*
     * @description: 读取excel数据 <br>
     * @create: 2023/9/20 16:12 <br>
     * @param file
     * @param tClass
     * @return java.util.List<T>
     */
    public static<T> List<T> readExcel(MultipartFile file, Class<T> tClass){
        if(file.isEmpty()){
            return new ArrayList<>();
        }
        //获取列名与属性名的映射
        Map<String, String> feildMap = getFeildMap(tClass);
        if(ObjectUtils.isEmpty(feildMap)){
            return new ArrayList<>();
        }
        InputStream inputStream = null;
        Workbook workbook = null;
        try {
            //解析文件
            inputStream = file.getInputStream();
            workbook = new XSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(0);
            int lastRowNum = sheet.getLastRowNum();
            int lastCellNum = sheet.getRow(0).getLastCellNum();
            //解析表头
            Row headerRow = sheet.getRow(0);
            List<String> headerNameList = new ArrayList<>();
            for (int i = 0; i < lastCellNum; i++) {
                headerNameList.add(headerRow.getCell(i).getStringCellValue());
            }
            //读取数据
            List<Map<String, Object>> dataList = new ArrayList<>();
            for (int i = 1; i <= lastRowNum; i++) {
                Row row = sheet.getRow(i);
                Map<String, Object> rowValueMap = new HashMap<>();
                for (int j = 0; j < lastCellNum; j++) {
                    String key = feildMap.get(headerNameList.get(j));
                    Object value = getCellValue(row.getCell(j));
                    rowValueMap.put(key, value);
                }
                dataList.add(rowValueMap);
            }
            workbook.close();
            inputStream.close();
            List<T> list = convertToList(dataList);
            return list;
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(workbook != null){
                    workbook.close();
                }
                if(inputStream !=null){
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return new ArrayList<>();
    }

    /*
     * @description: 解析导入的实体,获取列名与属性名的映射 <br>
     * @create: 2023/9/20 16:27 <br>
     * @param tClass
     * @return java.util.Map<java.lang.String,java.lang.String>
     */
    private static<T> Map<String, String> getFeildMap(Class<T> tClass){
        Field[] fields = tClass.getDeclaredFields();
        if(ObjectUtils.isEmpty(fields)){
            return null;
        }
        Map<String, String> keyMap = new HashMap<>();
        for(Field field : fields){
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if(ObjectUtils.isNotEmpty(excelField)){
                keyMap.put(excelField.name(), field.getName());
            }
        }
        return keyMap;
    }

    /*
     * @description: 获取单元格的值 <br>
     * @create: 2023/9/20 16:47 <br>
     * @param cell
     * @return java.lang.Object
     */
    private static Object getCellValue(Cell cell){
        if(cell == null){
            return null;
        }
        CellType cellType = cell.getCellType();
        if(cellType.equals(CellType.BLANK)){
            return null;
        }
        //字符串
        if (cellType.equals(CellType.STRING)){
            return cell.getStringCellValue();
        }
        if(cellType.equals(CellType.NUMERIC)){
            //日期
            if(HSSFDateUtil.isCellDateFormatted(cell)){
                return cell.getDateCellValue();
            }else{
                //数值
                return cell.getNumericCellValue();
            }
        }
        //布尔
        if(cellType.equals(CellType.BOOLEAN)){
            return cell.getBooleanCellValue();
        }
        return null;
    }

    /*
     * @description: 转list <br>
     * @create: 2023/9/20 17:54 <br>
     * @param obj
     * @return java.util.List<T>
     */
    private static<T> List<T> convertToList(Object obj){
        ObjectMapper objectMapper = new ObjectMapper();
        //日期格式
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        //设置时区
        objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        //序列化-忽略null值的属性
        objectMapper.setSerializationInclusion(Include.NON_NULL);
        //序列化-允许序列化空对象
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        //反序列化-在遇到未知属性的时候不抛出异常
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        if(null == obj){
            return null;
        }
        return objectMapper.convertValue(obj, new TypeReference<List<T>>() {});
    }
}

测试

导入模板

导入的泛型(对象)

java 复制代码
@Data
public class ImportTest {

    @ExcelField(name = "字符串")
    private String feild1;

    @ExcelField(name = "数值")
    private BigDecimal feild2;

    @ExcelField(name = "布尔")
    private Boolean feild3;

    @ExcelField(name = "日期")
    private Date feild4;
}

controller

java 复制代码
@Api(tags = "测试")
@RestController
@RequestMapping("/test")
public class TestController {

    @ApiOperation("导入")
    @PostMapping("/importExcel")
    public ResponseEntity<List<ImportTest>> importExcel(@ApiParam(name = "file") @RequestPart("file") MultipartFile file){
        List<ImportTest> list = ExcelImportUtil.readExcel(file, ImportTest.class);
        System.out.print(list);
        return ResponseEntity.ok(list);
    }
}

response

相关推荐
魔道不误砍柴功1 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2341 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨1 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
种树人202408191 小时前
如何在 Spring Boot 中启用定时任务
spring boot
测开小菜鸟3 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity4 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天4 小时前
java的threadlocal为何内存泄漏
java
caridle4 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^4 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋34 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx