版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
前言
最近在项目中有一个需求对企业列表批量导入或生成excel表格,在过程中遇到了很多坑,今天和大家分享一下。springboot 1.5.x版本
pom文件
需要引入的jar包
<!-- poi操作excel -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.8</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.8</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.8</version>
</dependency>
工具类
package com.sinoyd.util;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @Desc excel读取工具类
*/
public class ExcelUtil {
private static int totalRows = 0;// 总行数
private static int totalCells = 0;// 总列数
private static String errorInfo;// 错误信息
/**
* 无参构造方法
*/
public ExcelUtil() {
}
public static int getTotalRows() {
return totalRows;
}
public static int getTotalCells() {
return totalCells;
}
public static String getErrorInfo() {
return errorInfo;
}
/**
* 根据流读取Excel文件
*
* @param inputStream
* @param isExcel2003
* @return
* @see [类、类#方法、类#成员]
*/
public List<List<String>> read(InputStream inputStream, boolean isExcel2003)
throws IOException {
List<List<String>> dataLst = null;
/** 根据版本选择创建Workbook的方式 */
Workbook wb = null;
if (isExcel2003) {
wb = new HSSFWorkbook(inputStream);
} else {
wb = new XSSFWorkbook(inputStream);
}
dataLst = readData(wb);
return dataLst;
}
/**
* 读取数据
*
* @param wb
* @return
* @see [类、类#方法、类#成员]
*/
private List<List<String>> readData(Workbook wb) {
List<List<String>> dataLst = new ArrayList<List<String>>();
/** 得到第一个shell */
Sheet sheet = wb.getSheetAt(0);
/** 得到Excel的行数 */
totalRows = sheet.getPhysicalNumberOfRows();
/** 得到Excel的列数 */
if (totalRows >= 1 && sheet.getRow(0) != null) {
totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
}
/** 循环Excel的行 */
for (int r = 0; r < totalRows; r++) {
Row row = sheet.getRow(r);
if (row == null) {
continue;
}
List<String> rowLst = new ArrayList<String>();
/** 循环Excel的列 */
for (int c = 0; c < getTotalCells(); c++) {
Cell cell = row.getCell(c);
String cellValue = "";
if (null != cell) {
// 以下是判断数据的类型
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_NUMERIC: // 数字
cellValue = cell.getNumericCellValue() + "";
break;
case HSSFCell.CELL_TYPE_STRING: // 字符串
cellValue = cell.getStringCellValue();
break;
case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
cellValue = cell.getBooleanCellValue() + "";
break;
case HSSFCell.CELL_TYPE_FORMULA: // 公式
cellValue = cell.getCellFormula() + "";
break;
case HSSFCell.CELL_TYPE_BLANK: // 空值
cellValue = "";
break;
case HSSFCell.CELL_TYPE_ERROR: // 故障
cellValue = "非法字符";
break;
default:
cellValue = "未知类型";
break;
}
}
rowLst.add(cellValue);
}
/** 保存第r行的第c列 */
dataLst.add(rowLst);
}
return dataLst;
}
/**
* 根据Excel表格中的数据判断类型得到值
*
* @param cell
* @return
* @see [类、类#方法、类#成员]
*/
public static String getCellValue(Cell cell) {
String cellValue = "";
if (null != cell) {
// 以下是判断数据的类型
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_NUMERIC: // 数字
if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
Date theDate = cell.getDateCellValue();
SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd");
cellValue = dff.format(theDate);
} else {
DecimalFormat df = new DecimalFormat("0");
cellValue = df.format(cell.getNumericCellValue());
}
break;
case HSSFCell.CELL_TYPE_STRING: // 字符串
cellValue = cell.getStringCellValue();
break;
case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
cellValue = cell.getBooleanCellValue() + "";
break;
case HSSFCell.CELL_TYPE_FORMULA: // 公式
cellValue = cell.getCellFormula() + "";
break;
case HSSFCell.CELL_TYPE_BLANK: // 空值
cellValue = "";
break;
case HSSFCell.CELL_TYPE_ERROR: // 故障
cellValue = "非法字符";
break;
default:
cellValue = "未知类型";
break;
}
}
return cellValue;
}
/**
* 根据路径或文件名选择Excel版本
*
* @param filePathOrName
* @param in
* @return
* @throws IOException
* @see [类、类#方法、类#成员]
*/
public static Workbook chooseWorkbook(String filePathOrName, InputStream in)
throws IOException {
/** 根据版本选择创建Workbook的方式 */
Workbook wb = null;
boolean isExcel2003 = ExcelVersionUtil.isExcel2003(filePathOrName);
if (isExcel2003) {
wb = new HSSFWorkbook(in);
} else {
wb = new XSSFWorkbook(in);
}
return wb;
}
static class ExcelVersionUtil {
/**
* 是否是2003的excel,返回true是2003
*
* @param filePath
* @return
* @see [类、类#方法、类#成员]
*/
public static boolean isExcel2003(String filePath) {
return filePath.matches("^.+\\.(?i)(xls)$");
}
/**
* 是否是2007的excel,返回true是2007
*
* @param filePath
* @return
* @see [类、类#方法、类#成员]
*/
public static boolean isExcel2007(String filePath) {
return filePath.matches("^.+\\.(?i)(xlsx)$");
}
}
}
这个工具类主要是针对导入excel表格,个人觉得导入比较难。
service层关键代码
/**
* 导入excel表格
* post方法
*/
@Transactional
public String upload(MultipartFile file) throws Exception {
if (file == null || file.isEmpty()) {
throw new Exception("导入文件不能为空");
}
// 获取文件名
String fileName = file.getOriginalFilename();
int len = fileName.lastIndexOf(".");
if (len <= 0) {
throw new Exception("文件类型有误,请确认!");
}
String fileType = fileName.substring(len + 1).toLowerCase();
if (!fileType.equals("xls") && !fileType.equals("xlsx")) {
throw new Exception("只允许上传xls、xlsx");
}
InputStream in = file.getInputStream();
Workbook wb = ExcelUtil.chooseWorkbook(fileName, in);
List<Company> companies = getCompaniesFromExcel(wb);
List<String> creditCodes = companies.stream().map(Company::getCreditCode).collect(Collectors.toList());
List<Company> exists = companyRepository.findCompaniesByCreditCodeIn(creditCodes);
if (exists != null && !exists.isEmpty()) {
throw new ResException("信用代码为" + com.sinoyd.common.util.StringExtendUtil.join(creditCodes, ",") + "的企业已存在");
}
companyRepository.save(companies);
return "企业导入成功!";
}
/**
* 导出excel表格
* get方法
* @param request
* @param response
* @return
* @throws Exception
*/
public String export(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<Company> companies = companyRepository.findAll();
HSSFWorkbook wb = new HSSFWorkbook();//创建Excel文件
HSSFSheet sheet = wb.createSheet("企业信息表");
String sheetName = sheet.getSheetName();
wb.setSheetName(0, sheetName);
sheet.setDefaultRowHeight((short) (20 * 20));
CellStyle style = wb.createCellStyle();
HSSFFont font = wb.createFont();
font.setFontHeightInPoints((short) 12);
style.setFont(font);
HSSFRow row = sheet.createRow(0);
row.createCell(0).setCellValue("企业名称");//为第一个单元格设值
row.createCell(1).setCellValue("社会信用代码");//为第二个单元格设值
row.createCell(2).setCellValue("联系人");//为第三个单元格设值
row.createCell(3).setCellValue("联系电话");//为第三个单元格设值
row.createCell(4).setCellValue("法人");//为第三个单元格设值
row.createCell(5).setCellValue("地址");
row.createCell(6).setCellValue("行业");
row.createCell(7).setCellValue("创建日期");
row.createCell(8).setCellValue("开业日期");
row.createCell(9).setCellValue("员工数");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
if (companies != null && companies.size() > 0) {
int i = 0;
for (Company company : companies) {
i++;
row = sheet.createRow(i);
row.createCell(0).setCellValue(company.getName());
row.createCell(1).setCellValue(company.getCreditCode());
row.createCell(2).setCellValue(company.getContactName());
row.createCell(3).setCellValue(company.getContactPhone());
row.createCell(4).setCellValue(company.getCorporation());
row.createCell(5).setCellValue(company.getAddress());
row.createCell(6).setCellValue(company.getIndustryName());
String establishedDate = company.getEstablishedDate() != null ? sdf.format(company.getEstablishedDate()) : "";
row.createCell(7).setCellValue(establishedDate);
String openedDate = company.getOpenedDate() != null ? sdf.format(company.getOpenedDate()) : "";
row.createCell(8).setCellValue(openedDate);
Integer staffNum = company.getStaffNum() == null ? 0 : company.getStaffNum();
row.createCell(9).setCellValue(staffNum);
}
}
//列宽自适应
for (int i = 0; i <= 9; i++) {
sheet.autoSizeColumn(i);
}
// 针对IE或者以IE为内核的浏览器:
String userAgent = request.getHeader("User-Agent").toLowerCase();
String fileName = sheetName + ".xlsx";
if (userAgent.contains("msie") || userAgent.contains("trident")) {
fileName = URLEncoder.encode(fileName, "UTF-8");
} else {
// 非IE浏览器的处理:
fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
}
response.setCharacterEncoding("UTF-8");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("success", "true");
OutputStream os = response.getOutputStream();
response.setHeader("Content-disposition", "attachment;filename=" + fileName);//默认Excel名称
wb.write(os);
os.flush();
os.close();
return "导出企业信息成功";
}
private Integer getRowNum(Sheet sheet) {
int totalRows = sheet.getPhysicalNumberOfRows();
for (int r = 1; r < totalRows; r++) {
Row row = sheet.getRow(r);
if (row == null) {
return r;
}
String companyName = ExcelUtil.getCellValue(row.getCell(0));
String creditCode = ExcelUtil.getCellValue(row.getCell(1));
if (companyName.trim().equals("") && creditCode.trim().equals("")) {
return r;
}
}
return totalRows;
}
private List<Company> getCompaniesFromExcel(Workbook wb) throws Exception {
List<Company> companies = new ArrayList<>();
/** 得到第一个shell */
Sheet sheet = wb.getSheetAt(0);
/** 得到Excel的行数 */
int totalRows = getRowNum(sheet);
List<String> creditCodes = new ArrayList<>();
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
/** 循环Excel的行 */
for (int r = 1; r < totalRows; r++) {
Company company = new Company();
Row row = sheet.getRow(r);
if (row == null) {
continue;
}
String cellValue = ExcelUtil.getCellValue(row.getCell(0));
if (cellValue.trim().equals("")) {
throw new Exception("企业名称不能为空,请确认!");
}
company.setName(cellValue);
cellValue = ExcelUtil.getCellValue(row.getCell(1));
if (cellValue.trim().equals("")) {
throw new Exception("企业信用代码不能为空,请确认!");
}
if (creditCodes.contains(cellValue)) {
throw new Exception("有重复的企业信用代码" + cellValue + ",请确认!");
}
creditCodes.add(cellValue);
company.setCreditCode(cellValue);
cellValue = ExcelUtil.getCellValue(row.getCell(2));
if (cellValue.trim().length() > 0) {
company.setContactName(cellValue);
}
cellValue = ExcelUtil.getCellValue(row.getCell(3));
if (cellValue.trim().length() > 0) {
company.setContactPhone(cellValue);
}
cellValue = ExcelUtil.getCellValue(row.getCell(4));
company.setCorporation(cellValue);
cellValue = ExcelUtil.getCellValue(row.getCell(5));
if (Helpers.isNotNullAndEmpty(cellValue)) {
if (!Validator.isEmail(cellValue)) {
throw new Exception("邮箱格式不正确" + cellValue + ",请确认!");
}
company.setEmail(cellValue);
}
cellValue = ExcelUtil.getCellValue(row.getCell(6));
if (Helpers.isNotNullAndEmpty(cellValue)) {
if (!Validator.isFax(cellValue)) {
throw new Exception("传真格式不正常" + cellValue + ",请确认!");
}
company.setFax(cellValue);
}
cellValue = ExcelUtil.getCellValue(row.getCell(7));
company.setAddress(cellValue);
cellValue = ExcelUtil.getCellValue(row.getCell(8));
Double area = cellValue.equals("") ? 0 : Double.valueOf(cellValue);
if (area < 0) {
throw new Exception("占地面积不能为负数" + cellValue + ",请确认!");
}
company.setFloorArea(area);
companies.add(company);
}
List<Company> companyList = companyRepository.findCompaniesByCreditCodeIn(creditCodes);
if (companyList != null && companyList.size() > 0) {
List<String> list = companyList.stream().map(Company::getCreditCode).collect(Collectors.toList());
throw new Exception("以下信用代码已存在:" + String.join(",", list));
}
return companies;
}
关键代码都已经贴出来了,实体类和Controller层就不放出来了。