Cannot get a NUMERIC value from a STRING cell? 已解決
阿新 • • 發佈:2018-12-20
最近在寫專案中用到了excel的匯入,遇到了Cannot get a NUMERIC value from a STRING cell的報錯。原因是無法從純數字的單元格用獲取String的方式獲取。跟了一下蛋碼,但是我明明做了處理了啊,看這裡
真是奇了個怪。。。。
網上百度了一堆,基本都指出了這個錯誤的原因,但。。。可能是我這個新手看不懂別人的蛋碼吧,其實我覺得他們的蛋碼沒有抽出來真的難看。
好了,看看我之前的程式碼:
再看看我修改之後的程式碼:
總結起來就是,我已經把讀取到的單元格內容的型別(NUMERIC)改為了STRING了,但我不知道為什麼switch還是走了NUMERIC(可能是我沒有轉換格式成功),然後我又用NUMERIC的取值方式 getNumericCellValue(),所以就報錯咯。
這是全部程式碼
Controller
/** * 兌換碼匯入 * * @return * @throws ParseException * @author lmh */ @PostMapping(value = "/readExcel") // @ApiOperation(value = "兌換碼匯入") @Transactional // @RequiresPermissions("/lotteryPrize/readExcel") // @ApiImplicitParams({ // @ApiImplicitParam(name = "prizeId", value = "獎品id", required = true, dataType = "String"),// @ApiImplicitParam(name = "prizeUrl", value = "兌換URI", required = true, dataType = "String")}) public ResponseEntity<Map<String, Object>> readExcel(/*String prizeId, String prizeUrl,*/ @RequestParam(value = "excelFile") MultipartFile excelFile) throwsParseException { Map<String, Object> resultMap = new HashMap<>(); try { // 修改獎品表 // LotteryPrize prize = new LotteryPrize(); // prize.setId(prizeId); // prize.setPrizeUrl(prizeUrl); // prize.setUpdateTime(new Date(System.currentTimeMillis())); // boolean ret = this.prizeService.updateById(prize); // 匯入兌換碼 List<LotteryRedeemCode> redeemCodes = new ArrayList<LotteryRedeemCode>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); List<String[]> codeList = ReadExcelUtil.readExcel(excelFile); Map<String, Integer> titleMap = new HashMap<String, Integer>(); for (int i = 0; i < codeList.size(); i++) { String[] code = codeList.get(i); if (i == 0) { for (int j = 0; j < code.length; j++) { titleMap.put(code[j], j); } continue; } LotteryRedeemCode redeemCode = new LotteryRedeemCode(); redeemCode.setCreateTime(new Date(System.currentTimeMillis())); redeemCode.setRedeemCode(code[titleMap.get("兌換碼")]); // redeemCode.setPrizeId(prizeId); redeemCodes.add(redeemCode); } if (redeemCodes.size() > 0) { // 批量新增(這裡是Mybatis-Plus框架),你們可以用for進行新增操作 this.redeemCodeService.insertBatch(redeemCodes); } if (!ret) { // 刪除失敗, 500 resultMap.put("status", 500); resultMap.put("message", "上傳失敗!"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resultMap); } resultMap.put("status", 201); resultMap.put("message", "上傳成功!"); return ResponseEntity.status(HttpStatus.CREATED).body(resultMap); } catch (IOException e) { logger.info("讀取excel檔案失敗", e); } return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); }
package 這裡自己寫; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.multipart.MultipartFile; /** * 匯入excel工具類 * * @author lmh */ public class ReadExcelUtil { private static Logger logger = LoggerFactory.getLogger(ReadExcelUtil.class); private final static String xls = "xls"; private final static String xlsx = "xlsx"; /** * 讀入excel檔案,解析後返回 * * @param file * @throws IOException */ public static List<String[]> readExcel(MultipartFile file) throws IOException { // 檢查檔案 checkFile(file); // 獲得Workbook工作薄物件 Workbook workbook = getWorkBook(file); // 建立返回物件,把每行中的值作為一個數組,所有行作為一個集合返回 List<String[]> list = new ArrayList<String[]>(); if (workbook != null) { for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) { // 獲得當前sheet工作表 Sheet sheet = workbook.getSheetAt(sheetNum); if (sheet == null) { continue; } // 獲得當前sheet的開始行 int firstRowNum = sheet.getFirstRowNum(); // 獲得當前sheet的結束行 int lastRowNum = sheet.getLastRowNum(); if (firstRowNum <= 0 && lastRowNum < 1) { break; } // 獲取頭部的長度 Row tiRow = sheet.getRow(firstRowNum); int totalClumNum = tiRow.getPhysicalNumberOfCells(); // 迴圈所有行 for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++) { // 獲得當前行 Row row = sheet.getRow(rowNum); if (row == null) { continue; } int lastCellNum = row.getPhysicalNumberOfCells(); if (lastCellNum <= 0) { continue; } // 獲得當前行的開始列 // int firstCellNum = row.getFirstCellNum(); 區第一個有值的列 // //獲得當前行的列數 // int lastCellNum = row.getPhysicalNumberOfCells(); String[] cells = new String[totalClumNum]; // 迴圈當前行 for (int cellNum = 0; cellNum < totalClumNum; cellNum++) { Cell cell = row.getCell(cellNum); cells[cellNum] = getCellValue(cell); } list.add(cells); } } workbook.close(); } return list; } public static void checkFile(MultipartFile file) throws IOException { // 判斷檔案是否存在 if (null == file) { logger.error("檔案不存在!"); throw new FileNotFoundException("檔案不存在!"); } // 獲得檔名 String fileName = file.getOriginalFilename(); // 判斷檔案是否是excel檔案 if (!fileName.endsWith(xls) && !fileName.endsWith(xlsx)) { logger.error(fileName + "不是excel檔案"); throw new IOException(fileName + "不是excel檔案"); } } public static Workbook getWorkBook(MultipartFile file) { // 獲得檔名 String fileName = file.getOriginalFilename(); // 建立Workbook工作薄物件,表示整個excel Workbook workbook = null; try { // 獲取excel檔案的io流 InputStream is = file.getInputStream(); // 根據檔案字尾名不同(xls和xlsx)獲得不同的Workbook實現類物件 if (fileName.endsWith(xls)) { // 2003 workbook = new HSSFWorkbook(is); } else if (fileName.endsWith(xlsx)) { // 2007 workbook = new XSSFWorkbook(is); } } catch (IOException e) { logger.info(e.getMessage()); } return workbook; } public static String getCellValue(Cell cell) { SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd"); String cellValue = ""; if (cell == null) { return cellValue; } CellType cellType = cell.getCellTypeEnum(); // 把數字當成String來讀,避免出現1讀成1.0的情況 if (cellType == CellType.NUMERIC) { cell.setCellType(CellType.STRING); } // 判斷資料的型別 switch (cellType) { case NUMERIC: // 數字、日期 if (DateUtil.isCellDateFormatted(cell)) { cellValue = fmt.format(cell.getDateCellValue()); // 日期型 } else { cellValue = String.valueOf(cell.getStringCellValue()); // cellValue = String.valueOf(cell.getNumericCellValue()); // 數字 if (cellValue.contains("E")) { cellValue = String.valueOf(new Double(cell.getNumericCellValue()).longValue()); // 數字 } } break; case STRING: // 字串 cellValue = String.valueOf(cell.getStringCellValue()); break; case BOOLEAN: // Boolean cellValue = String.valueOf(cell.getBooleanCellValue()); break; case FORMULA: // 公式 cellValue = String.valueOf(cell.getCellFormula()); break; case BLANK: // 空值 cellValue = cell.getStringCellValue(); break; case ERROR: // 故障 cellValue = "非法字元"; break; default: cellValue = "未知型別"; break; } return cellValue; } }
上面是工具類,下面是實體類:
@TableName("lottery_redeem_code") public class LotteryRedeemCode extends Model<LotteryRedeemCode> { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.UUID) private String id; /** * 獎品ID */ @ApiModelProperty(value = "獎品ID") @TableField("prize_id") private String prizeId; /** * 兌換碼 */ @ApiModelProperty(value = "兌換碼") @TableField("redeem_code") private String redeemCode; /** * 0-已抽中 1-未抽中 */ @ApiModelProperty(value = "0-已抽中 1-未抽中") private Integer status; /** * 建立時間 */ @ApiModelProperty(value = "建立時間") @TableField("create_time") private Date createTime; /** * 修改時間 */ @ApiModelProperty(value = "修改時間", hidden = true) @TableField("update_time") private Date updateTime; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPrizeId() { return prizeId; } public void setPrizeId(String prizeId) { this.prizeId = prizeId; } public String getRedeemCode() { return redeemCode; } public void setRedeemCode(String redeemCode) { this.redeemCode = redeemCode; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } @Override protected Serializable pkVal() { return this.id; } @Override public String toString() { return "LotteryRedeemCode{" + ", id=" + id + ", prizeId=" + prizeId + ", redeemCode=" + redeemCode + ", status=" + status + ", createTime=" + createTime + ", updateTime=" + updateTime + "}"; } }
MySQL:
CREATE TABLE `lottery_redeem_code` ( `id` CHAR(32) NOT NULL, `redeem_code` VARCHAR(100) NOT NULL COMMENT '兌換碼', `status` TINYINT(4) NOT NULL DEFAULT '1' COMMENT '0-已抽中 1-未抽中', `create_time` DATETIME NOT NULL COMMENT '建立時間', `update_time` DATETIME NULL DEFAULT NULL COMMENT '修改時間', PRIMARY KEY (`id`) ) COMMENT='獎品兌換碼錶' COLLATE='utf8_general_ci' ENGINE=InnoDB ;
這是excel表的格式,格式要求不高,只要有一列的表頭是“兌換碼”就行了,可以隨意更改,只要和Controller中的
redeemCode.setRedeemCode(code[titleMap.get("兌換碼")]);對應起來就行了,假如我把”兌換碼“換成”牛逼“,excel的表頭也要換成”牛逼“。多個表頭的操作也一樣。