石河子本地岗位上传

This commit is contained in:
chenshaohua
2026-07-30 16:17:01 +08:00
parent 3158317dfd
commit ffaf47bd3d
9 changed files with 941 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
package com.ruoyi.cms.controller.cms;
import com.ruoyi.cms.domain.JobExcelImportRecord;
import com.ruoyi.cms.service.JobExcelImportRecordService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 石河子岗位数据入库监测记录Controller
*/
@RestController
@RequestMapping("/cms/jobImportRecord")
@Api(value = "后台:石河子岗位数据入库监测记录")
public class JobExcelImportRecordController extends BaseController {
@Autowired
private JobExcelImportRecordService jobExcelImportRecordService;
/**
* 查询列表
*/
@PreAuthorize("@ss.hasPermi('cms:jobImportRecord:list')")
@GetMapping("/list")
public TableDataInfo list(JobExcelImportRecord shzJobExcelImportRecord) {
startPage();
List<JobExcelImportRecord> list = jobExcelImportRecordService.selectShzJobExcelImportRecordList(shzJobExcelImportRecord);
return getDataTable(list);
}
/**
* 通用上传请求(单个)
*/
@PostMapping("/shzLocalUploadFile")
@PreAuthorize("@ss.hasPermi('cms:jobImportRecord:upload')")
@ApiOperation("石河子本地岗位上传")
public AjaxResult upload(@RequestParam("file") MultipartFile file) throws Exception {
if (file.isEmpty()) {
return AjaxResult.error("上传文件不能为空");
}
String fileName = file.getOriginalFilename();
if (fileName == null || !fileName.endsWith(".xlsx") && !fileName.endsWith(".xls")) {
return AjaxResult.error("请上传Excel格式的文件");
}
jobExcelImportRecordService.uploadFile(file);
return success();
}
}

View File

@@ -0,0 +1,51 @@
package com.ruoyi.cms.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 石河子岗位数据入库监测记录 shz.job_excel_import_record
*/
@Data
@ApiModel("石河子岗位数据入库监测记录")
@TableName("job_excel_import_record")
public class JobExcelImportRecord extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 监测主键ID */
@Excel(name = "监测主键ID")
@ApiModelProperty("监测主键ID")
private String detectionId;
/** 原始文件名称 */
@Excel(name = "原始文件名称")
@ApiModelProperty("原始文件名称")
private String fileName;
/** 入库数量 */
@Excel(name = "入库数量")
@ApiModelProperty("入库数量")
private Integer storageNumber;
/** 入库结果简述 */
@Excel(name = "入库结果简述")
@ApiModelProperty("入库结果简述")
private String storageResult;
/** 入库详情 */
@Excel(name = "入库详情")
@ApiModelProperty("入库详情")
private String storageDetail;
/** 失败原因 */
@Excel(name = "失败原因")
@ApiModelProperty("失败原因")
private String failedReason;
}

View File

