添加岗位详情接口
This commit is contained in:
@@ -2,15 +2,13 @@ package org.jiayunet.controller;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.jiayunet.pojo.PageResult;
|
||||
import org.jiayunet.pojo.dto.job.JobDetailDto;
|
||||
import org.jiayunet.pojo.dto.job.JobDto;
|
||||
import org.jiayunet.pojo.param.job.JobQueryParam;
|
||||
import org.jiayunet.service.JobService;
|
||||
import org.jiayunet.tool.UserSecurityTool;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 岗位接口
|
||||
@@ -33,4 +31,14 @@ public class JobController {
|
||||
Long userId = UserSecurityTool.getUserId();
|
||||
return jobService.listJobs(param, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 岗位详情
|
||||
* <p>返回岗位完整信息、公司信息、匹配度、收藏状态</p>
|
||||
*/
|
||||
@GetMapping("/{jobId}")
|
||||
public JobDetailDto getJobDetail(@PathVariable Long jobId) {
|
||||
Long userId = UserSecurityTool.getUserId();
|
||||
return jobService.getJobDetail(jobId, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.jiayunet.pojo.dto.job;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 岗位详情出参
|
||||
*
|
||||
* @author zk
|
||||
*/
|
||||
@Data
|
||||
public class JobDetailDto {
|
||||
// ========== 岗位信息 ==========
|
||||
/** 岗位ID */
|
||||
private Long jobId;
|
||||
/** 岗位标题 */
|
||||
private String jobTitle;
|
||||
/** 薪资描述 */
|
||||
private String salary;
|
||||
/** 工作类型 0=全职 1=兼职 */
|
||||
private Integer employmentType;
|
||||
/** 学历要求 0=不限 1=大专 2=本科 3=硕士 4=博士 */
|
||||
private Integer education;
|
||||
/** 最低工作年限 */
|
||||
private Integer minExperience;
|
||||
/** 岗位职责 */
|
||||
private String description;
|
||||
/** 任职要求 */
|
||||
private String requirement;
|
||||
/** 加分项 */
|
||||
private String bonus;
|
||||
/** 岗位标签 */
|
||||
private List<String> tags;
|
||||
/** 技能标签 */
|
||||
private List<String> skillTags;
|
||||
/** 来源链接 */
|
||||
private String sourceUrl;
|
||||
/** 岗位类型名称 */
|
||||
private String categoryName;
|
||||
/** 要求的行业经验名称 */
|
||||
private String requiredIndustryName;
|
||||
|
||||
// ========== 公司信息 ==========
|
||||
/** 公司ID */
|
||||
private Long companyId;
|
||||
/** 公司名称 */
|
||||
private String companyName;
|
||||
/** 公司简称 */
|
||||
private String companyShortName;
|
||||
/** 公司Logo */
|
||||
private String companyLogoUrl;
|
||||
/** 公司类型 */
|
||||
private String companyType;
|
||||
/** 公司所属行业名称 */
|
||||
private String companyIndustryName;
|
||||
/** 公司标签 */
|
||||
private List<String> companyTags;
|
||||
/** 公司简介 */
|
||||
private String companySummary;
|
||||
/** 公司描述 */
|
||||
private String companyDescription;
|
||||
/** 成立时间 */
|
||||
private String companyFoundedYear;
|
||||
/** 公司地址 */
|
||||
private String companyAddress;
|
||||
/** 公司规模 */
|
||||
private String companyScale;
|
||||
/** 公司官网 */
|
||||
private String companyWebsite;
|
||||
/** 融资状态 */
|
||||
private String companyFinancingStage;
|
||||
/** 最新估值 */
|
||||
private String companyLatestValuation;
|
||||
/** 公司新闻 */
|
||||
private List<String> companyNews;
|
||||
/** 地区名称 */
|
||||
private String regionName;
|
||||
|
||||
// ========== 匹配度信息 ==========
|
||||
/** 匹配总分 */
|
||||
private Integer matchScore;
|
||||
/** 匹配度详情 */
|
||||
private JobMatchScoreDto matchDetail;
|
||||
|
||||
// ========== 用户操作状态 ==========
|
||||
/** 是否已收藏 */
|
||||
private Boolean isFavorite;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jiayunet.mapper.*;
|
||||
import org.jiayunet.pojo.PageResult;
|
||||
import org.jiayunet.pojo.dto.job.JobDetailDto;
|
||||
import org.jiayunet.pojo.dto.job.JobDto;
|
||||
import org.jiayunet.pojo.dto.job.JobMatchScoreDto;
|
||||
import org.jiayunet.pojo.param.job.JobQueryParam;
|
||||
@@ -19,9 +20,9 @@ import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 岗位服务
|
||||
* <p>主要功能:岗位列表查询、匹配度计算</p>
|
||||
* <p>依赖:JobMatchService(匹配度计算)</p>
|
||||
* <p>使用表:bg_job(查询岗位)、bg_user_job_dislike(查询不感兴趣记录)、bg_user_job_favorite(查询收藏状态)、bg_china_regions_code(扩展地区子级)、bg_job_category(扩展岗位类型子级)、bg_industry(扩展行业子级)</p>
|
||||
* <p>主要功能:岗位列表查询、岗位详情查询、匹配度计算</p>
|
||||
* <p>依赖服务:JobMatchService(匹配度计算)</p>
|
||||
* <p>使用的表:bg_job、bg_company、bg_user_job_dislike、bg_user_job_favorite、bg_china_regions_code、bg_job_category、bg_industry</p>
|
||||
*
|
||||
* @author zk
|
||||
*/
|
||||
@@ -48,11 +49,21 @@ public class JobService {
|
||||
private IndustryMapper industryMapper;
|
||||
|
||||
@Autowired
|
||||
private org.jiayunet.service.JobMatchService jobMatchService;
|
||||
private CompanyMapper companyMapper;
|
||||
|
||||
@Autowired
|
||||
private JobMatchService jobMatchService;
|
||||
|
||||
/**
|
||||
* 岗位列表查询
|
||||
* <p>1. 扩展筛选条件子级 2. 查询不感兴趣记录 3. 扩展不感兴趣的地区和行业子级 4. 执行分页查询 5. 查询收藏状态 6. 批量计算匹配度 7. 组装返回数据</p>
|
||||
* <p>方法逻辑流程:</p>
|
||||
* <p>1. 扩展筛选条件的子级(地区/岗位类型/行业)</p>
|
||||
* <p>2. 查询用户不感兴趣记录</p>
|
||||
* <p>3. 提取排除列表(岗位/公司/地区/行业)</p>
|
||||
* <p>4. 执行分页查询</p>
|
||||
* <p>5. 查询收藏状态</p>
|
||||
* <p>6. 批量计算匹配度</p>
|
||||
* <p>7. 组装返回数据</p>
|
||||
*/
|
||||
public PageResult<JobDto> listJobs(JobQueryParam param, Long userId) {
|
||||
// 1. 扩展筛选条件的子级
|
||||
@@ -150,4 +161,104 @@ public class JobService {
|
||||
List<UserJobFavorite> favorites = userJobFavoriteMapper.selectList(new LambdaQueryWrapper<UserJobFavorite>().eq(UserJobFavorite::getUserId, userId).in(UserJobFavorite::getJobId, jobIds));
|
||||
return favorites.stream().collect(Collectors.toMap(UserJobFavorite::getJobId, f -> true));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询岗位详情
|
||||
* <p>方法逻辑流程:</p>
|
||||
* <p>1. 查询岗位信息(校验状态)</p>
|
||||
* <p>2. 查询公司信息</p>
|
||||
* <p>3. 查询收藏状态</p>
|
||||
* <p>4. 计算匹配度</p>
|
||||
* <p>5. 查询关联名称(岗位类型/行业/地区)</p>
|
||||
* <p>6. 组装返回数据</p>
|
||||
*/
|
||||
public JobDetailDto getJobDetail(Long jobId, Long userId) {
|
||||
// 1. 查询岗位
|
||||
Job job = jobMapper.selectOne(new LambdaQueryWrapper<Job>().eq(Job::getId, jobId).eq(Job::getStatus, 0));
|
||||
if (job == null) throw new RuntimeException("岗位不存在或已下架");
|
||||
|
||||
// 2. 查询公司
|
||||
Company company = companyMapper.selectById(job.getCompanyId());
|
||||
if (company == null) throw new RuntimeException("公司信息不存在");
|
||||
|
||||
// 3. 查询收藏状态
|
||||
Long count = userJobFavoriteMapper.selectCount(new LambdaQueryWrapper<UserJobFavorite>().eq(UserJobFavorite::getUserId, userId).eq(UserJobFavorite::getJobId, jobId));
|
||||
|
||||
// 4. 计算匹配度
|
||||
List<JobListItemVo> jobList = new ArrayList<>();
|
||||
JobListItemVo item = new JobListItemVo();
|
||||
item.setId(job.getId());
|
||||
item.setRequiredIndustryId(job.getRequiredIndustryId());
|
||||
item.setMinExperience(job.getMinExperience());
|
||||
jobList.add(item);
|
||||
Map<Long, Map<String, Integer>> matchScoreMap = jobMatchService.batchCalculateMatchScore(jobList, userId);
|
||||
Map<String, Integer> scoreMap = matchScoreMap.get(jobId);
|
||||
|
||||
// 5. 查询关联名称
|
||||
String categoryName = null;
|
||||
if (job.getCategoryId() != null) {
|
||||
JobCategory category = categoryMapper.selectById(job.getCategoryId());
|
||||
if (category != null) categoryName = category.getName();
|
||||
}
|
||||
String requiredIndustryName = null;
|
||||
if (job.getRequiredIndustryId() != null) {
|
||||
Industry industry = industryMapper.selectById(job.getRequiredIndustryId());
|
||||
if (industry != null) requiredIndustryName = industry.getName();
|
||||
}
|
||||
String companyIndustryName = null;
|
||||
if (company.getIndustryId() != null) {
|
||||
Industry industry = industryMapper.selectById(company.getIndustryId());
|
||||
if (industry != null) companyIndustryName = industry.getName();
|
||||
}
|
||||
String regionName = null;
|
||||
if (company.getRegionCode() != null) {
|
||||
ChinaRegionsCode region = regionMapper.selectOne(new LambdaQueryWrapper<ChinaRegionsCode>().eq(ChinaRegionsCode::getCode, company.getRegionCode()));
|
||||
if (region != null) regionName = region.getName();
|
||||
}
|
||||
|
||||
// 6. 组装返回
|
||||
JobDetailDto dto = new JobDetailDto();
|
||||
dto.setJobId(job.getId());
|
||||
dto.setJobTitle(job.getTitle());
|
||||
dto.setSalary(job.getSalary());
|
||||
dto.setEmploymentType(job.getEmploymentType());
|
||||
dto.setEducation(job.getEducation());
|
||||
dto.setMinExperience(job.getMinExperience());
|
||||
dto.setDescription(job.getDescription());
|
||||
dto.setRequirement(job.getRequirement());
|
||||
dto.setBonus(job.getBonus());
|
||||
dto.setTags(job.getTags());
|
||||
dto.setSkillTags(job.getSkillTags());
|
||||
dto.setSourceUrl(job.getSourceUrl());
|
||||
dto.setCategoryName(categoryName);
|
||||
dto.setRequiredIndustryName(requiredIndustryName);
|
||||
dto.setCompanyId(company.getId());
|
||||
dto.setCompanyName(company.getName());
|
||||
dto.setCompanyShortName(company.getShortName());
|
||||
dto.setCompanyLogoUrl(company.getLogoUrl());
|
||||
dto.setCompanyType(company.getCompanyType());
|
||||
dto.setCompanyIndustryName(companyIndustryName);
|
||||
dto.setCompanyTags(company.getTags());
|
||||
dto.setCompanySummary(company.getSummary());
|
||||
dto.setCompanyDescription(company.getDescription());
|
||||
dto.setCompanyFoundedYear(company.getFoundedYear());
|
||||
dto.setCompanyAddress(company.getAddress());
|
||||
dto.setCompanyScale(company.getScale());
|
||||
dto.setCompanyWebsite(company.getWebsite());
|
||||
dto.setCompanyFinancingStage(company.getFinancingStage());
|
||||
dto.setCompanyLatestValuation(company.getLatestValuation());
|
||||
dto.setCompanyNews(company.getNews());
|
||||
dto.setRegionName(regionName);
|
||||
dto.setIsFavorite(count > 0);
|
||||
if (scoreMap != null) {
|
||||
dto.setMatchScore(scoreMap.get("totalScore"));
|
||||
dto.setMatchDetail(new JobMatchScoreDto(scoreMap.get("industryScore"), scoreMap.get("skillScore"), scoreMap.get("experienceScore")));
|
||||
} else {
|
||||
dto.setMatchScore(0);
|
||||
dto.setMatchDetail(new JobMatchScoreDto(0, 0, 0));
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package org.jiayunet.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公司表(bg_company)
|
||||
@@ -13,7 +16,7 @@ import java.time.Instant;
|
||||
* @author zk
|
||||
*/
|
||||
@Data
|
||||
@TableName(value = "bg_company")
|
||||
@TableName(value = "bg_company", autoResultMap = true)
|
||||
public class Company {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@@ -37,8 +40,9 @@ public class Company {
|
||||
/** 行业ID */
|
||||
private Long industryId;
|
||||
|
||||
/** 公司标签(JSON数组) */
|
||||
private String tags;
|
||||
/** 公司标签 */
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> tags;
|
||||
|
||||
/** 公司简要 */
|
||||
private String summary;
|
||||
@@ -64,8 +68,9 @@ public class Company {
|
||||
/** 最新估值 */
|
||||
private String latestValuation;
|
||||
|
||||
/** 新闻动态(JSON数组) */
|
||||
private String news;
|
||||
/** 新闻动态 */
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> news;
|
||||
|
||||
/** 状态 0=待完善 1=已完善 2=禁用 3=补充中 4=补充失败 */
|
||||
private Integer status;
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -62,7 +63,9 @@ public class CompanyCleanTransactionService {
|
||||
// tags:JSON数组
|
||||
JsonNode tagsNode = root.path("tags");
|
||||
if (tagsNode.isArray() && !tagsNode.isEmpty()) {
|
||||
company.setTags(tagsNode.toString());
|
||||
List<String> tags = new ArrayList<>();
|
||||
tagsNode.forEach(node -> tags.add(node.asText()));
|
||||
company.setTags(tags);
|
||||
}
|
||||
|
||||
// summary
|
||||
@@ -116,7 +119,9 @@ public class CompanyCleanTransactionService {
|
||||
// news:JSON数组
|
||||
JsonNode newsNode = root.path("news");
|
||||
if (newsNode.isArray() && !newsNode.isEmpty()) {
|
||||
company.setNews(newsNode.toString());
|
||||
List<String> news = new ArrayList<>();
|
||||
newsNode.forEach(node -> news.add(node.asText()));
|
||||
company.setNews(news);
|
||||
}
|
||||
|
||||
// 更新状态和时间
|
||||
|
||||
Reference in New Issue
Block a user