根据简历ID同步更新个人资料

This commit is contained in:
zk
2026-05-12 09:57:01 +08:00
parent 8496f8ed42
commit bc9694fbec
2 changed files with 212 additions and 0 deletions
@@ -53,6 +53,14 @@ public class UserProfileController {
userProfileService.saveProfile(po);
}
/**
* 根据简历ID同步更新个人资料(主表+5子表全量覆盖,触发一次异步AI分析)
*/
@PostMapping("/syncFromResume")
public void syncFromResume(@RequestParam Long resumeId) {
userProfileService.syncProfileFromResume(resumeId);
}
// ==================== 教育经历 ====================
/**
@@ -2,6 +2,8 @@ package org.jiayunet.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.jiayunet.exception.BusinessException;
import org.jiayunet.exception.BusinessExpCodeEnum;
import org.jiayunet.mapper.*;
import org.jiayunet.pojo.po.*;
import org.jiayunet.tool.UserSecurityTool;
@@ -11,6 +13,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
@@ -47,6 +51,34 @@ public class UserProfileService {
@Autowired
private org.jiayunet.service.UserProfileAnalyzeService userProfileAnalyzeService;
@Autowired
private UserResumeMapper userResumeMapper;
@Autowired
private UserResumeEducationMapper resumeEducationMapper;
@Autowired
private UserResumeWorkMapper resumeWorkMapper;
@Autowired
private UserResumeInternshipMapper resumeInternshipMapper;
@Autowired
private UserResumeProjectMapper resumeProjectMapper;
@Autowired
private UserResumeCompetitionMapper resumeCompetitionMapper;
/** 学历文本→枚举映射 */
private static final Map<String, Integer> DEGREE_MAP = Map.of(
"大专", 1, "本科", 2, "硕士", 3, "博士", 4
);
/** 学习形式文本→枚举映射 */
private static final Map<String, Integer> STUDY_TYPE_MAP = Map.of(
"全日制", 0, "非全日制", 1
);
// ==================== 主表 ====================
/** 查询当前用户个人资料 */
@@ -265,6 +297,178 @@ public class UserProfileService {
userProfileAnalyzeService.analyzeUserProfile(userId);
}
// ==================== 从简历同步到个人资料 ====================
/**
* 根据简历ID同步更新个人资料
* <p>1. 校验简历归属 2. 读取简历主表+5子表 3. 事务内覆盖写入Profile主表+5子表 4. 触发一次异步AI分析</p>
*/
@Transactional(rollbackFor = Exception.class)
public void syncProfileFromResume(Long resumeId) {
Long userId = UserSecurityTool.getUserId();
// 1. 校验简历归属当前用户
UserResume resume = userResumeMapper.selectById(resumeId);
if (resume == null || !resume.getUserId().equals(userId)) {
throw new BusinessException(BusinessExpCodeEnum.PERMISSION_DENIED, "简历不存在或无权操作");
}
// 2. 读取简历5张子表
List<UserResumeEducation> resumeEducationList = resumeEducationMapper.selectList(
new LambdaQueryWrapper<UserResumeEducation>().eq(UserResumeEducation::getResumeId, resumeId).orderByAsc(UserResumeEducation::getSortOrder));
List<UserResumeWork> resumeWorkList = resumeWorkMapper.selectList(
new LambdaQueryWrapper<UserResumeWork>().eq(UserResumeWork::getResumeId, resumeId).orderByAsc(UserResumeWork::getSortOrder));
List<UserResumeInternship> resumeInternshipList = resumeInternshipMapper.selectList(
new LambdaQueryWrapper<UserResumeInternship>().eq(UserResumeInternship::getResumeId, resumeId).orderByAsc(UserResumeInternship::getSortOrder));
List<UserResumeProject> resumeProjectList = resumeProjectMapper.selectList(
new LambdaQueryWrapper<UserResumeProject>().eq(UserResumeProject::getResumeId, resumeId).orderByAsc(UserResumeProject::getSortOrder));
List<UserResumeCompetition> resumeCompetitionList = resumeCompetitionMapper.selectList(
new LambdaQueryWrapper<UserResumeCompetition>().eq(UserResumeCompetition::getResumeId, resumeId).orderByAsc(UserResumeCompetition::getSortOrder));
Instant now = Instant.now();
// 3. 同步主表(upsert,只更新共有字段,保留Profile独有字段原值)
UserProfile existing = userProfileMapper.selectOne(
new LambdaQueryWrapper<UserProfile>().eq(UserProfile::getUserId, userId));
Long profileId;
if (existing != null) {
profileId = existing.getId();
existing.setName(resume.getName());
existing.setEmail(resume.getEmail());
existing.setMobileNumber(resume.getMobileNumber());
existing.setWechatNumber(resume.getWechatNumber());
existing.setPortfolioUrl(resume.getPortfolioUrl());
existing.setSkills(resume.getSkills());
existing.setCertificates(resume.getCertificates());
existing.setUpdateTime(now);
userProfileMapper.updateById(existing);
} else {
UserProfile profile = new UserProfile();
profile.setUserId(userId);
profile.setName(resume.getName());
profile.setEmail(resume.getEmail());
profile.setMobileNumber(resume.getMobileNumber());
profile.setWechatNumber(resume.getWechatNumber());
profile.setPortfolioUrl(resume.getPortfolioUrl());
profile.setSkills(resume.getSkills());
profile.setCertificates(resume.getCertificates());
profile.setCreateTime(now);
profile.setUpdateTime(now);
userProfileMapper.insert(profile);
profileId = profile.getId();
}
// 4. 同步教育经历(先删后插,含degree/studyType映射)
educationMapper.delete(new LambdaQueryWrapper<UserProfileEducation>().eq(UserProfileEducation::getUserId, userId));
if (!resumeEducationList.isEmpty()) {
List<UserProfileEducation> profileEducationList = IntStream.range(0, resumeEducationList.size()).mapToObj(i -> {
UserResumeEducation src = resumeEducationList.get(i);
UserProfileEducation dest = new UserProfileEducation();
dest.setProfileId(profileId);
dest.setUserId(userId);
dest.setSchool(src.getSchool());
dest.setMajor(src.getMajor());
dest.setDegree(DEGREE_MAP.get(src.getDegree()));
dest.setStudyType(STUDY_TYPE_MAP.get(src.getStudyType()));
dest.setStartDate(src.getStartDate());
dest.setEndDate(src.getEndDate());
dest.setDescription(src.getDescription());
dest.setSortOrder(i);
dest.setCreateTime(now);
dest.setUpdateTime(now);
return dest;
}).collect(Collectors.toList());
educationMapper.batchInsert(profileEducationList);
}
// 5. 同步工作经历
workMapper.delete(new LambdaQueryWrapper<UserProfileWork>().eq(UserProfileWork::getUserId, userId));
if (!resumeWorkList.isEmpty()) {
List<UserProfileWork> profileWorkList = IntStream.range(0, resumeWorkList.size()).mapToObj(i -> {
UserResumeWork src = resumeWorkList.get(i);
UserProfileWork dest = new UserProfileWork();
dest.setProfileId(profileId);
dest.setUserId(userId);
dest.setCompanyName(src.getCompanyName());
dest.setPosition(src.getPosition());
dest.setStartDate(src.getStartDate());
dest.setEndDate(src.getEndDate());
dest.setDescription(src.getDescription());
dest.setSortOrder(i);
dest.setCreateTime(now);
dest.setUpdateTime(now);
return dest;
}).collect(Collectors.toList());
workMapper.batchInsert(profileWorkList);
}
// 6. 同步实习经历
internshipMapper.delete(new LambdaQueryWrapper<UserProfileInternship>().eq(UserProfileInternship::getUserId, userId));
if (!resumeInternshipList.isEmpty()) {
List<UserProfileInternship> profileInternshipList = IntStream.range(0, resumeInternshipList.size()).mapToObj(i -> {
UserResumeInternship src = resumeInternshipList.get(i);
UserProfileInternship dest = new UserProfileInternship();
dest.setProfileId(profileId);
dest.setUserId(userId);
dest.setCompanyName(src.getCompanyName());
dest.setPosition(src.getPosition());
dest.setStartDate(src.getStartDate());
dest.setEndDate(src.getEndDate());
dest.setDescription(src.getDescription());
dest.setSortOrder(i);
dest.setCreateTime(now);
dest.setUpdateTime(now);
return dest;
}).collect(Collectors.toList());
internshipMapper.batchInsert(profileInternshipList);
}
// 7. 同步项目经历
projectMapper.delete(new LambdaQueryWrapper<UserProfileProject>().eq(UserProfileProject::getUserId, userId));
if (!resumeProjectList.isEmpty()) {
List<UserProfileProject> profileProjectList = IntStream.range(0, resumeProjectList.size()).mapToObj(i -> {
UserResumeProject src = resumeProjectList.get(i);
UserProfileProject dest = new UserProfileProject();
dest.setProfileId(profileId);
dest.setUserId(userId);
dest.setCompanyName(src.getCompanyName());
dest.setProjectName(src.getProjectName());
dest.setRole(src.getRole());
dest.setStartDate(src.getStartDate());
dest.setEndDate(src.getEndDate());
dest.setDescription(src.getDescription());
dest.setSortOrder(i);
dest.setCreateTime(now);
dest.setUpdateTime(now);
return dest;
}).collect(Collectors.toList());
projectMapper.batchInsert(profileProjectList);
}
// 8. 同步竞赛经历
competitionMapper.delete(new LambdaQueryWrapper<UserProfileCompetition>().eq(UserProfileCompetition::getUserId, userId));
if (!resumeCompetitionList.isEmpty()) {
List<UserProfileCompetition> profileCompetitionList = IntStream.range(0, resumeCompetitionList.size()).mapToObj(i -> {
UserResumeCompetition src = resumeCompetitionList.get(i);
UserProfileCompetition dest = new UserProfileCompetition();
dest.setProfileId(profileId);
dest.setUserId(userId);
dest.setCompetitionName(src.getCompetitionName());
dest.setAward(src.getAward());
dest.setAwardDate(src.getAwardDate());
dest.setDescription(src.getDescription());
dest.setSortOrder(i);
dest.setCreateTime(now);
dest.setUpdateTime(now);
return dest;
}).collect(Collectors.toList());
competitionMapper.batchInsert(profileCompetitionList);
}
// 9. 事务内所有数据写入完成,触发一次异步AI分析
userProfileAnalyzeService.analyzeUserProfile(userId);
}
// ==================== 内部方法 ====================
/**