之前也做过excel文件导入数据库与数据库导出成excel文件的测试,但是没有给大家分享出开发业务时简洁的模板,可能根据需求不同导入与导出的元数据样板也不同,开发人员就需要不断地修改代码。
实现方式
我们利用POI的依赖实现这类的文件解析与文件创建功能:
org.apache.poi
poi
5.0.0
org.apache.poi
poi-ooxml
5.0.0
实现代码
我们将实现代码的过程分为先创建枚举来规定数据样板的类型:
public enum ExcelDataType {
/*价格表类型,设备表类型,用户表类型,订单表类型*/
DATA_PRICE,DATA_DEVICE,DATA_USER,DATA_ORDER
}
其次我们需要分析一下:数据的导出很简单就是接受请求之后将数据库的数据一一放入你创建的表里的行里,将属性一个一个的填入单元格中,然后利用response写入流文件传输到前端。数据导入则需要解析传递的文件,将文件中的表行单元格一一的对应到属性上去,注意数据格式,然后就是批量导入的方法直接保存进数据库,注意数据的重复问题。
@Component("excelUtils")
public class ExcelUtils {
@Resource
private PriceService priceService;
@Resource
private OrderService orderService;
@Resource
private DeviceService deviceService;
@Resource
private UserService userService;
private Price price = new Price();
private Device device = new Device();
private Order order = new Order();
private User user = new User();
private List priceList = new LinkedList<>();
private List deviceList = new LinkedList<>();
private List orderList = new LinkedList<>();
private List userList = new LinkedList<>();
/**
* 导入Excel文件到数据库
*
* @param excelFile 文件对象
* @param fileInputStream 文件输入流
* @param dataType 文件批量导入实体类型 例如Price是价格清单实体
* @return 是否导入完成
*/
public boolean fromExcelInDB(@Nullable MultipartFile excelFile, @Nullable InputStream fileInputStream, ExcelDataType dataType) {
if (excelFile != null && fileInputStream == null) {
String filename = excelFile.getOriginalFilename();
if (filename != null) {
String suffix = filename.substring(filename.lastIndexOf(".") + 1);
InputStream inputStream = null;
try {
inputStream = excelFile.getInputStream();
Workbook workbook = null;
if ("xlsx".equals(suffix)) {
/*针对不同版本的Excel文件*/
workbook = WorkbookFactory.create(inputStream);
} else {
workbook = WorkbookFactory.create(inputStream);
}
Sheet sheet = workbook.getSheetAt(0);
if (sheet != null) {
for (int i = 2; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row == null) continue;
if (row.getCell(0) == null || row.getCell(0).getStringCellValue() == null) break;
if (dataType == ExcelDataType.DATA_PRICE) {
price.setDeviceId(row.getCell(0).getStringCellValue());
price.setDeviceTime((int) row.getCell(1).getNumericCellValue());
price.setReceipt((int) row.getCell(2).getNumericCellValue());
price.setInfo(row.getCell(3).getStringCellValue());
priceList.add(price);
price.clear();
} else if (dataType == ExcelDataType.DATA_DEVICE) {
device.setId(row.getCell(0).getStringCellValue());
device.setState(row.getCell(1).getBooleanCellValue());
device.setLock(row.getCell(2).getBooleanCellValue());
device.setPower(row.getCell(3).getBooleanCellValue());
device.setOutSign((int) row.getCell(4).getNumericCellValue());
device.setInfo(row.getCell(5).getStringCellValue());
deviceList.add(device);
device.clear();
} else if (dataType == ExcelDataType.DATA_ORDER) {
order.setUserId(row.getCell(0).getStringCellValue());
order.setDeviceId(row.getCell(1).getStringCellValue());
order.setOrderTime(String.valueOf(row.getCell(2).getLocalDateTimeCellValue()));
order.setUseTime((int) row.getCell(3).getNumericCellValue());
order.setReceipt(row.getCell(4).getNumericCellValue());
order.setOrderState(row.getCell(5).getBooleanCellValue());
orderList.add(order);
order.clear();
} else {
user.setId(row.getCell(0).getStringCellValue());
user.setName(row.getCell(1).getStringCellValue());
user.setPhone(row.getCell(2).getStringCellValue());
user.setAmount((int) row.getCell(3).getNumericCellValue());
user.setPassword(row.getCell(4).getStringCellValue());
user.setWxId(row.getCell(5).getStringCellValue());
userList.add(user);
user.clear();
}
}
}
if (dataType == ExcelDataType.DATA_PRICE) {
return priceService.savePriceBatch(priceList);
} else if (dataType == ExcelDataType.DATA_ORDER) {
/*订单的批量导入......*/
return false;
} else if (dataType == ExcelDataType.DATA_DEVICE) {
return deviceService.saveBatchDevice(deviceList);
} else
return false;
} catch (IOException e) {
e.printStackTrace();
try {
inputStream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
} else if (excelFile == null && fileInputStream != null) {
try {
Workbook workbook = null;
workbook = WorkbookFactory.create(fileInputStream);
Sheet sheet = workbook.getSheetAt(0);
if (sheet != null) {
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
// System.out.println(row.getLastCellNum()+row.getCell(0).getStringCellValue());
if (row == null) continue;
if (row.getCell(0) == null || row.getCell(0).getStringCellValue() == null) break;
if (dataType == ExcelDataType.DATA_PRICE) {
price.setDeviceId(row.getCell(0).getStringCellValue());
price.setDeviceTime((int) row.getCell(1).getNumericCellValue());
price.setReceipt((int) row.getCell(2).getNumericCellValue());
price.setInfo(row.getCell(3).getStringCellValue());
priceList.add(price);
price.clear();
} else if (dataType == ExcelDataType.DATA_DEVICE) {
device.setId(row.getCell(0).getStringCellValue());
device.setState(row.getCell(1).getBooleanCellValue());
device.setLock(row.getCell(2).getBooleanCellValue());
device.setPower(row.getCell(3).getBooleanCellValue());
device.setOutSign((int) row.getCell(4).getNumericCellValue());
device.setInfo(row.getCell(5).getStringCellValue());
deviceList.add(device);
device.clear();
} else if (dataType == ExcelDataType.DATA_ORDER) {
order.setUserId(row.getCell(0).getStringCellValue());
order.setDeviceId(row.getCell(1).getStringCellValue());
order.setOrderTime(String.valueOf(row.getCell(2).getLocalDateTimeCellValue()));
order.setUseTime((int) row.getCell(3).getNumericCellValue());
order.setReceipt(row.getCell(4).getNumericCellValue());
order.setOrderState(row.getCell(5).getBooleanCellValue());
orderList.add(order);
order.clear();
} else {
user.setId(row.getCell(0).getStringCellValue());
user.setName(row.getCell(1).getStringCellValue());
user.setPhone(row.getCell(2).getStringCellValue());
user.setAmount((int) row.getCell(3).getNumericCellValue());
user.setPassword(row.getCell(4).getStringCellValue());
user.setWxId(row.getCell(5).getStringCellValue());
userList.add(user);
user.clear();
}
}
}
if (dataType == ExcelDataType.DATA_PRICE) {
return priceService.savePriceBatch(priceList);
} else if (dataType == ExcelDataType.DATA_ORDER) {
/*订单的批量导入......*/
return false;
} else if (dataType == ExcelDataType.DATA_DEVICE) {
return deviceService.saveBatchDevice(deviceList);
} else
return false;
} catch (IOException e) {
e.printStackTrace();
try {
fileInputStream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
return false;
}
/**
* 将数据输出成Excel文件(前端传递数据,或是接口搜索将数据放入Attribute中)
*
* @param request 请求
* @param response 响应
* @param dataType 实体数据类型 例如Price是价格清单实体
* @param columnCount 实体的属性数量 例如Price实体具备4个属性
*/
public void fromDBToExcel(HttpServletRequest request, HttpServletResponse response, ExcelDataType dataType, int columnCount) {
try {
HSSFWorkbook workbook = new HSSFWorkbook();
if (dataType == ExcelDataType.DATA_PRICE) {
priceList = (List) request.getAttribute("priceList");
HSSFSheet sheet = workbook.createSheet("设备价格清单");
int rowIndex = 0;
int cellIndex = 0;
while (cellIndex < columnCount) {
HSSFRow row = sheet.createRow(rowIndex++);
row.createCell(cellIndex++, CellType.STRING).setCellValue("设备号");
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue("使用时长");
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue("价格/元");
row.createCell(cellIndex++, CellType.STRING).setCellValue("备注");
}
cellIndex = 0;
for (Price price : priceList) {
while (cellIndex < columnCount) {
HSSFRow row = sheet.createRow(rowIndex++);
row.createCell(cellIndex++, CellType.STRING).setCellValue(price.getDeviceId());
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue(price.getDeviceTime());
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue(price.getReceipt());
row.createCell(cellIndex++, CellType.STRING).setCellValue(price.getInfo());
}
cellIndex = 0;
}
} else if (dataType == ExcelDataType.DATA_DEVICE) {
deviceList = (List) request.getAttribute("deviceList");
HSSFSheet sheet = workbook.createSheet("设备清单");
int rowIndex = 0;
int cellIndex = 0;
while (cellIndex < columnCount) {
HSSFRow row = sheet.createRow(rowIndex++);
row.createCell(cellIndex++, CellType.STRING).setCellValue("设备号");
row.createCell(cellIndex++, CellType.BOOLEAN).setCellValue("设备可用状态");
row.createCell(cellIndex++, CellType.BOOLEAN).setCellValue("设备锁状态");
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue("设备输出端口");
row.createCell(cellIndex++, CellType.BOOLEAN).setCellValue("设备电源状态");
row.createCell(cellIndex++, CellType.STRING).setCellValue("设备区号");
row.createCell(cellIndex++, CellType.STRING).setCellValue("备注");
}
cellIndex = 0;
for (Device device : deviceList) {
while (cellIndex < columnCount) {
HSSFRow row = sheet.createRow(rowIndex++);
row.createCell(cellIndex++, CellType.STRING).setCellValue(device.getId());
row.createCell(cellIndex++, CellType.BOOLEAN).setCellValue(device.getState());
row.createCell(cellIndex++, CellType.BOOLEAN).setCellValue(device.getLock());
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue(device.getOutSign());
row.createCell(cellIndex++, CellType.BOOLEAN).setCellValue(device.getPower());
row.createCell(cellIndex++, CellType.STRING).setCellValue(device.getAreaCode());
row.createCell(cellIndex++, CellType.STRING).setCellValue(device.getInfo());
}
cellIndex = 0;
}
} else if (dataType == ExcelDataType.DATA_ORDER) {
orderList = (List) request.getAttribute("orderList");
HSSFSheet sheet = workbook.createSheet("订单清单");
int rowIndex = 0;
int cellIndex = 0;
while (cellIndex < columnCount) {
HSSFRow row = sheet.createRow(rowIndex++);
row.createCell(cellIndex++, CellType.STRING).setCellValue("用户账号");
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue("使用时长");
row.createCell(cellIndex++, CellType.STRING).setCellValue("设备号");
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue("付款金额");
row.createCell(cellIndex++, CellType.STRING).setCellValue("创建订单时间");
row.createCell(cellIndex++, CellType.BOOLEAN).setCellValue("订单支付状态");
}
cellIndex = 0;
for (Order order : orderList) {
while (cellIndex < columnCount) {
HSSFRow row = sheet.createRow(rowIndex++);
row.createCell(cellIndex++, CellType.STRING).setCellValue(order.getUserId());
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue(order.getUseTime());
row.createCell(cellIndex++, CellType.STRING).setCellValue(order.getDeviceId());
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue(order.getReceipt());
row.createCell(cellIndex++, CellType.STRING).setCellValue(order.getOrderTime());
row.createCell(cellIndex++, CellType.BOOLEAN).setCellValue(order.getOrderState());
}
cellIndex = 0;
}
} else {
userList = (List) request.getAttribute("userList");
HSSFSheet sheet = workbook.createSheet("用户清单");
int rowIndex = 0;
int cellIndex = 0;
while (cellIndex < columnCount) {
HSSFRow row = sheet.createRow(rowIndex++);
row.createCell(cellIndex++, CellType.STRING).setCellValue("用户账号");
row.createCell(cellIndex++, CellType.STRING).setCellValue("用户昵称");
row.createCell(cellIndex++, CellType.STRING).setCellValue("用户电话");
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue("用户余额");
row.createCell(cellIndex++, CellType.STRING).setCellValue("用户密码");
row.createCell(cellIndex++, CellType.STRING).setCellValue("用户微信openid");
}
cellIndex = 0;
for (User user : userList) {
while (cellIndex < columnCount) {
HSSFRow row = sheet.createRow(rowIndex++);
row.createCell(cellIndex++, CellType.STRING).setCellValue(user.getId());
row.createCell(cellIndex++, CellType.STRING).setCellValue(user.getName());
row.createCell(cellIndex++, CellType.STRING).setCellValue(user.getName());
row.createCell(cellIndex++, CellType.NUMERIC).setCellValue(user.getAmount());
row.createCell(cellIndex++, CellType.STRING).setCellValue(user.getPassword());
row.createCell(cellIndex++, CellType.STRING).setCellValue(user.getWxId());
}
cellIndex = 0;
}
}
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment;filename=" + dataType + ".xls");
response.flushBuffer();
workbook.write(response.getOutputStream());
workbook.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
priceList.clear();
orderList.clear();
deviceList.clear();
userList.clear();
}
}
如果测试失败,要记住实体类上打没打上lombok的注解@Data,有的话去掉,手写getter与setter方法,lombok的源码与源的字节码是有区别的,解析过程可能出现问题。代码里的clear方法是我自己加的,目的是将实体类的全部属性设置为null,这也就直接的要求你的属性类型不能是元类型,尽量都设置为对象引用类型。
测试代码
导入测试代码:
@PostMapping("exportExcel")
@ResponseBody
public GeneralResponse exportExcel(@RequestParam("fileName") MultipartFile file) {
try{
boolean result = excelUtils.fromExcelInDB(file, null, ExcelDataType.DATA_DEVICE);
return result ? GeneralResponse.ServerSuccess(true, "服务访问成功") :
GeneralResponse.ServerError("服务拒绝访问");
}catch (Exception e){
try {
InputStream inputStream = file.getInputStream();
boolean result = excelUtils.fromExcelInDB(null,inputStream,ExcelDataType.DATA_DEVICE);
return result ? GeneralResponse.ServerSuccess(true, "服务访问成功") :
GeneralResponse.ServerError("服务拒绝访问");
} catch (IOException ex) {
e.printStackTrace();
ex.printStackTrace();
return GeneralResponse.ServerError("服务拒绝访问");
}
}
}
导出测试代码:
@GetMapping("/PriceDBToExcel")
@ResponseBody
public void PriceDBtoExcel(HttpServletRequest request, HttpServletResponse response){
List priceList = priceService.getPriceByDeviceId("A101");
request.setAttribute("priceList",priceList);
excelUtils.fromDBToExcel(request,response, ExcelDataType.DATA_PRICE,4);
}