diff --git a/.kiro/steering/项目结构说明.md b/.kiro/steering/项目结构说明.md index 59c3b2b..ad94fb6 100644 --- a/.kiro/steering/项目结构说明.md +++ b/.kiro/steering/项目结构说明.md @@ -25,7 +25,7 @@ offerpie/back-end │ │ ├─ UserProfileController.java # 用户个人资料接口(主表+5张子表的查询与保存) │ │ ├─ JobIntentionController.java # 求职意向接口(查询与保存) │ │ ├─ JobController.java # 岗位接口(岗位列表查询) -│ │ └─ UserResumeController.java # 用户简历接口(简历列表查询等) +│ │ └─ UserResumeController.java # 用户简历接口(简历列表、主表及5张子表的查询与保存、子表单条添加/编辑/删除、简历删除) │ ├─ service/ │ │ ├─ LoginService.java # 登录业务逻辑(验证码校验、自动注册、JWT生成、Cookie设置) │ │ ├─ UserRegisterService.java # 用户注册服务(注册逻辑、邀请码生成与绑定) @@ -34,12 +34,12 @@ offerpie/back-end │ │ ├─ UserProfileService.java # 用户个人资料服务(主表+5张子表的CRUD) │ │ ├─ JobIntentionService.java # 求职意向服务(查询与保存/更新) │ │ ├─ JobService.java # 岗位服务(岗位列表查询、匹配度计算编排) -│ │ ├─ UserResumeService.java # 用户简历服务(简历列表查询等) +│ │ ├─ UserResumeService.java # 用户简历服务(简历列表、主表及5张子表的CRUD、子表单条添加/编辑/删除) │ │ └─ WxPayNotifyMessageAbstractImpl.java # 微信支付回调实现 │ └─ pojo/ │ ├─ param/ │ │ ├─ userProfile/ # 个人资料入参(UserProfileParam、各子表Param) -│ │ ├─ resume/ # 简历入参(ResumeParam、各子表Param、ResumeSubTableParam) +│ │ ├─ resume/ # 简历入参(ResumeParam、各子表Param、各子表UpdateParam、ResumeSubTableParam) │ │ └─ job/ # 岗位相关入参(JobIntentionParam、JobQueryParam) │ ├─ dto/ │ │ ├─ SmsLoginDto.java # 短信登录入参(mobileNumber + code + inviteCode) diff --git a/client-api/src/main/java/org/jiayunet/controller/UserResumeController.java b/client-api/src/main/java/org/jiayunet/controller/UserResumeController.java index a313d2a..2bc1402 100644 --- a/client-api/src/main/java/org/jiayunet/controller/UserResumeController.java +++ b/client-api/src/main/java/org/jiayunet/controller/UserResumeController.java @@ -82,6 +82,28 @@ public class UserResumeController { }).collect(Collectors.toList()); } + /** 添加单条教育经历,返回新记录id */ + @PostMapping("/education/add") + public Long addEducation(@RequestParam Long resumeId, @Validated @RequestBody ResumeEducationParam param) { + UserResumeEducation po = new UserResumeEducation(); + BeanUtils.copyProperties(param, po); + return userResumeService.addEducation(po, resumeId); + } + + /** 根据id编辑单条教育经历 */ + @PostMapping("/education/update") + public void updateEducation(@Validated @RequestBody ResumeEducationUpdateParam param) { + UserResumeEducation po = new UserResumeEducation(); + BeanUtils.copyProperties(param, po); + userResumeService.updateEducation(po); + } + + /** 根据id删除单条教育经历 */ + @PostMapping("/education/delete") + public void deleteEducation(@RequestParam Long id) { + userResumeService.deleteEducation(id); + } + /** 保存简历的教育经历列表(先删后插),返回resumeId */ @PostMapping("/education") public Long saveEducation(@Validated @RequestBody ResumeSubTableParam param) { @@ -105,6 +127,28 @@ public class UserResumeController { }).collect(Collectors.toList()); } + /** 添加单条工作经历,返回新记录id */ + @PostMapping("/work/add") + public Long addWork(@RequestParam Long resumeId, @Validated @RequestBody ResumeWorkParam param) { + UserResumeWork po = new UserResumeWork(); + BeanUtils.copyProperties(param, po); + return userResumeService.addWork(po, resumeId); + } + + /** 根据id编辑单条工作经历 */ + @PostMapping("/work/update") + public void updateWork(@Validated @RequestBody ResumeWorkUpdateParam param) { + UserResumeWork po = new UserResumeWork(); + BeanUtils.copyProperties(param, po); + userResumeService.updateWork(po); + } + + /** 根据id删除单条工作经历 */ + @PostMapping("/work/delete") + public void deleteWork(@RequestParam Long id) { + userResumeService.deleteWork(id); + } + /** 保存简历的工作经历列表(先删后插),返回resumeId */ @PostMapping("/work") public Long saveWork(@Validated @RequestBody ResumeSubTableParam param) { @@ -128,6 +172,28 @@ public class UserResumeController { }).collect(Collectors.toList()); } + /** 添加单条实习经历,返回新记录id */ + @PostMapping("/internship/add") + public Long addInternship(@RequestParam Long resumeId, @Validated @RequestBody ResumeInternshipParam param) { + UserResumeInternship po = new UserResumeInternship(); + BeanUtils.copyProperties(param, po); + return userResumeService.addInternship(po, resumeId); + } + + /** 根据id编辑单条实习经历 */ + @PostMapping("/internship/update") + public void updateInternship(@Validated @RequestBody ResumeInternshipUpdateParam param) { + UserResumeInternship po = new UserResumeInternship(); + BeanUtils.copyProperties(param, po); + userResumeService.updateInternship(po); + } + + /** 根据id删除单条实习经历 */ + @PostMapping("/internship/delete") + public void deleteInternship(@RequestParam Long id) { + userResumeService.deleteInternship(id); + } + /** 保存简历的实习经历列表(先删后插),返回resumeId */ @PostMapping("/internship") public Long saveInternship(@Validated @RequestBody ResumeSubTableParam param) { @@ -151,6 +217,28 @@ public class UserResumeController { }).collect(Collectors.toList()); } + /** 添加单条项目经历,返回新记录id */ + @PostMapping("/project/add") + public Long addProject(@RequestParam Long resumeId, @Validated @RequestBody ResumeProjectParam param) { + UserResumeProject po = new UserResumeProject(); + BeanUtils.copyProperties(param, po); + return userResumeService.addProject(po, resumeId); + } + + /** 根据id编辑单条项目经历 */ + @PostMapping("/project/update") + public void updateProject(@Validated @RequestBody ResumeProjectUpdateParam param) { + UserResumeProject po = new UserResumeProject(); + BeanUtils.copyProperties(param, po); + userResumeService.updateProject(po); + } + + /** 根据id删除单条项目经历 */ + @PostMapping("/project/delete") + public void deleteProject(@RequestParam Long id) { + userResumeService.deleteProject(id); + } + /** 保存简历的项目经历列表(先删后插),返回resumeId */ @PostMapping("/project") public Long saveProject(@Validated @RequestBody ResumeSubTableParam param) { @@ -174,6 +262,28 @@ public class UserResumeController { }).collect(Collectors.toList()); } + /** 添加单条竞赛经历,返回新记录id */ + @PostMapping("/competition/add") + public Long addCompetition(@RequestParam Long resumeId, @Validated @RequestBody ResumeCompetitionParam param) { + UserResumeCompetition po = new UserResumeCompetition(); + BeanUtils.copyProperties(param, po); + return userResumeService.addCompetition(po, resumeId); + } + + /** 根据id编辑单条竞赛经历 */ + @PostMapping("/competition/update") + public void updateCompetition(@Validated @RequestBody ResumeCompetitionUpdateParam param) { + UserResumeCompetition po = new UserResumeCompetition(); + BeanUtils.copyProperties(param, po); + userResumeService.updateCompetition(po); + } + + /** 根据id删除单条竞赛经历 */ + @PostMapping("/competition/delete") + public void deleteCompetition(@RequestParam Long id) { + userResumeService.deleteCompetition(id); + } + /** 保存简历的竞赛经历列表(先删后插),返回resumeId */ @PostMapping("/competition") public Long saveCompetition(@Validated @RequestBody ResumeSubTableParam param) { diff --git a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeCompetitionUpdateParam.java b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeCompetitionUpdateParam.java new file mode 100644 index 0000000..7712ef3 --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeCompetitionUpdateParam.java @@ -0,0 +1,20 @@ +package org.jiayunet.pojo.param.resume; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + * 简历-竞赛经历编辑入参 + * + * @author zk + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ResumeCompetitionUpdateParam extends ResumeCompetitionParam { + + /** 记录ID */ + @NotNull(message = "id不能为空") + private Long id; +} diff --git a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeEducationUpdateParam.java b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeEducationUpdateParam.java new file mode 100644 index 0000000..88cf580 --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeEducationUpdateParam.java @@ -0,0 +1,20 @@ +package org.jiayunet.pojo.param.resume; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + * 简历-教育经历编辑入参 + * + * @author zk + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ResumeEducationUpdateParam extends ResumeEducationParam { + + /** 记录ID */ + @NotNull(message = "id不能为空") + private Long id; +} diff --git a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeInternshipUpdateParam.java b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeInternshipUpdateParam.java new file mode 100644 index 0000000..6790a6c --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeInternshipUpdateParam.java @@ -0,0 +1,20 @@ +package org.jiayunet.pojo.param.resume; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + * 简历-实习经历编辑入参 + * + * @author zk + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ResumeInternshipUpdateParam extends ResumeInternshipParam { + + /** 记录ID */ + @NotNull(message = "id不能为空") + private Long id; +} diff --git a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeProjectUpdateParam.java b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeProjectUpdateParam.java new file mode 100644 index 0000000..78bcea4 --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeProjectUpdateParam.java @@ -0,0 +1,20 @@ +package org.jiayunet.pojo.param.resume; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + * 简历-项目经历编辑入参 + * + * @author zk + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ResumeProjectUpdateParam extends ResumeProjectParam { + + /** 记录ID */ + @NotNull(message = "id不能为空") + private Long id; +} diff --git a/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeWorkUpdateParam.java b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeWorkUpdateParam.java new file mode 100644 index 0000000..97c5f11 --- /dev/null +++ b/client-api/src/main/java/org/jiayunet/pojo/param/resume/ResumeWorkUpdateParam.java @@ -0,0 +1,20 @@ +package org.jiayunet.pojo.param.resume; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + * 简历-工作经历编辑入参 + * + * @author zk + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ResumeWorkUpdateParam extends ResumeWorkParam { + + /** 记录ID */ + @NotNull(message = "id不能为空") + private Long id; +} diff --git a/client-api/src/main/java/org/jiayunet/service/UserResumeService.java b/client-api/src/main/java/org/jiayunet/service/UserResumeService.java index 37e6229..6530b49 100644 --- a/client-api/src/main/java/org/jiayunet/service/UserResumeService.java +++ b/client-api/src/main/java/org/jiayunet/service/UserResumeService.java @@ -12,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; import java.time.Instant; import java.util.List; @@ -319,6 +320,262 @@ public class UserResumeService { return resumeId; } + // ==================== 子表单条添加 ==================== + + /** + * 添加单条教育经历 + *

