本文目录导读:

我来提供一个完整的Java批量导入Excel的案例,包含多种常用方式。
项目依赖配置
Maven依赖
<!-- Apache POI - 处理xls和xlsx -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<!-- EasyExcel - 阿里开源,性能更好 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
使用EasyExcel实现批量导入
1 定义实体类
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class UserExcelDTO {
@ExcelProperty("用户名")
private String username;
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年龄")
private Integer age;
@ExcelProperty("邮箱")
private String email;
@ExcelProperty("手机号")
private String phone;
@ExcelProperty("地址")
private String address;
@ExcelProperty("创建时间")
private Date createTime;
}
2 定义Excel监听器
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class UserExcelListener extends AnalysisEventListener<UserExcelDTO> {
// 每批处理的条数
private static final int BATCH_COUNT = 100;
// 批量处理接口
private final ExcelDataHandler<UserExcelDTO> dataHandler;
// 临时存储数据
private final List<UserExcelDTO> dataList = new ArrayList<>();
public UserExcelListener(ExcelDataHandler<UserExcelDTO> dataHandler) {
this.dataHandler = dataHandler;
}
/**
* 每解析一行数据会调用一次
*/
@Override
public void invoke(UserExcelDTO data, AnalysisContext context) {
dataList.add(data);
// 达到批量处理数量时,处理数据
if (dataList.size() >= BATCH_COUNT) {
processData();
dataList.clear();
}
}
/**
* 解析完所有数据后调用
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 处理剩余数据
if (!dataList.isEmpty()) {
processData();
dataList.clear();
}
log.info("Excel解析完成");
}
/**
* 批量处理数据
*/
private void processData() {
try {
dataHandler.handleData(new ArrayList<>(dataList));
} catch (Exception e) {
log.error("批量处理数据失败", e);
throw new RuntimeException("批量处理数据失败: " + e.getMessage());
}
}
}
3 定义数据处理接口
public interface ExcelDataHandler<T> {
/**
* 批量处理数据
*/
void handleData(List<T> dataList);
}
4 实现业务处理逻辑
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class UserImportService implements ExcelDataHandler<UserExcelDTO> {
@Autowired
private UserMapper userMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void handleData(List<UserExcelDTO> dataList) {
log.info("开始批量导入用户数据, 数量: {}", dataList.size());
// 校验数据
for (UserExcelDTO user : dataList) {
// 数据校验
validateUser(user);
}
// 批量插入
int result = userMapper.batchInsert(dataList);
log.info("批量导入完成, 影响行数: {}", result);
}
private void validateUser(UserExcelDTO user) {
if (StringUtils.isBlank(user.getUsername())) {
throw new RuntimeException("用户名不能为空");
}
// 检查用户名是否已存在
User existingUser = userMapper.findByUsername(user.getUsername());
if (existingUser != null) {
throw new RuntimeException("用户名 " + user.getUsername() + " 已存在");
}
// 手机号格式校验
if (StringUtils.isNotBlank(user.getPhone())) {
if (!user.getPhone().matches("^1[3-9]\\d{9}$")) {
throw new RuntimeException("手机号格式不正确: " + user.getPhone());
}
}
}
}
5 Controller层实现
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.excel.EasyExcel;
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserImportService userImportService;
/**
* 批量导入用户
*/
@PostMapping("/import")
public Result<?> importUsers(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Result.error("上传文件不能为空");
}
// 检查文件类型
String filename = file.getOriginalFilename();
if (!filename.endsWith(".xlsx") && !filename.endsWith(".xls")) {
return Result.error("文件格式不正确,请上传Excel文件");
}
try {
// 定义监听器
UserExcelListener listener = new UserExcelListener(userImportService);
// 读取Excel文件
EasyExcel.read(file.getInputStream())
.head(UserExcelDTO.class)
.sheet()
.doRead();
return Result.success("导入成功");
} catch (Exception e) {
log.error("导入Excel失败", e);
return Result.error("导入失败: " + e.getMessage());
}
}
}
6 MyBatis批量插入
<insert id="batchInsert" parameterType="list">
INSERT INTO user (username, name, age, email, phone, address, create_time)
VALUES
<foreach collection="list" item="user" separator=",">
(#{user.username}, #{user.name}, #{user.age}, #{user.email},
#{user.phone}, #{user.address}, NOW())
</foreach>
</insert>
使用Apache POI实现(传统方式)
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;
@Service
public class ExcelImportService {
/**
* 使用POI解析Excel
*/
public List<UserExcelDTO> parseExcel(MultipartFile file) throws Exception {
List<UserExcelDTO> userList = new ArrayList<>();
try (Workbook workbook = WorkbookFactory.create(file.getInputStream())) {
Sheet sheet = workbook.getSheetAt(0); // 第一个sheet
// 跳过表头(第一行)
for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
Row row = sheet.getRow(rowNum);
if (row == null) {
continue;
}
// 跳过空行
if (isRowEmpty(row)) {
continue;
}
UserExcelDTO user = new UserExcelDTO();
user.setUsername(getCellValue(row.getCell(0)));
user.setName(getCellValue(row.getCell(1)));
user.setAge(Integer.parseInt(getCellValue(row.getCell(2))));
user.setEmail(getCellValue(row.getCell(3)));
user.setPhone(getCellValue(row.getCell(4)));
user.setAddress(getCellValue(row.getCell(5)));
userList.add(user);
// 每1000条处理一次
if (userList.size() == 1000) {
batchImport(userList);
userList.clear();
}
}
// 处理剩余数据
if (!userList.isEmpty()) {
batchImport(userList);
}
}
return userList;
}
/**
* 获取单元格值
*/
private String getCellValue(Cell cell) {
if (cell == null) {
return null;
}
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
return cell.getDateCellValue().toString();
}
return String.valueOf(cell.getNumericCellValue());
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
default:
return null;
}
}
/**
* 判断行是否为空
*/
private boolean isRowEmpty(Row row) {
for (int i = 0; i < row.getLastCellNum(); i++) {
Cell cell = row.getCell(i);
if (cell != null && cell.getCellType() != CellType.BLANK) {
return false;
}
}
return true;
}
/**
* 批量导入
*/
@Transactional(rollbackFor = Exception.class)
public void batchImport(List<UserExcelDTO> userList) {
// 批量插入数据库
// ...
}
}
异常数据处理示例
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.converters.Converter;
/**
* 自定义转换器示例
*/
public class CustomDateConverter implements Converter<Date> {
@Override
public Date convertToJavaData(ReadCellData<?> cellData,
ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
String value = cellData.getStringValue();
try {
return new SimpleDateFormat("yyyy-MM-dd").parse(value);
} catch (Exception e) {
throw new RuntimeException("日期格式错误: " + value);
}
}
}
添加错误处理机制
public class ImportException extends RuntimeException {
private int rowNum;
private String message;
public ImportException(int rowNum, String message) {
super("第" + rowNum + "行: " + message);
this.rowNum = rowNum;
this.message = message;
}
}
性能优化建议
- 使用EasyExcel替代POI:EasyExcel内存占用更低,性能更好
- 合理设置批量大小:根据实际需求调整批量处理条数(建议100-500条)
- 使用多线程处理:大数据量时可以使用线程池并行处理
- 减少事务范围:不要将整个导入过程放在一个事务中
- 使用数据库批量插入:使用MyBatis的foreach或JDBC的batchUpdate
这就是一个完整的Java批量导入Excel案例,包含了EasyExcel和POI两种实现方式,以及异常处理和性能优化建议。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播