@@ -0,0 +1,146 @@
package com.ruoyi.cms.domain.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.cms.domain.JobContact;
import com.ruoyi.cms.util.excel.*;
import com.ruoyi.common.annotation.Excel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 石河子本地导入岗位对象 job
*/
@Data
public class JobShzLocalExcelVo
{
@ExcelProperty(value = "序号", index = 0)
@Excel(name = "序号")
@ApiModelProperty("序号")
private String xh;
@ExcelProperty(value = "所属行业", index = 1)
@Excel(name = "所属行业")
@ApiModelProperty("所属行业")
private String industry;
@ExcelProperty(value = "单位名称", index = 2)
@Excel(name = "单位名称")
@ApiModelProperty("单位名称")
private String companyName;
@ExcelProperty(value = "统一社会信用代码", index = 3)
@ApiModelProperty("统一社会信用代码")
private String code;
@ExcelProperty(value = "单位类型", index = 4)
@ApiModelProperty("单位类型")
private String companyNature;
@ExcelProperty(value = "人员规模", index = 5)
@ApiModelProperty("人员规模")
private String scale;
@ExcelProperty(value = "工作地区", index = 6)
@ApiModelProperty("工作地区")
private String jobAddress;
@ExcelProperty(value = "岗位工种名称", index =7)
@Excel(name = "岗位工种名称")
@ApiModelProperty("岗位工种名称")
private String jobTitle;
@ExcelProperty(value = "招聘人数", index = 8,converter = VacancyLongConverter.class)
@Excel(name = "招聘人数")
@ApiModelProperty("招聘人数")
private Long vacancies;
@ExcelProperty(value = "任职要求", index = 9)
@ApiModelProperty("任职要求")
private String description;
@Excel(name = "学历要求 对应字典education")
@ExcelProperty(value = "任职要求", index = 10)
@ApiModelProperty("学历要求 对应字典education")
private String education;
@ExcelProperty(value = "工作性质", index = 11)
@ApiModelProperty("工作性质")
private String workNature;
@ExcelProperty(value = "薪酬类型", index = 12)
@ApiModelProperty("薪酬类型")
private String salaryType;
@ExcelProperty(value = "最小薪资", index = 13)
@Excel(name = "最小薪资", readConverterExp = "元=")
@ApiModelProperty("最小薪资(元)")
private Long minSalary;
@ExcelProperty(value = "最大薪资", index = 14)
@Excel(name = "最大薪资", readConverterExp = "元=")
@ApiModelProperty("最大薪资(元)")
private Long maxSalary;
@ExcelProperty(value = "工作经验", index = 15)
@Excel(name = "工作经验要求 对应字典experience")
@ApiModelProperty("工作经验要求 对应字典experience")
private String experience;
@ExcelProperty(value = "专业要求", index = 16)
@Excel(name = "专业要求")
private String majorRequire;
@ExcelProperty(value = "联系人对象", index = 17, converter = ContactParseConverter.class)
private ContactParseResult contactParseResult;
@ExcelProperty(value = "邮箱", index = 18)
private String email;
@ExcelProperty(value = "岗位收集人", index = 19)
@ApiModelProperty("岗位收集人")
private String gwsjr;
@ExcelProperty(value = "需求月份", index = 20,converter = PostingDateConverter.class)
@JsonFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty("发布时间")
private Date postingDate;
@ExcelProperty(value = "经办站点", index = 21)
@ApiModelProperty("数据来源/经办站点")
private String dataSource;
@ExcelProperty(value = "联系人")
@ApiModelProperty("联系人")
private String contactPerson;
@ExcelProperty(value = "联系人电话")
@ApiModelProperty("联系人电话")
private String contactPersonPhone;
@ExcelProperty(value = "岗位区划")
@Excel(name = "岗位区划")
@ApiModelProperty("岗位区划")
private String jobLocation;
@ExcelProperty(value = "岗位类型")
@ApiModelProperty("岗位类型 0疆内 1疆外")
private String jobType;
@ExcelProperty(value = "类型")
@ApiModelProperty("类型 0常规岗位 1就业见习岗位 2实习实训岗位 3社区实践岗位 4零工 对应字段字典position_type")
private String type;
@ApiModelProperty("是否发布 0未发布 1发布")
private Integer isPublish;
@ApiModelProperty("工作地点区县字典代码")
private Integer jobLocationAreaCode;
@ApiModelProperty("联系人列表")
private List<JobContact> jobContacts;
}

View File

@@ -0,0 +1,19 @@
package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cms.domain.JobExcelImportRecord;
import java.util.List;
/**
* 石河子岗位数据入库监测记录Mapper
*/
public interface JobExcelImportRecordMapper extends BaseMapper<JobExcelImportRecord> {
/**
* 查询石河子岗位数据入库监测记录列表
*
* @param shzJobExcelImportRecord 石河子岗位数据入库监测记录
* @return 石河子岗位数据入库监测记录集合
*/
List<JobExcelImportRecord> selectShzJobExcelImportRecordList(JobExcelImportRecord shzJobExcelImportRecord);
}

