Bootstrap

EasyExcel数据导入导-数据转换

前言

日常工作中,我们会经常遇到excel导入导出的需求,这里就不可避免的遇到2个问题:

  1. 将excel中的数据转换为数据库中存储的code值;
  2. 将数据库中的code值转换为其对应的数据导出;

使用easyExcel就可以轻松解决这两个问题。

背景

职业字典表

在这里插入图片描述

用户表

在这里插入图片描述

如图有一个用户类,其中的性别、职业两个属性在数据库中存储其对应的编码,导出时需要转换为编码对应的值。

代码演示

User类

@ExcelProperty中的index属性会影响导入的顺序和excel读取数据的顺序,不能重复。在读取excel时要特别注意

package com.sunny.excel.entity;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serial;
import java.io.Serializable;

import com.sunny.excel.converter.GenderConverter;
import com.sunny.excel.converter.JobConverter;
import lombok.Data;

/**
 * 
 * @TableName user
 */
@TableName(value ="user")
@Data
public class User implements Serializable {

    @TableId(value = "id")
    @ExcelProperty(value = "id", index = 0)
    private String id;

    @TableField(value = "name")
    @ExcelProperty(value = "姓名", index = 1)
    private String name;

    /**
     * 1:男, 2:女
     */
    @TableField(value = "gender")
    @ExcelProperty(value = "性别", converter = GenderConverter.class, index = 2)
    private String gender;
    
    @TableField(value = "phone")
    @ExcelProperty(value = "电话号码", index = 3)
    private String phone;

    /**
     * 职业
     */
    @TableField(value = "job")
    @ExcelProperty(value = "职业", converter = JobConverter.class, index = 4)
    private String job;

    /**
     * 1: 正常, 0:删除
     */
    @TableField(value = "status")
    @ExcelProperty(value = "状态", index = 5)
    private String status;

    @Serial
    @TableField(exist = false)
    @ExcelIgnore
    private static final long serialVersionUID = 1L;
}

Dict类

package com.sunny.excel.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serial;
import java.io.Serializable;
import lombok.Data;

/**
 * 
 * @TableName dict
 */
@TableName(value ="dict")
@Data
public class Dict implements Serializable {
    /**
     * 
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 
     */
    @TableField(value = "code")
    private String code;

    /**
     * 
     */
    @TableField(value = "label")
    private String label;

    @Serial
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

性别转换器

package com.sunny.excel.converter;

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

public class c implements Converter<String> {

    @Override
    public Class<?> supportJavaTypeKey() {
        return String.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 写入excel时数据转换
     *
     * @return {@code WriteCellData<?> }
     * @author maym
     * @date 2024/10/15
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) throws Exception {
        // 将code值转换为其对应的汉字,写入excel中
        String value = context.getValue();
        String gender = "";
        if (value != null) {
            if (value.equals("1")) {
                gender = "男";
            } else if (value.equals("2")) {
                gender = "女";
            } else {
                gender = "未知";
            }
        }
        return new WriteCellData<>(gender);
    }

    @Override
    public String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        // 将excel中读到的汉字,转换为其对应的code值
        String value = cellData.getStringValue();
        if (value.equals("男")) {
            return "1";
        } else if (value.equals("女")) {
            return "2";
        } else {
            return "0";
        }
    }
}

数据读取监听器

package com.sunny.excel.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.sunny.excel.entity.User;
import com.sunny.excel.mapper.UserMapper;

import java.util.ArrayList;
import java.util.List;

public class UserReadListener extends AnalysisEventListener<User> {

    private static final int BATCH_COUNT = 5;
    private final List<User> list = new ArrayList<>();

    private final UserMapper userMapper;

    public UserReadListener(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /**
     * 从excel读取到数据,将数据存储到list,供批量处理,或后续自己业务逻辑处理。
     * @param user user
     */
    @Override
    public void invoke(User user, AnalysisContext analysisContext) {
        user.setId(String.valueOf(System.currentTimeMillis()));
        list.add(user);
        if (list.size() >= BATCH_COUNT) {
            userMapper.saveBatch(list);
            list.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        userMapper.saveBatch(list);
    }
}

UserServiceImpl类

package com.sunny.excel.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunny.excel.entity.User;
import com.sunny.excel.listener.UserReadListener;
import com.sunny.excel.service.UserService;
import com.sunny.excel.mapper.UserMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
* @author 13736
* @description 针对表【user】的数据库操作Service实现
* @createDate 2024-10-15 17:06:19
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{


    @Resource
    private UserMapper userMapper;

    @Override
    public void export(HttpServletResponse response) throws IOException {
        response.setHeader("Content-Disposition", "attachment;filename=userinfo.xlsx");
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");

        List<User> list = this.list();
        EasyExcel.write(response.getOutputStream())
                .autoCloseStream(true)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .sheet("userinfo")
                .head(User.class)
                .doWrite(list);
    }

    @Override
    public void importUser(MultipartFile file) {
        ExcelReader excelReader = null;
        try (InputStream inputStream = file.getInputStream() ) {
            excelReader = EasyExcel.read(
                    inputStream,
                    User.class,
                    // 自定义监听器处理读取的数据
                    new UserReadListener(userMapper)
            ).build();

            ReadSheet sheet = EasyExcel.readSheet(0).build();
            excelReader.read(sheet);
        } catch (IOException e) {
            throw new RuntimeException("文件读取异常");
        }finally {
            if (excelReader != null) {
                excelReader.finish();
            }
        }
    }
}

UserController类

package com.sunny.excel.controller;

import com.sunny.excel.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;
    

    @GetMapping("/export")
    public void export(HttpServletResponse response) throws IOException {
        userService.export(response);
    }

    @PostMapping("/import")
    public void importUser(MultipartFile file) {
        userService.importUser(file);
    }

}

测试

导入

表头要和实体User属性上的@ExcelProperty中value一致, 列的顺序要和index一致

在这里插入图片描述

导入结果

在这里插入图片描述

导出

数据库内容

在这里插入图片描述

导出结果

在这里插入图片描述

创作不易,您的赏识是我前进的动力!

;