weaver-hrm-recruit/src/com/engine/recruit/service/impl/ResumeRecognitionServiceImp...

534 lines
20 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.engine.recruit.service.impl;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.engine.core.impl.Service;
import com.engine.recruit.conn.*;
import com.engine.recruit.constant.RecruitConstant;
import com.engine.recruit.enums.ApplicationStatusEnum;
import com.engine.recruit.exception.CustomizeRunTimeException;
import com.engine.recruit.service.ResumeRecognitionService;
import com.weaver.formmodel.data.model.Formfield;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import weaver.conn.RecordSet;
import weaver.file.ImageFileManager;
import weaver.formmode.recruit.modeexpand.util.RecruitModeUtil;
import weaver.general.BaseBean;
import weaver.general.Util;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author:dxfeng
* @createTime: 2023/12/12
* @version: 1.0
*/
public class ResumeRecognitionServiceImpl extends Service implements ResumeRecognitionService {
@Override
public Map<String, Object> resumeUpload(Map<String, Object> param) {
Map<String, Object> returnMap = new HashMap<>(16);
String resumeId = Util.null2String(param.get("resumeId"));
int imageField = ApplicantCommonInfo.getImageFieldByDocId(resumeId);
if (-1 == imageField) {
throw new CustomizeRunTimeException("原始简历文件获取失败,请重新上传原始简历");
}
qllResumeUpload(imageField, returnMap, true);
returnMap.put("isOcr", true);
return returnMap;
}
@Override
public Map<String, Object> importResume(Map<String, Object> param) {
Map<String, Object> returnMap = new HashMap<>();
String resumeId = Util.null2String(param.get("resumeId"));
Map<String, Object> uploadDataMap = new HashMap<>();
qllResumeUpload(Convert.toInt(resumeId), uploadDataMap, false);
Map<String, Object> resumeData = (Map<String, Object>) uploadDataMap.get("data");
// 添加原始附件字段信息
int secCategory = Convert.toInt(RecruitConstant.APPLICANTS_RESUMES_CATEGORY);
try {
int docId = RecruitModeUtil.createDocId(secCategory, Convert.toInt(resumeId), user);
resumeData.put("ysjl", docId);
} catch (Exception e) {
throw new RuntimeException(e);
}
List<RecruitDataMap<Object>> studyList = (List<RecruitDataMap<Object>>) resumeData.remove("jyjl");
List<RecruitDataMap<Object>> workList = (List<RecruitDataMap<Object>>) resumeData.remove("gzjl");
// 状态
resumeData.put("zt", ApplicationStatusEnum.DISTRIBUTION.getValue());
List<Formfield> fieldList = RecruitModeUtil.getFieldList("uf_jcl_yppc");
Set<String> keySet = fieldList.stream().map(Formfield::getFieldname).collect(Collectors.toSet());
// 移除不在 keySet 中的键值对
resumeData.entrySet().removeIf(entry -> !keySet.contains(entry.getKey()));
// 判断简历信息
CheckRepeatResume instance = CheckRepeatResume.getInstance();
Map<String, Object> map = instance.insertResumeAndReturn(resumeData);
String mainId = Util.null2String(map.get("mainId"));
String sourceId = Util.null2String(map.get("sourceId"));
returnMap.put("mainId", mainId);
returnMap.put("sourceId", sourceId);
returnMap.put("id", StringUtils.isNotBlank(sourceId) ? sourceId : mainId);
instance.insertResumeDetailTable(studyList, "uf_jcl_yppc_dt1", mainId, sourceId);
instance.insertResumeDetailTable(workList, "uf_jcl_yppc_dt2", mainId, sourceId);
return returnMap;
}
@Override
public Map<String, Object> fetchResume(Map<String, Object> param) {
String id = Util.null2String(param.get("id"));
String sql = "select * from uf_jcl_yppc where id = ? ";
RecordSet rs = new RecordSet();
rs.executeQuery(sql, id);
Map<String, Object> dataMap = RecruitRecordSet.getSingleRecordMap(rs);
List<Formfield> fieldList = RecruitModeUtil.getFieldList("uf_jcl_yppc");
Map<String, Formfield> fieldMap = fieldList.stream().collect(Collectors.toMap(Formfield::getFieldname, item -> item, (k1, k2) -> k1));
for (String key : dataMap.keySet()) {
Object value = dataMap.get(key);
if (StringUtils.isBlank(Convert.toStr(value))) {
continue;
}
// 计算新的value值
Formfield formfield = fieldMap.get(key);
value = RecruitModeUtil.getFieldShowName(formfield, Convert.toStr(value)).replaceAll("<[^>]*>", "");
// 更新value值
dataMap.put(key, value);
}
return dataMap;
}
/**
* @param resumeId 简历ID
* @param returnMap 响应集合
*/
private void qllResumeUpload(int resumeId, Map<String, Object> returnMap, boolean isCard) {
String response = doQllPost(resumeId);
if (StringUtils.isBlank(response)) {
throw new CustomizeRunTimeException("千里聆接口调用失败,响应结果为空");
}
BaseBean baseBean = new BaseBean();
JSONObject all = JSONObject.parseObject(response);
baseBean.writeLog("千里聆相应数据:" + all);
if (!all.getBoolean("isSuccess")) {
throw new CustomizeRunTimeException("千里聆接口调用失败,接口不通");
}
JSONObject resultall = all.getJSONObject("data");
String status = resultall.getString("state");
if ("fail".equals(status)) {
throw new CustomizeRunTimeException("调用千里聆接口失败,失败原因:" + resultall.getString("info"));
}
JSONObject result = resultall.getJSONObject("result");
baseBean.writeLog("千里聆OCR解析数据" + result);
Map<String, Object> dataMap = parseQllJsonToMap(result, isCard);
returnMap.put("data", dataMap);
}
/**
* 千里聆解析字段内容处理
*
* @param obj
* @return
*/
private Map<String, Object> parseQllJsonToMap(JSONObject obj, boolean isCard) {
Map<String, Object> dataMap = new HashMap<>(16);
// 姓名
String xm = parseArray(obj.getJSONArray("姓名"));
dataMap.put("xm", xm);
// 电子邮箱
String dzyx = parseArray(obj.getJSONArray("电子邮箱"));
dataMap.put("dzyx", dzyx);
// 手机号码
String sjhm = parseArray(obj.getJSONArray("手机号"));
dataMap.put("sjhm", sjhm);
// 年龄
String nl = parseArray(obj.getJSONArray("年龄"));
dataMap.put("nl", nl);
// 出生日期
String csrq = parseArray(obj.getJSONArray("出生日期"));
dataMap.put("csrq", parseDateObject(csrq));
// 民族
// 性别 默认为男
String xb = "".equals(parseArray(obj.getJSONArray("性别"))) ? "1" : "0";
dataMap.put("xb", xb);
// 体重KG
// 身高CM
// 籍贯
//dataMap.put("jg", parseArray(obj.getJSONArray("籍贯")));
// 婚姻状况
// 当前所在地
//dataMap.put("jzd", parseArray(obj.getJSONArray("现居住地")));
// 政治面貌
// 在职状态
// 工作经验
List<Map<String, String>> gzjy = getBrowserArray(parseArray(obj.getJSONArray("工作经验")), this::getWorkExperienceArray);
if (CollectionUtils.isNotEmpty(gzjy)) {
dataMap.put("gzjy", gzjy);
if (!isCard) {
dataMap.put("gzjy", gzjy.stream().map(item -> item.get("id")).collect(Collectors.joining(",")));
}
}
// 最高学位
List<Map<String, String>> zgxw = getBrowserArray(parseArray(obj.getJSONArray("最高学位")), this::getDegreeArray);
if (CollectionUtils.isNotEmpty(zgxw)) {
dataMap.put("zgxw", zgxw);
if (!isCard) {
dataMap.put("zgxw", zgxw.stream().map(item -> item.get("id")).collect(Collectors.joining(",")));
}
}
// 最高学历
List<Map<String, String>> zgxl = getBrowserArray(parseArray(obj.getJSONArray("最高学历")), this::getEducationLevelArray);
if (CollectionUtils.isNotEmpty(zgxl)) {
dataMap.put("zgxl", zgxl);
if (!isCard) {
dataMap.put("zgxl", zgxl.stream().map(item -> item.get("id")).collect(Collectors.joining(",")));
}
}
// 专业
String zy = parseArray(obj.getJSONArray("专业"));
dataMap.put("zy", zy);
// 毕业院校
String byyx = parseArray(obj.getJSONArray("毕业院校"));
dataMap.put("byyx", byyx);
// 期望税前月薪K
String qwxz = parseArray(obj.getJSONArray("期望薪资"));
dataMap.put("qwxz", qwxz);
// 现税前月薪K
// 自我评价
String zwpj = parseArray(obj.getJSONArray("个人评价"));
dataMap.put("zwpj", zwpj);
// 民族
dataMap.put("mz", parseArray(obj.getJSONArray("民族")));
// 明细表数据
// 教育经历
JSONArray jyjl = obj.getJSONArray("学业信息");
List<RecruitDataMap<Object>> studyList = new ArrayList<>();
if (null != jyjl && jyjl.size() > 0) {
for (int i = 0; i < jyjl.size(); i++) {
JSONObject o = (JSONObject) jyjl.get(i);
String studyDate = o.getString("就读时期");
RecruitDataMap<Object> studyMap = new RecruitDataMap<>();
studyMap.putAll(getDateRange(studyDate, true));
studyMap.put("xxmc", o.getString("院校"));
List<Map<String, String>> xl = getBrowserArray(o.getString("学历"), this::getEducationLevelArray);
studyMap.put("xl", xl);
if (!isCard && CollectionUtils.isNotEmpty(xl)) {
studyMap.put("xl", xl.stream().map(item -> item.get("id")).collect(Collectors.joining(",")));
}
studyMap.put("zy", o.getString("专业"));
studyList.add(studyMap);
}
}
dataMap.put("jyjl", studyList);
// 工作经历
JSONArray gzjl = obj.getJSONArray("工作信息");
List<RecruitDataMap<Object>> workList = new ArrayList<>();
if (null != gzjl && gzjl.size() > 0) {
for (int i = 0; i < gzjl.size(); i++) {
JSONObject o = (JSONObject) gzjl.get(i);
String workDate = o.getString("工作时间");
RecruitDataMap<Object> workMap = new RecruitDataMap<>();
workMap.putAll(getDateRange(workDate, false));
workMap.put("gsmc", o.getString("工作单位"));
workMap.put("gw", o.getString("工作岗位"));
workMap.put("gzzz", o.getString("工作内容"));
workList.add(workMap);
}
}
dataMap.put("gzjl", workList);
// 项目经验
// 语言能力
// 目前表单暂无字段
//dataMap.put("wx", parseArray(obj.getJSONArray("微信")));
//dataMap.put("qq", parseArray(obj.getJSONArray("QQ")));
//dataMap.put("ah", parseArray(obj.getJSONArray("爱好")));
//dataMap.put("bysj", parseArray(obj.getJSONArray("毕业时间")));
//
//
//dataMap.put("zyjn", parseArray(obj.getJSONArray("专业技能")));
//dataMap.put("sxjl", parseArray(obj.getJSONArray("实习经历")));
//dataMap.put("yysp", parseArray(obj.getJSONArray("英语水平")));
//dataMap.put("jnzs", parseArray(obj.getJSONArray("技能证书")));
//dataMap.put("xyjl", parseArray(obj.getJSONArray("校园经历")));
//dataMap.put("qwcsgw", parseArray(obj.getJSONArray("期望从事岗位")));
//
//dataMap.put("qwgzdd", parseArray(obj.getJSONArray("期望工作地点")));
//dataMap.put("xmjl", parseArray(obj.getJSONArray("项目经历")));
return dataMap;
}
/**
* @param resumeId
* @return
*/
private String doQllPost(int resumeId) {
String url = RecruitConstant.OCR_URL;
String appId = RecruitConstant.APP_ID;
String appSecret = RecruitConstant.APP_SECRET;
if (StringUtils.isAnyBlank(url, appId, appSecret)) {
throw new CustomizeRunTimeException("千里聆配置出错,请检查配置文件");
}
long currentTime = System.currentTimeMillis();
ImageFileManager manager = new ImageFileManager();
manager.getImageFileInfoById(resumeId);
HttpPost postRequest = new HttpPost(url);
postRequest.addHeader("sign", getSign(appId, appSecret, currentTime));
postRequest.addHeader("appId", appId);
postRequest.addHeader("timestamp", String.valueOf(currentTime));
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
String fileName = manager.getImageFileName();
builder.addTextBody("type", fileName.substring(fileName.lastIndexOf('.') + 1));
builder.addBinaryBody("resume", manager.getInputStream(), ContentType.APPLICATION_OCTET_STREAM, manager.getImageFileName());
HttpEntity entity = builder.build();
postRequest.setEntity(entity);
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(postRequest);
HttpEntity responseEntity = response.getEntity();
return EntityUtils.toString(responseEntity);
} catch (Exception e) {
throw new CustomizeRunTimeException(e);
}
}
/**
* 千里聆签名
*
* @param appId 开发者AppId
* @param appSecret 开发者appSecret
* @param timestamp 当前时间戳(毫秒数)
* @return
*/
private static String getSign(String appId, String appSecret, long timestamp) {
if (appId != null && appId.length() != 0) {
if (appSecret != null && appSecret.length() != 0) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(appId.getBytes());
md5.update((timestamp + "").getBytes());
md5.update(appSecret.getBytes());
byte[] bytes = md5.digest();
return (new BigInteger(1, bytes)).toString(16);
} catch (NoSuchAlgorithmException var8) {
throw new CustomizeRunTimeException("不支持的加密算法", var8);
}
} else {
throw new CustomizeRunTimeException("appSecret不能为空");
}
} else {
throw new CustomizeRunTimeException("appId不能为空");
}
}
/**
* 文本转换
*
* @param ar
* @return
*/
private String parseArray(JSONArray ar) {
StringBuilder rs = new StringBuilder();
if (ar != null && ar.size() > 0) {
for (int i = 0; i < ar.size(); ++i) {
if (i == ar.size() - 1) {
rs.append(ar.get(i));
} else {
rs.append(ar.get(i)).append(",");
}
}
}
return StringUtils.isBlank(rs) ? null : rs.toString();
}
/**
* 转换日期对象
*
* @param value
* @return
*/
private String parseDateObject(String value) {
if (StringUtils.isBlank(value)) {
return null;
}
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setLenient(false);
try {
sdf.parse(value);
} catch (Exception e) {
new BaseBean().writeLog("日期格式化失败", e);
value = null;
}
return value;
}
/**
* 获取开始时间和结束时间
*
* @param date
* @return
*/
private RecruitDataMap<Object> getDateRange(String date, boolean isStudy) {
RecruitDataMap<Object> dataRangeMap = new RecruitDataMap<>();
String[] split = date.split("-");
if (split.length == 2) {
String start = getFormatDate(split[0]);
String end = getFormatDate(split[1]);
if (start.length() == 4) {
if (isStudy) {
start += "-09-01";
} else {
start = "";
}
}
if (end.length() == 4) {
if (isStudy) {
end += "-07-01";
} else {
end = "";
}
}
dataRangeMap.put("kssj", start);
dataRangeMap.put("jssj", end);
}
return dataRangeMap;
}
/**
* 获取yyyy-MM-dd时间格式日期
*
* @param dateStr
* @return
*/
private String getFormatDate(String dateStr) {
dateStr = dateStr.replace(".", "-").replace("\\/", "-");
if (dateStr.length() == 7) {
return dateStr + "-01";
} else if (dateStr.length() == 10) {
return dateStr;
} else if (dateStr.length() == 4) {
return dateStr;
}
return "";
}
/**
* 构建学位字段信息
*
* @param text
* @return
*/
private Map<String, String> getDegreeArray(String text) {
Map<String, String> map = new HashMap<>(2);
if (StringUtils.isNotBlank(text)) {
String id = ModeBrowserCommonInfo.getDegreeId(text);
if (StringUtils.isNotBlank(id)) {
map.put("id", id);
map.put("name", text);
}
}
return map;
}
/**
* 构建工作经验字段信息
*
* @param text
* @return
*/
private Map<String, String> getWorkExperienceArray(String text) {
Map<String, String> map = new HashMap<>(2);
if (StringUtils.isNotBlank(text)) {
String id = ModeBrowserCommonInfo.getWorkExperience(text);
if (StringUtils.isNotBlank(id)) {
map.put("id", id);
map.put("name", text);
}
}
return map;
}
/**
* 构建浏览按钮字段信息格式
*
* @param text
* @param fun
* @return
*/
private List<Map<String, String>> getBrowserArray(String text, Function<String, Map<String, String>> fun) {
List<Map<String, String>> list = new ArrayList<>();
if (StringUtils.isNotBlank(text)) {
String[] split = text.split(",");
for (String s : split) {
Map<String, String> apply = fun.apply(s);
list.add(apply);
}
}
return list;
}
/**
* 构建学历字段信息
*
* @param text
* @return
*/
private Map<String, String> getEducationLevelArray(String text) {
Map<String, String> map = new HashMap<>(2);
if (StringUtils.isNotBlank(text)) {
String id = ModeBrowserCommonInfo.getEducationLevelId(text);
if (StringUtils.isNotBlank(id)) {
map.put("id", id);
map.put("name", text);
}
}
return map;
}
}