View File

@@ -0,0 +1,22 @@
package com.ruoyi.cms.service;
import com.ruoyi.cms.domain.JobExcelImportRecord;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 石河子岗位数据入库监测记录Service接口
*/
public interface JobExcelImportRecordService {
/**
* 查询石河子岗位数据入库监测记录列表
*
* @param jobExcelImportRecord 石河子岗位数据入库监测记录
* @return 石河子岗位数据入库监测记录集合
*/
List<JobExcelImportRecord> selectShzJobExcelImportRecordList(JobExcelImportRecord jobExcelImportRecord);
void uploadFile(MultipartFile file) throws Exception;
}

View File

@@ -0,0 +1,292 @@
package com.ruoyi.cms.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.cms.domain.BussinessDictData;
import com.ruoyi.cms.domain.Job;
import com.ruoyi.cms.domain.JobContact;
import com.ruoyi.cms.domain.JobExcelImportRecord;
import com.ruoyi.cms.domain.query.CompanySearch;
import com.ruoyi.cms.domain.vo.ContactParseResult;
import com.ruoyi.cms.domain.vo.JobShzLocalExcelVo;
import com.ruoyi.cms.mapper.CompanyMapper;
import com.ruoyi.cms.mapper.JobExcelImportRecordMapper;
import com.ruoyi.cms.mapper.JobMapper;
import com.ruoyi.cms.service.*;
import com.ruoyi.cms.util.excel.JobShzLocalExcelListener;
import com.ruoyi.cms.util.excel.UpExcelDictUtil;
import com.ruoyi.common.core.domain.entity.Company;
import com.ruoyi.common.core.domain.entity.Industry;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
/**
* 石河子岗位数据入库监测记录Service实现
*/
@Service
public class JobExcelImportRecordServiceImpl extends ServiceImpl<JobExcelImportRecordMapper, JobExcelImportRecord> implements JobExcelImportRecordService {
@Autowired
private JobExcelImportRecordMapper jobExcelImportRecordMapper;
@Autowired
private JobMapper jobMapper;
@Autowired
private CompanyMapper companyMapper;
@Autowired
private IBussinessDictTypeService iBussinessDictTypeService;
@Autowired
private IBussinessDictDataService iBussinessDictDataService;
@Autowired
private IIndustryService industryService;
@Autowired
private IJobService jobService;
@Override
public List<JobExcelImportRecord> selectShzJobExcelImportRecordList(JobExcelImportRecord jobExcelImportRecord) {
return jobExcelImportRecordMapper.selectShzJobExcelImportRecordList(jobExcelImportRecord);
}
@Override
public void uploadFile(MultipartFile file) throws Exception{
String originalName = file.getOriginalFilename();
String nameNoSuffix = FileNameUtil.getName(originalName);
//获取字典
List<BussinessDictData> workNaData = iBussinessDictTypeService.selectDictDataByType("work_nature");
List<BussinessDictData> majorRData = iBussinessDictTypeService.selectDictDataByType("major_require");
List<BussinessDictData> salarTypeData = iBussinessDictTypeService.selectDictDataByType("salary_type");
List<BussinessDictData> companyNatureData = iBussinessDictTypeService.selectDictDataByType("company_nature");
List<BussinessDictData> areaData = iBussinessDictTypeService.selectDictDataByType("area");
//查询第一级
List<Industry> industries=industryService.selectFirstLevelIndustryList();
JobExcelImportRecord jobExcelImportRecord=new JobExcelImportRecord();
jobExcelImportRecord.setFileName(nameNoSuffix);
String detectionId = IdUtils.fastSimpleUUID();
jobExcelImportRecord.setDetectionId(detectionId);
List<JobShzLocalExcelVo> validDataList;
try (InputStream inputStream = file.getInputStream()){
JobShzLocalExcelListener listener = new JobShzLocalExcelListener();
EasyExcel.read(inputStream, JobShzLocalExcelVo.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet(0).headRowNumber(2).doRead();
validDataList = listener.getValidDataList();
jobExcelImportRecord.setStorageNumber(validDataList.size());
}
if (CollUtil.isEmpty(validDataList)) {
jobExcelImportRecord.setStorageNumber(0);
jobExcelImportRecordMapper.insert(jobExcelImportRecord);
return;
}
jobExcelImportRecord.setStorageNumber(validDataList.size());
// 2.1 所有已存在企业 name -> companyId
Map<String, Long> companyNameIdMap = new HashMap<>();
List<Company> allCompany = companyMapper.selectCompanyCleanList(new CompanySearch());
if (CollUtil.isNotEmpty(allCompany)) {
allCompany.forEach(c -> companyNameIdMap.put(c.getName(), c.getCompanyId()));
}
// 收集当前批次所有匹配key只查需要的岗位避免全量企业岗位加载上万条
Set<String> matchKeySet = new HashSet<>();
for (JobShzLocalExcelVo vo : validDataList) {
String cName = vo.getCompanyName();
String title = vo.getJobTitle();
String key=buildFullMatchKey(cName,title,vo.getVacancies(),vo.getMinSalary(),vo.getMaxSalary());
matchKeySet.add(key);
}
List<String> targetKeyList = new ArrayList<>(matchKeySet);
// 精准查询当前批次需要对比的存量岗位
List<Job> existJobList = jobMapper.selectJobByMatchKeyList(targetKeyList);
Map<String, Job> existJobMap = new HashMap<>();
for (Job job : existJobList) {
String key=buildFullMatchKey(job.getCompanyName(),job.getJobTitle(),job.getVacancies(),job.getMinSalary(),job.getMaxSalary());
existJobMap.put(key, job);
}
// 本批计数器
List<Company> waitInsertCompany = new ArrayList<>();
List<Job> waitInsertJob = new ArrayList<>();
List<Job> waitUpdateJob = new ArrayList<>();
// 3. 批量容器 & 统计计数器
int addCompanyNum = 0;
int addJobNum = 0;
int updateJobNum = 0;
// 4. 循环解析每行Excel数据
for (JobShzLocalExcelVo excelVo : validDataList) {
Job job = new Job();
BeanUtil.copyProperties(excelVo, job);
// 岗位固定默认值
job.setIsPublish(1);
job.setView(0L);
job.setApplyNum(0);
job.setCreateBy(detectionId);
job.setJobLocation(job.getJobAddress());
job.setExperience("0");
job.setJobType("0");
job.setJobStatus("0");
job.setDataSource("5");
String companyName = excelVo.getCompanyName();
String creditCode = excelVo.getCode();
Long companyId = null;
// ========== 企业处理逻辑 ==========
if (StringUtils.isNotBlank(companyName)) {
if (companyNameIdMap.containsKey(companyName)) {
// 企业已存在
companyId = companyNameIdMap.get(companyName);
} else {
// 新增企业
Company newCompany = new Company();
newCompany.setCreateBy(detectionId);
newCompany.setCompanyStatus("0");
newCompany.setCode(creditCode);
newCompany.setName(companyName);
// 企业字典转换
newCompany.setIndustry(UpExcelDictUtil.getIndustry(industries, excelVo.getIndustry()));
String companyNature = iBussinessDictDataService.findCode(companyNatureData, excelVo.getCompanyNature());
newCompany.setCompanyNature(StringUtils.isNotBlank(companyNature) ? companyNature : "9");
String scaleKey = UpExcelDictUtil.KEY_TO_SCALE_KEY.get(excelVo.getScale());
newCompany.setScale(StringUtils.isNotBlank(scaleKey) ? scaleKey : "0");
waitInsertCompany.add(newCompany);
addCompanyNum++;
companyId = -1L; // 临时占位批量插入后回填真实ID
}
}
job.setCompanyId(companyId);
// ========== 岗位字典赋值 ==========
String eduKey = UpExcelDictUtil.KEY_TO_SCALE_KEY.get(excelVo.getEducation());
job.setEducation(StringUtils.isNotBlank(eduKey) ? eduKey : "-1");
String expKey = UpExcelDictUtil.KEY_TO_EXPERIENCE_KEY.get(excelVo.getExperience());
job.setExperience(StringUtils.isNotBlank(expKey) ? expKey : "0");
job.setWorkNature(iBussinessDictDataService.findCode(workNaData, excelVo.getWorkNature()));
job.setSalaryType(iBussinessDictDataService.findCode(salarTypeData, excelVo.getSalaryType()));
job.setMajorRequire(iBussinessDictDataService.findCode(majorRData, excelVo.getMajorRequire()));
job.setJobLocationAreaCode(UpExcelDictUtil.matchRegionCode(areaData, excelVo.getJobAddress()));
// ========== 联系人解析 ==========
List<JobContact> contactList = new ArrayList<>();
ContactParseResult parseResult = excelVo.getContactParseResult();
if (ObjectUtil.isNotNull(parseResult) && CollUtil.isNotEmpty(parseResult.getContactItemList())) {
parseResult.getContactItemList().stream()
.filter(item -> StringUtils.isNotBlank(StrUtil.trim(item.getPhone())))
.forEach(item -> {
JobContact contact = new JobContact();
contact.setContactPerson(companyName);
contact.setContactPersonPhone(StrUtil.trim(item.getPhone()));
contact.setRemark(item.getRemark());
contactList.add(contact);
});
}
if (CollUtil.isNotEmpty(contactList)) {
job.setJobContactList(contactList);
}
// ========== 判断岗位新增/更新兼容历史无companyId数据 ==========
String matchKey=buildFullMatchKey(excelVo.getCompanyName(), excelVo.getJobTitle(),excelVo.getVacancies(), excelVo.getMinSalary(), excelVo.getMaxSalary());
if (existJobMap.containsKey(matchKey)) {
// 命中存量岗位含历史无企业ID脏数据
Job oldJob = existJobMap.get(matchKey);
job.setJobId(oldJob.getJobId());
waitUpdateJob.add(job);
updateJobNum++;
} else {
// 全新岗位
waitInsertJob.add(job);
addJobNum++;
}
}
//批量入库
if (CollUtil.isNotEmpty(waitInsertCompany)) {
companyMapper.batchInsert(waitInsertCompany);
// 重新查询新增企业刷新name-id映射
List<String> newCompanyNames = waitInsertCompany.stream()
.map(Company::getName)
.collect(Collectors.toList());
List<Company> newInsertCompanies = companyMapper.selectCompanyByNameList(newCompanyNames);
newInsertCompanies.forEach(c -> companyNameIdMap.put(c.getName(), c.getCompanyId()));
// 给待新增岗位回填真实companyId
for (Job j : waitInsertJob) {
if (j.getCompanyId() != null && j.getCompanyId() == -1L) {
Long realCid = companyNameIdMap.get(j.getCompanyName());
j.setCompanyId(realCid);
}
}
// 给历史待更新岗位补全companyId存量数据标准化
for (Job j : waitUpdateJob) {
if (j.getCompanyId() == null && companyNameIdMap.containsKey(j.getCompanyName())) {
j.setCompanyId(companyNameIdMap.get(j.getCompanyName()));
}
}
}
//批量新增岗位
if (CollUtil.isNotEmpty(waitInsertJob)) {
jobMapper.batchInsert(waitInsertJob);
}
//批量更新岗位
if (CollUtil.isNotEmpty(waitUpdateJob)) {
List<List<Job>> splitList = CollUtil.split(waitUpdateJob, 500);
for (List<Job> sub : splitList) {
sub.forEach(it -> {
it.setCreateBy(null);
it.setCreateTime(null);
it.setUpdateBy(detectionId);
jobMapper.updateById(it);
}
);
}
}
//记录结果
String brief = String.format("共导入%d条数据新增企业%d家新增岗位%d条更新岗位%d条",
jobExcelImportRecord.getStorageNumber(), addCompanyNum, addJobNum, updateJobNum);
jobExcelImportRecord.setStorageResult(brief);
// 入库详情
StringBuilder detailSb = new StringBuilder();
detailSb.append("【导入统计明细】\n");
detailSb.append("有效导入行数:").append(jobExcelImportRecord.getStorageNumber()).append("\n");
detailSb.append("新增企业:").append(addCompanyNum).append("\n");
detailSb.append("新增岗位:").append(addJobNum).append("\n");
detailSb.append("更新岗位:").append(updateJobNum).append("");
jobExcelImportRecord.setStorageDetail(detailSb.toString());
jobExcelImportRecordMapper.insert(jobExcelImportRecord);
//更新坐标并且刷选es
jobService.updateLon();
}
/**
* 获取key
* @param companyName
* @param jobTitle
* @param vacancies
* @param minSalary
* @param maxSalary
* @return
*/
private String buildFullMatchKey(String companyName, String jobTitle, Long vacancies, Long minSalary, Long maxSalary) {
String vacStr = vacancies == null ? "" : vacancies.toString();
String minSalStr = minSalary == null ? "" : minSalary.toString();
String maxSalStr = maxSalary == null ? "" : maxSalary.toString();
return companyName + "|" + jobTitle + "|" + vacStr + "|" + minSalStr + "|" + maxSalStr;
}
}

View File

@@ -0,0 +1,161 @@
package com.ruoyi.cms.util.excel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.ruoyi.cms.domain.JobContact;
import com.ruoyi.cms.domain.vo.*;
import com.ruoyi.cms.util.StringUtil;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 企业岗位excel监听
*/
@Getter
public class JobShzLocalExcelListener extends AnalysisEventListener<JobShzLocalExcelVo> {
private final List<JobShzLocalExcelVo> validDataList = new ArrayList<>();
private final List<CellExtra> mergeCellList = new ArrayList<>();
private final Map<Integer, Field> columnFieldMap = new HashMap<>();
private String columnErrorMsg;
public JobShzLocalExcelListener() {
initColumnFieldMap();
}
@Override
public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
}
@Override
public void extra(CellExtra extra, AnalysisContext context) {
if (extra.getType() == CellExtraTypeEnum.MERGE) {
mergeCellList.add(extra);
}
}
@Override
public void invoke(JobShzLocalExcelVo jobExcelVo, AnalysisContext analysisContext) {
//处理联系方式
ContactParseResult contactResult = jobExcelVo.getContactParseResult();
if (contactResult == null) {
contactResult = new ContactParseResult();
contactResult.setRawText("");
}
// 遍历拆分好的【联系人+号码】,可单独入库
List<JobContact> jobContacts=new ArrayList<>();
for (ContactUploadItem item : contactResult.getContactItemList()) {
JobContact jobContact=new JobContact();
if(StringUtils.isNotBlank(item.getPhone().trim())){
String name = item.getName();
String phone = item.getPhone();
String remark = item.getRemark();
jobContact.setContactPerson(name);
jobContact.setContactPersonPhone(phone);
jobContact.setRemark(remark);
jobContacts.add(jobContact);
}
}
if(!jobContacts.isEmpty()){
jobExcelVo.setJobContacts(jobContacts);
}
//数据来源
jobExcelVo.setDataSource(StringUtil.DATA_SOURCE_LOCAL);
validDataList.add(jobExcelVo);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
fillMergedCellData(analysisContext);
}
/**
* 填充合并单元格空值,实现拆分效果
*/
private void fillMergedCellData(AnalysisContext context) {
int headRowNum = context.readSheetHolder().getHeadRowNumber();
if (columnFieldMap.isEmpty()) {
return;
}
for (CellExtra merge : mergeCellList) {
int firstRow = merge.getFirstRowIndex();
int lastRow = merge.getLastRowIndex();
int firstCol = merge.getFirstColumnIndex();
// 跳过表头
if (firstRow < headRowNum) {
continue;
}
Field field = columnFieldMap.get(firstCol);
if (field == null) {
continue;
}
try {
int firstDataIndex = firstRow - headRowNum;
if (firstDataIndex >= validDataList.size()) {
continue;
}
// 获取合并首行的值
Object mergeValue = field.get(validDataList.get(firstDataIndex));
// 给合并区域所有行赋值
for (int row = firstRow + 1; row <= lastRow; row++) {
int dataIndex = row - headRowNum;
if (dataIndex >= validDataList.size()) {
continue;
}
field.set(validDataList.get(dataIndex), mergeValue);
}
} catch (Exception e) {
columnErrorMsg = "合并单元格填充失败:" + e.getMessage();
}
}
}
/**
* 扫描VO实体 @ExcelProperty(index) 构建列-字段映射
*/
private void initColumnFieldMap() {
Class<JobLocalExcelVo> clazz = JobLocalExcelVo.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
ExcelProperty excelProp = field.getAnnotation(ExcelProperty.class);
if (excelProp == null || excelProp.index() < 0) {
continue;
}
field.setAccessible(true);
columnFieldMap.put(excelProp.index(), field);
}
}
@Override
public void onException(Exception exception, AnalysisContext context) {
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException e = (ExcelDataConvertException) exception;
int realExcelRow = e.getRowIndex() + 3;
int colNum = e.getColumnIndex() + 1;
String cellText = e.getCellData().getStringValue();
System.out.println("Excel导入失败实际行号" + realExcelRow + ",列号" + colNum + ",单元格内容【" + cellText + "");
}
}
public boolean hasColumnError() {
return StringUtils.isNotBlank(columnErrorMsg);
}
}