1. 校验简历归属 2. 设置系统字段 3. insert 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public Long addEducation(UserResumeEducation po, Long resumeId) { + checkResumeOwnership(resumeId); + Long userId = UserSecurityTool.getUserId(); + Instant now = Instant.now(); + po.setResumeId(resumeId); + po.setUserId(userId); + po.setSortOrder(0); + po.setCreateTime(now); + po.setUpdateTime(now); + educationMapper.insert(po); + touchResumeUpdateTime(resumeId); + return po.getId(); + } + + /** + * 添加单条工作经历 + *

1. 校验简历归属 2. 设置系统字段 3. insert 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public Long addWork(UserResumeWork po, Long resumeId) { + checkResumeOwnership(resumeId); + Long userId = UserSecurityTool.getUserId(); + Instant now = Instant.now(); + po.setResumeId(resumeId); + po.setUserId(userId); + po.setSortOrder(0); + po.setCreateTime(now); + po.setUpdateTime(now); + workMapper.insert(po); + touchResumeUpdateTime(resumeId); + return po.getId(); + } + + /** + * 添加单条实习经历 + *

1. 校验简历归属 2. 设置系统字段 3. insert 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public Long addInternship(UserResumeInternship po, Long resumeId) { + checkResumeOwnership(resumeId); + Long userId = UserSecurityTool.getUserId(); + Instant now = Instant.now(); + po.setResumeId(resumeId); + po.setUserId(userId); + po.setSortOrder(0); + po.setCreateTime(now); + po.setUpdateTime(now); + internshipMapper.insert(po); + touchResumeUpdateTime(resumeId); + return po.getId(); + } + + /** + * 添加单条项目经历 + *

1. 校验简历归属 2. 设置系统字段 3. insert 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public Long addProject(UserResumeProject po, Long resumeId) { + checkResumeOwnership(resumeId); + Long userId = UserSecurityTool.getUserId(); + Instant now = Instant.now(); + po.setResumeId(resumeId); + po.setUserId(userId); + po.setSortOrder(0); + po.setCreateTime(now); + po.setUpdateTime(now); + projectMapper.insert(po); + touchResumeUpdateTime(resumeId); + return po.getId(); + } + + /** + * 添加单条竞赛经历 + *

1. 校验简历归属 2. 设置系统字段 3. insert 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public Long addCompetition(UserResumeCompetition po, Long resumeId) { + checkResumeOwnership(resumeId); + Long userId = UserSecurityTool.getUserId(); + Instant now = Instant.now(); + po.setResumeId(resumeId); + po.setUserId(userId); + po.setSortOrder(0); + po.setCreateTime(now); + po.setUpdateTime(now); + competitionMapper.insert(po); + touchResumeUpdateTime(resumeId); + return po.getId(); + } + + // ==================== 子表单条删除 ==================== + + /** + * 根据id删除教育经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 删除 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void deleteEducation(Long id) { + UserResumeEducation existing = educationMapper.selectById(id); + Assert.notNull(existing, "教育经历不存在"); + checkResumeOwnership(existing.getResumeId()); + educationMapper.deleteById(id); + touchResumeUpdateTime(existing.getResumeId()); + } + + /** + * 根据id删除工作经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 删除 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void deleteWork(Long id) { + UserResumeWork existing = workMapper.selectById(id); + Assert.notNull(existing, "工作经历不存在"); + checkResumeOwnership(existing.getResumeId()); + workMapper.deleteById(id); + touchResumeUpdateTime(existing.getResumeId()); + } + + /** + * 根据id删除实习经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 删除 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void deleteInternship(Long id) { + UserResumeInternship existing = internshipMapper.selectById(id); + Assert.notNull(existing, "实习经历不存在"); + checkResumeOwnership(existing.getResumeId()); + internshipMapper.deleteById(id); + touchResumeUpdateTime(existing.getResumeId()); + } + + /** + * 根据id删除项目经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 删除 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void deleteProject(Long id) { + UserResumeProject existing = projectMapper.selectById(id); + Assert.notNull(existing, "项目经历不存在"); + checkResumeOwnership(existing.getResumeId()); + projectMapper.deleteById(id); + touchResumeUpdateTime(existing.getResumeId()); + } + + /** + * 根据id删除竞赛经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 删除 4. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void deleteCompetition(Long id) { + UserResumeCompetition existing = competitionMapper.selectById(id); + Assert.notNull(existing, "竞赛经历不存在"); + checkResumeOwnership(existing.getResumeId()); + competitionMapper.deleteById(id); + touchResumeUpdateTime(existing.getResumeId()); + } + + // ==================== 子表单条编辑 ==================== + + /** + * 根据id编辑教育经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 覆盖字段 4. updateById 5. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void updateEducation(UserResumeEducation po) { + UserResumeEducation existing = educationMapper.selectById(po.getId()); + Assert.notNull(existing, "教育经历不存在"); + checkResumeOwnership(existing.getResumeId()); + po.setResumeId(existing.getResumeId()); + po.setUserId(existing.getUserId()); + po.setSortOrder(existing.getSortOrder()); + po.setCreateTime(existing.getCreateTime()); + po.setUpdateTime(Instant.now()); + educationMapper.updateById(po); + touchResumeUpdateTime(existing.getResumeId()); + } + + /** + * 根据id编辑工作经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 覆盖字段 4. updateById 5. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void updateWork(UserResumeWork po) { + UserResumeWork existing = workMapper.selectById(po.getId()); + Assert.notNull(existing, "工作经历不存在"); + checkResumeOwnership(existing.getResumeId()); + po.setResumeId(existing.getResumeId()); + po.setUserId(existing.getUserId()); + po.setSortOrder(existing.getSortOrder()); + po.setCreateTime(existing.getCreateTime()); + po.setUpdateTime(Instant.now()); + workMapper.updateById(po); + touchResumeUpdateTime(existing.getResumeId()); + } + + /** + * 根据id编辑实习经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 覆盖字段 4. updateById 5. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void updateInternship(UserResumeInternship po) { + UserResumeInternship existing = internshipMapper.selectById(po.getId()); + Assert.notNull(existing, "实习经历不存在"); + checkResumeOwnership(existing.getResumeId()); + po.setResumeId(existing.getResumeId()); + po.setUserId(existing.getUserId()); + po.setSortOrder(existing.getSortOrder()); + po.setCreateTime(existing.getCreateTime()); + po.setUpdateTime(Instant.now()); + internshipMapper.updateById(po); + touchResumeUpdateTime(existing.getResumeId()); + } + + /** + * 根据id编辑项目经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 覆盖字段 4. updateById 5. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void updateProject(UserResumeProject po) { + UserResumeProject existing = projectMapper.selectById(po.getId()); + Assert.notNull(existing, "项目经历不存在"); + checkResumeOwnership(existing.getResumeId()); + po.setResumeId(existing.getResumeId()); + po.setUserId(existing.getUserId()); + po.setSortOrder(existing.getSortOrder()); + po.setCreateTime(existing.getCreateTime()); + po.setUpdateTime(Instant.now()); + projectMapper.updateById(po); + touchResumeUpdateTime(existing.getResumeId()); + } + + /** + * 根据id编辑竞赛经历 + *

1. 查记录是否存在 2. 校验简历归属 3. 覆盖字段 4. updateById 5. 刷新主表updateTime

+ */ + @Transactional(rollbackFor = Exception.class) + public void updateCompetition(UserResumeCompetition po) { + UserResumeCompetition existing = competitionMapper.selectById(po.getId()); + Assert.notNull(existing, "竞赛经历不存在"); + checkResumeOwnership(existing.getResumeId()); + po.setResumeId(existing.getResumeId()); + po.setUserId(existing.getUserId()); + po.setSortOrder(existing.getSortOrder()); + po.setCreateTime(existing.getCreateTime()); + po.setUpdateTime(Instant.now()); + competitionMapper.updateById(po); + touchResumeUpdateTime(existing.getResumeId()); + } + // ==================== 内部方法 ==================== /**