JAVA用poi包导入Excel
一、先看效果
1、点击【数据导入】按钮,弹窗里,可以下载模板,可以选择导入的Excel文件
2、下载的模板,第一行是标题,后边几行是数据
3、导入结果,有结果回馈,如果错误有下载
4、下载的错误模板,只回显错误的,错误字段会标红
也可以在标红的单元格,鼠标点击显示为啥标红
二、JAVA代码实现
1、ctrl层
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/importExcelWithAbnormal", method = RequestMethod.POST)
public Result<?> importExcelWithAbnormal(HttpServletRequest request, HttpServletResponse response) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
Result<?> res = wsInstallationBaseInfoService.importExcelWithAbnormal(fileMap, localPath);
return res;
}
2、service层
(这个方法有点长,用的亲可以再封装下)
演示了3种情况,excel里的批注怎么加,枚举怎么赋值,String、Integer怎么赋值
import org.framework.common.api.vo.Result;
import java.util.*;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.multipart.MultipartFile;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import cn.hutool.core.collection.CollUtil;
import java.util.stream.Collectors;
import org.springframework.util.ObjectUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.util.HSSFColor;
private final static String excel2003L =".xls";
private final static String excel2007U =".xlsx";
public Result<?> importExcelWithAbnormal(Map<String, MultipartFile> fileMap, String uploadPath) {
// excel的列标题,做校验是否为模板
List<String> titleArr = CollUtil.newArrayList("地市","县(市、区)","乡镇(街道)","行政村名称","行政村编号","设备名称","水质标准");
List<String> propertyList = CollUtil.newArrayList("cityName","countyName","townName","villageName","villageCode","installationName","waterQualityNorm");
// 枚举 演示匹配
List<DictModel> waterQualityNormDictList = baseMapper.getDictItemByCode("waterQualityNorm");
Map<String, String> waterQualityNormDictMap = waterQualityNormDictList.stream().collect(Collectors.toMap(DictModel::getText, DictModel::getValue));
// 开始
List<List<Object>> lstDatas = new ArrayList<>();
List<JSONObject> errorRowList = new ArrayList<>();
int successLines = 0, errorLines = 0;
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
MultipartFile file = entity.getValue();// 获取上传文件对象
String fileName = file.getOriginalFilename();
String fileType = fileName.substring(fileName.lastIndexOf("."));
if(!excel2003L.equals(fileType) && !excel2007U.equals(fileType)){
return Result.error("请上传excel文件!");
}
try{
// 判断是否是导入模板
XSSFWorkbook wb1 = new XSSFWorkbook(file.getInputStream());
Sheet sheet1 = wb1.getSheetAt(0);
Boolean isTemplate = true;
if (!ObjectUtils.isEmpty(sheet1)){
Row row = sheet1.getRow(0);
if (ObjectUtils.isEmpty(row) || row.getPhysicalNumberOfCells() != titleArr.size()){
isTemplate = false;
}else {
for (int i = 0; i < titleArr.size() ; i++) {
Cell cell = row.getCell(i);
if (!titleArr.get(i).equals(cell.getStringCellValue())){
isTemplate = false;
break;
}
}
}
}else {
isTemplate = false;
}
if (!isTemplate){
return Result.error("导入模板不正确!请使用正确的导入模板");
}
int rowSize = sheet1.getLastRowNum();
Row row;
for(int i = 1; i <= rowSize; i++) {
row = sheet1.getRow(i);
if (row == null) {
continue;
}
WsInstallationBaseInfo baseInfo = new WsInstallationBaseInfo();
boolean error = false;
List<Object> item = new ArrayList<>();
List<Integer> errorRow = new ArrayList<>();
List<JSONObject> commentList = new ArrayList<>();
boolean hasComment = false;
for(int a = 0; a < titleArr.size(); a++) {
Cell cell = row.getCell(a);
boolean cellFlag = false;
if (cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK) {
//空值
if (a < 7) {
cellFlag = true;
item.add("空");
} else {
item.add(ExcelExportUtil.getCellValueByCell(cell));
}
} else {
String cellValueByCell = ExcelExportUtil.getCellValueByCell(cell);
item.add(cellValueByCell);
if (propertyList.get(a).equals("cityName")) {
// 市
// 1、此处演示如何加提示
baseInfo.setCityName(cellValueByCell);
if(true){
//市不存在
cellFlag = true;
String realName = "我是来女士 ";
if(StringUtils.isNotEmpty(realName)){
JSONObject comment = new JSONObject();
comment.put("num",a);
comment.put("tex","系统中数据:"+realName);
hasComment = true;
commentList.add(comment);
}
}
}else if(propertyList.get(a).equals("waterQualityNorm")){// 出水水质标准
// 2、此处演示枚举如何由value匹配为key
baseInfo.setWaterQualityNorm(waterQualityNormDictMap.getOrDefault(cellValueByCell, null));
}else{// 3、此处演示其他字符串
setBaseInfoProperty(baseInfo, propertyList.get(a), cellValueByCell);
}
}
if(cellFlag){
errorRow.add(a);
error = true;
}
}
if(error){
lstDatas.add(item);
JSONObject errorRowJSON = new JSONObject();
errorRowJSON.put("errorRow",errorRow);
errorRowJSON.put("hasComment",hasComment);
errorRowJSON.put("commentList",commentList);
errorRowList.add(errorRowJSON);
errorLines++;
}else {
if(this.save(baseInfo)){
successLines++;
}else{
errorLines++;
}
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
try {
file.getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (errorLines == 0) {
return Result.ok("共" + successLines + "行数据全部导入成功!");
} else {
SXSSFWorkbook workbook = new SXSSFWorkbook(1000);
Sheet sheet = workbook.createSheet("错误数据");
ExcelExportUtil writer = new ExcelExportUtil(sheet,workbook);
List<Integer> cellNum = new ArrayList<>();
for(int i = 0; i < titleArr.size(); i++){
cellNum.add(i);
sheet.setColumnWidth(i, 12 * 256);
}
writer.writeTitle(titleArr);
sheet.createFreezePane( 0, 1, 0, 1 );
writer.writeData(lstDatas);
for(int i = 0; i < errorRowList.size(); i++){
JSONObject errorRowJSON = errorRowList.get(i);
List<Integer> cellList = (List<Integer>)errorRowJSON.get("errorRow");
writer.setCellFontColor(false, HSSFColor.RED.index,true,i+1,cellList);
//批注
boolean hasComment = errorRowJSON.getBoolean("hasComment");
if(hasComment){
List<JSONObject> commentList = (List<JSONObject>)errorRowJSON.get("commentList");
for(JSONObject comment : commentList){
writer.setComment(i+1,comment.getIntValue("num"),comment.getString("tex"));
}
}
}
FileOutputStream fos = null;
String dir = uploadPath + File.separator + "temp" + File.separator;
File f = new File(dir);
if(!f.exists()){
f.mkdirs();
}
String fileName = UUIDGenerator.generate() +".xlsx";
try {
fos = new FileOutputStream(dir+fileName);
workbook.write(fos);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
JSONObject result = new JSONObject(5);
int totalCount = successLines + errorLines;
result.put("totalCount", totalCount);
result.put("errorCount", errorLines);
result.put("successCount", successLines);
result.put("msg", "总上传行数:" + totalCount + ",已导入行数:" + successLines + ",错误行数:" + errorLines);
result.put("fileUrl", "/sys/common/static/" + "temp"+ File.separator+fileName);
result.put("fileName", fileName);
result.put("code", 200);
Result res = Result.ok(result);
res.setCode(201);
res.setMessage("文件导入成功,但有错误。");
return res;
}
}
3、service层中的反射方法
/**
* 用反射,给 entity ,设置其他属性
* @param baseInfo
* @param propertyName
* @param value
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static void setBaseInfoProperty(WsInstallationBaseInfo baseInfo, String propertyName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = WsInstallationBaseInfo.class.getDeclaredField(propertyName);
field.setAccessible(true);
// 看接收实体的属性类型
Class<?> type=field.getType();
if(type == String.class){
if (value instanceof Integer){
field.set(baseInfo, String.valueOf(value));
}else if(value instanceof String){
field.set(baseInfo, value);
}
}else if(type == Integer.class){
if (value instanceof Integer){
field.set(baseInfo, value);
}else if(value instanceof String){
field.set(baseInfo, Integer.valueOf((String)value));
}
}
}
Excel操作的公共类
import cn.hutool.poi.excel.RowUtil;
import cn.hutool.poi.excel.cell.CellUtil;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.framework.common.util.DateUtils;
import org.framework.common.util.ExportExcel;
import org.springframework.util.ObjectUtils;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class ExcelExportUtil {
private SXSSFWorkbook workbook;
/** Excel中对应的Sheet */
private Sheet sheet;
private CellStyle headCellStyle;
private CellStyle cellStyle;
/** 当前行 */
private AtomicInteger currentRow = new AtomicInteger(0);
public ExcelExportUtil(Sheet sheet,SXSSFWorkbook workbook) {
this.workbook = workbook;
this.sheet = sheet;
this.headCellStyle = ExportExcel.getTitleStyle(workbook,false);
this.cellStyle = ExportExcel.getStyle(workbook);
}
/**
* 合并单元格
* @param firstRow 开始行
* @param lastRow 结束行
* @param firstColumn 开始列
* @param lastColumn 结束列
* @param content 合并后内容
* @param isSetHeaderStyle 是否为列头
* @return
*/
public ExcelExportUtil merge(int firstRow, int lastRow, int firstColumn, int lastColumn, Object content, boolean isSetHeaderStyle) {
CellRangeAddress region = new CellRangeAddress(firstRow, lastRow, firstColumn, lastColumn);
sheet.addMergedRegion(region);
setBorderStyle(region,isSetHeaderStyle?this.headCellStyle:this.cellStyle);
// 设置内容
if (null != content) {
final Cell cell = getOrCreateCell(firstColumn, firstRow);
generateValue(content, cell,isSetHeaderStyle);
}
return this;
}
/**
* 设置合并单元格的边框样式
* @param region
* @param cellStyle
*/
public void setBorderStyle(CellRangeAddress region,CellStyle cellStyle){
RegionUtil.setBorderBottom(cellStyle.getBorderBottom(), region, sheet, workbook);
RegionUtil.setBorderLeft(cellStyle.getBorderLeft(), region, sheet, workbook);
RegionUtil.setBorderRight(cellStyle.getBorderRight(), region, sheet, workbook);
RegionUtil.setBorderTop(cellStyle.getBorderTop(), region, sheet, workbook);
}
/**
* 获取或创建指定坐标单元格
*
* @param x X坐标,从0计数,即列号
* @param y Y坐标,从0计数,即行号
*/
public Cell getOrCreateCell(int x, int y) {
return getCell(x, y, true);
}
/**
* 获取指定坐标单元格,如果isCreateIfNotExist为false,则在单元格不存在时返回<code>null</code>
*
* @param x X坐标,从0计数,即列号
* @param y Y坐标,从0计数,即行号
* @param isCreateIfNotExist 单元格不存在时是否创建
*/
public Cell getCell(int x, int y, boolean isCreateIfNotExist) {
final Row row = isCreateIfNotExist ? RowUtil.getOrCreateRow(this.sheet, y) : this.sheet.getRow(y);
if (null != row) {
return isCreateIfNotExist ? CellUtil.getOrCreateCell(row, x) : row.getCell(x);
}
return null;
}
/**
* 创建单元格
* @param row
* @param cellNum
* @param value
*/
public void createCell(Row row, int cellNum, Object value) {
Cell cell = row.createCell(cellNum);
generateValue(value, cell,false);
}
private void generateValue(Object value, Cell cell,boolean isSetHeaderStyle) {
if (value instanceof String) {
cell.setCellValue((String) value);
} else if (value instanceof Boolean) {
cell.setCellValue((Boolean) value);
} else if (value instanceof Double) {
cell.setCellValue((Double) value);
} else if (value instanceof Date) {
cell.setCellValue((Date) value);
} else if (value instanceof Calendar) {
cell.setCellValue((Calendar) value);
} else if (value instanceof RichTextString) {
cell.setCellValue((RichTextString) value);
}else if(value instanceof Integer){
cell.setCellValue((Integer) value);
}else{
cell.setCellValue(value+"");
}
cell.setCellStyle(isSetHeaderStyle?this.headCellStyle:this.cellStyle);
}
/**
* 写入标题
* @param rowData
* @return
*/
public ExcelExportUtil writeTitle(Iterable<?> rowData) {
Row row = this.sheet.createRow(this.currentRow.getAndIncrement());
int i = 0;
for (Object value : rowData) {
this.createCell(row,i,value);
i++;
}
return this;
}
/**
* 写入内容数据
* @param lstDatas
* @return
*/
public ExcelExportUtil writeData(List<List<Object>> lstDatas) {
if(!ObjectUtils.isEmpty(lstDatas)){
int rowNum = 0;
Row row;
for(List<Object> rowData : lstDatas){
row = this.sheet.createRow(this.currentRow.getAndIncrement());
int i = 0;
for (Object value : rowData) {
this.createCell(row,i,value);
i++;
}
rowNum++;
//每当行数达到设置的值就刷新数据到硬盘,以清理内存
if(rowNum / 1000 == 0){
try {
((SXSSFSheet)sheet).flushRows(1000);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return this;
}
/**
* 设置单元格字体颜色
* @param isTitle 是否为列头
* @param color 颜色值
* @param bold 字体是否加粗
* @param row 行号
* @param cellNum 单元格号
*/
public void setCellFontColor(boolean isTitle,short color,boolean bold,int row, List<Integer> cellNum) {
CellStyle style = isTitle ? ExportExcel.getTitleStyle(workbook,false) : ExportExcel.getStyle(workbook);
Font font = ExportExcel.getFont(workbook,bold);
font.setColor(color);
style.setFont(font);
for(int c : cellNum){
Cell cell = this.getCell(c,row,false);
if(cell != null){
cell.setCellStyle(style);
}
}
}
public static String getCellValueByCell(Cell cell) {
//判断是否为null或空串
if (cell == null || cell.toString().trim().equals("") || cell.getCellType() == Cell.CELL_TYPE_BLANK) {
return "";
}
String cellValue = "";
int cellType=cell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING: //字符串类型
cellValue= cell.getStringCellValue().trim();
break;
case Cell.CELL_TYPE_BOOLEAN: //布尔类型
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_NUMERIC: //数值类型
if (HSSFDateUtil.isCellDateFormatted(cell)) { //判断日期类型
cellValue = DateUtils.formatDate(cell.getDateCellValue(), "yyyy-MM-dd");
} else { //否
cellValue = new DecimalFormat("#.######").format(cell.getNumericCellValue());
}
break;
default: //其它类型,取空串吧
cellValue = "";
break;
}
return cellValue;
}
/**
* 给单元格设置批注
* @param rowNum 行号
* @param cellNum 列号
* @param richText 批注内容
*/
public void setComment(int rowNum, int cellNum,String richText){
Cell cell = this.getCell(cellNum,rowNum,false);
Drawing p = sheet.createDrawingPatriarch();
XSSFClientAnchor clientAnchor = new XSSFClientAnchor(0,0,0,0,cellNum,rowNum,cellNum,rowNum);
Comment comment = p.createCellComment(clientAnchor);
// 输入批注信息
comment.setString(new XSSFRichTextString(richText));
cell.setCellComment(comment);
}
}