View File

@@ -0,0 +1,136 @@
package com.ruoyi.cms.util.excel;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.cms.domain.BussinessDictData;
import com.ruoyi.common.core.domain.entity.Industry;
import java.util.*;
public class UpExcelDictUtil {
/**
* 工作经验集合
* 1,应届毕业生
* 11,10年以上
* 2,1年
* 20,20年以上
* 3,2年
* 4,3-4年
* 6,5-7年
* 80,在读生
* 9,8-9年
* 90,不限
*/
public static final Map<String, String> KEY_TO_EXPERIENCE_KEY = new HashMap<>();
/**
* 学历
* 11博士
* 14硕士
* 21本科
* 31专科
* 41中专
* 61高中
* 71初中
* 81小学
* 90学历不限
*/
public static final Map<String, String> KEY_TO_EDUCATION_KEY = new HashMap<>();
/**
* 规模
* 1_3000人以上
* 2_1000--2999人
* 3_500--999人
* 4_100--499人
* 5_10--99人
* 6_10人以下
* 9_其他
*/
public static final Map<String, String> KEY_TO_SCALE_KEY = new HashMap<>();
//默认石河子市
private static final Integer SHIHEZI_DEFAULT_CODE = 0;
static {
//工作经验
KEY_TO_EXPERIENCE_KEY.put("应届毕业生","2");
KEY_TO_EXPERIENCE_KEY.put("在读生","10");
KEY_TO_EXPERIENCE_KEY.put("1年","4");
KEY_TO_EXPERIENCE_KEY.put("2年","4");
KEY_TO_EXPERIENCE_KEY.put("3-4年","5");
KEY_TO_EXPERIENCE_KEY.put("5-7年","6");
KEY_TO_EXPERIENCE_KEY.put("8-9年","6");
KEY_TO_EXPERIENCE_KEY.put("10年以上","7");
KEY_TO_EXPERIENCE_KEY.put("20年以上","8");
KEY_TO_EXPERIENCE_KEY.put("不限","0");
//学历
KEY_TO_EDUCATION_KEY.put("博士","6");
KEY_TO_EDUCATION_KEY.put("硕士","5");
KEY_TO_EDUCATION_KEY.put("本科","4");
KEY_TO_EDUCATION_KEY.put("专科","3");
KEY_TO_EDUCATION_KEY.put("中专","1");
KEY_TO_EDUCATION_KEY.put("高中","2");
KEY_TO_EDUCATION_KEY.put("初中","1");
KEY_TO_EDUCATION_KEY.put("小学","0");
KEY_TO_EDUCATION_KEY.put("学历不限","-1");
//规模
KEY_TO_SCALE_KEY.put("3000人以上","6");
KEY_TO_SCALE_KEY.put("1000--2999人","6");
KEY_TO_SCALE_KEY.put("500--999人","5");
KEY_TO_SCALE_KEY.put("100--499人","3");
KEY_TO_SCALE_KEY.put("10--99人","2");
KEY_TO_SCALE_KEY.put("10人以下","1");
KEY_TO_SCALE_KEY.put("其他","0");
}
/**
* 获取行业
* @param industryList
* @param name
* @return
*/
public static String getIndustry(List<Industry> industryList,String name){
if (Objects.isNull(industryList) || StrUtil.isBlank(name)) {
return null;
}
String targetName = name.trim();
for(Industry industry:industryList){
String industryName = StrUtil.trim(industry.getIndustryName());
if(Objects.equals(industryName, targetName)){
return String.valueOf(industry.getIndustryId());
}
}
return null;
}
/**
* 获取区划
* @param dictDataList
* @param address
* @return
*/
public static Integer matchRegionCode(List<BussinessDictData> dictDataList, String address) {
// 空参数直接返回默认值
if (StrUtil.isBlank(address) || dictDataList == null || dictDataList.isEmpty()) {
return SHIHEZI_DEFAULT_CODE;
}
String addr = address.trim();
// 重点:按标签长度倒序,长关键词优先匹配,防止短词误命中
Optional<BussinessDictData> matchDict = dictDataList.stream()
.filter(d -> StrUtil.isNotBlank(d.getDictLabel()))
.sorted((o1, o2) -> Integer.compare(o2.getDictLabel().length(), o1.getDictLabel().length()))
.filter(d -> addr.contains(d.getDictLabel()))
.findFirst();
return matchDict.map(BussinessDictData::getDictValue).map(val -> {
try {
return Integer.valueOf(val);
} catch (NumberFormatException e) {
return null;
}
}).orElse(SHIHEZI_DEFAULT_CODE);
}
}

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.cms.mapper.JobExcelImportRecordMapper">
<resultMap type="com.ruoyi.cms.domain.JobExcelImportRecord" id="JobExcelImportRecordResult">
<result property="detectionId" column="detection_id" />
<result property="fileName" column="file_name" />
<result property="storageNumber" column="storage_number" />
<result property="storageResult" column="storage_result" />
<result property="storageDetail" column="storage_detail" />
<result property="failedReason" column="failed_reason" />
<result property="delFlag" column="del_flag" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectShzJobExcelImportRecordVo">
select detection_id,
file_name,
storage_number,
storage_result,
storage_detail,
failed_reason,
del_flag,
create_by,
create_time,
update_by,
update_time,
remark
from job_excel_import_record
</sql>
<select id="selectShzJobExcelImportRecordList" resultMap="JobExcelImportRecordResult">
<include refid="selectShzJobExcelImportRecordVo"/>
<where> del_flag='0'
<if test="fileName != null and fileName != ''">
and file_name like concat('%',#{fileName},'%')
</if>
<if test="storageResult != null and storageResult != ''">
and storage_result like concat('%',#{storageResult},'%')
</if>
<if test="params.beginTime != null and params.beginTime != ''">
and create_time &gt;= #{params.beginTime}
</if>
<if test="params.endTime != null and params.endTime != ''">
and create_time &lt;= #{params.endTime}
</if>
</where>
order by create_time desc
</select>
</mapper>