|
@@ -0,0 +1,338 @@
|
|
|
+package com.nokia.financeapi.service.car;
|
|
|
+
|
|
|
+import com.nokia.financeapi.common.exception.BizException;
|
|
|
+import com.nokia.financeapi.common.exception.MyRuntimeException;
|
|
|
+import com.nokia.financeapi.common.utils.psql.PsqlUtil;
|
|
|
+import com.nokia.financeapi.config.CarDataImportConfig;
|
|
|
+import com.nokia.financeapi.dao.car.CarChaoBaoDao;
|
|
|
+import com.nokia.financeapi.dao.gdc.GdcCarChaoBaoDao;
|
|
|
+import com.nokia.financeapi.pojo.dto.CarDataImportDto;
|
|
|
+import com.nokia.financeapi.pojo.po.common.AreaPo;
|
|
|
+import com.nokia.financeapi.pojo.po.common.OrganizationPo;
|
|
|
+import com.nokia.financeapi.service.common.AreaService;
|
|
|
+import com.nokia.financeapi.service.common.OrganizationService;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.csv.CSVFormat;
|
|
|
+import org.apache.commons.csv.CSVPrinter;
|
|
|
+import org.apache.commons.io.FileUtils;
|
|
|
+import org.apache.poi.ss.usermodel.Cell;
|
|
|
+import org.apache.poi.ss.usermodel.DateUtil;
|
|
|
+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.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.io.OutputStreamWriter;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.stream.Stream;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class CarChaoBaoImportService {
|
|
|
+ private final CarDataImportConfig carDataImportConfig;
|
|
|
+ private final CarService carService;
|
|
|
+ private final OrganizationService organizationService;
|
|
|
+ private final AreaService areaService;
|
|
|
+ private final CarChaoBaoDao carChaoBaoDao;
|
|
|
+ private final GdcCarChaoBaoDao gdcCarChaoBaoDao;
|
|
|
+
|
|
|
+ public CarChaoBaoImportService(CarDataImportConfig carDataImportConfig, CarService carService,
|
|
|
+ OrganizationService organizationService, AreaService areaService,
|
|
|
+ CarChaoBaoDao carChaoBaoDao, GdcCarChaoBaoDao gdcCarChaoBaoDao) {
|
|
|
+ this.carDataImportConfig = carDataImportConfig;
|
|
|
+ this.carService = carService;
|
|
|
+ this.organizationService = organizationService;
|
|
|
+ this.areaService = areaService;
|
|
|
+ this.carChaoBaoDao = carChaoBaoDao;
|
|
|
+ this.gdcCarChaoBaoDao = gdcCarChaoBaoDao;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(timeout = 120, rollbackFor = Exception.class)
|
|
|
+ public synchronized void dataImport(CarDataImportDto dto, MultipartFile file) throws IOException {
|
|
|
+ boolean flag = carChaoBaoDao.hasData(dto.getYearMonth());
|
|
|
+ if (flag) {
|
|
|
+ throw new BizException("该账期数据已存在");
|
|
|
+ }
|
|
|
+ Files.createDirectories(Paths.get(carDataImportConfig.getChaoBao()));
|
|
|
+ File fileNew = new File(carDataImportConfig.getChaoBao() + dto.getYearMonth() + ".xlsx");
|
|
|
+ FileUtils.copyInputStreamToFile(file.getInputStream(), fileNew);
|
|
|
+ Path path = fileNew.toPath();
|
|
|
+ List<Map<String, String>> list = readFile(path);
|
|
|
+ List<Map<String, String>> distinctList = dataProcessing(path, list, dto);
|
|
|
+ Path csvPath = toCsv(path, distinctList);
|
|
|
+ copyCsv(csvPath);
|
|
|
+ procedure(dto);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 读取文件
|
|
|
+ *
|
|
|
+ * @param path 文件路径
|
|
|
+ */
|
|
|
+ public List<Map<String, String>> readFile(Path path) throws IOException {
|
|
|
+ log.info("读取: {}", path);
|
|
|
+ List<String> rawHeaders = Stream.of("账期", "车牌号", "车型", "单位", "二级单位", "三级单位", "登记日期",
|
|
|
+ "进厂时间", "进厂公里数", "截止数据提取日行驶里程", "是否应该保养", "超出建议保养时间(天)", "超出建议保养公里数")
|
|
|
+ .toList();
|
|
|
+ List<String> headers = Stream.of("year_month", "che_pai_hao", "che_xing", "raw_yi_ji", "raw_er_ji",
|
|
|
+ "raw_san_ji", "deng_ji_ri_qi", "jin_chang_shi_jian", "jin_chang_gong_li", "li_cheng", "bao_yang",
|
|
|
+ "chao_bao_tian_shu", "chao_bao_gong_li").toList();
|
|
|
+ try (InputStream inputStream = Files.newInputStream(path);
|
|
|
+ Workbook workbook = new XSSFWorkbook(inputStream)
|
|
|
+ ) {
|
|
|
+ List<Map<String, String>> resultList = new ArrayList<>();
|
|
|
+ // 读取第一个工作表
|
|
|
+ Sheet sheet = workbook.getSheetAt(0);
|
|
|
+ // 表头行
|
|
|
+ Row headerRow = sheet.getRow(0);
|
|
|
+ // 列数
|
|
|
+ int columnCount = headerRow.getPhysicalNumberOfCells();
|
|
|
+ log.info("columnCount: {}", columnCount);
|
|
|
+ // 检查表头
|
|
|
+ if (headers.size() != columnCount) {
|
|
|
+ throw new BizException("列数错误");
|
|
|
+ }
|
|
|
+ for (int i = 0; i < columnCount; i++) {
|
|
|
+ Cell cell = headerRow.getCell(i);
|
|
|
+ if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
|
|
|
+ throw new BizException("表头错误");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 最后行数
|
|
|
+ int lastRowNum = sheet.getLastRowNum();
|
|
|
+ log.info("lastRowNum: {}", lastRowNum);
|
|
|
+ if (lastRowNum == 0) {
|
|
|
+ throw new BizException("文件为空");
|
|
|
+ }
|
|
|
+ // 遍历行
|
|
|
+ for (int i = 1; i <= lastRowNum; i++) {
|
|
|
+ Row row = sheet.getRow(i);
|
|
|
+ if (row == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Map<String, String> rowMap = new LinkedHashMap<>();
|
|
|
+ // 遍历列
|
|
|
+ for (int j = 0; j < columnCount; j++) {
|
|
|
+ String header = headers.get(j);
|
|
|
+ String cellValue = "";
|
|
|
+ rowMap.put(header, cellValue);
|
|
|
+ Cell cell = row.getCell(j);
|
|
|
+ if (cell == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ switch (cell.getCellType()) {
|
|
|
+ case STRING:
|
|
|
+ boolean skipTrim = "deng_ji_ri_qi".equals(header) || "jin_chang_shi_jian".equals(header);
|
|
|
+ // 删除字符串空白字符
|
|
|
+ cellValue = skipTrim ? cell.getStringCellValue()
|
|
|
+ : StringUtils.trimAllWhitespace(cell.getStringCellValue());
|
|
|
+ break;
|
|
|
+ case NUMERIC:
|
|
|
+ if (DateUtil.isCellDateFormatted(cell)) {
|
|
|
+ cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
|
|
|
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ cellValue = String.valueOf(cell.getNumericCellValue());
|
|
|
+ break;
|
|
|
+ case BOOLEAN:
|
|
|
+ cellValue = String.valueOf(cell.getBooleanCellValue());
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ rowMap.put(header, cellValue);
|
|
|
+ }
|
|
|
+ resultList.add(rowMap);
|
|
|
+ }
|
|
|
+ return resultList;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 数据加工
|
|
|
+ *
|
|
|
+ * @param path 文件路径
|
|
|
+ * @param list 数据
|
|
|
+ * @param dto 请求参数
|
|
|
+ */
|
|
|
+ public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list, CarDataImportDto dto) {
|
|
|
+ String yearMonth = dto.getYearMonth().toString();
|
|
|
+ LocalDate localDate = LocalDate.parse(yearMonth + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
|
|
|
+ String year = String.valueOf(localDate.getYear());
|
|
|
+ String month = String.valueOf(localDate.getMonthValue());
|
|
|
+ List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
|
|
|
+ List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
|
|
|
+ Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
|
|
|
+ Map<String, List<OrganizationPo>> thirdOrganizationListMap =
|
|
|
+ organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
|
|
|
+ List<AreaPo> cities = areaService.getCities();
|
|
|
+ List<AreaPo> districts = areaService.getDistricts();
|
|
|
+ Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
|
|
|
+ Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
|
|
|
+ for (Map<String, String> map : list) {
|
|
|
+ map.put("year_month", yearMonth);
|
|
|
+ map.put("year_no", year);
|
|
|
+ map.put("month_no", month);
|
|
|
+ String rawChePaiHao = map.get("che_pai_hao");
|
|
|
+ map.put("raw_che_pai_hao", rawChePaiHao);
|
|
|
+ String chePaiHao = carService.getChePai(rawChePaiHao);
|
|
|
+ map.put("che_pai_hao", chePaiHao);
|
|
|
+ String chePaiFail = carService.chePaiFail(rawChePaiHao);
|
|
|
+ map.put("che_pai_fail", chePaiFail);
|
|
|
+ String yj = map.get("raw_yi_ji");
|
|
|
+ String ej = map.get("raw_er_ji");
|
|
|
+ String sj = map.get("raw_san_ji");
|
|
|
+ String firstUnit = carService.getFirstUnit(yj);
|
|
|
+ map.put("first_unit", firstUnit);
|
|
|
+ String secondUnit = carService.getSecondUnit(ej, firstUnit);
|
|
|
+ map.put("second_unit", secondUnit);
|
|
|
+ String thirdUnit = carService.getThirdUnit(sj, secondUnit);
|
|
|
+ map.put("third_unit", thirdUnit);
|
|
|
+ String areaNo = carService.getAreaNo(secondOrgs, yj);
|
|
|
+ map.put("area_no", areaNo);
|
|
|
+ String areaName = carService.getOrgName(orgMap, areaNo);
|
|
|
+ map.put("area_name", areaName);
|
|
|
+ String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, ej);
|
|
|
+ map.put("city_no", cityNo);
|
|
|
+ String cityName = carService.getOrgName(orgMap, cityNo);
|
|
|
+ map.put("city_name", cityName);
|
|
|
+ String areaNo2 = carService.getAreaNo2(areaName, cityName);
|
|
|
+ map.put("area_no2", areaNo2);
|
|
|
+ String areaName2 = carService.getOrgName(orgMap, areaNo2);
|
|
|
+ map.put("area_name2", areaName2);
|
|
|
+ String cityId = carService.getCityId(cities, yj);
|
|
|
+ map.put("city_id", cityId);
|
|
|
+ String city = carService.getAreaName(areaMap, cityId);
|
|
|
+ map.put("city", city);
|
|
|
+ String districtId = carService.getDistrictId(districtListMap, cityId, cityName, ej);
|
|
|
+ map.put("district_id", districtId);
|
|
|
+ String district = carService.getAreaName(areaMap, districtId);
|
|
|
+ map.put("district", district);
|
|
|
+ map.put("source", path.getFileName().toString());
|
|
|
+ String dengJiRiQi = map.get("deng_ji_ri_qi");
|
|
|
+ if (StringUtils.hasText(dengJiRiQi)) {
|
|
|
+ try {
|
|
|
+ map.put("deng_ji_ri_qi",
|
|
|
+ LocalDate.parse(dengJiRiQi).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
|
|
+ } catch (Exception e) {
|
|
|
+ map.put("deng_ji_ri_qi", "");
|
|
|
+ log.warn("{}登记日期解析失败: {}", rawChePaiHao, dengJiRiQi);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String jinChangShiJian = map.get("jin_chang_shi_jian");
|
|
|
+ if (StringUtils.hasText(jinChangShiJian)) {
|
|
|
+ try {
|
|
|
+ map.put("jin_chang_shi_jian",
|
|
|
+ LocalDate.parse(jinChangShiJian).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
|
|
+ } catch (Exception e) {
|
|
|
+ map.put("jin_chang_shi_jian", "");
|
|
|
+ log.warn("{}进厂时间解析失败: {}", rawChePaiHao, jinChangShiJian);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String jinChangGongLi = map.get("jin_chang_gong_li");
|
|
|
+ if (StringUtils.hasText(jinChangGongLi)) {
|
|
|
+ try {
|
|
|
+ map.put("jin_chang_gong_li", new BigDecimal(jinChangGongLi).toString());
|
|
|
+ } catch (Exception e) {
|
|
|
+ map.put("jin_chang_gong_li", "");
|
|
|
+ log.warn("{}进厂公里数解析失败: {}", rawChePaiHao, jinChangGongLi);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String liCheng = map.get("li_cheng");
|
|
|
+ if (StringUtils.hasText(liCheng)) {
|
|
|
+ try {
|
|
|
+ map.put("li_cheng", new BigDecimal(liCheng).toString());
|
|
|
+ } catch (Exception e) {
|
|
|
+ map.put("li_cheng", "");
|
|
|
+ log.warn("{}截止数据提取日行驶里程解析失败: {}", rawChePaiHao, liCheng);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String chaoBaoTianShu = map.get("chao_bao_tian_shu");
|
|
|
+ if (StringUtils.hasText(chaoBaoTianShu)) {
|
|
|
+ try {
|
|
|
+ map.put("chao_bao_tian_shu", new BigDecimal(chaoBaoTianShu).toString());
|
|
|
+ } catch (Exception e) {
|
|
|
+ map.put("chao_bao_tian_shu", "");
|
|
|
+ log.warn("{}超出建议保养时间(天)解析失败: {}", rawChePaiHao, chaoBaoTianShu);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String chaoBaoGongLi = map.get("chao_bao_gong_li");
|
|
|
+ if (StringUtils.hasText(chaoBaoGongLi)) {
|
|
|
+ try {
|
|
|
+ map.put("chao_bao_gong_li", new BigDecimal(chaoBaoGongLi).toString());
|
|
|
+ } catch (Exception e) {
|
|
|
+ map.put("chao_bao_gong_li", "");
|
|
|
+ log.warn("{}超出建议保养公里数解析失败: {}", rawChePaiHao, chaoBaoGongLi);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成csv
|
|
|
+ *
|
|
|
+ * @param path 源文件路径
|
|
|
+ * @param list 数据
|
|
|
+ */
|
|
|
+ public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
|
|
|
+ log.info("条数:{}", list.size());
|
|
|
+ Path csvPath = Paths.get(path + ".csv");
|
|
|
+ try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
|
|
|
+ StandardCharsets.UTF_8);
|
|
|
+ CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
|
|
|
+ // 添加bom头避免excel乱码
|
|
|
+ osw.write('\ufeff');
|
|
|
+ Map<String, String> header = list.get(0);
|
|
|
+ // 表头
|
|
|
+ printer.printRecord(header.keySet());
|
|
|
+ for (Map<String, String> map : list) {
|
|
|
+ printer.printRecord(map.values());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return csvPath;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导入数据库
|
|
|
+ *
|
|
|
+ * @param path 文件路径
|
|
|
+ */
|
|
|
+ public void copyCsv(Path path) {
|
|
|
+ String dbTable = "car.car_chao_bao";
|
|
|
+ String csv = path.toString();
|
|
|
+ String columns = "(year_month,che_pai_hao,che_xing,raw_yi_ji,raw_er_ji,raw_san_ji,deng_ji_ri_qi,jin_chang_shi_jian,jin_chang_gong_li,li_cheng,bao_yang,chao_bao_tian_shu,chao_bao_gong_li,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,source)";
|
|
|
+ Long timeout = 60000L;
|
|
|
+ PsqlUtil.copyCsv(carDataImportConfig.getCopyScriptPath(), carDataImportConfig.getDbHost(),
|
|
|
+ carDataImportConfig.getDbPort(), carDataImportConfig.getDbUsername(), carDataImportConfig.getDbPassword(),
|
|
|
+ carDataImportConfig.getDbName(), dbTable, csv, columns, timeout, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新数据库
|
|
|
+ */
|
|
|
+ public void procedure(CarDataImportDto dto) {
|
|
|
+ int update1 = gdcCarChaoBaoDao.insertChaoBao(dto.getYearMonth());
|
|
|
+ if (update1 == 0) {
|
|
|
+ throw new MyRuntimeException("插入car_theme.wz_f_severely_over_maintained_leased_vehicles_details失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|