前言
日常工作中,我们会经常遇到excel导入导出的需求,这里就不可避免的遇到2个问题:
- 将excel中的数据转换为数据库中存储的code值;
- 将数据库中的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一致
导入结果
导出
数据库内容
导出结果