| | |
| | | Map<String, Integer> colMap; |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderCols(sheet, "道路货物运输月度生产情况", "企业名称", "货运量_总计"); |
| | | colMap = buildHeaderMap(sheet.getRow(0)); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | // sheet0: 公路旅客6月报 |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderCols(sheet, "公路旅客运输月度生产情况", "企业名称", "客运量_总计"); |
| | | Map<String, Integer> colMap = buildHeaderMap(sheet.getRow(0)); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | Map<String, Integer> colMap = buildHeaderMap(sheet.getRow(0)); |
| | | requireHeaderCols(sheet, "旅客运政车辆数", "企业名称", "车辆数", "载客位数"); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | // sheet0: 第二季度货车能耗明细(每行左右各5组车辆,每组固定18列) |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderKeyword(sheet, "道路货运车辆能源消耗情况", "企业名称", "车牌号"); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | |
| | | List<EnergyAuthVehicle> authList = new ArrayList<>(); |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderKeyword(sheet, "能耗车辆运政信息", "车牌号"); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | |
| | | int failRows = 0; |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderKeyword(sheet, "运政车辆", "企业名称"); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | |
| | | int failRows = 0; |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderKeyword(sheet, "轨迹里程", "企业名称"); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | |
| | | List<ScaleSplitTransport> list = new ArrayList<>(); |
| | | int failRows = 0; |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | boolean hasPeriodSheet = false; |
| | | for (int i = 0; i < wb.getNumberOfSheets(); i++) { |
| | | String sn = wb.getSheetAt(i).getSheetName(); |
| | | if (sn != null && (sn.contains("当月") || sn.contains("累计"))) { hasPeriodSheet = true; break; } |
| | | } |
| | | if (!hasPeriodSheet) { |
| | | throw new RuntimeException("所选数据类型【规上规下拆分】与文件内容不符:未找到含 当月/累计 的 sheet,请确认是否选错了数据类型"); |
| | | } |
| | | for (int i = 0; i < wb.getNumberOfSheets(); i++) { |
| | | Sheet sheet = wb.getSheetAt(i); |
| | | String sheetName = sheet.getSheetName(); |
| | |
| | | int monthCount = Integer.parseInt(period.split("-")[1]); |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | boolean cityRowFound = false; |
| | | for (int r = 1; r <= Math.min(sheet.getLastRowNum(), 30); r++) { |
| | | Row rr = sheet.getRow(r); |
| | | if (rr == null) continue; |
| | | String nm = getString(rr, 0); |
| | | if (nm == null || nm.trim().isEmpty()) continue; |
| | | String region = RegionUtil.normalizeCityName(nm); |
| | | if (RegionUtil.cityList().contains(region) || "湖北省".equals(region)) { cityRowFound = true; break; } |
| | | } |
| | | if (!cityRowFound) { |
| | | throw new RuntimeException("所选数据类型【货运量周转量】与文件内容不符:未识别到市州行(首列应为市州名称),请确认是否选错了数据类型"); |
| | | } |
| | | Map<String, FreightTurnoverImport> freightMap = new HashMap<>(); |
| | | Map<String, FreightTurnoverImport> turnoverMap = new HashMap<>(); |
| | | Set<String> seen = new HashSet<>(); |
| | |
| | | } |
| | | } |
| | | |
| | | /** 类型-表头校验:按必需列名(解析器实际依赖的列),缺失即抛"类型与文件不符" */ |
| | | private void requireHeaderCols(Sheet sheet, String typeLabel, String... cols) { |
| | | Map<String, Integer> colMap = buildHeaderMap(sheet.getRow(0)); |
| | | List<String> missing = new ArrayList<>(); |
| | | for (String c : cols) { |
| | | if (!colMap.containsKey(c)) missing.add(c); |
| | | } |
| | | if (!missing.isEmpty()) { |
| | | throw new RuntimeException("所选数据类型【" + typeLabel + "】与文件内容不符:表头缺少必需列【" + String.join("】【", missing) + "】,请确认是否选错了数据类型"); |
| | | } |
| | | } |
| | | |
| | | /** 类型-表头校验:扫描表头行,命中任一关键字即通过 */ |
| | | private void requireHeaderKeyword(Sheet sheet, String typeLabel, String... keywords) { |
| | | Row header = sheet == null ? null : sheet.getRow(0); |
| | | if (header != null) { |
| | | for (Cell cell : header) { |
| | | String v = FORMATTER.formatCellValue(cell); |
| | | if (v == null || v.isEmpty()) continue; |
| | | for (String k : keywords) { |
| | | if (v.contains(k)) return; |
| | | } |
| | | } |
| | | } |
| | | throw new RuntimeException("所选数据类型【" + typeLabel + "】与文件内容不符:表头未包含【" + String.join("】【", keywords) + "】等列,请确认是否选错了数据类型"); |
| | | } |
| | | |
| | | /** 按表头名称建立列号映射,兼容新旧模板列位差异 */ |
| | | private Map<String, Integer> buildHeaderMap(Row header) { |
| | | Map<String, Integer> colMap = new HashMap<>(); |
| | |
| | | } |
| | | } |
| | | if (headerRow < 0) { |
| | | throw new RuntimeException("未找到表头行(需包含 序号/项目名称 列)"); |
| | | throw new RuntimeException("所选数据类型【" + (passenger ? "投资月报(客运站场)" : "投资月报(物流园区)") + "】与文件内容不符:未找到表头行(需包含 序号/项目名称 列),请确认是否选错了数据类型"); |
| | | } |
| | | for (int r = headerRow + 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | |
| | | } |
| | | fileResults.add(fr); |
| | | } |
| | | // 幂等清理:同类别同报表期月度数据 + INVEST 审核结果(项目主档跨月保留,按名 upsert) |
| | | cleanInvestMonthly(category, period); |
| | | // 幂等清理:按本次文件涉及市州清理月度数据 + INVEST 审核结果(项目主档跨月保留,按名 upsert) |
| | | cleanInvestMonthlyByCity(category, period, rows); |
| | | Map<String, Set<String>> knownCities = loadInvestKnownCities(category); |
| | | Map<String, String> fileFirstMismatch = new LinkedHashMap<>(); |
| | | int success = 0; |
| | | List<String> failDetails = new ArrayList<>(); |
| | | for (InvestCityRow item : rows) { |
| | | String mismatch = investCityMismatchReason(item, knownCities); |
| | | if (mismatch != null) { |
| | | failDetails.add(mismatch); |
| | | fileFirstMismatch.putIfAbsent(item.fileName, mismatch); |
| | | continue; |
| | | } |
| | | try { |
| | | saveInvestProjectRow(item.project, item.monthly); |
| | | success++; |
| | |
| | | failDetails.add(item.fileName + " 第 " + item.excelRow + " 行(" + item.project.getProjectName() + "):" + reason); |
| | | log.error("Invest city insert error: file {}, row {}", item.fileName, item.excelRow, e); |
| | | } |
| | | } |
| | | // 把首个市州错位提示挂到对应文件结果上,便于页面弹窗直接看到 |
| | | for (Map<String, Object> fr2 : fileResults) { |
| | | String msg = fileFirstMismatch.get(fr2.get("fileName")); |
| | | if (msg != null && fr2.get("error") == null) fr2.put("error", msg); |
| | | } |
| | | String errorDetail = String.join("\n", failDetails); |
| | | if (errorDetail.length() > 4000) errorDetail = errorDetail.substring(0, 4000) + "\n……"; |
| | |
| | | result.put("fiveYearTemplateProjects", fiveYearNames.size()); |
| | | result.put("fiveYearMatched", fiveYearMatched); |
| | | log.info("Invest city {} {} imported: {} rows (fiveYear matched {}/{})", |
| | | category, period, success, fiveYearMatched, fiveYearNames.size()); |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 多文件批量导入:前端一次选择多个 Excel 上传。 |
| | | * 投资类型(investment/investmentLogistics)按市州单表解析(文件名/填报单位识别市州,十五五自动标记); |
| | | * 其他类型逐个走现有解析逻辑(importDirFile)。 |
| | | */ |
| | | public Map<String, Object> importBatchFiles(String type, String period, List<MultipartFile> files) throws Exception { |
| | | if (files == null || files.isEmpty()) { |
| | | throw new RuntimeException("未接收到任何文件"); |
| | | } |
| | | if ("investment".equals(type) || "investmentLogistics".equals(type)) { |
| | | String category = "investment".equals(type) ? "客运站场" : "物流园区"; |
| | | return importInvestCityFiles(period, category, files); |
| | | } |
| | | List<Map<String, Object>> fileResults = new ArrayList<>(); |
| | | int totalSuccess = 0, totalFail = 0; |
| | | for (MultipartFile f : files) { |
| | | Map<String, Object> fr = new LinkedHashMap<>(); |
| | | fr.put("fileName", f.getOriginalFilename()); |
| | | try { |
| | | ImportResult r = importDirFile(type, f, period); |
| | | fr.put("success", r.getSuccess()); |
| | | fr.put("fail", r.getFail()); |
| | | if (r.getFail() > 0 && r.getFailDetails() != null && !r.getFailDetails().isEmpty()) { |
| | | fr.put("error", r.getFailDetails().get(0)); |
| | | } |
| | | totalSuccess += r.getSuccess(); |
| | | totalFail += r.getFail(); |
| | | } catch (Exception e) { |
| | | fr.put("success", 0); |
| | | fr.put("fail", 0); |
| | | fr.put("error", e.getMessage() == null ? e.toString() : e.getMessage()); |
| | | totalFail++; |
| | | } |
| | | fileResults.add(fr); |
| | | } |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("type", type); |
| | | result.put("total", files.size()); |
| | | result.put("success", totalSuccess); |
| | | result.put("fail", totalFail); |
| | | result.put("files", fileResults); |
| | | return result; |
| | | } |
| | | |
| | | /** 投资多文件批量:逐文件按市州单表解析,统一幂等清理落库,批次汇总 */ |
| | | public Map<String, Object> importInvestCityFiles(String period, String category, List<MultipartFile> files) throws Exception { |
| | | boolean passenger = "客运站场".equals(category); |
| | | Set<String> fiveYearNames = loadFiveYearProjectNames(); |
| | | List<InvestCityRow> rows = new ArrayList<>(); |
| | | List<Map<String, Object>> fileResults = new ArrayList<>(); |
| | | for (MultipartFile f : files) { |
| | | Map<String, Object> fr = new LinkedHashMap<>(); |
| | | fr.put("fileName", f.getOriginalFilename()); |
| | | try (Workbook wb = WorkbookFactory.create(f.getInputStream())) { |
| | | parseInvestCityWorkbook(wb, f.getOriginalFilename(), category, period, fiveYearNames, rows, fr); |
| | | } catch (Exception e) { |
| | | fr.put("success", 0); |
| | | fr.put("error", e.getMessage() == null ? e.toString() : e.getMessage()); |
| | | log.error("invest city file parse error: {}", f.getOriginalFilename(), e); |
| | | } |
| | | fileResults.add(fr); |
| | | } |
| | | String catDir = passenger ? "客运(客运站)" : "物流(物流园区)"; |
| | | cleanInvestMonthlyByCity(category, period, rows); |
| | | Map<String, Set<String>> knownCities = loadInvestKnownCities(category); |
| | | Map<String, String> fileFirstMismatch = new LinkedHashMap<>(); |
| | | int success = 0; |
| | | List<String> failDetails = new ArrayList<>(); |
| | | for (InvestCityRow item : rows) { |
| | | String mismatch = investCityMismatchReason(item, knownCities); |
| | | if (mismatch != null) { |
| | | failDetails.add(mismatch); |
| | | fileFirstMismatch.putIfAbsent(item.fileName, mismatch); |
| | | continue; |
| | | } |
| | | try { |
| | | saveInvestProjectRow(item.project, item.monthly); |
| | | success++; |
| | | } catch (Exception e) { |
| | | Throwable cause = e; |
| | | while (cause.getCause() != null) cause = cause.getCause(); |
| | | String reason = cause.getMessage(); |
| | | if (reason == null || reason.trim().isEmpty()) reason = e.getMessage(); |
| | | failDetails.add(item.fileName + " 第 " + item.excelRow + " 行(" + item.project.getProjectName() + "):" + reason); |
| | | log.error("Invest city insert error: file {}, row {}", item.fileName, item.excelRow, e); |
| | | } |
| | | } |
| | | // 把首个市州错位提示挂到对应文件结果上,便于页面弹窗直接看到 |
| | | for (Map<String, Object> fr2 : fileResults) { |
| | | String msg = fileFirstMismatch.get(fr2.get("fileName")); |
| | | if (msg != null && fr2.get("error") == null) fr2.put("error", msg); |
| | | } |
| | | String errorDetail = String.join("\n", failDetails); |
| | | if (errorDetail.length() > 4000) errorDetail = errorDetail.substring(0, 4000) + "\n……"; |
| | | recordBatch("多文件批量导入(" + catDir + "/" + period + ")", "INVEST_" + category + "_CITY", |
| | | period, rows.size(), success, failDetails.size(), errorDetail); |
| | | int fiveYearMatched = 0; |
| | | for (InvestCityRow item : rows) { |
| | | if (Integer.valueOf(1).equals(item.project.getIsFiveYear())) fiveYearMatched++; |
| | | } |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("total", rows.size()); |
| | | result.put("success", success); |
| | | result.put("fail", failDetails.size()); |
| | | result.put("failDetails", failDetails); |
| | | result.put("files", fileResults); |
| | | result.put("fiveYearTemplateProjects", fiveYearNames.size()); |
| | | result.put("fiveYearMatched", fiveYearMatched); |
| | | log.info("Invest city multi-file {} {} imported: {} rows (fiveYear matched {}/{})", |
| | | category, period, success, fiveYearMatched, fiveYearNames.size()); |
| | | return result; |
| | | } |
| | |
| | | } |
| | | String city = cityFromFileName(fileName); |
| | | if (city == null) city = cityFromSheetHeader(best); |
| | | fr.put("city", city == null ? "" : city); |
| | | String currentCity = city; |
| | | Map<String, Integer> col = bestCol; |
| | | int nameCol = col.get("name"); |
| | |
| | | Row row = best.getRow(r); |
| | | if (row == null) continue; |
| | | String name = cellStr(row, nameCol); |
| | | String seq = hasSeq ? cellStr(row, seqCol) : null; |
| | | // 市州小节行:部分汇总表把市州名写在序号列(如十堰汇总表 A 列写"武汉"),需同样识别 |
| | | if (seq != null && !seq.trim().isEmpty()) { |
| | | String seqCity = investmentCity(seq.trim()); |
| | | if (seqCity != null) { |
| | | currentCity = seqCity; |
| | | continue; |
| | | } |
| | | } |
| | | if (name == null || name.trim().isEmpty()) continue; |
| | | String nt = name.trim().replaceAll("[\r\n]+", ""); |
| | | if (nt.contains("合计") || nt.contains("总计")) continue; |
| | |
| | | if (nt.replace(" ", "").matches(".*小\\s*计.*")) continue; |
| | | if (nt.startsWith("填报") || nt.startsWith("单位负责人") || nt.matches("^\\d+、.*")) continue; |
| | | if (hasSeq) { |
| | | String seq = cellStr(row, seqCol); |
| | | if (seq == null || seq.trim().isEmpty()) { |
| | | // 市州小节行(如 "武汉" "天 门"),更新当前市州 |
| | | String c = investmentCity(nt); |
| | |
| | | return null; |
| | | } |
| | | |
| | | /** 同类别同报表期月度数据 + INVEST 审核结果清理(幂等) */ |
| | | /** 同类别同报表期月度数据 + INVEST 审核结果清理(幂等,全省汇总大表全量清理) */ |
| | | private void cleanInvestMonthly(String category, String period) { |
| | | List<InvestmentProject> sameCat = investProjectMapper.selectList( |
| | | new LambdaQueryWrapper<InvestmentProject>().eq(InvestmentProject::getCategory, category)); |
| | |
| | | .eq(InvestmentMonthly::getReportPeriod, period) |
| | | .in(InvestmentMonthly::getProjectId, catProjectIds)); |
| | | } |
| | | deleteInvestAuditResults(period, null); |
| | | } |
| | | |
| | | /** 按市州清理:只删除本次文件涉及市州(含未识别市州的 null 项目)的月度数据 + INVEST 审核结果 */ |
| | | private void cleanInvestMonthlyByCity(String category, String period, List<InvestCityRow> rows) { |
| | | Set<String> citySet = new HashSet<>(); |
| | | boolean hasNullCity = false; |
| | | for (InvestCityRow item : rows) { |
| | | String c = item.project.getCity(); |
| | | if (c == null || c.trim().isEmpty()) hasNullCity = true; |
| | | else citySet.add(c.trim()); |
| | | } |
| | | if (citySet.isEmpty() && !hasNullCity) return; |
| | | boolean cleanNullCity = hasNullCity; |
| | | LambdaQueryWrapper<InvestmentProject> pw = new LambdaQueryWrapper<InvestmentProject>() |
| | | .eq(InvestmentProject::getCategory, category); |
| | | pw.and(w -> { |
| | | if (!citySet.isEmpty()) w.in(InvestmentProject::getCity, citySet); |
| | | if (cleanNullCity) { |
| | | if (!citySet.isEmpty()) w.or(); |
| | | w.isNull(InvestmentProject::getCity); |
| | | } |
| | | }); |
| | | List<InvestmentProject> cityProjects = investProjectMapper.selectList(pw); |
| | | java.util.Set<Long> catProjectIds = new HashSet<>(); |
| | | for (InvestmentProject pc : cityProjects) catProjectIds.add(pc.getId()); |
| | | if (catProjectIds.isEmpty()) return; |
| | | List<InvestmentMonthly> oldMonthlies = investMonthlyMapper.selectList( |
| | | new LambdaQueryWrapper<InvestmentMonthly>() |
| | | .eq(InvestmentMonthly::getReportPeriod, period) |
| | | .in(InvestmentMonthly::getProjectId, catProjectIds)); |
| | | java.util.Set<Long> oldMonthlyIds = new HashSet<>(); |
| | | for (InvestmentMonthly m : oldMonthlies) oldMonthlyIds.add(m.getId()); |
| | | investMonthlyMapper.delete(new LambdaQueryWrapper<InvestmentMonthly>() |
| | | .eq(InvestmentMonthly::getReportPeriod, period) |
| | | .in(InvestmentMonthly::getProjectId, catProjectIds)); |
| | | deleteInvestAuditResults(period, oldMonthlyIds); |
| | | } |
| | | |
| | | /** 清理 INVEST 审核结果(monthlyIds 为 null 表示该期间全量清理) */ |
| | | private void deleteInvestAuditResults(String period, java.util.Set<Long> monthlyIds) { |
| | | List<Long> investRuleIds = new ArrayList<>(); |
| | | for (com.trafficaudit.rulemanage.entity.AuditRule rule : ruleMapper.selectList(null)) { |
| | | if ("INVEST".equals(rule.getReportType())) investRuleIds.add(rule.getId()); |
| | | } |
| | | if (!investRuleIds.isEmpty()) { |
| | | auditResultMapper.delete(new LambdaQueryWrapper<AuditResult>() |
| | | .eq(AuditResult::getReportPeriod, period) |
| | | .in(AuditResult::getRuleId, investRuleIds)); |
| | | if (investRuleIds.isEmpty()) return; |
| | | LambdaQueryWrapper<AuditResult> w = new LambdaQueryWrapper<AuditResult>() |
| | | .eq(AuditResult::getReportPeriod, period) |
| | | .in(AuditResult::getRuleId, investRuleIds); |
| | | if (monthlyIds != null) { |
| | | if (monthlyIds.isEmpty()) return; |
| | | w.in(AuditResult::getReportId, monthlyIds); |
| | | } |
| | | auditResultMapper.delete(w); |
| | | } |
| | | |
| | | /** 项目主档 upsert(按 项目名+类别)+ 月度写入 */ |
| | |
| | | monthly.setProjectId(exist.getId()); |
| | | } |
| | | investMonthlyMapper.insert(monthly); |
| | | } |
| | | |
| | | /** 载入某类别「规范化项目名 -> 已入库市州集合」,用于市州一致性校验(名称在多个市州重复时放弃校验) */ |
| | | private Map<String, Set<String>> loadInvestKnownCities(String category) { |
| | | Map<String, Set<String>> map = new HashMap<>(); |
| | | List<InvestmentProject> list = investProjectMapper.selectList( |
| | | new LambdaQueryWrapper<InvestmentProject>().eq(InvestmentProject::getCategory, category)); |
| | | for (InvestmentProject p : list) { |
| | | if (p.getCity() == null || p.getCity().trim().isEmpty()) continue; |
| | | map.computeIfAbsent(normalizeProjectName(p.getProjectName()), k -> new HashSet<>()) |
| | | .add(p.getCity().trim()); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** 市州一致性校验:库中唯一归属市州与本次解析不一致时返回错误说明,否则返回 null */ |
| | | private String investCityMismatchReason(InvestCityRow item, Map<String, Set<String>> knownCities) { |
| | | String parsed = item.project.getCity(); |
| | | if (parsed == null || parsed.trim().isEmpty()) return null; |
| | | Set<String> known = knownCities.get(normalizeProjectName(item.project.getProjectName())); |
| | | if (known == null || known.size() != 1) return null; |
| | | String knownCity = known.iterator().next(); |
| | | if (knownCity.equals(parsed.trim())) return null; |
| | | return item.fileName + " 第 " + item.excelRow + " 行(" + item.project.getProjectName() |
| | | + "):市州一致性校验未通过——库中该项目归属「" + knownCity + "」,本次文件解析为「" + parsed.trim() |
| | | + "」,疑似市州错位,已跳过导入,请核对源文件"; |
| | | } |
| | | |
| | | private String cellStr(Row row, int idx) { |
| | |
| | | int failRows = 0; |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderKeyword(sheet, "投资系统导出", "项目名称"); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | |
| | | List<CityTaxiAuth> list = new ArrayList<>(); |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderKeyword(sheet, "出租车运政车辆", "车牌"); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |