Compare commits

..

84 Commits

Author SHA1 Message Date
sh
461e3adb12 修改161:11111改为161:80 2025-12-12 13:08:06 +08:00
sh
cb5835fcaf 修改转发人员配置、新增工作人员接口权限配置 2025-12-11 17:25:17 +08:00
sh
3822488f26 添加微信抓取判重的方法 2025-12-11 15:51:13 +08:00
sh
6385dd163b 获取移动端用户信息提示 2025-12-09 12:29:17 +08:00
sh
22d2e40264 岗位-详情时查询岗位申请人信息 2025-12-08 21:20:08 +08:00
sh
aaa7d5ec3f 修改附件上传-必须登录有token才能上传 2025-12-08 20:03:59 +08:00
sh
77397ff40a 修改pc端技能保存 2025-12-08 18:01:42 +08:00
sh
e04ef92a65 修改企业用户注册 2025-12-08 17:06:42 +08:00
sh
9e4191fc90 修改个人信息-保存一体机密码 2025-12-08 16:37:45 +08:00
sh
b61f280567 修改竞争力分析-添加area判断为空的情况 2025-12-08 16:25:12 +08:00
sh
fe9c72ff6c 修改es的查询数据,只获取有效的 2025-12-08 12:08:06 +08:00
sh
8b072cbcbe 修改nls、微信授权地址,通过修改状态来控制测试和正式 2025-12-08 10:49:01 +08:00
sh
b77af1ca0d 添加工作人员管理、转发人员配置-基础类 2025-12-06 18:42:36 +08:00
sh
97deb1aef6 修改swagger报错问题 2025-12-06 18:08:34 +08:00
sh
7d8a15bcdc 修改小程序注册方法-已测试改为调用新方法 2025-12-06 16:25:47 +08:00
sh
c2a8b4013b 修改微信登录方法-已测试改为调用新方法 2025-12-06 15:42:27 +08:00
sh
28e4a9983e 修改微信登录方法-未调用,需要测试 2025-12-06 13:32:36 +08:00
sh
ac12331e8d 修改微信登录方法-未调用,需要测试 2025-12-06 13:31:46 +08:00
sh
0fe02ff1a9 修改问题岗位-保存联系人 2025-12-04 20:59:10 +08:00
sh
6e5455ca25 岗位列表-添加岗位联系人 2025-12-04 19:30:51 +08:00
sh
879bd8c009 修改岗位详情-添加岗位联系人 2025-12-04 17:52:22 +08:00
sh
5c02fb16ca 修改岗位详情-添加岗位联系人 2025-12-04 16:17:02 +08:00
sh
cb5d4d00a7 修改移动端,展示附件信息 2025-12-04 16:00:26 +08:00
sh
c8f9b6547a 修改附件展示 2025-12-04 12:29:50 +08:00
sh
905bfa1996 修改互联网地址和修改附件 2025-12-04 11:03:41 +08:00
sh
4b06d2d0f9 修改正式环境服务器-附件信息(未完成) 2025-12-03 19:42:47 +08:00
sh
50a5c5e128 修改pc端查询推荐岗位逻辑
1.添加过期时间
2.限制条数
2025-12-03 17:55:21 +08:00
sh
6adda93d5d 查询岗位列表-返回附件信息 2025-12-03 16:15:15 +08:00
sh
5f76945039 修改新增岗位问题,修改上传附件问题 2025-12-03 15:35:58 +08:00
sh
d7e92d9b59 修改查看岗位详情-返回附件信息 2025-12-03 14:38:17 +08:00
sh
9080ae2e07 修改查看岗位详情-返回附件信息 2025-12-03 12:46:31 +08:00
sh
11aa1b11b1 修改测试环境地址 2025-12-03 12:03:09 +08:00
sh
9ef94da845 修改返回测试环境附件地址 2025-12-03 12:01:43 +08:00
sh
98e3c15410 修改移动端岗位发布时-文件上传 2025-12-02 17:41:45 +08:00
sh
f05d74f8cc 修改岗位发布和修改是上传附件 2025-12-02 17:02:40 +08:00
sh
ffb9803bf3 1.修改移动端技能接口
2.修改查询足迹列表
2025-12-02 13:01:09 +08:00
sh
06c7b86056 添加用户过滤技能信息 2025-12-02 12:10:20 +08:00
sh
bb53beb0ee 添加getMyTj-方法判断,身份证查询用户时,查询不到,则提示关联不起了 2025-12-02 11:41:13 +08:00
sh
c0ce6236f3 添加清洗行业父级代码-添加描述 2025-12-02 11:25:22 +08:00
sh
e5e3c8723c 添加清洗行业父级代码-添加限制 2025-12-02 11:24:25 +08:00
sh
338cb16634 添加清洗行业父级代码 2025-12-02 11:22:11 +08:00
sh
ce08f8a5f8 pc端添加足迹 2025-12-01 18:15:41 +08:00
sh
feae33489b 删除部署金蝶不需要的文件 2025-12-01 13:38:57 +08:00
sh
ffa68734bc 修改es查询岗位类别时,条件改为类比和名称 2025-12-01 12:45:36 +08:00
sh
da3307a7b7 修改不影响测试环境启动 2025-12-01 12:20:46 +08:00
sh
6c19e45f10 修改适配金蝶部署 2025-12-01 11:39:50 +08:00
sh
be44ee8c54 修改权限 2025-11-29 16:37:56 +08:00
sh
d91c4cfb1c 修改测试环境登录问题 2025-11-27 17:55:12 +08:00
sh
b21c4dbcb8 1.修改互联网单点问题
2.放开相应招聘会接口
2025-11-25 18:45:38 +08:00
sh
6e2cdba1d9 1.修改求职者生日验证及参数验证 2025-11-25 16:56:32 +08:00
sh
46c78f72a4 1.修改求职者生日验证及参数验证 2025-11-25 16:38:02 +08:00
sh
a9822c34fe 1.给浪潮添加岗位申请、录用接口 2025-11-25 14:40:43 +08:00
sh
63dc346ca0 1.添加pc端查询求职者列表
2.添加pc录用接口
2025-11-25 13:27:10 +08:00
sh
f37508674b 添加阿里云内网获取统一token类 2025-11-24 18:01:57 +08:00
sh
cdf93bdfca 限制返回50条 2025-11-24 13:05:46 +08:00
sh
dbf5f4ea7b 修改互联网登录失败问题 2025-11-21 17:59:41 +08:00
sh
85478f7378 修改查询列表的权限 2025-11-21 17:02:12 +08:00
sh
ee9af47af6 app_user添加户籍地和地址 2025-11-21 14:17:51 +08:00
sh
29fd6d715e 修改互联网单点报错问题 2025-11-21 12:58:45 +08:00
sh
48ce78f331 修改按名称查询报错的问题 2025-11-21 12:32:36 +08:00
sh
e1c15b1610 1.添加查询企业打印问题
2.修改查询app用户报错问题
2025-11-21 11:54:04 +08:00
sh
32bacfa02d 修改企业联系人和企业信息 2025-11-20 18:31:45 +08:00
sh
c348a809a5 1.修改权限问题
2.修改获取经办端token方法
2025-11-20 14:32:37 +08:00
sh
9b1983292c 修改互联网端-返回手机号,向app_user插入数据 2025-11-19 19:00:05 +08:00
sh
67aff89de2 打印获取用户信息 2025-11-18 22:58:40 +08:00
sh
97d667f267 修改问题 2025-11-18 19:29:46 +08:00
sh
8203fa5290 1.修改字典放白 2.修改给山大提供的推荐岗位接口 2025-11-18 18:43:06 +08:00
sh
02f5ee320d 修改互联网单点登录 2025-11-18 14:45:53 +08:00
sh
19270088fe 修改互联网单点登录 2025-11-18 14:45:05 +08:00
sh
306bc9cb3e 修改互联网单点登录 2025-11-18 13:16:05 +08:00
sh
95cc75de29 修改-一体机我的报错问题 2025-11-18 10:41:20 +08:00
sh
1e3823f0de 修改互联网生成的用户信息和微信小程序生成的用户信息对照 2025-11-17 18:08:26 +08:00
sh
7d488d9d12 修改互联网端用户信息和用户权限 2025-11-17 16:21:13 +08:00
sh
b86c9baadb 修改经办端-登录情况,修改用户信息和用户权限 2025-11-17 15:53:46 +08:00
sh
4150c82e89 修改互联网单点登录 2025-11-17 10:56:24 +08:00
sh
433ec1f8b0 修改互联网单点登录 2025-11-16 23:35:14 +08:00
sh
cc37ece461 添加互联网端,单点登录基础类 2025-11-16 18:32:13 +08:00
sh
2a866ce0e6 修改经办段统一门户登录 2025-11-16 11:32:36 +08:00
sh
31662c3a11 修改经办段统一门户登录 2025-11-16 11:19:37 +08:00
sh
4716127fc2 1.修改1101(求职者)、1102(招聘者)、1103(网格员)、1104(内部工作者)
2.添加门户认证的类
2025-11-15 14:04:05 +08:00
sh
6b376ad8e1 添加一体机身份证、手机号密码登录接口 2025-11-14 14:52:07 +08:00
sh
c0698040dc 修改技能和工作经历的保存 2025-11-13 16:06:04 +08:00
sh
29406eb437 修改技能和工作经历的保存 2025-11-13 16:02:29 +08:00
sh
1cf21957e1 修改技能和工作经历的保存 2025-11-13 15:49:34 +08:00
107 changed files with 4149 additions and 229 deletions

View File

@@ -3,8 +3,12 @@ package com.ruoyi.web.controller.system;
import java.util.List;
import java.util.Set;
import com.ruoyi.common.annotation.BussinessLog;
import com.ruoyi.common.core.domain.entity.tymh.wwToken.WwTokenResult;
import com.ruoyi.common.core.domain.entity.tymh.wwToken.WwUserLogin;
import com.ruoyi.common.core.domain.model.RegisterBody;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.OauthLoginHlwService;
import com.ruoyi.framework.web.service.OauthLoginService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -18,6 +22,7 @@ import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.system.service.ISysMenuService;
/**
* 登录验证
*
@@ -34,6 +39,10 @@ public class SysLoginController
@Autowired
private SysPermissionService permissionService;
@Autowired
private OauthLoginService oauthLoginService;
@Autowired
private OauthLoginHlwService oauthLoginHlwService;
/**
* 登录方法
@@ -61,11 +70,55 @@ public class SysLoginController
return ajax;
}
/**
* 微信小程序登录
* @param loginBody
* @return
*/
@PostMapping("/app/appLogin")
public AjaxResult appLogin(@RequestBody LoginBody loginBody)
{
AjaxResult ajax = AjaxResult.success();
ajax=loginService.appLogin(loginBody);
//ajax=loginService.appLogin(loginBody);
ajax=loginService.appLoginNew(loginBody);
return ajax;
}
/**
* 一体机身份证登录
* @param loginBody
* @return
*/
@PostMapping("/app/idCardLogin")
public AjaxResult idCardLogin(@RequestBody LoginBody loginBody)
{
if(loginBody==null||StringUtils.isBlank(loginBody.getIdCard())){
return AjaxResult.error("请输入有效的身份证号!");
}
AjaxResult ajax = AjaxResult.success();
ajax=loginService.idCardLogin(loginBody);
return ajax;
}
/**
* 一体机手机号/密码登录
* @param loginBody
* @return
*/
@PostMapping("/app/phoneLogin")
public AjaxResult phoneLogin(@RequestBody LoginBody loginBody)
{
if(loginBody == null){
return AjaxResult.error("登录参数不能为空!");
}
if(StringUtils.isBlank(loginBody.getUsername())){
return AjaxResult.error("用户名为空,请输入用户名!");
}
if(StringUtils.isBlank(loginBody.getPassword())){
return AjaxResult.error("密码为空,请输入密码!");
}
AjaxResult ajax = AjaxResult.success();
ajax=loginService.phoneLogin(loginBody);
return ajax;
}
@@ -123,4 +176,55 @@ public class SysLoginController
String token=loginService.registerAppUser(registerBody);
return AjaxResult.success().put("token",token);
}
/**
* 获取统一门户token
*/
@GetMapping("/getTjmhToken")
public AjaxResult getTjmhToken(@RequestParam("code") String code){
System.out.println("参数code==========================="+code);
if(StringUtils.isBlank(code)){
return AjaxResult.error("参数code为空请传递code参数");
}
String token = oauthLoginService.oauthLogin(code);
return AjaxResult.success("门户登录成功")
.put("token", token)
.put("accessUrl", "");
}
/**
*互联网获取token
* @param wwUserLogin
* @return
*/
@GetMapping("/getWwTjmhToken")
public AjaxResult getWwTjmhToken(@RequestBody WwUserLogin wwUserLogin){
if(wwUserLogin==null){
return AjaxResult.error("参数wwUserLogin为空请传递wwUserLogin实体参数");
}
String token = oauthLoginHlwService.getWwTjmhToken(wwUserLogin);
return AjaxResult.success("门户登录成功")
.put("token", token)
.put("accessUrl", "");
}
/**
*互联网获取token
* @return
*/
@GetMapping("/getWwTjmHlwToken")
public AjaxResult getWwTjmHlwToken(@RequestParam("token") String token){
System.out.println("互联网token================================"+token);
if (StringUtils.isNotBlank(token)) {
WwTokenResult wwTokenResult=new WwTokenResult();
wwTokenResult.setAccessToken(token);
String localToken = oauthLoginHlwService.getWwTjmHlwToken(wwTokenResult);
return AjaxResult.success("门户登录成功")
.put("token", localToken)
.put("accessUrl", "");
} else {
return AjaxResult.error("token为空!");
}
}
}

View File

@@ -283,7 +283,7 @@ public class SysUserController extends BaseController
}
sysUser.setPhonenumber(getUsername());
Long[] postIds = {1L};
Long[] roleIds = {100L};
Long[] roleIds = {1102L};
sysUser.setPostIds(postIds);
sysUser.setRoleIds(roleIds);
userService.insertUser(sysUser);

View File

@@ -147,10 +147,40 @@ wx:
#统一门户认证
oauth:
appid: aa
clientsecretkey: bb
getToken: http://ip:80/serviceAPI/getToken
getUserInfo: http://ip:80/serviceAPI/getUserInfo
#客户端的ID
appid: 251112100000000015
#授权码
clientsecretkey: 2a44cb8d21dcf4b0777881ca11ea0d83ebea94bbe1ab1f405508db0873cdcc99
#内网
usptnw:
#获取访问令牌
nwGatewayGetTokenUrl: http://10.98.80.146/uspt/serviceAPI/getToken
#获取用户信息
nwGatewayGetUserInfoUrl: http://10.98.80.146/uspt/serviceAPI/getUserInfo
#外网
usptww:
#门户注册
wwRegisterPostUrl: http://10.98.80.50/uspt/webWhiteListServiceAPI/doWebRegister
#门户登录
wwTokenPostUrl: http://10.98.80.50/uspt/webWhiteListServiceAPI/doWebLogon
#查询用户信息
wwQueryWebUserInfo: http://10.98.80.50/uspt/webWhiteListServiceAPI/queryWebUserInfo
#查询个人信息
wwQueryWebPersonalInfoPostUrl: http://10.98.80.50/uspt/webWhiteListServiceAPI/queryWebPersonalInfo
#查询单位信息
wwQueryWebEnterpriseInfoPostUrl: http://10.98.80.50/uspt//webWhiteListServiceAPI/queryWebEnterpriseInfo
#用户新增接口
tyAddUserUrl: http://10.98.80.146/qxgl_backend/security/add_user
#获取当前用户有权系统列表
tyQueryUserSysListUrl: http://10.98.80.146/qxgl_backend/security/get_effective_app_list
#获取当前用户有权角色列表
tyQueryUserRoleListUrl: http://10.98.80.146/qxgl_backend/security/get_role_by_userid
#获取角色功能权限信息
tyQueryRoleInfoUrl: http://10.98.80.146/qxgl_backend/security/get_path_by_role
#获取用户详细信息
tyQueryUserInfo: http://10.98.80.146/qxgl_backend/security/get_user_by_userid
#获取机构详细信息
tyQueryUnitInfo: http://10.98.80.146/qxgl_backend/security/get_organization_by_organizationid
connect-timeout: 10
read-timeout: 30
write-timeout: 30

View File

@@ -111,6 +111,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--localDate-->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,15 +1,20 @@
package com.ruoyi.cms.controller.app;
import com.ruoyi.cms.util.IdGenerator;
import com.ruoyi.cms.util.ProxyServerUtil;
import com.ruoyi.common.core.domain.entity.File;
import com.ruoyi.cms.service.IFileService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.SiteSecurityUtils;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@RestController
@@ -17,10 +22,16 @@ import java.util.List;
public class AppFileController extends BaseController {
@Autowired
private IFileService fileService;
@Autowired
private IdGenerator idGenerator;
@ApiOperation("上传文件")
@PostMapping("/upload")
public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, @RequestParam(value = "bussinessid",required = false) Long bussinessId) {
return fileService.uploadFile(file,bussinessId);
public AjaxResult upload(@RequestParam("file") MultipartFile file, @RequestParam(value = "bussinessid",required = false) Long bussinessId) {
if(!(SiteSecurityUtils.isLogin() || SecurityUtils.isLogin())){
return AjaxResult.error("未登录,请登录后在上传文件!");
}
return fileService.upload(file,bussinessId);
}
@ApiOperation("获取附件列表")
@@ -30,4 +41,25 @@ public class AppFileController extends BaseController {
List<File> results = fileService.selectFileList(file);
return getDataTable(results);
}
@ApiOperation("删除附件")
@DeleteMapping("/{id}")
public AjaxResult remove(@PathVariable Long id)
{
return toAjax(fileService.deleteFileByIds(new Long[]{id}));
}
@ApiOperation("上传文件")
@PostMapping("/uploadFile")
public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, @RequestParam(value = "bussinessid",required = false) Long bussinessId, HttpServletRequest request) {
String proxyServer = ProxyServerUtil.getProxyServer(request);
System.out.println("获取服务器地址======================"+proxyServer);
if(!(SiteSecurityUtils.isLogin() || SecurityUtils.isLogin())){
return AjaxResult.error("未登录,请登录后在上传文件!");
}
if(bussinessId==null){
bussinessId=idGenerator.generateId();
}
return fileService.uploadFile(file,bussinessId,request);
}
}

View File

@@ -21,6 +21,7 @@ import org.dromara.easyes.core.biz.EsPageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
@@ -148,9 +149,13 @@ public class AppJobController extends BaseController
*/
@ApiOperation("获取岗位详细信息")
@GetMapping(value = "/{jobId}")
public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
public AjaxResult getInfo(@PathVariable("jobId") Long jobId, HttpServletRequest request)
{
Job job = jobService.selectJobByJobIdApp(jobId);
if (jobId == null) {
return AjaxResult.error("jobId不能为空");
}
//Job job = jobService.selectJobByJobIdApp(jobId);
Job job = jobService.selectHttpJobByJobIdApp(jobId,request);
return success(job);
}

View File

@@ -6,6 +6,8 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.AppSkill;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.SiteSecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@@ -57,6 +59,15 @@ public class AppSkillController extends BaseController {
@ApiOperation("新增技能信息")
@PostMapping("/add")
public AjaxResult save(@RequestBody AppSkill appSkill){
if(StringUtils.isEmpty(appSkill.getName())){
return AjaxResult.error("技能名称为空!");
}
if(StringUtils.isEmpty(appSkill.getLevels())){
return AjaxResult.error("技能等级为空!");
}
if(appSkill.getUserId()==null){
appSkill.setUserId(SiteSecurityUtils.getUserId());
}
return toAjax(appSkillService.insertAppskill(appSkill));
}
@@ -66,6 +77,18 @@ public class AppSkillController extends BaseController {
@ApiOperation("修改技能详细信息")
@PutMapping("/edit")
public AjaxResult update(@RequestBody AppSkill appSkill){
if(appSkill.getId()==null){
return AjaxResult.error("技能id为空!");
}
if(StringUtils.isEmpty(appSkill.getName())){
return AjaxResult.error("技能名称为空!");
}
if(StringUtils.isEmpty(appSkill.getLevels())){
return AjaxResult.error("技能等级为空!");
}
if(appSkill.getUserId()==null){
appSkill.setUserId(SiteSecurityUtils.getUserId());
}
return toAjax(appSkillService.updateAppskillById(appSkill));
}
@@ -75,6 +98,9 @@ public class AppSkillController extends BaseController {
@ApiOperation("删除技能详细信息")
@DeleteMapping("/{id}")
public AjaxResult delete(@ApiParam("主键id") @PathVariable Long id){
if(id==null){
return AjaxResult.error("参数id未传递!");
}
return toAjax(appSkillService.removeAppskillIds(new Long[]{id}));
}

View File

@@ -2,6 +2,7 @@ package com.ruoyi.cms.controller.app;
import com.alibaba.nls.client.AccessToken;
import com.ruoyi.cms.handler.SpeechRecognizerAI;
import com.ruoyi.cms.util.AliyunNlsUtils;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import io.swagger.annotations.Api;
@@ -24,14 +25,14 @@ public class AppSpeechController extends BaseController
private String appKey = "4lFYn2yPsQymwGu8";
private String id = "LTAI5t9hhSqdDHqwH3RjgyYj";
private String secret = "ni5aW3vxrWouMwcGqJPfh9Uu56PBuv";
private String url = System.getenv().getOrDefault("NLS_GATEWAY_URL", "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1");
private String url = System.getenv().getOrDefault("NLS_GATEWAY_URL", AliyunNlsUtils.getNlsUrl()+"/ws/v1/");
@ApiOperation("统计")
@GetMapping("/getToken")
public AjaxResult getToken()
{
SpeechRecognizerAI recognizerDemo = new SpeechRecognizerAI(appKey, id, secret, url);
AccessToken accessToken = recognizerDemo.getAccessToken();
String token = "wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1?appkey="+appKey+"&token="+accessToken.getToken();
String token = AliyunNlsUtils.getNlsUrl()+"/ws/v1/?appkey="+appKey+"&token="+accessToken.getToken();
return AjaxResult.success(token);
}
}

View File

@@ -3,6 +3,7 @@ package com.ruoyi.cms.controller.cms;
import com.ruoyi.cms.domain.BussinessDictData;
import com.ruoyi.cms.service.IBussinessDictDataService;
import com.ruoyi.cms.service.IBussinessDictTypeService;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
@@ -29,6 +30,7 @@ import java.util.List;
*/
@RestController
@RequestMapping("/cms/dict/data")
@Anonymous
public class BussinessDictDataController extends BaseController
{
@Autowired

View File

@@ -1,12 +1,21 @@
package com.ruoyi.cms.controller.cms;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.cms.domain.AppReviewJob;
import com.ruoyi.cms.domain.vo.AppUserLky;
import com.ruoyi.cms.service.IAppReviewJobService;
import com.ruoyi.cms.util.DateValidateUtil;
import com.ruoyi.cms.util.RoleUtils;
import com.ruoyi.common.annotation.BussinessLog;
import com.ruoyi.common.core.domain.entity.AppUserShow;
import com.ruoyi.common.core.domain.model.RegisterBody;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.SiteSecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
@@ -42,12 +51,14 @@ public class CmsAppUserController extends BaseController
{
@Autowired
private IAppUserService appUserService;
@Autowired
private IAppReviewJobService appReviewJobService;
/**
* 查询APP用户列表
*/
@ApiOperation("查询APP用户列表")
// @PreAuthorize("@ss.hasPermi('cms:appUser:list')")
@PreAuthorize("@ss.hasPermi('cms:appUser:list')")
@GetMapping("/list")
public TableDataInfo list(AppUser appUser)
{
@@ -169,6 +180,88 @@ public class CmsAppUserController extends BaseController
return AjaxResult.error("用户信息为空!");
}
AppUser appUser=appUserService.selectAppuserByIdcard(RoleUtils.getCurrentUseridCard());
if (Objects.isNull(appUser)) {
return AjaxResult.error("未查询到用户信息(身份证号:" + RoleUtils.getCurrentUseridCard() + "!");
}
return AjaxResult.success(appUserService.getMyTj(appUser.getUserId()));
}
@ApiOperation("返回求职者劳科院-当前职位名称、技能标签")
@GetMapping("/appUserInfo")
public AjaxResult appUserInfo(AppUser appUser)
{
if(!SecurityUtils.isLogin()){
return AjaxResult.error("未登录!");
}
if(StringUtils.isEmpty(RoleUtils.getCurrentUseridCard())){
return AjaxResult.error("用户信息为空!");
}
appUser=appUserService.selectAppuserByIdcard(RoleUtils.getCurrentUseridCard());
if (Objects.isNull(appUser)) {
return AjaxResult.error("未查询到用户信息(身份证号:" + RoleUtils.getCurrentUseridCard() + "!");
}
AppUserLky appUserLky = appUserService.selectAppUserInfo(appUser);
return AjaxResult.success(appUserLky);
}
@ApiOperation("查询APP申请用户列表")
//@PreAuthorize("@ss.hasPermi('cms:appUser:userApplyList')")
@GetMapping("/userApplyList")
public TableDataInfo userApplyList(AppUser appUser)
{
String birthDateError = DateValidateUtil.validateBirthDate(appUser.getBirthDate());
if (birthDateError != null) {
TableDataInfo errorResult = new TableDataInfo();
errorResult.setCode(400);
errorResult.setMsg(birthDateError);
errorResult.setRows(null);
errorResult.setTotal(0);
return errorResult;
}
startPage();
List<AppUserShow> list = appUserService.selectUserApplyList(appUser);
return getDataTable(list);
}
/**
* 添加足迹信息
* @param appReviewJob
* @return
*/
@PostMapping("/browse")
@ApiOperation("用户浏览")
public AjaxResult browse(@RequestBody AppReviewJob appReviewJob)
{
if (Objects.isNull(appReviewJob) || Objects.isNull(appReviewJob.getJobId())) {
return AjaxResult.error("岗位id为空");
}
if (!SecurityUtils.isLogin()) {
return AjaxResult.error("用户未登录!");
}
Long frontUserId = appReviewJob.getUserId();
String useridCard = RoleUtils.getCurrentUseridCard();
Long targetUserId;
if (Objects.nonNull(frontUserId)) {
targetUserId = frontUserId;
} else {
if (StringUtils.isEmpty(useridCard)) {
return AjaxResult.error("用户身份证信息为空无法获取用户ID!");
}
AppUser appUser = appUserService.selectAppuserByIdcard(useridCard);
if (Objects.isNull(appUser)) {
return AjaxResult.error("未查询到用户信息(身份证号:" + useridCard + "!");
}
targetUserId = appUser.getUserId();
}
appReviewJob.setUserId(targetUserId);
if(StringUtils.isEmpty(appReviewJob.getReviewDate())){
appReviewJob.setReviewDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,new Date()));
}
return toAjax(appReviewJobService.insertAppReviewJob(appReviewJob));
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
@@ -66,14 +67,15 @@ public class CmsJobController extends BaseController
@ApiOperation("查询岗位列表")
// @PreAuthorize("@ss.hasPermi('cms:job:list')")
@GetMapping("/list")
public TableDataInfo list(Job job)
public TableDataInfo list(Job job,HttpServletRequest request)
{
if (RoleUtils.isCompanyAdmin()) {
Company company = companyService.queryCodeCompany(RoleUtils.getCurrentUseridCard());
job.setCompanyId(Objects.nonNull(company) ? company.getCompanyId() : null);
}
startPage();
List<Job> list = jobService.selectJobList(job);
//List<Job> list = jobService.selectJobList(job);
List<Job> list = jobService.selectHttpJobList(job,request);
return getDataTable(list);
}
@@ -83,9 +85,13 @@ public class CmsJobController extends BaseController
@ApiOperation("获取岗位详细信息")
// @PreAuthorize("@ss.hasPermi('bussiness:job:query')")
@GetMapping(value = "/{jobId}")
public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
public AjaxResult getInfo(@PathVariable("jobId") Long jobId, HttpServletRequest request)
{
return success(jobService.selectJobByJobId(jobId));
if (jobId == null) {
return AjaxResult.error("jobId不能为空");
}
//return success(jobService.selectJobByJobId(jobId));
return success(jobService.selectHttpJobByJobId(jobId,request));
}
/**
@@ -314,4 +320,38 @@ public class CmsJobController extends BaseController
}
return toAjax(iAppReviewJobService.insertAppReviewJob(appReviewJob));
}
@ApiOperation("获取推荐岗位-给数据底座的")
@GetMapping("/recommendTosjdz")
public AjaxResult recommendTosjdz(ESJobSearch esJobSearch)
{
if (RoleUtils.isCompanyAdmin()) {
esJobSearch.setCode(RoleUtils.getCurrentUseridCard());
esJobSearch.setUserType(StringUtil.IS_COMPANY_USER);
}
esJobSearch.setPageSize(20);
List<ESJobDocument> jobList = jobService.sysRecommend(esJobSearch);
jobList.stream().forEach(it->{
it.setAppJobUrl(StringUtil.BASE_WW_GW+it.getJobId());
});
return success(jobList);
}
@PostMapping("/wechat")
@ApiOperation("微信抓取功能调用的新增")
public AjaxResult wechatInsert(@RequestBody Job job) {
// 不发布
job.setIsPublish(0);
if (job.getJobContactList() == null) {
job.setJobContactList(new ArrayList<>());
}
Integer total=jobService.getTotals(job);
int totalNum = total != null ? total : 0;
System.out.println("岗位条数======================"+totalNum);
if (totalNum == 0) {
return toAjax(jobService.insertJob(job));
}
return AjaxResult.success("此岗位已存在!");
}
}

View File

@@ -187,7 +187,7 @@ public class CmsNoticeController extends BaseController
@GetMapping("/noticTotal")
public AjaxResult getNoticTotal(Notice notice){
if(!SecurityUtils.isLogin()){
error(HttpStatus.ERROR,"未登录!");
return AjaxResult.success("未登录!,返回为空");
}
if(notice.getUserId()==null){
String idCard= RoleUtils.getCurrentUseridCard();

View File

@@ -65,12 +65,14 @@ public class CmsSkillController extends BaseController {
@Log(title = "技能", businessType = BusinessType.INSERT)
@PostMapping("/add")
public AjaxResult save(@RequestBody AppSkill appSkill){
if(!SecurityUtils.isLogin()){
if(SecurityUtils.isLogin()){
AppUser appUser=appUserService.selectAppuserByIdcard(RoleUtils.getCurrentUseridCard());
if(appUser==null){
return AjaxResult.error("未传递userId!");
}
appSkill.setUserId(appUser.getUserId());
}else {
return AjaxResult.error("未登录!");
}
return toAjax(appSkillService.insertAppskill(appSkill));
}

View File

@@ -0,0 +1,54 @@
package com.ruoyi.cms.controller.cms;
import com.ruoyi.cms.domain.CommunityUser;
import com.ruoyi.cms.service.ICommunityUserService;
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 java.util.List;
@RestController
@RequestMapping("/cms/communityUser")
@Api(tags = "后台:工作人员管理")
public class CommunityUserController extends BaseController {
@Autowired
private ICommunityUserService communityUserService;
@ApiOperation("查询工作人员列表")
@PreAuthorize("@ss.hasPermi('application:mgmt:list')")
@GetMapping("/list")
public TableDataInfo list(CommunityUser communityUser) {
startPage();
List<CommunityUser> list = communityUserService.selectCommunityUserList(communityUser);
return getDataTable(list);
}
@ApiOperation("新增工作人员")
@PreAuthorize("@ss.hasPermi('application:mgmt:add')")
@PostMapping
public AjaxResult add(@RequestBody CommunityUser communityUser) {
return toAjax(communityUserService.save(communityUser));
}
@ApiOperation("修改工作人员")
@PreAuthorize("@ss.hasPermi('application:mgmt:edit')")
@PutMapping
public AjaxResult update(@RequestBody CommunityUser communityUser) {
return toAjax(communityUserService.updateById(communityUser));
}
@ApiOperation("删除工作人员")
@PreAuthorize("@ss.hasPermi('application:mgmt:del')")
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable("ids") Long[] ids) {
return toAjax(communityUserService.delCommunityUser(ids));
}
}

View File

@@ -42,6 +42,7 @@ public class CompanyController extends BaseController
public TableDataInfo list(Company company)
{
if (RoleUtils.isCompanyAdmin()) {
System.out.println("企业社会信用代码============================="+RoleUtils.getCurrentUseridCard());
company.setCode(RoleUtils.getCurrentUseridCard());
}
startPage();

View File

@@ -6,6 +6,7 @@ import com.ruoyi.common.core.domain.entity.Industry;
import com.ruoyi.common.utils.poi.ExcelUtil;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
@@ -52,7 +53,7 @@ public class IndustryController extends BaseController
return getDataTable(list);
}
@ApiOperation("行业树结构")
@PreAuthorize("@ss.hasPermi('cms:industry:list')")
// @PreAuthorize("@ss.hasPermi('cms:industry:list')")
@GetMapping("/treeselect")
public AjaxResult treeselect(Industry industry)
{
@@ -131,4 +132,115 @@ public class IndustryController extends BaseController
return success();
}
/**
* 修改行业父级代码
* select * from industry where length(remark)=1 order by order_num;
* select * from industry where length(remark)=3 and remark like 'A%' order by order_num;
* select * from industry where length(remark)=4 and remark like 'A01%' order by order_num;
* select * from industry where length(remark)=5 and remark like 'A011%' order by order_num;
*/
@PostMapping("/updateParentHierarchy")
@Transactional(rollbackFor = Exception.class)
public void updateParentHierarchy() {
// 第一层所有1位长度的大类orderNum=1 → LENGTH(remark)=1无前缀过滤包含20个大类
Industry queryLevel1 = new Industry();
queryLevel1.setOrderNum(1L); // 对应 SQLLENGTH(remark)=1
List<Industry> level1List = industryService.selectIndustryList(queryLevel1);
if (level1List.isEmpty()) {
throw new RuntimeException("未查询到1位长度的大类数据");
}
System.out.println("共查询到 " + level1List.size() + " 个1位大类开始更新层级关系...");
// 遍历每个1位大类处理其下的3位子级
for (Industry level1 : level1List) {
Long level1Id = level1.getIndustryId();
String level1Remark = level1.getRemark();
// 跳过无效数据ID或remark为空
if (level1Id == null || level1Remark == null) {
System.out.println("跳过无效大类ID=" + level1Id + "remark=" + level1Remark);
continue;
}
System.out.println("处理大类remark=" + level1Remark + "ID=" + level1Id);
// 第二层3位长度orderNum=3 + 前缀=当前大类remark比如" B"→"B%"
Industry queryLevel2 = new Industry();
queryLevel2.setOrderNum(3L); // LENGTH(remark)=3
queryLevel2.setRemark(level1Remark); // remark like 'B%'(自动匹配当前大类前缀)
List<Industry> level2List = industryService.selectIndustryList(queryLevel2);
if (level2List.isEmpty()) {
System.out.println("大类 " + level1Remark + " 无3位子级跳过");
continue;
}
// 遍历3位子级处理其下的4位孙级
for (Industry level2 : level2List) {
Long level2Id = level2.getIndustryId();
String level2Remark = level2.getRemark();
if (level2Id == null || level2Remark == null) {
continue;
}
// 第三层4位长度orderNum=4 + 前缀=当前3位子级remark比如"B02"→"B02%"
Industry queryLevel3 = new Industry();
queryLevel3.setOrderNum(4L); // LENGTH(remark)=4
queryLevel3.setRemark(level2Remark); // remark like 'B02%'
List<Industry> level3List = industryService.selectIndustryList(queryLevel3);
if (level3List.isEmpty()) {
// 无4位孙级直接更新3位子级的父ID=1位大类ID
updateParentId(level2Id, level1Id);
continue;
}
// 遍历4位孙级处理其下的5位曾孙级
for (Industry level3 : level3List) {
Long level3Id = level3.getIndustryId();
String level3Remark = level3.getRemark();
if (level3Id == null || level3Remark == null) {
continue;
}
// 第四层5位长度orderNum=5 + 前缀=当前4位孙级remark比如"B021"→"B021%"
Industry queryLevel4 = new Industry();
queryLevel4.setOrderNum(5L); // LENGTH(remark)=5
queryLevel4.setRemark(level3Remark); // remark like 'B021%'
List<Industry> level4List = industryService.selectIndustryList(queryLevel4);
// 更新5位曾孙级的父ID=4位孙级ID
for (Industry level4 : level4List) {
if (level4.getIndustryId() != null && level4.getRemark() != null) {
updateParentId(level4.getIndustryId(), level3Id);
System.out.println("更新5位数据" + level4.getRemark() + " → 父ID=" + level3Id);
}
}
// 更新4位孙级的父ID=3位子级ID
updateParentId(level3Id, level2Id);
System.out.println("更新4位数据" + level3Remark + " → 父ID=" + level2Id);
}
// 更新3位子级的父ID=1位大类ID
updateParentId(level2Id, level1Id);
System.out.println("更新3位数据" + level2Remark + " → 父ID=" + level1Id);
}
}
System.out.println("层级关系更新完成!");
}
/**
* 修改行业父级代码
* @param targetIndustryId
* @param parentId
*/
private void updateParentId(Long targetIndustryId, Long parentId) {
Industry updateIndustry = new Industry();
updateIndustry.setIndustryId(targetIndustryId);
updateIndustry.setParentId(parentId);
industryService.updateIndustry(updateIndustry);
}
}

View File

@@ -1,11 +1,13 @@
package com.ruoyi.cms.controller.cms;
import com.alibaba.excel.util.StringUtils;
import com.ruoyi.cms.domain.Job;
import com.ruoyi.cms.domain.JobApply;
import com.ruoyi.cms.domain.vo.CandidateVO;
import com.ruoyi.cms.service.IAppUserService;
import com.ruoyi.cms.service.IJobApplyService;
import com.ruoyi.cms.util.RoleUtils;
import com.ruoyi.cms.util.StringUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
@@ -92,4 +94,72 @@ public class JobApplyController extends BaseController {
}
return success(iJobApplyService.applyComJob(jobApply));
}
@Log(title = "岗位", businessType = BusinessType.UPDATE)
@ApiOperation("求职者管理-用户列表录用")
@PutMapping("/applyAgree")
public AjaxResult applyAgree(@RequestBody JobApply jobApply)
{
if(jobApply.getId()==null){
return AjaxResult.error("参数id为空");
}
jobApply.setHire(StringUtil.HIRE_LY);
jobApply.setHireSource(StringUtil.HIRE_SOURCE_SYSTEM);
return success(iJobApplyService.updateJobApply(jobApply));
}
@Log(title = "岗位", businessType = BusinessType.INSERT)
@ApiOperation("招聘会-岗位申请")
@PostMapping("/zphApply")
public AjaxResult zphApply(@RequestBody JobApply jobApply)
{
if(jobApply.getJobId()==null){
return AjaxResult.error("岗位id为空");
}
String idCard = jobApply.getIdCard();
if(StringUtils.isBlank(idCard)){
return AjaxResult.error("身份证为空!");
}
if (!idCard.matches(StringUtil.SFZ_VALID_REGEX)) {
return AjaxResult.error("身份证格式不正确");
}
AppUser appUser=appUserService.selectAppuserByIdcard(idCard);
if(appUser==null){
return AjaxResult.error("在系统库中未查询到当前用户信息!");
}
jobApply.setUserId(appUser.getUserId());
JobApply parm=new JobApply();
parm.setJobId(jobApply.getJobId());
parm.setUserId(appUser.getUserId());
List<JobApply> applies=iJobApplyService.selectJobApplyList(parm);
if(applies!=null&&applies.size()>0){
return AjaxResult.error("当前用户,已申请过该岗位,请勿重复申请!");
}
return success(iJobApplyService.applyComJob(jobApply));
}
@Log(title = "岗位", businessType = BusinessType.INSERT)
@ApiOperation("招聘会-岗位录用")
@PostMapping("/zphApplyAgree")
public AjaxResult zphApplyAgree(@RequestBody JobApply jobApply)
{
if(jobApply.getJobId()==null){
return AjaxResult.error("岗位id为空");
}
String idCard = jobApply.getIdCard();
if(StringUtils.isBlank(idCard)){
return AjaxResult.error("身份证为空!");
}
if (!idCard.matches(StringUtil.SFZ_VALID_REGEX)) {
return AjaxResult.error("身份证格式不正确");
}
AppUser appUser=appUserService.selectAppuserByIdcard(idCard);
if(appUser==null){
return AjaxResult.error("在系统库中未查询到当前用户信息!");
}
jobApply.setUserId(appUser.getUserId());
jobApply.setHire(StringUtil.HIRE_LY);
jobApply.setHireSource(StringUtil.HIRE_SOURCE_ZPH);
return success(iJobApplyService.updateJobZphApply(jobApply));
}
}

View File

@@ -37,7 +37,7 @@ public class JobFairController extends BaseController
* 查询招聘会信息列表
*/
@ApiOperation("查询招聘会信息列表")
@PreAuthorize("@ss.hasPermi('app:fair:list')")
@PreAuthorize("@ss.hasPermi('jobfair:list:list')")
@GetMapping("/list")
public TableDataInfo list(JobFair jobFair)
{

View File

@@ -40,7 +40,7 @@ public class UserWorkExperiencesController extends BaseController {
* 列表
*/
@ApiOperation("工作经历列表信息")
@PreAuthorize("@ss.hasPermi('cms:userworkexperiences:list')")
@PreAuthorize("@ss.hasPermi('management:match:details')")
@GetMapping("/list")
public TableDataInfo list(UserWorkExperiences userWorkExperiences){
startPage();
@@ -56,7 +56,7 @@ public class UserWorkExperiencesController extends BaseController {
* 获取详细信息
*/
@ApiOperation("获取工作经历详细信息")
@PreAuthorize("@ss.hasPermi('cms:userworkexperiences:query')")
@PreAuthorize("@ss.hasPermi('management:match:query')")
@GetMapping(value = "/{id}")
public AjaxResult query(@PathVariable("id") Long id){
return success(userWorkExperiencesService.getWorkExperiencesById(id));

View File

@@ -0,0 +1,68 @@
package com.ruoyi.cms.controller.cms;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.cms.domain.WechatGroup;
import com.ruoyi.cms.domain.vo.WechatGroupVo;
import com.ruoyi.cms.service.IWechatGroupService;
import com.ruoyi.common.annotation.Anonymous;
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 java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/cms/wechatGroup")
@Api(tags = "后台:转发对象管理")
public class WechatGroupController extends BaseController {
@Autowired
private IWechatGroupService wechatGroupService;
@ApiOperation("查询转发对象列表")
@PreAuthorize("@ss.hasPermi('application:group:list')")
@GetMapping("/list")
public TableDataInfo list(WechatGroup wechatGroup) {
startPage();
List<WechatGroupVo> list = wechatGroupService.selectWechatGroupList(wechatGroup);
return getDataTable(list);
}
@ApiOperation("新增转发对象")
@PreAuthorize("@ss.hasPermi('application:group:add')")
@PostMapping
public AjaxResult add(@RequestBody WechatGroup wechatGroup) {
return toAjax(wechatGroupService.save(wechatGroup));
}
@ApiOperation("修改转发对象")
@PreAuthorize("@ss.hasPermi('application:group:update')")
@PutMapping
public AjaxResult update(@RequestBody WechatGroup wechatGroup) {
return toAjax(wechatGroupService.updateById(wechatGroup));
}
@ApiOperation("删除转发对象")
@PreAuthorize("@ss.hasPermi('application:group:del')")
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable("ids") Long[] ids) {
return toAjax(wechatGroupService.removeBatchByIds(CollUtil.newArrayList(ids)));
}
@GetMapping("/enableList")
@Anonymous
public List<WechatGroupVo> enableList() {
WechatGroup wechatGroup = new WechatGroup();
wechatGroup.setIsPush(1);
return wechatGroupService.selectWechatGroupList(wechatGroup)
.stream().peek(e->e.setPhoneNumber(""))
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,33 @@
package com.ruoyi.cms.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 工作人员配置
*/
@TableName("community_user")
@EqualsAndHashCode(callSuper = true)
@Data
public class CommunityUser extends BaseEntity {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 微信名
*/
private String wechatName;
/**
* 手机号
*/
private String phoneNumber;
}

View File

@@ -54,7 +54,7 @@ public class ESJobDocument
@ApiModelProperty("用人单位名称")
private String companyName;
@ApiModelProperty("工作地点")
@ApiModelProperty("岗位区划")
private String jobLocation;
@ApiModelProperty("工作地点区县字典代码")
@@ -150,6 +150,9 @@ public class ESJobDocument
@ApiModelProperty("信用代码")
private String code;
@ApiModelProperty("工作地点")
private String jobAddress;
@ApiModelProperty("公司信息")
@IndexField(fieldType = FieldType.TEXT)
private String companyVoJson;

View File

@@ -9,6 +9,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ruoyi.cms.domain.vo.CompanyVo;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.core.domain.entity.Company;
import com.ruoyi.common.core.domain.entity.File;
import io.swagger.annotations.ApiModel;
@@ -59,8 +60,8 @@ public class Job extends BaseEntity
@ApiModelProperty("用人单位名称")
private String companyName;
@Excel(name = "工作地点")
@ApiModelProperty("工作地点")
@Excel(name = "岗位区划")
@ApiModelProperty("岗位区划")
private String jobLocation;
@ApiModelProperty("工作地点区县字典代码")
@@ -168,6 +169,9 @@ public class Job extends BaseEntity
@ApiModelProperty("类型 0常规岗位 1就业见习岗位 2实习实训岗位 3社区实践岗位 4零工 对应字段字典position_type")
private String type;
@ApiModelProperty("工作地点")
private String jobAddress;
@TableField(exist = false)
@ApiModelProperty("岗位联系人列表")
private List<JobContact> jobContactList;
@@ -184,4 +188,8 @@ public class Job extends BaseEntity
@JsonFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty("时间(足迹、投简历、收藏)")
private String shareTime;
@TableField(exist = false)
@ApiModelProperty("申请人列表")
private List<AppUser> applyUsers;
}

View File

@@ -40,4 +40,11 @@ public class JobApply extends BaseEntity
@ApiModelProperty("是否录用 0录用 2或null未录用")
private String hire;
@ApiModelProperty("录用来源 0本系统 1招聘会")
private String hireSource;
@TableField(exist = false)
@ApiModelProperty("身份证,招聘传递")
private String idCard;
}

View File

@@ -79,5 +79,5 @@ public class JobFair extends BaseEntity
@TableField(exist = false)
@ApiModelProperty("是否收藏")
public Integer isCollection;
private Integer isCollection;
}

View File

@@ -0,0 +1,39 @@
package com.ruoyi.cms.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 转发对象配置
*/
@TableName("wechat_group")
@EqualsAndHashCode(callSuper = true)
@Data
public class WechatGroup extends BaseEntity {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 群聊名称
*/
private String name;
/**
* 工作人员 ID
*/
private Long communityId;
/**
* 是否启用 0=禁用 1=启用
*/
private Integer isPush;
}

View File

@@ -0,0 +1,20 @@
package com.ruoyi.cms.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class WechatGroupVo {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private Long id;
private String name;
private Integer isPush;
private String wechatNumber;
private String phoneNumber;
private String wechatName;
private Long communityId;
}

View File

@@ -0,0 +1,138 @@
package com.ruoyi.cms.handler;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AliyunNlsTokenUtil {
private static final Logger logger = LoggerFactory.getLogger(AliyunNlsTokenUtil.class);
// Nginx 代理配置(与 Nginx 一致)
private static final String PROXY_HOST = "192.168.2.102";
private static final int PROXY_PORT = 10044;
// Token 接口代理地址(通过 Nginx 转发)
private static final String TOKEN_PROXY_URL = "http://" + PROXY_HOST + ":" + PROXY_PORT + "/";
// 单例 OkHttp 客户端(带代理,全局复用)
private static OkHttpClient proxyOkHttpClient;
static {
// 初始化带代理的 OkHttp 客户端(仅初始化一次)
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_HOST, PROXY_PORT));
proxyOkHttpClient = new OkHttpClient.Builder()
.proxy(proxy)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
}
/**
* 手动生成 Token绕开 SDK 无代理逻辑)
* @param accessKeyId 阿里云 AccessKeyId
* @param accessKeySecret 阿里云 AccessKeySecret
* @param accessToken SDK 的 AccessToken 对象(用于设置 token 和 expireTime
*/
public static void generateToken(String accessKeyId, String accessKeySecret, com.alibaba.nls.client.AccessToken accessToken) throws Exception {
// 1. 生成阿里云 API 签名HMAC-SHA1
String timestamp = getIso8601UtcTimestamp();
String nonce = String.valueOf(System.currentTimeMillis());
String signature = generateSignature(accessKeyId, accessKeySecret, timestamp, nonce);
// 2. 构造请求 URL带签名参数
String requestUrl = TOKEN_PROXY_URL +
"?Action=CreateToken" +
"&Format=JSON" +
"&Version=2019-02-28" +
"&AccessKeyId=" + URLEncoder.encode(accessKeyId, "UTF-8") +
"&Timestamp=" + URLEncoder.encode(timestamp, "UTF-8") +
"&SignatureNonce=" + URLEncoder.encode(nonce, "UTF-8") +
"&Signature=" + URLEncoder.encode(signature, "UTF-8") +
"&SignatureMethod=HMAC-SHA1" +
"&SignatureVersion=1.0";
// 打印完整请求 URL用于排查参数问题
logger.info("Token 生成请求 URL{}", requestUrl);
// 3. 发送 GET 请求(走 Nginx 代理)
Request request = new Request.Builder().url(requestUrl).build();
try (Response response = proxyOkHttpClient.newCall(request).execute()) {
String responseBody = response.body() != null ? response.body().string() : "无响应内容";
logger.info("Token 接口响应 - 状态码:{},响应体:{}", response.code(), responseBody);
if (!response.isSuccessful()) {
throw new RuntimeException("Token 生成失败,状态码:" + response.code() + ",错误信息:" + responseBody);
}
com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSON.parseObject(responseBody);
// 4. 提取 Token 和过期时间
String token = json.getJSONObject("Token").getString("Id");
long expireTime = json.getJSONObject("Token").getLong("ExpireTime");
// 5. 反射设置到 SDK 的 AccessToken 对象
setAccessTokenField(accessToken, "token", token);
setAccessTokenField(accessToken, "expireTime", expireTime);
logger.info("Token 生成成功,过期时间:{}", expireTime);
}
}
/**
* 生成阿里云 API 签名(遵循阿里云规范)
*/
private static String generateSignature(String accessKeyId, String accessKeySecret, String timestamp, String nonce) throws Exception {
// 1. 按字典序拼接参数(必须严格排序)
StringBuilder paramBuilder = new StringBuilder();
paramBuilder.append("AccessKeyId=").append(URLEncoder.encode(accessKeyId, "UTF-8"))
.append("&Action=").append(URLEncoder.encode("CreateToken", "UTF-8"))
.append("&Format=").append(URLEncoder.encode("JSON", "UTF-8"))
.append("&SignatureMethod=").append(URLEncoder.encode("HMAC-SHA1", "UTF-8"))
.append("&SignatureNonce=").append(URLEncoder.encode(nonce, "UTF-8"))
.append("&SignatureVersion=").append(URLEncoder.encode("1.0", "UTF-8"))
.append("&Timestamp=").append(URLEncoder.encode(timestamp, "UTF-8"))
.append("&Version=").append(URLEncoder.encode("2019-02-28", "UTF-8"));
// 2. 构造签名原文Method + & + 编码后的URL + & + 编码后的参数)
String method = "GET";
String encodedUrl = URLEncoder.encode("/", "UTF-8"); // 根路径编码
String encodedParams = URLEncoder.encode(paramBuilder.toString(), "UTF-8");
String signatureText = method + "&" + encodedUrl + "&" + encodedParams;
// 调试日志:对比服务器端预期的签名原文
logger.info("本地计算的签名原文:{}", signatureText);
// 3. HMAC-SHA1 加密 + Base64 编码
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(new SecretKeySpec((accessKeySecret + "&").getBytes("UTF-8"), "HmacSHA1"));
byte[] signatureBytes = mac.doFinal(signatureText.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(signatureBytes);
}
/**
* 生成 ISO8601 格式的 UTC 时间戳2025-11-24T10:00:00Z
*/
private static String getIso8601UtcTimestamp() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("UTC")); // 强制使用 UTC 时区
return sdf.format(new Date());
}
/**
* 反射设置 AccessToken 的私有字段
*/
private static void setAccessTokenField(com.alibaba.nls.client.AccessToken accessToken, String fieldName, Object value) throws Exception {
java.lang.reflect.Field field = com.alibaba.nls.client.AccessToken.class.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(accessToken, value);
}
}

View File

@@ -1,6 +1,6 @@
package com.ruoyi.cms.handler;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizer;
import com.ruoyi.cms.util.AliyunNlsUtils;
import org.springframework.stereotype.Component;
import javax.websocket.*;
@@ -20,7 +20,7 @@ public class SpeechRecognitionWebSocketHandler {
String appKey = "4lFYn2yPsQymwGu8";
String id = "LTAI5t9hhSqdDHqwH3RjgyYj";
String secret = "ni5aW3vxrWouMwcGqJPfh9Uu56PBuv";
String url = System.getenv().getOrDefault("NLS_GATEWAY_URL", "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1");
String url = System.getenv().getOrDefault("NLS_GATEWAY_URL", AliyunNlsUtils.getNlsUrl()+"/ws/v1/");
recognizerDemo = new SpeechRecognizerAI(appKey, id, secret, url);
}

View File

@@ -7,6 +7,7 @@ import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizer;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizerListener;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizerResponse;
import com.ruoyi.cms.util.AliyunNlsUtils;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,7 +27,12 @@ public class SpeechRecognizerAI {
// 获取 AccessToken
accessToken = new AccessToken(id, secret);
try {
accessToken.apply(); // 申请 Token
if(AliyunNlsUtils.USE_TEST_ENV){
accessToken.apply(); // 申请 Token
}else{
AliyunNlsTokenUtil.generateToken(id, secret, this.accessToken);
}
//accessToken.apply(); // 申请 Token
logger.info("Token: {}, Expire Time: {}", accessToken.getToken(), accessToken.getExpireTime());
// 初始化 NlsClient
@@ -35,7 +41,7 @@ public class SpeechRecognizerAI {
} else {
this.client = new NlsClient(url, accessToken.getToken()); // 使用自定义服务地址
}
} catch (IOException e) {
} catch (Exception e) {
logger.error("Failed to initialize NlsClient: {}", e.getMessage());
}
}

View File

@@ -7,6 +7,7 @@ import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizer;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizerListener;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizerResponse;
import com.ruoyi.cms.util.AliyunNlsUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@@ -20,18 +21,23 @@ import java.nio.ByteBuffer;
@ServerEndpoint("/speech-synthesis")
public class SpeechSynthesisWebSocketHandler {
private static final Logger logger = LoggerFactory.getLogger(SpeechSynthesisWebSocketHandler.class);
private NlsClient client;
private String appKey = "mtA2pwmvCeefHT3Y";
private String accessKeyId = "LTAI5tRBahK93vPNF1JDVEPA";
private String accessKeySecret = "x95OWb4cV6ccQVtbEJ2Gxm2Uwl2thJ";
private String url = "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1";
private String url = AliyunNlsUtils.getNlsUrl()+"/ws/v1/";
public SpeechSynthesisWebSocketHandler() {
// Initialize NLS client with token
AccessToken accessToken = new AccessToken(accessKeyId, accessKeySecret);
try {
accessToken.apply();
if(AliyunNlsUtils.USE_TEST_ENV){
accessToken.apply();
}else{
AliyunNlsTokenUtil.generateToken(accessKeyId, accessKeySecret, accessToken);
}
//accessToken.apply();
String token = accessToken.getToken();
if(url.isEmpty()) {
this.client = new NlsClient(token);

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import java.util.Map;
import com.ruoyi.common.core.domain.entity.AppUserShow;
import com.ruoyi.common.core.domain.entity.MyChart;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.core.domain.entity.SysUser;
@@ -32,4 +33,8 @@ public interface AppUserMapper extends BaseMapper<AppUser>
int insertSysUser(SysUser sysUser);
MyChart getMyTj(Long userId);
SysUser selectSysUserIdcard(String idCard);
List<AppUserShow> selectUserApplyList(AppUser appUser);
}

View File

@@ -0,0 +1,7 @@
package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cms.domain.CommunityUser;
public interface CommunityUserMapper extends BaseMapper<CommunityUser> {
}

View File

@@ -2,6 +2,7 @@ package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.core.domain.entity.File;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -19,4 +20,10 @@ public interface FileMapper extends BaseMapper<File>
* @return 文件集合
*/
public List<File> selectFileList(File file);
public int updateBussinessids(@Param("longs") List<Long> longs,@Param("newBussinessid") Long bussinessid);
public List<File> selectFileListByBussinessIds(@Param("longs") List<Long> longs);
public int updateIds(@Param("longs") List<Long> longs,@Param("newBussinessid") Long bussinessid);
}

View File

@@ -37,4 +37,6 @@ public interface JobApplyMapper extends BaseMapper<JobApply>
List<CandidateVO> selectApplyJobUserList(AppUser appUser);
List<Job> selectJobApplyListJob(JobApply jobApply);
public int updateJobZphApply(JobApply jobApply);
}

View File

@@ -2,6 +2,7 @@ package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cms.domain.JobContact;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -17,4 +18,6 @@ public interface JobContactMapper extends BaseMapper<JobContact> {
List<JobContact> getSelectList(JobContact jobContact);
int batchInsert(List<JobContact> list);
List<JobContact> selectByJobIds(@Param("jobIds") List<Long> longs);
}

View File

@@ -58,4 +58,6 @@ public interface JobMapper extends BaseMapper<Job>
* @return
*/
Job getJobInfo(Long jobId);
Integer getTotals(Job job);
}

View File

@@ -0,0 +1,12 @@
package com.ruoyi.cms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cms.domain.WechatGroup;
import com.ruoyi.cms.domain.vo.WechatGroupVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface WechatGroupMapper extends BaseMapper<WechatGroup> {
List<WechatGroupVo> selectWechatGroupList(@Param("p") WechatGroup wechatGroup);
}

View File

@@ -16,5 +16,7 @@ public interface CompanyContactService {
List<CompanyContact> getSelectList(CompanyContact companyContact);
int insertUpadteCompanyContact(List<CompanyContact> list);
int insertContact(CompanyContact contact);
}

View File

@@ -2,6 +2,7 @@ package com.ruoyi.cms.service;
import java.util.List;
import com.ruoyi.common.core.domain.entity.AppUserShow;
import com.ruoyi.common.core.domain.entity.MyChart;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.cms.domain.vo.AppUserLky;
@@ -61,6 +62,8 @@ public interface IAppUserService
public AppUser registerAppUser(RegisterBody registerBody);
public AppUser registerAppUserNew(RegisterBody registerBody);
public AppUser selectAppuserByIdcard(String idCard);
public AppUserLky selectAppUserInfo(AppUser appUser);
@@ -72,4 +75,6 @@ public interface IAppUserService
public List<AppUser> selectNoTmAppUserList(AppUser appUser);
public MyChart getMyTj(Long userId);
public List<AppUserShow> selectUserApplyList(AppUser appUser);
}

View File

@@ -0,0 +1,12 @@
package com.ruoyi.cms.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.cms.domain.CommunityUser;
import java.util.List;
public interface ICommunityUserService extends IService<CommunityUser> {
List<CommunityUser> selectCommunityUserList(CommunityUser communityUser);
int delCommunityUser(Long[] ids);
}

View File

@@ -4,6 +4,7 @@ import com.ruoyi.common.core.domain.entity.File;
import com.ruoyi.common.core.domain.AjaxResult;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
@@ -54,5 +55,7 @@ public interface IFileService
*/
public int deleteFileByIds(Long[] ids);
AjaxResult uploadFile(MultipartFile file, Long bussinessid);
AjaxResult upload(MultipartFile file, Long bussinessid);
AjaxResult uploadFile(MultipartFile file, Long bussinessid, HttpServletRequest request);
}

View File

@@ -70,4 +70,6 @@ public interface IJobApplyService
public int applyComJob(JobApply jobApply);
public List<Job> selectJobApplyListJob(JobApply jobApply);
public int updateJobZphApply(JobApply jobApply);
}

View File

@@ -6,10 +6,11 @@ import com.ruoyi.cms.domain.ESJobDocument;
import com.ruoyi.cms.domain.Job;
import com.ruoyi.cms.domain.query.ESJobSearch;
import com.ruoyi.cms.domain.vo.CandidateVO;
import com.ruoyi.cms.util.AppWechatEntity;
import com.ruoyi.common.core.domain.entity.AppUser;
import org.dromara.easyes.core.biz.EsPageInfo;
import javax.servlet.http.HttpServletRequest;
/**
* 岗位Service接口
*
@@ -79,6 +80,8 @@ public interface IJobService
Job selectJobByJobIdApp(Long jobId);
Job selectHttpJobByJobIdApp(Long jobId,HttpServletRequest request);
void importRow(String path);
List<CandidateVO> candidates(Long jobId);
@@ -96,4 +99,15 @@ public interface IJobService
List<ESJobDocument> sysRecommend(ESJobSearch esJobSearch);
List<Job> selectAllJob();
public Job selectHttpJobByJobId(Long jobId, HttpServletRequest request);
public List<Job> selectHttpJobList(Job job,HttpServletRequest request);
/**
* 获取微信抓取的重复数据条数
* @param job
* @return
*/
public Integer getTotals(Job job);
}

View File

@@ -0,0 +1,11 @@
package com.ruoyi.cms.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.cms.domain.WechatGroup;
import com.ruoyi.cms.domain.vo.WechatGroupVo;
import java.util.List;
public interface IWechatGroupService extends IService<WechatGroup> {
List<WechatGroupVo> selectWechatGroupList(WechatGroup wechatGroup);
}

View File

@@ -3,6 +3,7 @@ package com.ruoyi.cms.service.impl;
import java.util.*;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.core.domain.entity.MyChart;
@@ -96,14 +97,7 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
@Override
public List<AppUser> selectAppUserList(AppUser appUser)
{
List<AppUser> list=appUserMapper.selectAppUserList(appUser);
if(list!=null){
//身份证脱敏处理
list.forEach(x->{
x.setIdCard(StringUtil.desensitizeIdCard(x.getIdCard()));
});
}
return list;
return appUserMapper.selectAppUserList(appUser);
}
/**
@@ -113,6 +107,7 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public int insertAppUser(AppUser appUser)
{
return appUserMapper.insert(appUser);
@@ -125,13 +120,48 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public int updateAppUser(AppUser appUser)
{
//工作经历
if(appUser.getExperiencesList()!=null&&appUser.getExperiencesList().size()>0){
userWorkExperiencesMapper.batchInsert(appUser.getExperiencesList());
List<UserWorkExperiences> add=new ArrayList<>();
List<UserWorkExperiences> upp=new ArrayList<>();
appUser.getExperiencesList().forEach(it->{
if(it.getId()!=null){upp.add(it);}else{it.setUserId(appUser.getUserId());add.add(it);}
});
if(add.size()>0){
userWorkExperiencesMapper.batchInsert(appUser.getExperiencesList());
}
if(upp.size()>0){
upp.forEach(it->{
it.setCreateTime(null);
it.setUserId(it.getUserId()==null?appUser.getUserId():it.getUserId());
userWorkExperiencesMapper.updateById(it);
});
}
}
//技能
if(appUser.getAppSkillsList()!=null&&appUser.getAppSkillsList().size()>0){
appSkillMapper.batchInsert(appUser.getAppSkillsList());
List<AppSkill> add=new ArrayList<>();
List<AppSkill> upp=new ArrayList<>();
appUser.getAppSkillsList().forEach(it->{
if(it.getId()!=null){upp.add(it);}else{it.setUserId(appUser.getUserId());add.add(it);}
});
if(add.size()>0){
appSkillMapper.batchInsert(appUser.getAppSkillsList());
}
if(upp.size()>0){
upp.forEach(it->{
it.setCreateTime(null);
it.setUserId(it.getUserId()==null?appUser.getUserId():it.getUserId());
appSkillMapper.updateById(it);
});
}
}
//添加一体机密码
if(StringUtils.isNotEmpty(appUser.getYtjPassword())){
appUser.setYtjPassword(SiteSecurityUtils.encryptPassword(appUser.getYtjPassword()));
}
return appUserMapper.updateById(appUser);
}
@@ -151,7 +181,7 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
@Override
public AppUser getPhone(String phone) {
return appUserMapper.selectOne(new LambdaQueryWrapper<AppUser>()
.eq(AppUser::getPhone, phone).orderByDesc(AppUser::getUpdateTime).last("LIMIT 1"));
.eq(AppUser::getPhone, phone).eq(AppUser::getDelFlag,"0").orderByDesc(AppUser::getUpdateTime).last("LIMIT 1"));
}
@Override
@@ -173,7 +203,7 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
}
}
//角色集合
Map mapUserRole=new HashMap<>();
Map<String,Object> mapUserRole=new HashMap<>();
switch (appUser.getIsCompanyUser()){
case StringUtil.IS_COMPANY_USER://企业
if(registerBody.getCompany()!=null){
@@ -210,20 +240,10 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
mapUserRole.put("roleId",StringUtil.SYS_QZZ);
}
//保存sys_user
SysUser sysUser=new SysUser();
sysUser.setUserName(appUser.getPhone());
sysUser.setNickName(StringUtils.isEmpty(appUser.getName())?appUser.getPhone():appUser.getName());
sysUser.setPassword(SecurityUtils.encryptPassword("123456"));
sysUser.setPhonenumber(appUser.getPhone());
sysUser.setSex(appUser.getSex());
sysUser.setStatus("0");
sysUser.setLoginIp(appUser.getLoginIp());
sysUser.setLoginDate(appUser.getLoginDate());
sysUser.setIdCard(appUser.getIdCard());
appUserMapper.insertSysUser(sysUser);
//保存sys_user_role
mapUserRole.put("userId",sysUser.getUserId());
appUserMapper.insertSysUserRole(mapUserRole);
SysUser parmUser=appUserMapper.selectSysUserIdcard(appUser.getIdCard());
if(parmUser==null){
registerInsertSysUser(appUser,mapUserRole);
}
//一体机密码
if(StringUtils.isNotEmpty(appUser.getYtjPassword())){
appUser.setYtjPassword(SiteSecurityUtils.encryptPassword(appUser.getYtjPassword()));
@@ -232,9 +252,228 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
return appUser;
}
@Override
@Transactional(rollbackFor = Exception.class)
public AppUser registerAppUserNew(RegisterBody registerBody) {
// 1. 参数校验
validateRegisterParam(registerBody);
// 2. 获取基础数据
AppUser appUser = registerBody.getAppUser();
Long loginUserId = SiteSecurityUtils.getUserId();
// 3. 登录态处理:关联已有用户信息
AppUser existingUser = handleLoginUserAssociation(appUser, loginUserId);
// 4. 差异化业务处理(企业用户/求职者)
handleUserTypeSpecificLogic(existingUser, registerBody);
// 5. 系统用户同步(不存在则创建)
syncSysUserIfNecessary(existingUser);
// 6. 一体机密码加密处理
encryptYtjPassword(existingUser);
// 7. 更新App用户信息
appUserMapper.updateById(existingUser);
return existingUser;
}
/**
* 注册参数校验
* @param registerBody 注册请求体
*/
private void validateRegisterParam(RegisterBody registerBody) {
if (registerBody == null) {
throw new IllegalArgumentException("注册请求参数不能为空");
}
}
/**
* 处理登录用户关联逻辑
* @param appUser 注册传入的用户信息
* @param loginUserId 登录用户ID
* @return 关联后的用户信息
*/
private AppUser handleLoginUserAssociation(AppUser appUser, Long loginUserId) {
if (SiteSecurityUtils.isLogin() && loginUserId != null) {
AppUser dbUser = appUserMapper.selectById(loginUserId);
if (dbUser != null) {
if (appUser == null) {
return dbUser;
} else {
appUser.setPhone(dbUser.getPhone());
appUser.setUserId(dbUser.getUserId());
return appUser;
}
}
}
return appUser;
}
/**
* 处理不同用户类型的差异化业务逻辑
* @param appUser 用户信息
* @param registerBody 注册请求体
*/
private void handleUserTypeSpecificLogic(AppUser appUser, RegisterBody registerBody) {
String userType = appUser.getIsCompanyUser();
switch (userType) {
case StringUtil.IS_COMPANY_USER:
handleCompanyUserLogic(appUser, registerBody.getCompany());
break;
default:
handleJobSeekerUserLogic(appUser, registerBody);
break;
}
}
/**
* 处理企业用户注册逻辑
* @param appUser 企业用户信息
* @param company 企业信息
*/
private void handleCompanyUserLogic(AppUser appUser, Company company) {
if (company != null) {
// 保存企业信息(新增场景)
if (company.getCompanyId() == null) {
companyMapper.insert(company);
// 批量保存企业联系人
saveCompanyContacts(company.getCompanyId(), company.getCompanyContactList());
}
// 关联企业信息到用户
appUser.setIdCard(company.getCode());
appUser.setName(company.getName());
}
}
/**
* 批量保存企业联系人
* @param companyId 企业ID
* @param contactList 联系人列表
*/
private void saveCompanyContacts(Long companyId, List<CompanyContact> contactList) {
if (contactList != null && !contactList.isEmpty()) {
contactList.forEach(contact -> contact.setCompanyId(companyId));
companyContactMapper.batchInsert(contactList);
}
}
/**
* 处理求职者用户注册逻辑
* @param appUser 求职者用户信息
* @param registerBody 注册请求体
*/
private void handleJobSeekerUserLogic(AppUser appUser, RegisterBody registerBody) {
Long userId = appUser.getUserId();
// 保存工作经历
saveUserWorkExperiences(userId, registerBody.getExperiencesList());
// 保存技能信息
saveUserAppSkills(userId, registerBody.getAppSkillsList());
}
/**
* 批量保存用户工作经历
* @param userId 用户ID
* @param experiencesList 工作经历列表
*/
private void saveUserWorkExperiences(Long userId, List<UserWorkExperiences> experiencesList) {
if (experiencesList != null && !experiencesList.isEmpty()) {
experiencesList.forEach(experience -> experience.setUserId(userId));
userWorkExperiencesMapper.batchInsert(experiencesList);
}
}
/**
* 批量保存用户技能信息
* @param userId 用户ID
* @param skillsList 技能列表
*/
private void saveUserAppSkills(Long userId, List<AppSkill> skillsList) {
if (skillsList != null && !skillsList.isEmpty()) {
skillsList.forEach(skill -> skill.setUserId(userId));
appSkillMapper.batchInsert(skillsList);
}
}
/**
* 同步系统用户(不存在则创建)
* @param appUser App用户信息
*/
private void syncSysUserIfNecessary(AppUser appUser) {
SysUser sysUser = appUserMapper.selectSysUserIdcard(appUser.getIdCard());
if (sysUser == null) {
// 构建角色映射
Map<String, Object> roleMap = buildUserRoleMap(appUser.getIsCompanyUser());
// 创建系统用户及角色关联
registerInsertSysUser(appUser, roleMap);
}
}
/**
* 构建用户角色映射
* @param userType 用户类型
* @return 角色ID映射
*/
private Map<String, Object> buildUserRoleMap(String userType) {
Map<String, Object> roleMap = new HashMap<>();
if (StringUtil.IS_COMPANY_USER.equals(userType)) {
roleMap.put("roleId", StringUtil.SYS_QY);
} else {
roleMap.put("roleId", StringUtil.SYS_QZZ);
}
return roleMap;
}
/**
* 加密一体机密码
* @param appUser 用户信息
*/
private void encryptYtjPassword(AppUser appUser) {
if (StringUtils.hasText(appUser.getYtjPassword())) {
appUser.setYtjPassword(SiteSecurityUtils.encryptPassword(appUser.getYtjPassword()));
}
}
/**
* 保存系统用户及角色关联
* @param appUser App用户信息
* @param roleMap 角色映射包含roleId
*/
private void registerInsertSysUser(AppUser appUser, Map<String, Object> roleMap) {
// 构建系统用户
SysUser sysUser = buildSysUser(appUser);
// 插入系统用户
appUserMapper.insertSysUser(sysUser);
// 关联用户角色
roleMap.put("userId", sysUser.getUserId());
appUserMapper.insertSysUserRole(roleMap);
}
/**
* 构建系统用户对象
* @param appUser App用户信息
* @return 系统用户对象
*/
private SysUser buildSysUser(AppUser appUser) {
SysUser sysUser = new SysUser();
sysUser.setUserName(StringUtil.USER_KEY + appUser.getIdCard());
sysUser.setNickName(StringUtils.isEmpty(appUser.getName()) ? appUser.getPhone() : appUser.getName());
sysUser.setPassword(SiteSecurityUtils.encryptPassword("123456"));
sysUser.setPhonenumber(appUser.getPhone());
sysUser.setSex(appUser.getSex());
sysUser.setStatus("0");
sysUser.setLoginIp(appUser.getLoginIp());
sysUser.setLoginDate(appUser.getLoginDate());
sysUser.setIdCard(appUser.getIdCard());
return sysUser;
}
@Override
public AppUser selectAppuserByIdcard(String idCard) {
return appUserMapper.selectOne(Wrappers.<AppUser>lambdaQuery().eq(AppUser::getIdCard, idCard).orderByDesc(AppUser::getUpdateTime).last("LIMIT 1"));
return appUserMapper.selectOne(Wrappers.<AppUser>lambdaQuery().eq(AppUser::getIdCard, idCard).eq(AppUser::getDelFlag,"0").orderByDesc(AppUser::getUpdateTime).last("LIMIT 1"));
}
@Override
@@ -260,8 +499,11 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
public AppUser getUserInfo() {
//查询用户信息
LoginUser loginUser=SecurityUtils.getLoginUser();
System.out.println("loginUser========================"+JSON.toJSONString(loginUser));
SysUser sysUser=loginUser.getUser();
System.out.println("sysUser========================"+JSON.toJSONString(sysUser));
AppUser appUser=selectAppuserByIdcard(sysUser.getIdCard());
System.out.println("appUser========================"+JSON.toJSONString(appUser));
if(appUser!=null&&appUser.getUserId()!=null){
//查询工作经历信息
UserWorkExperiences parm=new UserWorkExperiences();
@@ -351,4 +593,16 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
public MyChart getMyTj(Long userId) {
return appUserMapper.getMyTj(userId);
}
@Override
public List<AppUserShow> selectUserApplyList(AppUser appUser) {
List<AppUserShow> list=appUserMapper.selectUserApplyList(appUser);
if(list!=null){
//身份证脱敏处理
list.forEach(x->{
x.setIdCard(StringUtil.desensitizeIdCard(x.getIdCard()));
});
}
return list;
}
}

View File

@@ -0,0 +1,46 @@
package com.ruoyi.cms.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.cms.domain.CommunityUser;
import com.ruoyi.cms.domain.WechatGroup;
import com.ruoyi.cms.mapper.CommunityUserMapper;
import com.ruoyi.cms.mapper.WechatGroupMapper;
import com.ruoyi.cms.service.ICommunityUserService;
import com.ruoyi.common.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
@Service
public class CommunityUserServiceImpl extends ServiceImpl<CommunityUserMapper, CommunityUser>
implements ICommunityUserService {
@Autowired
private WechatGroupMapper wechatGroupMapper;
@Override
public List<CommunityUser> selectCommunityUserList(CommunityUser communityUser) {
return baseMapper.selectList(Wrappers.lambdaQuery(CommunityUser.class)
.like(StrUtil.isNotBlank(communityUser.getWechatName()), CommunityUser::getWechatName, communityUser.getWechatName())
.like(StrUtil.isNotBlank(communityUser.getPhoneNumber()), CommunityUser::getPhoneNumber, communityUser.getPhoneNumber())
);
}
@Override
public int delCommunityUser(Long[] ids) {
if (ids == null || ids.length == 0) return 0;
Collection<Long> userIds = CollUtil.newArrayList(ids);
Long count = wechatGroupMapper.selectCount(Wrappers.lambdaQuery(WechatGroup.class)
.in(WechatGroup::getCommunityId, userIds));
if (count > 0) {
throw new ServiceException("所选工作人员已配置转发对象!");
}
return baseMapper.deleteBatchIds(userIds);
}
}

View File

@@ -39,4 +39,9 @@ public class CompanyContactServiceImpl extends ServiceImpl<CompanyContactMapper,
}
return 0;
}
@Override
public int insertContact(CompanyContact contact) {
return companyContactMapper.insert(contact);
}
}

View File

@@ -406,7 +406,11 @@ public class ESJobSearchImpl implements IESJobSearchService
wrapper.and(x->x.le(ESJobDocument::getExperience_int,maxValue));
}
if(!StringUtil.isEmptyOrNull(esJobSearch.getJobCategory())){
wrapper.and(x->x.eq(ESJobDocument::getJobCategory,esJobSearch.getJobCategory()));
//wrapper.and(x->x.eq(ESJobDocument::getJobCategory,esJobSearch.getJobCategory()));
String targetValue = esJobSearch.getJobCategory();
wrapper.and(x -> x.like(ESJobDocument::getJobCategory, targetValue)
.or()
.like(ESJobDocument::getJobTitle, targetValue));
}
if(!StringUtil.isEmptyOrNull(esJobSearch.getScale())){
Integer maxValue = StringUtil.findMaxValue(esJobSearch.getScale());
@@ -437,6 +441,12 @@ public class ESJobSearchImpl implements IESJobSearchService
if(esJobSearch.getJobId()!=null){
wrapper.and(x->x.eq(ESJobDocument::getJobId,esJobSearch.getJobId()));
}
if(!StringUtil.isEmptyOrNull(esJobSearch.getJobAddress())){
wrapper.and(x->x.like(ESJobDocument::getJobAddress,esJobSearch.getJobAddress()));
}
if(!StringUtil.isEmptyOrNull(esJobSearch.getJobLocation())){
wrapper.and(x->x.like(ESJobDocument::getJobLocation,esJobSearch.getJobLocation()));
}
if(Objects.nonNull(esJobSearch.getOrder())){
if(esJobSearch.getOrder()==1){
wrapper.orderByDesc(ESJobDocument::getIsHot);

View File

@@ -9,6 +9,7 @@ import com.ruoyi.cms.mapper.JobApplyMapper;
import com.ruoyi.cms.mapper.JobMapper;
import com.ruoyi.cms.mapper.NoticeMapper;
import com.ruoyi.cms.service.EmployeeConfirmService;
import com.ruoyi.cms.util.StringUtil;
import com.ruoyi.cms.util.notice.NoticeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -40,7 +41,8 @@ public class EmployeeConfirmServiceImpl implements EmployeeConfirmService {
if(t>0){
JobApply apply=new JobApply();
apply.setId(employeeConfirm.getApplyId());
apply.setHire("0");
apply.setHire(StringUtil.HIRE_LY);
apply.setHireSource(StringUtil.HIRE_SOURCE_SYSTEM);//本系统录用
jobApplyMapper.updateById(apply);
}
Job job=jobMapper.getJobInfo(employeeConfirm.getJobId());

View File

@@ -6,6 +6,8 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Arrays;
import com.ruoyi.cms.util.StringUtil;
import com.ruoyi.common.core.domain.entity.File;
import com.ruoyi.cms.mapper.FileMapper;
import com.ruoyi.cms.service.IFileService;
@@ -17,6 +19,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
/**
* 文件Service业务层处理
*
@@ -91,7 +95,7 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IF
}
@Override
public AjaxResult uploadFile(MultipartFile file, Long bussinessid) {
public AjaxResult upload(MultipartFile file, Long bussinessid) {
if (file.isEmpty()) {
return AjaxResult.error("文件为空,请选择文件上传");
}
@@ -119,11 +123,52 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IF
return AjaxResult.error("文件上传失败");
}
}
private void saveFileInfo(String fileName, Long bussinessid) {
/**
* 添加返回bussinessid的接口新增时使用
* @param file
* @param bussinessid
* @return
*/
@Override
public AjaxResult uploadFile(MultipartFile file, Long bussinessid, HttpServletRequest request) {
if (file.isEmpty()) {
return AjaxResult.error("文件为空,请选择文件上传");
}
try {
// 创建上传目录
java.io.File dir = new java.io.File(uploadDir);
if (!dir.exists()) {
dir.mkdirs();
}
// 生成唯一的文件名
String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
Path filePath = Paths.get(uploadDir, fileName);
// 保存文件到服务器
Files.copy(file.getInputStream(), filePath);
// 保存文件信息到数据库
File svFile=saveFileInfo(fileName, bussinessid);
AjaxResult ajaxResult=AjaxResult.success();
ajaxResult.put("filePath", StringUtil.getFilePath(request)+fileName);
ajaxResult.put("bussinessid",String.valueOf(bussinessid));
ajaxResult.put("id",String.valueOf(svFile.getId()));
return ajaxResult;
} catch (IOException e) {
e.printStackTrace();
return AjaxResult.error("文件上传失败");
}
}
private File saveFileInfo(String fileName, Long bussinessid) {
// 这里假设你已经有了一个FileService来处理数据库操作
File file = new File();
file.setBussinessid(bussinessid);
file.setFileUrl(fileName);
this.save(file);
return file;
}
}

View File

@@ -155,4 +155,9 @@ public class JobApplyServiceImpl extends ServiceImpl<JobApplyMapper,JobApply> im
public List<Job> selectJobApplyListJob(JobApply jobApply) {
return jobApplyMapper.selectJobApplyListJob(jobApply);
}
@Override
public int updateJobZphApply(JobApply jobApply) {
return jobApplyMapper.updateJobZphApply(jobApply);
}
}

View File

@@ -262,12 +262,14 @@ public class JobCollectionServiceImpl extends ServiceImpl<JobCollectionMapper,Jo
}
// 4. 地点匹配
if (user.getArea() != null && user.getArea().contains(jobLocation) || jobLocation.contains(user.getArea())) {
matchScore += 1;
if (user.getArea() != null) {
if(user.getArea().contains(jobLocation) || jobLocation.contains(user.getArea())){
matchScore += 1;
}
}
// 5. 年龄估算(从生日计算)
int userAge = getUserAge(DateUtils.toDate(user.getBirthDate()));
int userAge = getUserAge(DateUtils.stringToDateWithYmd(user.getBirthDate(),DateUtils.YYYY_MM_DD));
// 假设最佳年龄区间为 22-35越接近越匹配
if (userAge >= 22 && userAge <= 35) {
matchScore += 1;
@@ -293,7 +295,7 @@ public class JobCollectionServiceImpl extends ServiceImpl<JobCollectionMapper,Jo
// ================== 计算雷达图数据(取平均值)==================
RadarChart radarChart = new RadarChart();
double avgAgeScore = userScores.stream().mapToInt(u -> getAgeScore(DateUtils.toDate(u.getUser().getBirthDate()))).average().orElse(0);
double avgAgeScore = userScores.stream().mapToInt(u -> getAgeScore(DateUtils.stringToDateWithYmd(u.getUser().getBirthDate(),DateUtils.YYYY_MM_DD))).average().orElse(0);
double avgExperienceScore = userScores.stream().mapToInt(u -> getExperienceScore(u.getUser().getExperience(), job.getExperience(), experienceRank)).average().orElse(0);
double avgEducationScore = userScores.stream().mapToInt(u -> getEducationScore(u.getUser().getEducation(), job.getEducation(), educationRank)).average().orElse(0);
double avgSkillScore = userScores.stream().mapToInt(u -> getSkillScore(u.getUser(), job)).average().orElse(0);

View File

@@ -4,6 +4,7 @@ import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
@@ -29,6 +30,7 @@ import com.ruoyi.common.utils.SiteSecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.dromara.easyes.core.biz.EsPageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,6 +38,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
@@ -45,6 +48,8 @@ import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 岗位Service业务层处理
*
@@ -221,13 +226,38 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
if(contacts!=null){
job.setJobContactList(contacts);
}
//查询附件
File file=new File();
file.setBussinessid(jobId);
List<File> filesList=fileMapper.selectFileList(file);
if(filesList!=null){
job.setFilesList(filesList);
return job;
}
@Override
public Job selectHttpJobByJobId(Long jobId, HttpServletRequest request)
{
Job job = jobMapper.selectById(jobId);
//查询公司信息
if(Objects.nonNull(job.getCompanyId())){
Company company = companyMapper.selectById(job.getCompanyId());
job.setCompany(company);
}
//查询联系人
JobContact contact = new JobContact();
contact.setJobId(jobId);
List<JobContact> contacts = jobContactMapper.getSelectList(contact);
job.setJobContactList(contacts == null ? Collections.emptyList() : contacts);
//查询附件
String baseFilePath = StringUtil.getFilePath(request);
//查询附件
File queryFile = new File();
queryFile.setBussinessid(jobId);
List<File> filesList = Optional.ofNullable(fileMapper.selectFileList(queryFile))
.orElseGet(Collections::emptyList);
//添加路径
List<File> processedFiles = filesList.stream()
.filter(Objects::nonNull)
.filter(file -> file.getFileUrl() != null && !file.getFileUrl().trim().isEmpty())
.peek(file -> file.setFileUrl(String.join("", baseFilePath, file.getFileUrl())))
.collect(Collectors.toList());
job.setFilesList(processedFiles);
return job;
}
@@ -245,6 +275,65 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
return jobs;
}
@Override
public List<Job> selectHttpJobList(Job job,HttpServletRequest request)
{
List<Job> jobs = jobMapper.selectJobList(job);
if (CollectionUtils.isNotEmpty(jobs)) {
String baseFilePath = StringUtil.getFilePath(request);
baseFilePath = baseFilePath == null ? "" : baseFilePath;
List<Long> jobIds = jobs.stream().filter(Objects::nonNull)
.map(Job::getJobId).filter(Objects::nonNull)
.collect(Collectors.toList());
//查询所有附件
List<File> allFiles = CollectionUtils.isNotEmpty(jobIds)
? Optional.ofNullable(fileMapper.selectFileListByBussinessIds(jobIds))
.orElseGet(Collections::emptyList)
: Collections.emptyList();
//查询所有联系人
List<JobContact> allJobContacts = CollectionUtils.isNotEmpty(jobIds)
? Optional.ofNullable(jobContactMapper.selectByJobIds(jobIds)).orElse(Collections.emptyList())
: Collections.emptyList();
//岗位联系人
Map<Long, List<JobContact>> jobContactGroupMap = allJobContacts.stream()
.filter(Objects::nonNull)
.filter(contact -> Objects.nonNull(contact.getJobId()))
.collect(Collectors.groupingBy(
JobContact::getJobId,
Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)
));
//附件分组
String finalBaseFilePath = baseFilePath;
Map<Long, List<File>> fileGroupMap = allFiles.stream()
.filter(Objects::nonNull)
.filter(file -> Objects.nonNull(file.getBussinessid()))
.filter(file -> StringUtils.isNotBlank(file.getFileUrl()))
.peek(file -> {
String fileUrl = file.getFileUrl().trim();
String fullFileUrl = StringUtils.join(finalBaseFilePath, fileUrl);
file.setFileUrl(fullFileUrl);
})
.collect(Collectors.groupingBy(
File::getBussinessid,
Collectors.collectingAndThen(Collectors.toList(),Collections::unmodifiableList)
));
jobs.forEach(jobItem -> {
if (Objects.nonNull(jobItem)) {
Long jobItemId = jobItem.getJobId();
List<File> jobFiles = fileGroupMap.getOrDefault(jobItemId, Collections.emptyList());
List<JobContact> jobContent = jobContactGroupMap.getOrDefault(jobItemId, Collections.emptyList());
jobItem.setFilesList(jobFiles);
jobItem.setJobContactList(jobContent);
}
});
}
return jobs;
}
@Override
public int view(Long jobId) {
Job job = jobMapper.selectById(jobId);
@@ -262,25 +351,34 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
* @param job 岗位
* @return 结果
*/
@Transactional
@Override
public int insertJob(Job job)
{
int insert = jobMapper.insert(job);
//todo 线程池管理
Thread thread = new Thread(() -> {
VectorJob jobVector = jobMapper.selectVectorJob(job.getJobId());
jobVector.setJobUrl("http://39.98.44.136/app#/packageA/pages/post/post?jobId="+job.getJobId());
String jsonBody = JSONUtil.toJsonStr(jobVector);
HttpUtil.post("http://39.98.44.136:6004/insert_vector", jsonBody);
});
thread.start();
// Thread thread = new Thread(() -> {
// VectorJob jobVector = jobMapper.selectVectorJob(job.getJobId());
// jobVector.setJobUrl("http://39.98.44.136/app#/packageA/pages/post/post?jobId="+job.getJobId());
// String jsonBody = JSONUtil.toJsonStr(jobVector);
// HttpUtil.post("http://39.98.44.136:6004/insert_vector", jsonBody);
// });
// thread.start();
if(insert>0){
job.getJobContactList().forEach(x->{
//添加联系人
List<JobContact> jobContactList = job.getJobContactList() != null ? job.getJobContactList() : Collections.emptyList();
jobContactList.forEach(x->{
JobContact jobContact=new JobContact();
BeanUtils.copyProperties(x,jobContact);
jobContact.setJobId(job.getJobId());
jobContactMapper.insert(jobContact);
});
//添加附件
List<File> filesList = job.getFilesList() != null ? job.getFilesList() : Collections.emptyList();
List<Long> longs = filesList.stream().filter(Objects::nonNull).map(File::getBussinessid).collect(Collectors.toList());
if(!longs.isEmpty()){
fileMapper.updateBussinessids(longs,job.getJobId());
}
}
return insert;
}
@@ -323,19 +421,75 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
int i=jobMapper.updateById(job);
//修改岗位联系人列表
if(i>0){
jobContactMapper.update(null,Wrappers.<JobContact>lambdaUpdate()
.eq(JobContact::getJobId, job.getJobId())
.set(JobContact::getDelFlag, Constants.Del_FLAG_DELETE));
if(Objects.isNull(job.getJobContactList())){return i;}
job.getJobContactList().forEach(x -> {
JobContact jobContact = new JobContact();
jobContact.setJobId(job.getJobId());
jobContactMapper.insert(jobContact);
});
// 处理联系人
handleJobContact(job);
//添加附件
handleJobFile(job);
}
return i;
}
/**
* 处理联系人
* @param job
*/
private void handleJobContact(Job job) {
List<JobContact> jobContactList = Optional.ofNullable(job.getJobContactList()).orElse(Collections.emptyList());
if (CollectionUtils.isEmpty(jobContactList)) {
return;
}
List<JobContact> insertList = new ArrayList<>();
List<JobContact> updateList = new ArrayList<>();
for (JobContact originContact : jobContactList) {
if (originContact == null) {
continue;
}
JobContact targetContact = new JobContact();
targetContact.setJobId(job.getJobId());
targetContact.setContactPerson(originContact.getContactPerson());
targetContact.setContactPersonPhone(originContact.getContactPersonPhone());
targetContact.setPosition(originContact.getPosition());
if (originContact.getId() == null) {
insertList.add(targetContact);
} else {
targetContact.setId(originContact.getId());
updateList.add(targetContact);
}
}
if (!CollectionUtils.isEmpty(insertList)) {
jobContactMapper.batchInsert(insertList);
}
if (!CollectionUtils.isEmpty(updateList)) {
updateList.forEach(contact -> {
LambdaUpdateWrapper<JobContact> updateWrapper = Wrappers.<JobContact>lambdaUpdate()
.eq(JobContact::getId, contact.getId());
jobContactMapper.update(contact, updateWrapper);
});
}
}
/**
* 处理附件
* @param job
*/
private void handleJobFile(Job job) {
List<File> filesList = Optional.ofNullable(job.getFilesList()).orElse(Collections.emptyList());
List<Long> fileIds = filesList.stream()
.filter(Objects::nonNull)
.map(File::getBussinessid)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(fileIds)) {
fileMapper.updateBussinessids(fileIds, job.getJobId());
}
}
/**
* 批量删除岗位
*
@@ -441,6 +595,63 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
}
@Override
public Job selectHttpJobByJobIdApp(Long jobId,HttpServletRequest request) {
Job job = jobMapper.selectById(jobId);
//查询公司信息
if(Objects.nonNull(job.getCompanyId())){
Company company = companyMapper.selectById(job.getCompanyId());
job.setCompany(company);
}
if(SiteSecurityUtils.isLogin()){
//查询申请信息
Long applyCount = jobApplyMapper.selectCount(Wrappers.<JobApply>lambdaQuery().eq(JobApply::getJobId, jobId).eq(JobApply::getUserId, SiteSecurityUtils.getUserId()));
job.setIsApply(applyCount>0?1:0);
//查询收藏信息
Long collectionCount = jobCollectionMapper.selectCount(Wrappers.<JobCollection>lambdaQuery().eq(JobCollection::getJobId, jobId).eq(JobCollection::getUserId, SiteSecurityUtils.getUserId()));
job.setIsCollection(collectionCount>0?1:0);
//todo asyn
//保存浏览记录
List<AppReviewJob> appReviewJobs = appReviewJobMapper.selectList(Wrappers.<AppReviewJob>lambdaQuery().eq(AppReviewJob::getUserId, SiteSecurityUtils.getUserId()).eq(AppReviewJob::getJobId, jobId));
//之前相同岗位的记录删除 保存最新的浏览记录
if(!appReviewJobs.isEmpty()){
appReviewJobMapper.deleteBatchIds(appReviewJobs.stream().map(AppReviewJob::getId).collect(Collectors.toList()));
}
AppReviewJob appReviewJob = new AppReviewJob();
appReviewJob.setUserId(SiteSecurityUtils.getUserId());
LocalDateTime now = LocalDateTime.now();
String formattedDate = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
appReviewJob.setReviewDate(formattedDate);
appReviewJob.setJobId(jobId);
appReviewJobMapper.insert(appReviewJob);
}
this.view(jobId);
//查询联系人
JobContact contact = new JobContact();
contact.setJobId(jobId);
List<JobContact> contacts = jobContactMapper.getSelectList(contact);
job.setJobContactList(contacts == null ? Collections.emptyList() : contacts);
//查询附件
String baseFilePath = StringUtil.getFilePath(request);
File queryFile = new File();
queryFile.setBussinessid(jobId);
List<File> filesList = Optional.ofNullable(fileMapper.selectFileList(queryFile))
.orElseGet(Collections::emptyList);
//添加路径
List<File> processedFiles = filesList.stream()
.filter(Objects::nonNull)
.filter(file -> file.getFileUrl() != null && !file.getFileUrl().trim().isEmpty())
.peek(file -> file.setFileUrl(String.join("", baseFilePath, file.getFileUrl())))
.collect(Collectors.toList());
job.setFilesList(processedFiles);
//查询投递人
List<AppUser> appUsers=jobMapper.selectApplyJobUserList(jobId);
job.setApplyUsers(appUsers == null ? Collections.emptyList() : appUsers);
return job;
}
@Override
public List<CandidateVO> candidates(Long jobId) {
List<CandidateVO> jobList = jobApplyMapper.candidates(jobId);
@@ -836,12 +1047,20 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
// }
// job.setCompanyId(company.getCompanyId());
jobMapper.insert(job);
if(job.getJobContactList()!=null){
job.getJobContactList().forEach(it->{
it.setJobId(job.getJobId());
});
jobContactMapper.batchInsert(job.getJobContactList());
//修改联系人
List<JobContact> jobContactList = job.getJobContactList() != null ? job.getJobContactList() : Collections.emptyList();
jobContactList.stream().filter(Objects::nonNull).forEach(it -> it.setJobId(job.getJobId()));
if(!jobContactList.isEmpty()){
jobContactMapper.batchInsert(jobContactList);
}
//添加附件
List<File> filesList = job.getFilesList() != null ? job.getFilesList() : Collections.emptyList();
List<Long> longs = filesList.stream().filter(Objects::nonNull).map(File::getBussinessid).collect(Collectors.toList());
if(!longs.isEmpty()){
fileMapper.updateBussinessids(longs,job.getJobId());
}
iesJobSearchService.updateJob(job.getJobId());
}
@@ -852,30 +1071,55 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
@Override
public List<ESJobDocument> sysRecommend(ESJobSearch esJobSearch) {
Long userId=SecurityUtils.isLogin()?SecurityUtils.getUserId():null;
List<Long> jobList=new ArrayList<>();
String jobKey="";
AppUser appUser=null;
if(userId!=null){
jobKey=CacheConstants.SYS_JOB_IDS+ userId;
RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
JSONArray cacheObject = redisCache.getCacheObject(jobKey);
jobList = new ArrayList<>();
if(Objects.isNull(cacheObject)){
ArrayList<Long> longs = new ArrayList<>();
jobList =longs;
}else {
jobList = cacheObject.toList(Long.class);
Long userId = SecurityUtils.isLogin() ? SecurityUtils.getUserId() : null;
List<Long> viewedJobIds = new ArrayList<>();
String jobCacheKey = "";
AppUser appUser = null;
if (userId != null) {
jobCacheKey = CacheConstants.SYS_JOB_IDS + userId;
try {
JSONArray cacheObject = redisCache.getCacheObject(jobCacheKey);
if (Objects.isNull(cacheObject)) {
cacheObject = new JSONArray();
}
viewedJobIds = cacheObject.stream()
.map(o -> Long.parseLong(o.toString()))
.distinct().limit(100).collect(Collectors.toList());
String idCard = RoleUtils.getCurrentUseridCard();
if (StringUtils.isNotEmpty(idCard)) {
appUser = appUserService.selectAppuserByIdcard(idCard);
}
} catch (Exception e) {
log.error("获取用户已查看岗位缓存失败", e);
viewedJobIds = new ArrayList<>();
}
appUser=appUserService.selectAppuserByIdcard(RoleUtils.getCurrentUseridCard());
}
//从es中查询
List<ESJobDocument> jobListResult = iesJobSearchService.selectSysTextListExceptJobId(esJobSearch,jobList,appUser);
//存入当前session中查看的岗位 避免重复 todo 定时删除 key上保存用户信息
jobList.addAll(jobListResult.stream().map(ESJobDocument::getJobId).collect(Collectors.toList()));
if(StringUtils.isNotEmpty(jobKey)){
redisCache.setCacheObject(jobKey,jobList);
List<ESJobDocument> jobListResult = new ArrayList<>();
try {
jobListResult = iesJobSearchService.selectSysTextListExceptJobId(esJobSearch, viewedJobIds, appUser);
//降级策略:如果过滤后无数据,忽略已查看记录重新查询
if (CollectionUtils.isEmpty(jobListResult) && !viewedJobIds.isEmpty()) {
log.warn("用户{}已查看岗位过多,忽略过滤条件重新查询");
jobListResult = iesJobSearchService.selectSysTextListExceptJobId(esJobSearch, new ArrayList<>(), appUser);
}
} catch (Exception e) {
log.error("ES推荐岗位查询失败", e);
return new ArrayList<>();
}
if (userId != null && !CollectionUtils.isEmpty(jobListResult)) {
try {
List<Long> newJobIds = jobListResult.stream().map(ESJobDocument::getJobId).distinct().collect(Collectors.toList());
List<Long> updatedJobIds = Stream.concat(viewedJobIds.stream(), newJobIds.stream()).distinct().limit(100).collect(Collectors.toList());
redisCache.setCacheObject(jobCacheKey, updatedJobIds, 24, TimeUnit.HOURS);
} catch (Exception e) {
log.error("更新用户已查看岗位缓存失败", e);
}
}
List<ESJobDocument> esJobDocuments = sysUserCollection(jobListResult);
return esJobDocuments;
}
@@ -888,4 +1132,9 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
params.put("offset", offset*batchSize);
return jobMapper.selectAllJob(params);
}
@Override
public Integer getTotals(Job job) {
return jobMapper.getTotals(job);
}
}

View File

@@ -0,0 +1,20 @@
package com.ruoyi.cms.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.cms.domain.WechatGroup;
import com.ruoyi.cms.domain.vo.WechatGroupVo;
import com.ruoyi.cms.mapper.WechatGroupMapper;
import com.ruoyi.cms.service.IWechatGroupService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class WechatGroupServiceImpl extends ServiceImpl<WechatGroupMapper, WechatGroup>
implements IWechatGroupService {
@Override
public List<WechatGroupVo> selectWechatGroupList(WechatGroup wechatGroup) {
return baseMapper.selectWechatGroupList(wechatGroup);
}
}

View File

@@ -0,0 +1,44 @@
package com.ruoyi.cms.util;
/**
* 阿里云配置
*/
public class AliyunNlsUtils {
/**
* 标志
*/
public static final boolean USE_TEST_ENV=true;
/**
* 测试nls
*/
public static final String NLS_TEST_URL="wss://nls-gateway-cn-shanghai.aliyuncs.com";
/**
* 测试微信获取oppenid链接
*/
public static final String WX_TEST_URL="https://api.weixin.qq.com/sns/jscode2session";
/**
* 正式nls
*/
public static final String NLS_FORMAL_URL="http://192.168.2.102:10044";
/**
* 根据环境判断正式还是测试
* @return
*/
public static String getNlsUrl(){
String url = USE_TEST_ENV ? NLS_TEST_URL : NLS_FORMAL_URL;
System.out.println("nls当前环境" + (USE_TEST_ENV ? "测试" : "正式") + "WebSocket地址" + url);
return url;
}
/**
* 微信授权登录
* @return
*/
public static String getWXoppenidUrl(){
String url = USE_TEST_ENV ? WX_TEST_URL : NLS_FORMAL_URL+"/weixin";
System.out.println("微信授权登录当前环境:" + (USE_TEST_ENV ? "测试" : "正式") + "获取oppenid地址" + url);
return url;
}
}

View File

@@ -0,0 +1,29 @@
package com.ruoyi.cms.util;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
/**
* 日期校验工具类
*/
public class DateValidateUtil {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final String ERROR_MSG = "生日格式错误!不为空时必须填写 yyyy-MM-dd 完整格式(如 1991-09-01";
// 改为校验 String 类型
public static String validateBirthDate(String birthDateStr) {
if (birthDateStr == null || birthDateStr.trim().isEmpty()) {
return null; // 为空放行
}
try {
// 严格校验格式:必须是 yyyy-MM-dd且日期合法如 1991-02-30 会失败)
LocalDate.parse(birthDateStr.trim(), FORMATTER);
return null; // 校验通过
} catch (DateTimeParseException e) {
return ERROR_MSG; // 格式错误返回提示
}
}
}

View File

@@ -0,0 +1,78 @@
package com.ruoyi.cms.util;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 分布式唯一 ID 生成工具类(适配 Hutool 5.7.22
* 生成 Long 型 ID适配数据库 bigint 字段,无高版本方法依赖
*/
@Component
public class IdGenerator {
// 雪花算法实例(全局单例)
private Snowflake snowflake;
/**
* 初始化雪花算法Spring 启动时执行,兼容 Hutool 5.7.22
* 核心:用 IP 哈希 + 随机数生成唯一机器码,避免高版本方法依赖
*/
@PostConstruct
public void initSnowflake() {
long workerId = generateWorkerId();
long dataCenterId = generateDataCenterId();
snowflake = IdUtil.createSnowflake(workerId, dataCenterId);
System.out.printf("雪花算法初始化成功workerId=%ddataCenterId=%d%n", workerId, dataCenterId);
}
/**
* 生成 workerId0-31基于本地 IP 哈希,避免重复
*/
private long generateWorkerId() {
try {
// 获取本地 IP 地址(兼容本地开发、服务器环境)
InetAddress localHost = InetAddress.getLocalHost();
String ip = localHost.getHostAddress();
// IP 哈希后取模 32确保在 0-31 范围内
return Math.abs(ip.hashCode()) % 32;
} catch (UnknownHostException e) {
// 异常降级IP 获取失败时用随机数生成0-31
return (long) (Math.random() * 32);
}
}
/**
* 生成 dataCenterId0-31基于系统信息哈希与 workerId 组合确保唯一性
*/
private long generateDataCenterId() {
// 取系统主机名哈希,避免与 workerId 重复
try {
String hostName = InetAddress.getLocalHost().getHostName();
return Math.abs(hostName.hashCode()) % 32;
} catch (UnknownHostException e) {
// 异常降级主机名获取失败时用随机数生成0-31
return (long) (Math.random() * 32);
}
}
/**
* 生成唯一 Long 型 ID适配数据库 bigint
*/
public Long generateId() {
if (snowflake == null) {
throw new RuntimeException("雪花算法未初始化,无法生成 ID");
}
return snowflake.nextId();
}
/**
* 生成 ID 字符串(前端避免精度丢失时使用)
*/
public String generateIdStr() {
return generateId().toString();
}
}

View File

@@ -0,0 +1,17 @@
package com.ruoyi.cms.util;
import javax.servlet.http.HttpServletRequest;
public class ProxyServerUtil {
private static final String PROXY_HEADER = "X-Proxy-Server";
/**
* 从请求头中获取代理服务器标识B或C
* @param request HttpServletRequest
* @return 代理标识(如"proxy-b"、"proxy-c"无则返回null
*/
public static String getProxyServer(HttpServletRequest request) {
// 从请求头中获取自定义标识
return request.getHeader(PROXY_HEADER);
}
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.cms.util;
import com.ruoyi.cms.domain.query.ESJobSearch;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -10,21 +9,84 @@ import java.util.stream.Collectors;
public class StringUtil {
public static final Long COMPANY_ADMIN_ROLE_KEY = 100L;
/*1101(求职者)、1102(招聘者)、1103(网格员)、1104(内部工作者)*/
public static final Long COMPANY_ADMIN_ROLE_KEY = 1102L;
/************************移动端角色开始***************************/
/**
* 企业用户
* 移动端-企业用户
*/
public static final String IS_COMPANY_USER = "0";
/**
* 移动端-求职者
*/
public static final String IS_JOB_REQUEST_USER = "1";
/**
* 移动端-网格员
*/
public static final String IS_GRID_USER = "2";
/**
* 移动端-内部工作者
*/
public static final String IS_INTERNAL_USER = "3";
/************************移动端角色结束***************************/
/**
* pc端-求职者
*/
public static final String SYS_QZZ = "2";
public static final String SYS_QZZ = "1101";
/**
* pc端-企业
*/
public static final String SYS_QY = "100";
public static final String SYS_QY = "1102";
/**
* 互联网用户头
*/
public static final String USER_KEY="hlw_";
/**
* 岗位互联网
*/
public static final String BASE_WW_GW="http://http://222.80.110.161:80/kashi/job-portal/detail/:";
/**
*录用
*/
public static final String HIRE_LY="0";
/**
*录用-系统
*/
public static final String HIRE_SOURCE_SYSTEM="0";
/**
*录用-招聘会
*/
public static final String HIRE_SOURCE_ZPH="1";
/**
* 标记
*/
public static final boolean PATH_TEST_ENV = true;
/**
* 测试环境附件地址
*/
public static final String PATH_DEV = "http://ks.zhaopinzao8dian.com/file/";
/**
* 正式环境环境地址
*/
public static final String PATH_PROXY_37 = "http://10.98.80.37/file/";
/**
* 互联网
*/
public static final String PATH_PROXY_50="http://222.80.110.161:80/file/";
/**
* 经办端
*/
public static final String PATH_PROXY_146="http://10.98.80.146/file/";
/**
* 身份证规则
*/
public static final String SFZ_VALID_REGEX="^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
public static Boolean isEmptyOrNull(String s){
if(Objects.isNull(s)){return true;}
@@ -87,4 +149,38 @@ public class StringUtil {
}
return idCard.substring(0, 4) + "***" + idCard.substring(14);
}
/**
* 获取附件地址
* @return
*/
public static String getFilePath(HttpServletRequest request){
String proxyServer = getProxyServer(request);
if ("proxy-50".equals(proxyServer)) {
return PATH_PROXY_50;
} else if ("proxy-146".equals(proxyServer)) {
return PATH_PROXY_146;
}
return !PATH_TEST_ENV ? PATH_PROXY_37 : PATH_DEV;
}
/**
* 原方法-不传request
* @return
*/
public static String getFilePath(){
return !PATH_TEST_ENV ? PATH_PROXY_37 : PATH_DEV;
}
/**
* 获取nginx地址
* @param request
* @return
*/
private static String getProxyServer(HttpServletRequest request) {
if (request == null) {
return null;
}
return request.getHeader("X-Proxy-Server");
}
}

View File

@@ -249,7 +249,7 @@ public class WechatUtil {
try {
System.out.println("appid==============="+appid);
System.out.println("secret================"+secret);
String response = getAccessData("https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code");
String response = getAccessData(AliyunNlsUtils.getWXoppenidUrl()+"?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code");
JSONObject result = JSONObject.parseObject(response);
// 微信返回错误码处理
if (result.containsKey("errcode") && result.getInteger("errcode") != 0) {

View File

@@ -0,0 +1,215 @@
package com.ruoyi.cms.util.oauth;
import com.alibaba.fastjson2.JSON;
import lombok.Data;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* 简化版 HTTP 客户端工具类仅保留核心POST功能保留超时配置
*/
public class HttpUtils {
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
// 保留默认超时配置
private static final int DEFAULT_CONNECT_TIMEOUT = 10;
private static final int DEFAULT_READ_TIMEOUT = 30;
private static final int DEFAULT_WRITE_TIMEOUT = 30;
// 媒体类型常量
public static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
public static final MediaType FORM_MEDIA_TYPE = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
// OkHttp 客户端(单例)
private static final OkHttpClient OK_HTTP_CLIENT;
static {
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_WRITE_TIMEOUT, TimeUnit.SECONDS);
OK_HTTP_CLIENT = builder.build();
}
/**
* POST JSON请求默认超时
*/
public static String doPostJson(String url, Map<String, Object> params) throws TimeoutException, IOException {
return doPostJson(url, params, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
}
/**
* POST JSON请求自定义超时
*/
public static String doPostJson(String url, Map<String, Object> params, int connectTimeout, int readTimeout, int writeTimeout)
throws TimeoutException, IOException {
String jsonParams = CollectionUtils.isEmpty(params) ? "{}" : JSON.toJSONString(params);
return doPost(url, jsonParams, JSON_MEDIA_TYPE, null, connectTimeout, readTimeout, writeTimeout);
}
/**
* POST JSON请求默认超时支持自定义 headers
*/
public static String doPostJson(String url, Map<String, Object> params, Map<String, String> headers) throws TimeoutException, IOException {
return doPostJson(url, params, headers, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
}
/**
* POST JSON请求自定义超时和 headers
*/
public static String doPostJson(String url, Map<String, Object> params, Map<String, String> headers,
int connectTimeout, int readTimeout, int writeTimeout) throws TimeoutException, IOException {
String jsonParams = CollectionUtils.isEmpty(params) ? "{}" : JSON.toJSONString(params);
return doPost(url, jsonParams, JSON_MEDIA_TYPE, headers, connectTimeout, readTimeout, writeTimeout);
}
/**
* POST 表单请求(默认超时)
*/
public static String doPostForm(String url, Map<String, Object> params) throws TimeoutException, IOException {
return doPostForm(url, params, null, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
}
/**
* POST 表单请求(自定义超时)
*/
public static String doPostForm(String url, Map<String, Object> params, Map<String, String> headers,
int connectTimeout, int readTimeout, int writeTimeout)
throws TimeoutException, IOException {
FormBody.Builder formBuilder = new FormBody.Builder();
if (!CollectionUtils.isEmpty(params)) {
params.forEach((key, value) -> {
if (value != null) {
formBuilder.add(encodeParam(key), value.toString());
}
});
}
RequestBody requestBody = formBuilder.build();
Request.Builder requestBuilder = new Request.Builder()
.url(url)
.post(requestBody)
.header("Content-Type", FORM_MEDIA_TYPE.toString());
addHeaders(requestBuilder, headers);
return executeRequest(requestBuilder.build(), connectTimeout, readTimeout, writeTimeout);
}
/**
* 通用POST方法
*/
private static String doPost(String url, String content, MediaType mediaType, Map<String, String> headers,
int connectTimeout, int readTimeout, int writeTimeout)
throws TimeoutException, IOException {
if (mediaType == null) {
mediaType = JSON_MEDIA_TYPE;
}
RequestBody requestBody = RequestBody.create(mediaType,content);
Request.Builder requestBuilder = new Request.Builder()
.url(url)
.post(requestBody)
.header("Content-Type", mediaType.toString());
addHeaders(requestBuilder, headers);
return executeRequest(requestBuilder.build(), connectTimeout, readTimeout, writeTimeout);
}
/**
* 执行请求核心方法
*/
private static String executeRequest(Request request, int connectTimeout, int readTimeout, int writeTimeout)
throws TimeoutException, IOException {
// 保留超时配置覆盖能力
OkHttpClient tempClient = OK_HTTP_CLIENT.newBuilder()
.connectTimeout(connectTimeout, TimeUnit.SECONDS)
.readTimeout(readTimeout, TimeUnit.SECONDS)
.writeTimeout(writeTimeout, TimeUnit.SECONDS)
.build();
try (Response response = tempClient.newCall(request).execute()) {
return response.body() != null ? response.body().string() : "";
} catch (SocketTimeoutException e) {
throw new TimeoutException(String.format("HTTP 请求超时 | URL: %s | 超时配置: 连接%d秒, 读取%d秒, 写入%d秒",
request.url(), connectTimeout, readTimeout, writeTimeout));
}
}
/**
* 参数编码
*/
private static String encodeParam(String param) {
try {
return URLEncoder.encode(param, "UTF-8");
} catch (Exception e) {
log.warn("参数编码失败 | param: {}", param, e);
return param;
}
}
/**
* 添加请求头
*/
private static void addHeaders(Request.Builder requestBuilder, Map<String, String> headers) {
if (!CollectionUtils.isEmpty(headers)) {
headers.forEach(requestBuilder::header);
}
}
/**************************增加获取cookie开始******************************/
@Data
public static class ResponseWrapper {
private String responseBody; // 响应体字符串
private Map<String, List<String>> headers; // 响应头key: 头名称value: 多个值)
}
// HttpUtils 中新增方法:发送 POST JSON 请求,返回响应体 + 响应头
public static ResponseWrapper doPostJsonWithHeaders(String url, Map<String, Object> params,
int connectTimeout, int readTimeout, int writeTimeout) throws IOException {
String jsonParams = CollectionUtils.isEmpty(params) ? "{}" : JSON.toJSONString(params);
MediaType mediaType = MediaType.parse("application/json");
RequestBody requestBody = RequestBody.create(mediaType, jsonParams);
// 构建 OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(connectTimeout, TimeUnit.SECONDS)
.readTimeout(readTimeout, TimeUnit.SECONDS)
.writeTimeout(writeTimeout, TimeUnit.SECONDS)
.build();
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
// 执行请求,获取响应体和响应头
try (Response response = client.newCall(request).execute()) {
String responseBody = response.body() != null ? response.body().string() : "";
Map<String, List<String>> headers = new HashMap<>();
for (String headerName : response.headers().names()) {
headers.put(headerName, response.headers(headerName));
}
// 封装并返回
ResponseWrapper wrapper = new ResponseWrapper();
wrapper.setResponseBody(responseBody);
wrapper.setHeaders(headers);
return wrapper;
}
}
/**************************增加获取cookie结束******************************/
}

View File

@@ -0,0 +1,489 @@
package com.ruoyi.cms.util.oauth;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.ruoyi.common.core.domain.entity.tymh.authority.QxUserRole;
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwTokenResult;
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwUserInfoResult;
import com.ruoyi.common.core.domain.entity.tymh.wwToken.WwTokenResult;
import com.ruoyi.common.core.domain.entity.tymh.wwToken.WwTyInfo;
import com.ruoyi.common.core.domain.entity.tymh.wwToken.WwUserLogin;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.crypto.CryptoUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* OAuth2.0 认证工具类(合并相似方法)
*/
@Component
public class OauthClient {
private static final Logger log = LoggerFactory.getLogger(OauthClient.class);
/*====================== 内网 ======================*/
@Value("${oauth.usptnw.nwGatewayGetTokenUrl}")
private String nwGatewayGetTokenUrl;
@Value("${oauth.usptnw.nwGatewayGetUserInfoUrl}")
private String nwGatewayGetUserInfoUrl;
/*====================== 外网 ======================*/
@Value("${oauth.usptww.wwRegisterPostUrl}")
private String wwRegisterPostUrl;
@Value("${oauth.usptww.wwTokenPostUrl}")
private String wwTokenPostUrl;
@Value("${oauth.usptww.wwQueryWebUserInfo}")
private String wwQueryWebUserInfo;
@Value("${oauth.usptww.wwQueryWebPersonalInfoPostUrl}")
private String wwQueryWebPersonalInfoPostUrl;
@Value("${oauth.usptww.wwQueryWebEnterpriseInfoPostUrl}")
private String wwQueryWebEnterpriseInfoPostUrl;
/*====================== 统一门户 ======================*/
@Value("${oauth.tyAddUserUrl}")
private String tyAddUserUrl;
@Value("${oauth.tyQueryUserSysListUrl}")
private String tyQueryUserSysListUrl;
@Value("${oauth.tyQueryUserRoleListUrl}")
private String tyQueryUserRoleListUrl;
@Value("${oauth.tyQueryRoleInfoUrl}")
private String tyQueryRoleInfoUrl;
@Value("${oauth.tyQueryUserInfo}")
private String tyQueryUserInfo;
@Value("${oauth.tyQueryUnitInfo}")
private String tyQueryUnitInfo;
@Value("${oauth.appid}")
private String appid;
@Value("${oauth.clientsecretkey}")
private String clientsecretkey;
@Value("${oauth.connect-timeout:10}")
private int connectTimeout;
@Value("${oauth.read-timeout:30}")
private int readTimeout;
@Value("${oauth.write-timeout:30}")
private int writeTimeout;
@Autowired
private RedisCache redisCache;
private final String MH_JBD_TOKEN="mhjdb:token:";
/**
* 获取经办段token
*/
public NwTokenResult nwGetToken(String code) throws IOException, TimeoutException {
if (StringUtils.isEmpty(code)) {
log.error("获取Token失败授权码code不能为空");
throw new IllegalArgumentException("授权码code不能为空");
}
String decryptedCode;
try {
decryptedCode = CryptoUtil.sm2Decrypt(clientsecretkey, code);
if (StringUtils.isEmpty(decryptedCode)) {
throw new RuntimeException("授权码解密后为空");
}
} catch (Exception e) {
log.error("授权码解密失败 | 原始code: {}", code, e);
throw new RuntimeException("授权码解密失败:" + e.getMessage(), e);
}
//判断redis中是否存在获取token
String redisKey=MH_JBD_TOKEN+decryptedCode;
NwTokenResult cacheResult=redisCache.getCacheObject(redisKey);
if(cacheResult!=null){
long ttlSeconds = redisCache.getExpire(redisKey);
if (ttlSeconds > 60) {
return cacheResult;
} else {
redisCache.deleteObject(redisKey);
throw new RuntimeException("令牌剩余时间不足(" + ttlSeconds + "秒),已清理旧数据");
}
}
Map<String, Object> params = new HashMap<>(2);
params.put("appid", appid);
params.put("code", decryptedCode);
NwTokenResult result = executePostRequest(
nwGatewayGetTokenUrl,
params,
new TypeReference<Response<NwTokenResult>>() {},
"获取Token"
);
if (StringUtils.isEmpty(result.getAccessToken())) {
redisCache.deleteObject(decryptedCode);
throw new RuntimeException("Token获取失败返回的accessToken为空");
}
redisCache.setCacheObject(redisKey,result,safeLongToInt(result.getExpiresIn()), TimeUnit.MINUTES);
return result;
}
/**
* 获取经办段用户id
*/
public NwUserInfoResult nwGetUserInfo(String accessToken) throws IOException, TimeoutException {
Map<String, Object> params = new HashMap<>(2);
params.put("appid", appid);
params.put("access_token", accessToken);
return executePostRequest(
nwGatewayGetUserInfoUrl,
params,
new TypeReference<Response<NwUserInfoResult>>() {},
"获取用户信息"
);
}
/**
* 根据用户id查询用户角色列表
* @param userid
* @return
* @throws IOException
* @throws TimeoutException
*/
public List<QxUserRole> getUserRoleList(Long userid) throws IOException, TimeoutException {
Map<String, Object> params = new HashMap<>(2);
params.put("appid", appid);
params.put("userid", String.valueOf(userid));
return executePostRequestResultList(
tyQueryUserRoleListUrl,
params,
QxUserRole.class,
"根据用户id获取用户角色列表"
);
}
/**
* 公共POST请求执行方法
*/
private <T> T executePostRequest(String url, Map<String, Object> params,
TypeReference<Response<T>> typeReference, String operationName)
throws IOException, TimeoutException {
String responseJson = HttpUtils.doPostJson(
url,
params,
connectTimeout,
readTimeout,
writeTimeout
);
return validateResponse(responseJson, operationName, typeReference);
}
/**
* 公共POST请求执行方法处理List
*/
private <T> List<T> executePostRequestResultList(String url, Map<String, Object> params,
Class<T> clazz, String operationName)
throws IOException, TimeoutException {
String responseJson = HttpUtils.doPostJson(
url,
params,
connectTimeout,
readTimeout,
writeTimeout
);
return parseMapOrDataArray(responseJson, operationName, clazz);
}
/**
* 传递heades
* @param url
* @param params
* @param typeReference
* @param operationName
* @return
* @param <T>
* @throws IOException
* @throws TimeoutException
*/
private <T> T executePostRequestHeaders(String url, Map<String, Object> params,Map<String,String> headers,
TypeReference<Response<T>> typeReference, String operationName)
throws IOException, TimeoutException {
String responseJson = HttpUtils.doPostJson(
url,
params,
headers,
connectTimeout,
readTimeout,
writeTimeout
);
return validateResponse(responseJson, operationName, typeReference);
}
/**
* 简化后的响应校验方法(已移除网关返回码判断)
*/
private <T> T validateResponse(String responseJson, String operationName, TypeReference<Response<T>> typeReference) {
// 1. 校验响应空值
if (StringUtils.isEmpty(responseJson)) {
String errorMsg = operationName + "失败:接口返回空";
log.error(errorMsg);
throw new RuntimeException(errorMsg);
}
log.debug("{}返回数据: {}", operationName, responseJson);
// 2. 解析响应并校验基础格式
Response<T> gatewayResponse = JSON.parseObject(responseJson, typeReference);
if (gatewayResponse == null) {
String errorMsg = operationName + "失败:响应格式错误";
log.error("{} | 原始响应: {}", errorMsg, responseJson);
throw new RuntimeException(errorMsg);
}
// 3. 校验业务数据移除了网关appcode的判断逻辑
T data = gatewayResponse.getData();
if (data == null) {
String errorMsg = operationName + "失败:业务数据为空";
log.error("{} | 原始响应: {}", errorMsg, responseJson);
throw new RuntimeException(errorMsg);
}
return data;
}
/**
* 解析List
* @param jsonStr
* @param clazz
* @return
*/
public static <T> List<T> parseMapOrDataArray(String jsonStr, String operationName, Class<T> clazz) {
if (StringUtils.isEmpty(jsonStr)) {
String errorMsg = operationName + "失败:接口返回空";
log.error(errorMsg);
throw new RuntimeException(errorMsg);
}
JSONObject jsonObject;
try {
jsonObject = JSON.parseObject(jsonStr);
} catch (Exception e) {
String errorMsg = operationName + "失败:响应格式错误(非合法 JSON";
log.error("{} | 原始响应: {}", errorMsg, jsonStr, e);
throw new RuntimeException(errorMsg, e);
}
if (jsonObject == null) {
String errorMsg = operationName + "失败:响应格式错误(解析后为 null";
log.error("{} | 原始响应: {}", errorMsg, jsonStr);
throw new RuntimeException(errorMsg);
}
JSONArray targetArray = getJSONArraySafe(jsonObject, "map");
if (targetArray == null || targetArray.isEmpty()) {
targetArray = getJSONArraySafe(jsonObject, "data");
}
if (targetArray == null || targetArray.isEmpty()) {
String errorMsg = operationName + "失败业务数据为空map/data 字段无有效数组)";
log.error("{} | 原始响应: {}", errorMsg, jsonStr);
throw new RuntimeException(errorMsg);
}
List<T> dataList;
try {
dataList = JSON.parseArray(targetArray.toJSONString(), clazz);
} catch (Exception e) {
String errorMsg = operationName + "失败:数据解析失败(数组元素与目标类不匹配)";
log.error("{} | 原始响应: {} | 目标类: {}", errorMsg, jsonStr, clazz.getName(), e);
throw new RuntimeException(errorMsg, e);
}
if (dataList == null || dataList.isEmpty()) {
String errorMsg = operationName + "失败:解析后业务数据为空";
log.error("{} | 原始响应: {}", errorMsg, jsonStr);
throw new RuntimeException(errorMsg);
}
return dataList;
}
/**
* 避免空值和类型转换异常
* @param jsonObject
* @param key
* @return
*/
private static JSONArray getJSONArraySafe(JSONObject jsonObject, String key) {
if (jsonObject == null || StringUtils.isEmpty(key)) {
return null;
}
if (!jsonObject.containsKey(key)) {
return null;
}
Object value = jsonObject.get(key);
return (value instanceof JSONArray) ? (JSONArray) value : null;
}
/**
* 从响应头中提取Cookie工具方法
*/
private String extractCookieFromHeaders(Map<String, List<String>> headers) {
if (headers == null || headers.isEmpty()) {
log.warn("响应头为空无法提取Cookie");
return "";
}
List<String> cookies = headers.get("Set-Cookie");
if (cookies == null || cookies.isEmpty()) {
log.warn("响应头中未包含Set-Cookie信息");
return "";
}
// 拼接Cookie只保留name=value部分忽略路径、过期时间等附加信息
StringBuilder cookieSb = new StringBuilder();
for (String cookie : cookies) {
if (cookieSb.length() > 0) {
cookieSb.append("; ");
}
int semicolonIndex = cookie.indexOf(';');
if (semicolonIndex > 0) {
cookieSb.append(cookie.substring(0, semicolonIndex));
} else {
cookieSb.append(cookie);
}
}
return cookieSb.toString();
}
/**
* 互联网-获取token
* @param wwUserLogin
* @return
* @throws Exception
*/
public WwTokenResult wwGetToken(WwUserLogin wwUserLogin) throws Exception {
if (wwUserLogin == null) {
log.error("获取互联网Token失败登录参数不能为空");
throw new IllegalArgumentException("登录参数不能为空");
}
if (StringUtils.isEmpty(wwUserLogin.getUsername())) {
log.error("获取互联网Token失败身份证号/统一社会信用代码不能为空");
throw new IllegalArgumentException("身份证号/统一社会信用代码不能为空");
}
if (StringUtils.isEmpty(wwUserLogin.getUsertype())) {
log.error("获取互联网Token失败用户类型usertype不能为空");
throw new IllegalArgumentException("用户类型usertype不能为空");
}
Map<String, Object> params = new HashMap<>(4);
params.put("username", wwUserLogin.getUsername());
params.put("usertype", wwUserLogin.getUsertype());
if (StringUtils.isNotEmpty(wwUserLogin.getLogontype())) {
params.put("logontype", wwUserLogin.getLogontype());
}
if (StringUtils.isNotEmpty(wwUserLogin.getLogonchannel())) {
params.put("logonchannel", wwUserLogin.getLogonchannel());
}
// 发送请求并获取响应体+响应头包含Cookie
HttpUtils.ResponseWrapper responseWrapper = HttpUtils.doPostJsonWithHeaders(
wwTokenPostUrl,
params,
connectTimeout,
readTimeout,
writeTimeout
);
String responseJson = responseWrapper.getResponseBody();
WwTokenResult tokenResult = validateResponse(
responseJson,
"获取互联网Token",
new TypeReference<Response<WwTokenResult>>() {}
);
if (tokenResult == null) {
log.error("获取互联网Token失败接口返回业务数据为空");
throw new Exception("获取互联网Token失败返回数据异常");
}
// 提取Cookie并设置到tokenResult中
String cookie = extractCookieFromHeaders(responseWrapper.getHeaders());
tokenResult.setSessionCookie(cookie);
log.info("获取互联网Token及Cookie成功 | username{} | accessToken{} | cookie{}",
wwUserLogin.getUsername(), tokenResult.getAccessToken(), cookie);
return tokenResult;
}
/**
* 互联网-端根据token获取用户信息
* @return
* @throws IOException
* @throws TimeoutException
*/
public WwTyInfo wwGetUserInfo(WwTokenResult wwTokenResult) throws IOException, TimeoutException{
if(wwTokenResult==null){
throw new IllegalArgumentException("wwTokenResult不能为空");
}
//headers
Map<String, String> headers = new HashMap<>();
/*headers.put("Access-Token", wwTokenResult.getAccessToken());
headers.put("Cookie", wwTokenResult.getSessionCookie());*/
//parm
Map<String, Object> params = new HashMap<>(1);
params.put("Access-Token",wwTokenResult.getAccessToken());
return executePostRequestHeaders(
wwQueryWebUserInfo,
params,
headers,
new TypeReference<OauthClient.Response<WwTyInfo>>() {},
"获取互联网用户信息"
);
}
/**
* Long 转 int
*/
private int safeLongToInt(Long value) {
if (value == null) {
throw new ServiceException("门户 Token 有效期不能为空");
}
// 校验是否超过 int 最大值(实际场景几乎不会触发)
if (value > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
// 校验是否为负数(无效有效期)
if (value < 0) {
throw new ServiceException("门户 Token 有效期不能为负数");
}
return value.intValue();
}
/**
* 静态返回解析
* @param <T>
*/
public static class Response<T> {
private String appcode;
private String msg;
private T data;
public String getAppcode() { return appcode; }
public String getMsg() { return msg; }
public T getData() { return data; }
public void setAppcode(String appcode) { this.appcode = appcode; }
public void setMsg(String msg) { this.msg = msg; }
public void setData(T data) { this.data = data; }
}
}

View File

@@ -31,7 +31,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectNoticeVo"/>
<where>
<if test="noticeTitle != null and noticeTitle != ''">
AND notice_title like concat('%', #{noticeTitle}, '%')
AND notice_title like concat('%', cast(#{noticeTitle, jdbcType=VARCHAR} as varchar), '%')
</if>
<if test="noticeType != null and noticeType != ''">
AND notice_type = #{noticeType}

View File

@@ -44,11 +44,21 @@
</select>
<select id="selectAppReviewJobListJob" parameterType="AppReviewJob" resultType="com.ruoyi.cms.domain.Job">
select b.*,a.review_date as shareTime from app_review_job a inner join job b on a.job_id=b.job_id and b.del_flag='0'
select distinct b.*,a.review_date as shareTime from app_review_job a inner join job b on a.job_id=b.job_id and b.del_flag='0'
inner join (select user_id, job_id, max(review_date) as max_review_date from app_review_job
where del_flag = '0'
<if test="jobId != null ">and job_id = #{jobId}</if>
<if test="userId != null ">and user_id = #{userId}</if>
group by user_id, job_id
) as max_date
on a.user_id = max_date.user_id
and a.job_id = max_date.job_id
and a.review_date = max_date.max_review_date
<where> a.del_flag = '0'
<if test="jobId != null "> and a.job_id = #{jobId}</if>
<if test="userId != null "> and a.user_id = #{userId}</if>
</where>
order by a.review_date desc
</select>
</mapper>

View File

@@ -27,6 +27,7 @@
<where> del_flag = '0'
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
<if test="levels != null and levels != ''"> and levels = #{levels}</if>
<if test="userId != null and userId != ''"> and user_id = #{userId}</if>
</where>
</select>

View File

@@ -40,7 +40,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectAppUserList" parameterType="AppUser" resultMap="AppUserResult">
<include refid="selectAppUserVo"/>
<where> del_flag = '0'
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
<if test="name != null and name != ''"> and name like concat('%', cast(#{name, jdbcType=VARCHAR} as varchar), '%')</if>
<if test="age != null and age != ''"> and age = #{age}</if>
<if test="sex != null and sex != ''"> and sex = #{sex}</if>
<if test="birthDate != null "> and birth_date = #{birthDate}</if>
@@ -115,4 +115,32 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
CROSS JOIN (SELECT COUNT(user_id) AS ytd FROM job_apply WHERE user_id = #{userId} AND del_flag = '0') t3
</select>
<select id="selectSysUserIdcard" resultType="com.ruoyi.common.core.domain.entity.SysUser">
select * from sys_user where del_flag='0'
<if test="idCard!=null and idCard!=''">
and id_card=#{idCard}
</if>
limit 1
</select>
<select id="selectUserApplyList" parameterType="AppUser" resultType="com.ruoyi.common.core.domain.entity.AppUserShow">
select a.user_id , a.name , a.age , a.sex , get_birth_date_from_id_card ( a.id_card ) as birth_date ,
a.education , a.political_affiliation , a.phone , a.avatar , c.min_salary salaryMin ,c.max_salary salaryMax,a.area ,a.id_card ,
b.job_id ,c.job_title,e.name as company_name,b.hire,b.hire_source,b.create_time,e.company_id,b.id as apply_id
from app_user a
inner join job_apply b on a.user_id = b.user_id and a.del_flag = '0' and b.del_flag = '0'
INNER join job c on b.job_id=c.job_id and c.del_flag='0'
INNER join company e on c.company_id=e.company_id and e.del_flag='0'
<where>
<if test="name != null and name != ''"> and a.name like concat('%', cast(#{name, jdbcType=VARCHAR} as varchar), '%')</if>
<if test="birthDate != null "> and get_birth_date_from_id_card(a.id_card) = #{birthDate}</if>
<if test="education != null and education != ''"> and a.education = #{education}</if>
<if test="politicalAffiliation != null and politicalAffiliation != ''"> and a.political_affiliation = #{politicalAffiliation}</if>
<if test="phone != null and phone != ''"> and a.phone = #{phone}</if>
<if test="idCard != null and idCard != ''"> and a.id_card like concat('%', CAST(#{idCard} AS VARCHAR), '%')</if>
<if test="userId != null"> and a.user_id = #{userId}</if>
</where>
order by b.create_time desc
</select>
</mapper>

View File

@@ -32,7 +32,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND dict_type = #{dictType}
</if>
<if test="dictLabel != null and dictLabel != ''">
AND dict_label like concat('%', #{dictLabel}, '%')
AND dict_label like concat('%', cast(#{dictLabel, jdbcType=VARCHAR} as varchar), '%')
</if>
<if test="status != null and status != ''">
AND status = #{status}

View File

@@ -42,6 +42,7 @@
<select id="getList" resultMap="bussinessDictJobCategoryResult" parameterType="bussinessDictJobCategory">
<include refid="selectBussinessDictJobCategoryVo"/>
<include refid="findPage_where" />
limit 50
</select>
</mapper>

View File

@@ -28,13 +28,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</where>
</select>
<select id="collectionJob" resultType="com.ruoyi.common.core.domain.entity.Company">
select *
from company
where del_flag = '0'
and company_id in (SELECT DISTINCT (company_id)
FROM company_collection
where del_flag = '0' and user_id = #{userId}
order by create_time desc)
select c.* from company c
JOIN ( SELECT company_id, MAX(create_time) as collect_time
FROM company_collection
where del_flag = '0' and user_id = #{userId}
GROUP BY company_id
) as cc on c.company_id = cc.company_id
where c.del_flag = '0'
ORDER BY cc.collect_time desc
</select>
<select id="selectAppuserList" resultType="com.ruoyi.common.core.domain.entity.AppUser">

View File

@@ -26,4 +26,62 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="bussinessid != null "> and bussinessid = #{bussinessid}</if>
</where>
</select>
<update id="updateBussinessids">
update file
<if test="newBussinessid != null">
set bussinessid = #{newBussinessid}
</if>
<if test="newBussinessid == null">
set bussinessid = bussinessid
where 1 = 2
</if>
where
<if test="longs != null and longs.size() > 0">
bussinessid in (
<foreach collection="longs" item="oldId" separator=",">
#{oldId}
</foreach>
)
</if>
<if test="longs == null or longs.size() == 0">
1 = 2
</if>
</update>
<select id="selectFileListByBussinessIds" resultMap="FileResult">
<include refid="selectFileVo"/>
<where> del_flag = '0'
<if test="longs != null and longs.size() > 0">
and bussinessid in (
<foreach collection="longs" item="oldId" separator=",">
#{oldId}
</foreach>
)
</if>
</where>
</select>
<update id="updateIds">
update file
<if test="newBussinessid != null">
set bussinessid = #{newBussinessid}
</if>
<if test="newBussinessid == null">
set bussinessid = bussinessid
where 1 = 2
</if>
where
<if test="longs != null and longs.size() > 0">
id in (
<foreach collection="longs" item="oldId" separator=",">
#{oldId}
</foreach>
)
</if>
<if test="longs == null or longs.size() == 0">
1 = 2
</if>
</update>
</mapper>

View File

@@ -15,6 +15,8 @@
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<result property="hire" column="hire" />
<result property="hireSource" column="hire_source" />
</resultMap>
<sql id="selectJobApplyVo">
@@ -124,4 +126,8 @@
</where>
</select>
<update id="updateJobZphApply" parameterType="JobApply">
update job_apply set update_time=sysdate(),update_by=#{updateBy},hire=#{hire},hire_source=#{hireSource} where user_id=#{userId} AND job_id=#{jobId}
</update>
</mapper>

View File

@@ -28,14 +28,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</where>
</select>
<select id="collectionJob" resultType="com.ruoyi.cms.domain.Job">
select *
from job
where del_flag = '0'
and is_publish = 1
and job_id in (SELECT DISTINCT (job_id)
FROM job_collection
where del_flag = '0' and user_id = #{userId}
order by create_time desc)
select j.* from job j
JOIN ( SELECT job_id, MAX(create_time) as collect_time
FROM job_collection
where del_flag = '0' and user_id = #{userId}
GROUP BY job_id ) as c on j.job_id = c.job_id
where j.del_flag = '0' and j.is_publish = 1
ORDER BY c.collect_time desc
</select>
<select id="selectJobCollectionListJob" parameterType="JobCollection" resultType="com.ruoyi.cms.domain.Job">

View File

@@ -55,4 +55,22 @@
</foreach>
</insert>
<select id="selectByJobIds" parameterType="java.util.List" resultMap="jobContactResult">
<include refid="JobContactVo"/>
<where> del_flag = '0'
<if test="jobIds != null and jobIds.size() > 0">
AND job_id IN (
<foreach collection="jobIds" item="jobId" separator=",">
<if test="jobId != null">
#{jobId}
</if>
</foreach>
)
</if>
<if test="jobIds == null or jobIds.size() == 0">
AND 1 = 0
</if>
</where>
</select>
</mapper>

View File

@@ -30,7 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectJobFairList" parameterType="JobFair" resultMap="JobFairResult">
<include refid="selectJobFairVo"/>
<where> del_flag = '0'
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
<if test="name != null and name != ''"> and name like concat('%', cast(#{name, jdbcType=VARCHAR} as varchar), '%')</if>
<if test="jobFairType != null and jobFairType != ''"> and job_fair_type = #{jobFairType}</if>
<if test="location != null and location != ''"> and location = #{location}</if>
<if test="latitude != null "> and latitude = #{latitude}</if>

View File

@@ -34,6 +34,7 @@
<result property="explainUrl" column="explain_url" />
<result property="cover" column="cover" />
<result property="jobType" column="job_type" />
<result property="jobAddress" column="job_address" />
</resultMap>
@@ -77,6 +78,7 @@
<result property="scale" column="scale" />
<result property="companyNature" column="company_nature" />
<result property="code" column="code" />
<result property="jobAddress" column="job_address" />
<association property="companyVo" resultMap="CompanyResult"/>
</resultMap>
@@ -95,7 +97,7 @@
</resultMap>
<sql id="selectJobVo">
select job_id, job_title, min_salary, max_salary, education, experience, company_name, job_location, posting_date, vacancies, del_flag, create_by, create_time, update_by, update_time, remark, latitude, longitude, "view", company_id , is_hot ,apply_num,is_publish, description,job_location_area_code,data_source,job_url,job_category,is_explain,explain_url,cover,job_type from job
select job_id, job_title, min_salary, max_salary, education, experience, company_name, job_location, posting_date, vacancies, del_flag, create_by, create_time, update_by, update_time, remark, latitude, longitude, "view", company_id , is_hot ,apply_num,is_publish, description,job_location_area_code,data_source,job_url,job_category,is_explain,explain_url,cover,job_type,job_address from job
</sql>
<insert id="insertBatchRowWork">
INSERT INTO row_work (
@@ -125,7 +127,7 @@
job_title, min_salary, max_salary, education, experience, company_name, job_location,
job_location_area_code, posting_date, vacancies, latitude, longitude, "view", company_id,
is_hot, apply_num, description, is_publish, data_source, job_url, remark, del_flag,
create_by, create_time, row_id, job_category,jobType
create_by, create_time, row_id, job_category,jobType,job_address
) VALUES
<foreach collection="list" item="job" separator=",">
(
@@ -134,7 +136,7 @@
#{job.vacancies}, #{job.latitude}, #{job.longitude}, #{job.view}, #{job.companyId},
#{job.isHot}, #{job.applyNum}, #{job.description}, #{job.isPublish}, #{job.dataSource},
#{job.jobUrl}, #{job.remark}, #{job.delFlag}, #{job.createBy}, #{job.createTime},
#{job.rowId}, #{job.jobCategory},#{job.jobType}
#{job.rowId}, #{job.jobCategory},#{job.jobType},#{job.jobAddress}
)
</foreach>
</insert>
@@ -275,7 +277,8 @@
<select id="selectAllJob" resultMap="JobEsResult">
SELECT j.*,c.industry,c.scale,c.nature as company_nature,c.code,c.description as company_description,c.name,c.company_id,t.contact_person,t.contact_person_phone FROM job as j
left join company as c on c.company_id = j.company_id and j.del_flag='0' and c.del_flag='0'
left join company_contact as t on t.company_id=j.company_id and t.del_flag='0' limit #{offset},#{batchSize}
LEFT JOIN (SELECT t1.*, ROW_NUMBER() OVER (PARTITION BY t1.company_id ORDER BY t1.id) AS rn FROM company_contact AS t1 WHERE t1.del_flag = '0' ) AS t
ON t.company_id = j.company_id AND t.rn = 1 WHERE j.del_flag = '0' AND c.del_flag = '0' limit #{offset},#{batchSize}
</select>
<select id="selectAllInsertRowWork" resultType="com.ruoyi.cms.domain.RowWork">
select Id, TaskId, TaskName, Std_class, SF, ZCMC, Aca112, Acb22a, Aac011, Acb240,
@@ -292,7 +295,7 @@
</select>
<select id="selectVectorJob" resultType="com.ruoyi.cms.domain.VectorJob">
SELECT
ANY_VALUE(job_id) as job_id,
j.job_id,
j.job_title,
ed.dict_label as education,
ex.dict_label as experience,
@@ -302,15 +305,15 @@
ar.dict_label as area,
ab.dict_label as nature,
ac.dict_label as scale,
concat(j.min_salary,"元-",j.max_salary,"元") as salary
concat(j.min_salary,'元-',j.max_salary,'元') as salary
FROM
job as j
inner join company as c on c.company_id = j.company_id
inner join qd.bussiness_dict_data as ed on ed.dict_type = 'education' and ed.dict_value = j.education
inner join qd.bussiness_dict_data as ex on ex.dict_type = 'experience' and ex.dict_value = j.experience
left join qd.bussiness_dict_data as ar on ar.dict_type = 'area' and ar.dict_value = j.job_location_area_code
left join qd.bussiness_dict_data as ab on ab.dict_type = 'company_nature' and ab.dict_value = c.nature
left join qd.bussiness_dict_data as ac on ac.dict_type = 'scale' and ac.dict_value = c.scale
inner join bussiness_dict_data as ed on ed.dict_type = 'education' and ed.dict_value = j.education
inner join bussiness_dict_data as ex on ex.dict_type = 'experience' and ex.dict_value = j.experience
left join bussiness_dict_data as ar on ar.dict_type = 'area' and ar.dict_value = j.job_location_area_code
left join bussiness_dict_data as ab on ab.dict_type = 'company_nature' and ab.dict_value = c.nature
left join bussiness_dict_data as ac on ac.dict_type = 'scale' and ac.dict_value = c.scale
where job_id =#{jobId}
</select>
@@ -328,4 +331,22 @@
left join company as c on c.company_id = j.company_id and j.del_flag='0' and j.job_id=#{jobId}
and c.del_flag='0' limit 1
</select>
<select id="getTotals" parameterType="Job" resultType="java.lang.Integer">
select count(job_id) as total_count from job
<where> del_flag = '0'
<if test="companyName != null and companyName != ''"> and company_name =#{companyName}</if>
<if test="dataSource != null and dataSource!='' "> and data_source = #{dataSource}</if>
<if test="description != null and description!='' "> and description = #{description}</if>
<if test="education != null and education != ''"> and education = #{education}</if>
<if test="experience != null and experience != ''"> and experience = #{experience}</if>
<if test="isPublish != null "> and is_publish = #{isPublish}</if>
<if test="jobLocation != null and jobLocation != ''"> and job_location = #{jobLocation}</if>
<if test="jobTitle != null and jobTitle != ''"> and job_title = #{jobTitle}</if>
<if test="minSalary != null "> and min_salary = #{minSalary}</if>
<if test="maxSalary != null "> and max_salary = #{maxSalary}</if>
<if test="vacancies != null "> and vacancies = #{vacancies}</if>
</where>
</select>
</mapper>

View File

@@ -25,7 +25,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectJobTitleVo"/>
<where> del_flag = '0'
<if test="parentId != null "> and parent_id = #{parentId}</if>
<if test="jobName != null and jobName != ''"> and job_name like concat('%', #{jobName}, '%')</if>
<if test="jobName != null and jobName != ''"> and job_name like concat('%', cast(#{jobName, jdbcType=VARCHAR} as varchar), '%')</if>
<if test="orderNum != null "> and order_num = #{orderNum}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
</where>

View File

@@ -24,7 +24,7 @@
<select id="selectSensitiveworddataList" resultMap="sensitiveWordDataResult" parameterType="SensitiveWordData">
<include refid="sensitiveWordDataVo"/>
<where> del_flag = '0'
<if test="sensitiveWord != null and sensitiveWord != ''"> and sensitive_word like concat('%', #{sensitiveWord}, '%')</if>
<if test="sensitiveWord != null and sensitiveWord != ''"> and sensitive_word like concat('%', cast(#{sensitiveWord, jdbcType=VARCHAR} as varchar), '%')</if>
<if test="type != null and type != ''"> and type = #{type}</if>
</where>
</select>

View File

@@ -34,7 +34,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectSubwayLineList" parameterType="SubwayLine" resultMap="SubwayLineResult">
<include refid="selectSubwayLineVo"/>
<where> del_flag = '0'
<if test="lineName != null and lineName != ''"> and line_name like concat('%', #{lineName}, '%')</if>
<if test="lineName != null and lineName != ''"> and line_name like concat('%', cast(#{lineName, jdbcType=VARCHAR} as varchar), '%')</if>
</where>
</select>
<select id="appSubway" resultMap="SubwayLineStationResult">

View File

@@ -0,0 +1,18 @@
<?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.WechatGroupMapper">
<select id="selectWechatGroupList" resultType="com.ruoyi.cms.domain.vo.WechatGroupVo">
select g.create_time, g.id, g.name, g.is_push, u.wechat_name, u.phone_number, u.id communityId
from wechat_group g join community_user u on g.community_id = u.id
where g.del_flag = 0 and u.del_flag = 0
<if test="p.name != null and p.name != ''">
and g.name like '%' || #{p.name} || '%'
</if>
<if test="p.isPush != null">
and g.is_push = #{p.isPush}
</if>
</select>
</mapper>

View File

@@ -68,7 +68,7 @@ public class UserConstants
* 用户名长度限制
*/
public static final int USERNAME_MIN_LENGTH = 2;
public static final int USERNAME_MAX_LENGTH = 20;
public static final int USERNAME_MAX_LENGTH = 50;
/**
* 密码长度限制

View File

@@ -14,6 +14,8 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseEntity;
import org.springframework.format.annotation.DateTimeFormat;
/**
* APP用户对象 app_user
* @author lishundong
@@ -43,10 +45,11 @@ public class AppUser extends BaseEntity
@ApiModelProperty("用户性别0男 1女对应字典sex")
private String sex;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd")
@ApiModelProperty("生日")
private LocalDate birthDate;
private String birthDate;
@Excel(name = "学历 对应字典education")
@ApiModelProperty("学历 对应字典education")
@@ -153,4 +156,10 @@ public class AppUser extends BaseEntity
@ApiModelProperty("一体机密码")
private String ytjPassword;
@ApiModelProperty("地址")
private String address;
@ApiModelProperty("户籍地址")
private String domicileAddress;
}

View File

@@ -0,0 +1,149 @@
package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
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.time.LocalDate;
import java.util.List;
/**
* APP用户对象 app_user
* @author lishundong
* @date 2024-09-03
*/
@Data
@ApiModel("APP用户Show")
public class AppUserShow extends BaseEntity
{
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@TableId(value = "user_id",type = IdType.AUTO)
@ApiModelProperty("用户ID")
private Long userId;
@Excel(name = "用户名称")
@ApiModelProperty("用户名称")
private String name;
@Excel(name = "年龄段 对应字典age")
@ApiModelProperty("年龄段 对应字典age")
private String age;
@Excel(name = "用户性别", readConverterExp = "0=男,1=女")
@ApiModelProperty("用户性别0男 1女对应字典sex")
private String sex;
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd")
@ApiModelProperty("生日")
private LocalDate birthDate;
@Excel(name = "学历 对应字典education")
@ApiModelProperty("学历 对应字典education")
private String education;
@Excel(name = "政治面貌")
@ApiModelProperty("政治面貌")
private String politicalAffiliation;
@Excel(name = "手机号码")
@ApiModelProperty("手机号码")
private String phone;
@Excel(name = "头像地址")
@ApiModelProperty("头像地址")
private String avatar;
@Excel(name = "最低工资")
@ApiModelProperty("最低工资")
private String salaryMin;
@Excel(name = "最高工资")
@ApiModelProperty("最高工资")
private String salaryMax;
@Excel(name = "期望工作地 对应字典area")
@ApiModelProperty("期望工作地 对应字典area")
private String area;
@ApiModelProperty("期望岗位,逗号分隔")
private String jobTitleId;
@ApiModelProperty("期望薪资")
private String experience;
@ApiModelProperty("是否开启推荐0不推荐 1推荐")
private Integer isRecommend;
@ApiModelProperty("身份证")
private String idCard;
/**
* 是否企业用户 0是1否改为0企业1求职者2网格员
*/
@ApiModelProperty("app角色0企业1求职者2网格员 3内部政府人员")
private String isCompanyUser;
@ApiModelProperty("民族")
private String nation;
@ApiModelProperty("工作经验")
private String workExperience;
@TableField(exist = false)
@ApiModelProperty("工作经历列表")
private List<UserWorkExperiences> experiencesList;
@TableField(exist = false)
@ApiModelProperty("技能列表")
private List<AppSkill> appSkillsList;
@TableField(exist = false)
@ApiModelProperty("附件列表")
private List<File> fileList;
@ApiModelProperty("一体机密码")
private String ytjPassword;
@ApiModelProperty("地址")
private String address;
@ApiModelProperty("户籍地址")
private String domicileAddress;
@TableField(exist = false)
@ApiModelProperty("录用来源 0本系统1招聘会")
private String hireSource;
@TableField(exist = false)
@ApiModelProperty("录用状态0 2或null未录用")
private String hire;
@TableField(exist = false)
@ApiModelProperty("企业名称")
private String companyName;
@TableField(exist = false)
@ApiModelProperty("企业id")
private String companyId;
@TableField(exist = false)
@ApiModelProperty("岗位名称")
private String jobTitle;
@TableField(exist = false)
@ApiModelProperty("岗位id")
private String jobId;
@TableField(exist = false)
@ApiModelProperty("岗位申请id")
private String applyId;
}

View File

@@ -0,0 +1,24 @@
package com.ruoyi.common.core.domain.entity.tymh.authority;
import lombok.Data;
/**
* 用户角色
*/
@Data
public class QxUserRole {
private Long roleId;
private String roleName;
private String roleType;
private String appId;
private String roleLevel;
private String aae100;
private String aae011;
private String postType;
private String agf001;
private String aae036;
private String agf003;
private String agf002;
private String agf004;
private String folderId;
}

View File

@@ -1,6 +1,6 @@
package com.ruoyi.common.core.domain.entity.tymh.nwToken;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.alibaba.fastjson2.annotation.JSONField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -10,13 +10,14 @@ public class NwTokenResult {
@ApiModelProperty("错误标识1错误0正常")
private String errflag;
@ApiModelProperty("错误标识1错误0正常")
@ApiModelProperty("错误文本")
private String errtext;
@JsonProperty("Access-Token")
@ApiModelProperty("错误标识1错误0正常")
@JSONField(name = "access_token")
@ApiModelProperty("访问令牌")
private String accessToken;
@ApiModelProperty("错误标识1错误0正常")
@JSONField(name = "expires_in")
@ApiModelProperty("access_token接口调用凭证超")
private Long expiresIn;
}

View File

@@ -0,0 +1,12 @@
package com.ruoyi.common.core.domain.entity.tymh.nwToken;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class PortalTokenCacheDTO {
@ApiModelProperty("门户 accessToken")
private String accessToken;
@ApiModelProperty("过期时间戳(毫秒)")
private Long expireTimestamp;
}

View File

@@ -0,0 +1,13 @@
package com.ruoyi.common.core.domain.entity.tymh.wwToken;
import com.alibaba.fastjson2.annotation.JSONField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class WwTokenResult {
@JSONField(name = "Access-Token")
private String accessToken;
@ApiModelProperty("cookie")
private String sessionCookie;
}

View File

@@ -0,0 +1,24 @@
package com.ruoyi.common.core.domain.entity.tymh.wwToken;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class WwTyInfo {
@ApiModelProperty("用户类型(1:个人 2:单位)")
private String usertype;
@ApiModelProperty("单位统一身份社会信用代码")
private String enterprisecode;
@ApiModelProperty("单位名称")
private String enterprisename;
@ApiModelProperty("单位经办人姓名")
private String contactperson;
@ApiModelProperty("单位经办人联系电话")
private String contactphone;
@ApiModelProperty("个人身份证号")
private String idno;
@ApiModelProperty("个人姓名")
private String name;
@ApiModelProperty("手机号")
private String phone;
}

View File

@@ -39,6 +39,11 @@ public class LoginBody
*/
private String userType;
/**
* 身份证
*/
private String idCard;
public String getUsername()
{
return username;
@@ -102,4 +107,12 @@ public class LoginBody
public void setUserType(String userType) {
this.userType = userType;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
}

View File

@@ -203,4 +203,20 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
.atZone(ZONE_ID)
.toLocalDateTime();
}
/**
* @param dateStr 日期字符串需符合yyyy-MM-dd格式
* @return 转换后的Date对象转换失败则返回null
*/
public static Date stringToDateWithYmd(String dateStr,String format) {
if (dateStr == null || dateStr.trim().isEmpty()) {
return null;
}
try {
return new SimpleDateFormat(format).parse(dateStr);
} catch (ParseException e) {
return null;
}
}
}

View File

@@ -111,13 +111,17 @@ public class SecurityConfig
.authorizeHttpRequests((requests) -> {
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
requests.antMatchers("/login", "/register", "/captchaImage","/app/login","/websocket/**","/speech-recognition","/speech-synthesis","/cms/company/listPage","/cms/appUser/noTmlist").permitAll()
requests.antMatchers("/login", "/register", "/captchaImage","/app/login","/websocket/**","/speech-recognition","/speech-synthesis",
"/cms/company/listPage","/cms/appUser/noTmlist","/getTjmhToken","/getWwTjmhToken","/getWwTjmHlwToken",
"/cms/notice/noticTotal","/cms/jobApply/zphApply","/cms/jobApply/zphApplyAgree").permitAll()
// 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
// 移动端公用查询,可匿名访问
.antMatchers("/app/common/**").permitAll()
.antMatchers("/app/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
//放行前端界面
.antMatchers("/kashi/job-portal/detail/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
})

View File

@@ -0,0 +1,29 @@
package com.ruoyi.framework.web.exception;
/**
* 参数校验错误常量类
* 集中管理参数校验的错误码和错误信息
*/
public class ParamErrorConstants {
// 基础参数错误
public static final String PARAM_NULL_MSG = "请求参数不能为空";
// 微信授权码错误
public static final String CODE_EMPTY_MSG = "微信授权码不能为空";
//用户类型
public static final String USER_TYPE_INVALID_MSG = "用户类型无效仅支持0-个人/1-企业)";
// 手机号加密数据错误
public static final String ENCRYPTED_DATA_EMPTY_MSG = "手机号加密数据不能为空";
// 加密向量错误
public static final String IV_EMPTY_MSG = "加密向量不能为空";
// 新增日志常量(放在 ParamErrorConstants 或单独的 LogConstants 中)
public static final String LOG_AJAX_RETURN = "返回ajax=====================================";
// 私有化构造器,禁止实例化
private ParamErrorConstants() {
}
}

View File

@@ -0,0 +1,371 @@
package com.ruoyi.framework.web.service;
import com.ruoyi.cms.service.CompanyContactService;
import com.ruoyi.cms.service.IAppUserService;
import com.ruoyi.cms.service.ICompanyService;
import com.ruoyi.cms.util.StringUtil;
import com.ruoyi.cms.util.oauth.OauthClient;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.core.domain.entity.Company;
import com.ruoyi.common.core.domain.entity.CompanyContact;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.entity.tymh.nwToken.PortalTokenCacheDTO;
import com.ruoyi.common.core.domain.entity.tymh.wwToken.WwTokenResult;
import com.ruoyi.common.core.domain.entity.tymh.wwToken.WwTyInfo;
import com.ruoyi.common.core.domain.entity.tymh.wwToken.WwUserLogin;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Service
public class OauthLoginHlwService {
@Autowired
private OauthClient oauthClient;
@Autowired
private TokenService tokenService;
@Autowired
private RedisCache redisCache;
@Autowired
private ISysUserService sysUserService;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private ICompanyService companyService;
@Autowired
private CompanyContactService companyContactService;
@Autowired
private IAppUserService appUserService;
// Redis缓存门户UserID → 若依本地用户名(避免重复匹配数据库)
private static final String REDIS_KEY_PORTAL_USER_MAPPING = "hlw:user:mapping:";
// 门户 Token 存储前缀Redis 键:门户 userId → 门户 Token 信息)
private static final String REDIS_KEY_PORTAL_TOKEN = "hlw:token:";
final private int expireTime=30;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
/**
* OAuth 登录流程:通过授权码获取系统令牌
* @return 系统内部令牌(供前端后续使用)
*/
public String getWwTjmhToken(WwUserLogin wwUserLogin){
try {
//获取门户token
WwTokenResult wwTokenResult = oauthClient.wwGetToken(wwUserLogin);
String wwToken=wwTokenResult.getAccessToken();
System.out.println("wwToken======================="+wwToken);
if (StringUtils.isBlank(wwToken)) {
throw new ServiceException("获取门户 Token 失败:" + wwToken);
}
//获取门户userInfo
WwTyInfo portalUser = oauthClient.wwGetUserInfo(wwTokenResult);
//匹配/创建本地用户
String localUsername = getOrCreateLocalUser(portalUser);
//执行原来的登录流程
Authentication authentication = authenticateLocalUser(localUsername);
AsyncManager.me().execute(AsyncFactory.recordLogininfor(localUsername, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
storePortalToken(loginUser.getUserId(), wwToken);
recordLoginInfo(loginUser.getUserId());
return tokenService.createToken(loginUser);
} catch (Exception e) {
throw new ServiceException("OAuth 登录失败:" + e.getMessage());
}
}
/**
* 匹配/创建本地用户,返回若依本地用户名
*/
private String getOrCreateLocalUser(WwTyInfo wwTyInfo) {
String idCard="";
switch (wwTyInfo.getUsertype()){
case "1"://个人
idCard=wwTyInfo.getIdno();
break;
default:
idCard=wwTyInfo.getEnterprisecode();
}
// 先从Redis查询缓存的本地用户名
String cacheKey = REDIS_KEY_PORTAL_USER_MAPPING + idCard;
String localUsername = redisCache.getCacheObject(cacheKey);
if (StringUtils.isNotBlank(localUsername)) {
if ("hlw_".equals(localUsername)) {
localUsername = String.format("%s%s", localUsername, idCard);
}
updateUserInfo(wwTyInfo);
return localUsername;
}
SysUser localUser=sysUserService.selectUserByIdCard(wwTyInfo.getIdno());
if (localUser == null) {
// 本地无用户,自动创建
localUser = createLocalUser(wwTyInfo);
// 缓存门户UserID与本地用户名的映射有效期1天可调整
redisCache.setCacheObject(cacheKey, localUser.getUserName(), 1, TimeUnit.DAYS);
return localUser.getUserName();
}
// 缓存映射关系(更新有效期)
redisCache.setCacheObject(cacheKey, localUser.getUserName(), 1, TimeUnit.DAYS);
return localUser.getUserName();
}
/**
* 门户UserID字符串转Long
*/
private Long parseStringToLoing(String portalUserIdStr) {
try {
return Long.parseLong(portalUserIdStr);
} catch (NumberFormatException e) {
throw new ServiceException("门户用户ID格式错误" + portalUserIdStr);
}
}
/**
* 自动创建本地用户
*/
private SysUser createLocalUser(WwTyInfo wwTyInfo) {
//移动端用户
AppUser appUserParm=new AppUser();
appUserParm.setIsRecommend(1);
//pc端
SysUser newUser = new SysUser();
String localUsername=StringUtil.USER_KEY+wwTyInfo.getIdno();
switch (wwTyInfo.getUsertype()) {
case "1"://个人
newUser.setNickName(wwTyInfo.getName());
newUser.setIdCard(wwTyInfo.getIdno());
newUser.setRoleIds(new Long[]{parseStringToLoing(StringUtil.SYS_QZZ)});
//移动端
appUserParm.setPhone(wwTyInfo.getPhone());
appUserParm.setIdCard(wwTyInfo.getIdno());
appUserParm.setName(wwTyInfo.getName());
break;
default://单位
newUser.setNickName(wwTyInfo.getEnterprisename());
newUser.setIdCard(wwTyInfo.getEnterprisecode());
newUser.setRoleIds(new Long[]{parseStringToLoing(StringUtil.SYS_QY)});
//修改企业和企业联系人
updateCompanyContact(wwTyInfo);
//移动端
appUserParm.setPhone(wwTyInfo.getPhone());
appUserParm.setIdCard(wwTyInfo.getEnterprisecode());
appUserParm.setName(wwTyInfo.getEnterprisename());
}
newUser.setPassword(SecurityUtils.encryptPassword("123456"));
newUser.setDelFlag("0");
newUser.setUserName(localUsername);
sysUserService.insertUser(newUser);
//插入app_user
AppUser appUser=appUserService.selectAppuserByIdcard(wwTyInfo.getIdno());
if(appUser!=null){
appUserParm.setUserId(appUser.getUserId());
appUserService.updateAppUser(appUserParm);
}else{
appUserService.insertAppUser(appUserParm);
}
return newUser;
}
/**
* 复用若依认证机制,触发 UserDetailsService 加载 LoginUser
* (关键:用本地用户名构建认证令牌,无需密码,因为门户已完成身份校验)
*/
private Authentication authenticateLocalUser(String localUsername) {
Authentication authentication = null;
try {
UserDetails userDetails = userDetailsService.loadUserByUsername(localUsername);
authentication = new UsernamePasswordAuthenticationToken(
userDetails,
null, // 密码为 null彻底绕过 Spring Security 的密码校验
userDetails.getAuthorities()
);
AuthenticationContextHolder.setContext(authentication);
} catch (Exception e) {
throw new ServiceException("本地用户认证失败:" + e.getMessage());
} finally {
AuthenticationContextHolder.clearContext();
}
return authentication;
}
/**
* 存储门户 Token 到 Redis结构化存储含过期时间
*/
private void storePortalToken(Long portalUserId, String accessToken) {
String redisKey = REDIS_KEY_PORTAL_TOKEN + portalUserId;
PortalTokenCacheDTO tokenCache = new PortalTokenCacheDTO();
tokenCache.setAccessToken(accessToken);
tokenCache.setExpireTimestamp(System.currentTimeMillis() + expireTime * MILLIS_MINUTE);
redisCache.setCacheObject(redisKey, tokenCache, expireTime, TimeUnit.SECONDS);
}
/**
* 记录登录信息(复用若依原生逻辑,直接复制过来)
*/
private void recordLoginInfo(Long userId) {
SysUser sysUser = new SysUser();
sysUser.setUserId(userId);
sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
sysUser.setLoginDate(new Date());
sysUserService.updateUserProfile(sysUser);
}
/**
* 获取互联网token
* @param wwTokenResult
* @return
*/
public String getWwTjmHlwToken(WwTokenResult wwTokenResult){
try {
//获取门户userInfo
WwTyInfo portalUser = oauthClient.wwGetUserInfo(wwTokenResult);
//匹配/创建本地用户
String localUsername = getOrCreateLocalUser(portalUser);
//执行原来的登录流程
Authentication authentication = authenticateLocalUser(localUsername);
AsyncManager.me().execute(AsyncFactory.recordLogininfor(localUsername, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
storePortalToken(loginUser.getUserId(), wwTokenResult.getAccessToken());
recordLoginInfo(loginUser.getUserId());
return tokenService.createToken(loginUser);
} catch (Exception e) {
throw new ServiceException("OAuth 登录失败:" + e.getMessage());
}
}
/**
* 修改个人信息
* @param wwTyInfo
*/
private void updateUserInfo(WwTyInfo wwTyInfo){
//移动端用户
AppUser appUserParm=new AppUser();
appUserParm.setIsRecommend(1);
//pc端
String code="";
SysUser sysUser=new SysUser();
switch (wwTyInfo.getUsertype()){
case "1":
sysUser.setNickName(wwTyInfo.getName());
sysUser.setIdCard(wwTyInfo.getIdno());
sysUser.setRoleIds(new Long[]{parseStringToLoing(StringUtil.SYS_QZZ)});
//移动端
appUserParm.setPhone(wwTyInfo.getPhone());
appUserParm.setIdCard(wwTyInfo.getIdno());
appUserParm.setName(wwTyInfo.getName());
code=wwTyInfo.getIdno();
break;
default:
sysUser.setNickName(wwTyInfo.getEnterprisename());
sysUser.setIdCard(wwTyInfo.getEnterprisecode());
sysUser.setRoleIds(new Long[]{parseStringToLoing(StringUtil.SYS_QY)});
//企业联系人->现根据社会信用代码查询企业信息
updateCompanyContact(wwTyInfo);
//移动端
appUserParm.setPhone(wwTyInfo.getPhone());
appUserParm.setIdCard(wwTyInfo.getEnterprisecode());
appUserParm.setName(wwTyInfo.getEnterprisename());
code=wwTyInfo.getEnterprisecode();
}
String localUsername=StringUtil.USER_KEY+code;
//查询用户角色
sysUser.setUserName(localUsername);
//查询用户id
SysUser parmUser=sysUserService.selectUserByIdCard(code);
sysUser.setUserId(parmUser.getUserId());
sysUserService.updateUser(sysUser);
//插入app_user
AppUser appUser=appUserService.selectAppuserByIdcard(code);
if(appUser!=null){
appUserParm.setUserId(appUser.getUserId());
appUserService.updateAppUser(appUserParm);
}else{
appUserService.insertAppUser(appUserParm);
}
}
/**
* 修改联系人信息
* @param wwTyInfo
*/
public void updateCompanyContact(WwTyInfo wwTyInfo) {
if (wwTyInfo == null) {
throw new IllegalArgumentException("参数WwTyInfo不能为空");
}
String enterpriseCode = wwTyInfo.getEnterprisecode();
String enterpriseName = wwTyInfo.getEnterprisename();
String contactPerson = wwTyInfo.getContactperson();
String contactPhone = wwTyInfo.getContactphone();
Company company = companyService.queryCodeCompany(enterpriseCode);
CompanyContact contact = new CompanyContact();
contact.setContactPerson(contactPerson);
contact.setContactPersonPhone(contactPhone);
if (Objects.nonNull(company)) {
Company updateCompany = new Company();
updateCompany.setCompanyId(company.getCompanyId());
updateCompany.setCode(enterpriseCode);
updateCompany.setName(enterpriseName);
companyService.updateCompany(updateCompany);
contact.setCompanyId(company.getCompanyId());
List<CompanyContact> existingContacts = companyContactService.getSelectList(contact);
List<CompanyContact> contactList = new ArrayList<>();
if (!CollectionUtils.isEmpty(existingContacts)) {
contact.setId(existingContacts.get(0).getId());
contactList.add(contact);
companyContactService.insertUpadteCompanyContact(contactList);
} else {
companyContactService.insertContact(contact);
}
} else {
Company newCompany = new Company();
newCompany.setCode(enterpriseCode);
newCompany.setName(enterpriseName);
companyService.insertCompany(newCompany);
if (Objects.nonNull(newCompany.getCompanyId())) {
contact.setCompanyId(newCompany.getCompanyId());
companyContactService.insertContact(contact);
} else {
throw new RuntimeException("新增企业失败:社会信用代码=" + enterpriseCode + "未返回有效企业ID");
}
}
}
}

View File

@@ -0,0 +1,258 @@
package com.ruoyi.framework.web.service;
import com.ruoyi.cms.util.oauth.OauthClient;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.entity.tymh.authority.QxUserRole;
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwTokenResult;
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwUserInfoResult;
import com.ruoyi.common.core.domain.entity.tymh.nwToken.PortalTokenCacheDTO;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@Service
public class OauthLoginService {
@Autowired
private OauthClient oauthClient;
@Autowired
private TokenService tokenService;
@Autowired
private RedisCache redisCache;
@Autowired
private ISysUserService sysUserService;
@Autowired
private UserDetailsService userDetailsService;
// Redis缓存门户UserID → 若依本地用户名(避免重复匹配数据库)
private static final String REDIS_KEY_PORTAL_USER_MAPPING = "portal:user:mapping:";
// 门户 Token 存储前缀Redis 键:门户 userId → 门户 Token 信息)
private static final String REDIS_KEY_PORTAL_TOKEN = "portal:token:";
/**
* OAuth 登录流程:通过授权码获取系统令牌
* @param code 前端传入的 OAuth 授权码
* @return 系统内部令牌(供前端后续使用)
*/
public String oauthLogin(String code) {
try {
//获取门户token
NwTokenResult nwTokenResult = oauthClient.nwGetToken(code);
if (!"0".equals(nwTokenResult.getErrflag())) {
throw new ServiceException("获取门户 Token 失败:" + nwTokenResult.getErrtext());
}
String accessToken = nwTokenResult.getAccessToken();
Long expiresIn = nwTokenResult.getExpiresIn();
if (StringUtils.isEmpty(accessToken) || expiresIn == null || expiresIn <= 0) {
throw new ServiceException("门户 Token 无效或有效期异常");
}
//获取门户userInfo
NwUserInfoResult portalUser = oauthClient.nwGetUserInfo(accessToken);
//匹配/创建本地用户
String localUsername = getOrCreateLocalUser(portalUser);
//执行原来的登录流程
Authentication authentication = authenticateLocalUser(localUsername);
AsyncManager.me().execute(AsyncFactory.recordLogininfor(localUsername, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
storePortalToken(loginUser.getUserId(), nwTokenResult);
recordLoginInfo(loginUser.getUserId());
return tokenService.createToken(loginUser);
} catch (IOException | TimeoutException e) {
throw new ServiceException("OAuth 登录失败:" + e.getMessage());
}
}
/**
* 匹配/创建本地用户,返回若依本地用户名
*/
private String getOrCreateLocalUser(NwUserInfoResult portalUser) {
Long portalUserId = parsePortalUserId(portalUser.getUserid());
// 先从Redis查询缓存的本地用户名
String cacheKey = REDIS_KEY_PORTAL_USER_MAPPING + portalUserId;
String localUsername = redisCache.getCacheObject(cacheKey);
if (StringUtils.isNotBlank(localUsername)) {
try {
//更新用户信息
updateUserInfo(portalUser);
}catch (Exception e){
e.printStackTrace();
}
return localUsername;
}
// 缓存未命中,查询本地用户
SysUser localUser = sysUserService.selectUserById(portalUserId);
if (localUser == null) {
// 本地无用户,自动创建
localUser = createLocalUser(portalUser, portalUserId);
// 缓存门户UserID与本地用户名的映射有效期1天可调整
redisCache.setCacheObject(cacheKey, localUser.getUserName(), 1, TimeUnit.DAYS);
return localUser.getUserName();
}
// 缓存映射关系(更新有效期)
redisCache.setCacheObject(cacheKey, localUser.getUserName(), 1, TimeUnit.DAYS);
return localUser.getUserName();
}
/**
* 门户UserID字符串转Long
*/
private Long parsePortalUserId(String portalUserIdStr) {
try {
return Long.parseLong(portalUserIdStr);
} catch (NumberFormatException e) {
throw new ServiceException("门户用户ID格式错误" + portalUserIdStr);
}
}
/**
* 自动创建本地用户
*/
private SysUser createLocalUser(NwUserInfoResult portalUser, Long portalUserId) {
SysUser newUser = new SysUser();
String localUsername = "portal_" + portalUserId;
newUser.setUserName(localUsername);
newUser.setNickName(portalUser.getName());
newUser.setIdCard(portalUser.getIdcardno());
newUser.setUserId(portalUserId);
newUser.setPassword(SecurityUtils.encryptPassword("123456"));
newUser.setDelFlag("0");
try {
//查询权限,保存权限
List<QxUserRole> userRoleList=oauthClient.getUserRoleList(portalUserId);
if(userRoleList!=null&&userRoleList.size()>0){
Long[] longs=userRoleList.stream().mapToLong(QxUserRole::getRoleId).boxed().toArray(Long[]::new);;
newUser.setRoleIds(longs);
}else {
throw new Exception("未查询到用户角色,请授权后访问!");
}
// 调用若依原生方法新增用户(自动处理角色关联,需提前配置默认角色)
sysUserService.insertUser(newUser);
}catch (Exception e){
e.printStackTrace();
}
return newUser;
}
/**
* 复用若依认证机制,触发 UserDetailsService 加载 LoginUser
* (关键:用本地用户名构建认证令牌,无需密码,因为门户已完成身份校验)
*/
private Authentication authenticateLocalUser(String localUsername) {
Authentication authentication = null;
try {
UserDetails userDetails = userDetailsService.loadUserByUsername(localUsername);
authentication = new UsernamePasswordAuthenticationToken(
userDetails,
null, // 密码为 null彻底绕过 Spring Security 的密码校验
userDetails.getAuthorities()
);
AuthenticationContextHolder.setContext(authentication);
} catch (Exception e) {
throw new ServiceException("本地用户认证失败:" + e.getMessage());
} finally {
AuthenticationContextHolder.clearContext();
}
return authentication;
}
/**
* 存储门户 Token 到 Redis结构化存储含过期时间
*/
private void storePortalToken(Long portalUserId, NwTokenResult tokenResult) {
// 构建 Redis 键(门户 userId 作为唯一标识)
String redisKey = REDIS_KEY_PORTAL_TOKEN + portalUserId;
// 封装 Token 信息(含 accessToken、过期时间戳
PortalTokenCacheDTO tokenCache = new PortalTokenCacheDTO();
tokenCache.setAccessToken(tokenResult.getAccessToken());
tokenCache.setExpireTimestamp(System.currentTimeMillis() + tokenResult.getExpiresIn() * 1000);
redisCache.setCacheObject(redisKey, tokenCache, safeLongToInt(tokenResult.getExpiresIn()), TimeUnit.SECONDS);
}
/**
* 修改用户信息
* @param portalUser
*/
private void updateUserInfo(NwUserInfoResult portalUser){
SysUser sysUser=new SysUser();
Long portalUserId=parsePortalUserId(portalUser.getUserid());
//查询用户角色
try {
List<QxUserRole> userRoleList=oauthClient.getUserRoleList(portalUserId);
if(userRoleList!=null&&userRoleList.size()>0){
Long[] longs=userRoleList.stream().mapToLong(QxUserRole::getRoleId).boxed().toArray(Long[]::new);;
sysUser.setRoleIds(longs);
}else {
throw new Exception("未查询到用户角色,请授权后访问!");
}
}catch (Exception e){
e.printStackTrace();
}
String localUsername = "portal_" + portalUserId;
sysUser.setUserName(localUsername);
sysUser.setNickName(portalUser.getName());
sysUser.setIdCard(portalUser.getIdcardno());
sysUser.setUserId(portalUserId);
sysUserService.updateUser(sysUser);
}
/**
* 记录登录信息(复用若依原生逻辑,直接复制过来)
*/
private void recordLoginInfo(Long userId) {
SysUser sysUser = new SysUser();
sysUser.setUserId(userId);
sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
sysUser.setLoginDate(new Date());
sysUserService.updateUserProfile(sysUser);
}
/**
* Long 转 int
*/
private int safeLongToInt(Long value) {
if (value == null) {
throw new ServiceException("门户 Token 有效期不能为空");
}
// 校验是否超过 int 最大值(实际场景几乎不会触发)
if (value > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
// 校验是否为负数(无效有效期)
if (value < 0) {
throw new ServiceException("门户 Token 有效期不能为负数");
}
return value.intValue();
}
}

View File

@@ -5,6 +5,7 @@ import javax.annotation.Resource;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.cms.service.IAppUserService;
import com.ruoyi.cms.util.StringUtil;
import com.ruoyi.cms.util.WechatUtil;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.AppUser;
@@ -12,6 +13,7 @@ import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.LoginSiteUser;
import com.ruoyi.common.core.domain.model.RegisterBody;
import com.ruoyi.common.utils.*;
import com.ruoyi.framework.web.exception.ParamErrorConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
@@ -36,6 +38,7 @@ import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.transaction.annotation.Transactional;
/**
* 登录校验方法
@@ -242,74 +245,291 @@ public class SysLoginService
* @param dto
* @return
*/
@Transactional(rollbackFor = Exception.class)
public AjaxResult appLogin(LoginBody dto){
AjaxResult ajax = AjaxResult.success();
System.out.println("小程序微信授权登录---------参数列表========dto========"+ JSON.toJSONString(dto));
JSONObject sessionInfo = wechatUtil.code2Session(dto.getCode());
String openid = sessionInfo.getString("openid");
String unionid = sessionInfo.getString("unionid");
String sessionKey = sessionInfo.getString("session_key");
if (openid == null) {
return AjaxResult.error("微信授权失败");
}
//验证是否登录过
AppUser existingUser=appUserService.selectByOpenid(openid);
if(existingUser!=null){
if(StringUtils.isEmpty(existingUser.getIsCompanyUser())){
existingUser.setIsCompanyUser(dto.getUserType());
appUserService.updateAppUser(existingUser);
try {
System.out.println("小程序微信授权登录---------参数列表========dto========"+ JSON.toJSONString(dto));
JSONObject sessionInfo = wechatUtil.code2Session(dto.getCode());
String openid = sessionInfo.getString("openid");
String unionid = sessionInfo.getString("unionid");
String sessionKey = sessionInfo.getString("session_key");
if (openid == null) {
return AjaxResult.error("微信授权失败");
}
String token = loginUserIdApp(existingUser);
ajax.put(Constants.TOKEN, token);
ajax.put("isNewUser", false);
ajax.put("idCard",existingUser.getIdCard());
ajax.put("isCompanyUser",existingUser.getIsCompanyUser());
return ajax;
}else {
//验证是否登录过
AppUser existingUser=appUserService.selectByOpenid(openid);
if(existingUser!=null){
if(StringUtils.isEmpty(existingUser.getIsCompanyUser())){
updateAppUserCommon(existingUser,openid,unionid,dto.getUserType());
}
String token = loginUserIdApp(existingUser);
ajax.put(Constants.TOKEN, token);
ajax.put("isNewUser", false);
ajax.put("idCard",existingUser.getIdCard());
ajax.put("isCompanyUser",existingUser.getIsCompanyUser());
System.out.println("返回ajax====================================="+JSON.toJSONString(ajax));
return ajax;
}else {
JSONObject phoneInfo = wechatUtil.decryptPhoneNumber(dto.getEncryptedData(), sessionKey, dto.getIv());
String phone = phoneInfo.getString("phoneNumber");
if (phone == null) {
return AjaxResult.error("获取手机号失败");
}
// 3. 检查手机号是否已被绑定
AppUser existUser = appUserService.getPhone(phone);
String token="";
boolean isNewUser=false;
if (existUser != null) {
updateAppUserCommon(existUser,openid,unionid,dto.getUserType());
// 5. 生成系统令牌
token = loginUserIdApp(existUser);
ajax.put("idCard",existUser.getIdCard());
ajax.put("isCompanyUser",existUser.getIsCompanyUser());
}else{
// 4. 创建用户并存储所有信息
AppUser appUser = new AppUser();
appUser.setOpenid(openid);
appUser.setUnionid(unionid);
appUser.setPhone(phone);
appUser.setIsCompanyUser(dto.getUserType());//保存角色
appUserService.insertAppUser(appUser);
// 5. 生成系统令牌
token = loginUserIdApp(appUser);
isNewUser=true;
ajax.put("idCard",null);
ajax.put("isCompanyUser",dto.getUserType());
}
ajax.put("isNewUser", isNewUser);
ajax.put(Constants.TOKEN, token);
System.out.println("返回ajax====================================="+JSON.toJSONString(ajax));
return ajax;
}
}catch (Exception e) {
System.err.println("登录失败:" + e.getMessage());
return AjaxResult.error("登录失败,请稍后重试");
}
}
/**
* 小程序登录主逻辑
*/
public AjaxResult appLoginNew(LoginBody dto) {
AjaxResult validateResult = validateLoginParam(dto, false);
if (validateResult != null) {
return validateResult;
}
try {
JSONObject sessionInfo = wechatUtil.code2Session(dto.getCode());
String openid = sessionInfo.getString("openid");
String unionid = sessionInfo.getString("unionid");
String sessionKey = sessionInfo.getString("session_key");
if (openid == null) {
return AjaxResult.error("微信授权失败");
}
AppUser existingUser = appUserService.selectByOpenid(openid);
if (existingUser != null) {
return handleExistingUser(existingUser, dto.getUserType());
}
validateResult = validateLoginParam(dto, true);
if (validateResult != null) {
return validateResult;
}
JSONObject phoneInfo = wechatUtil.decryptPhoneNumber(dto.getEncryptedData(), sessionKey, dto.getIv());
String phone = phoneInfo.getString("phoneNumber");
if (phone == null) {
return AjaxResult.error("获取手机号失败");
}
// 3. 检查手机号是否已被绑定
AppUser existUser = appUserService.getPhone(phone);
String token="";
boolean isNewUser=false;
if (existUser != null) {
existUser.setOpenid(openid);
appUserService.updateAppUser(existUser);
// 5. 生成系统令牌
token = loginUserIdApp(existUser);
ajax.put("idCard",existUser.getIdCard());
ajax.put("isCompanyUser",existUser.getIsCompanyUser());
}else{
// 4. 创建用户并存储所有信息
AppUser appUser = new AppUser();
appUser.setOpenid(openid);
appUser.setUnionid(unionid);
appUser.setPhone(phone);
appUser.setIsCompanyUser(dto.getUserType());//保存角色
appUserService.insertAppUser(appUser);
// 5. 生成系统令牌
token = loginUserIdApp(appUser);
isNewUser=true;
ajax.put("idCard",null);
ajax.put("isCompanyUser",dto.getUserType());
AppUser phoneUser = appUserService.getPhone(phone);
if (phoneUser != null) {
return handlePhoneBoundUser(phoneUser, openid, unionid, dto.getUserType());
} else {
return handleNewUser(openid, unionid, phone, dto.getUserType());
}
ajax.put("isNewUser", isNewUser);
ajax.put(Constants.TOKEN, token);
return ajax;
} catch (Exception e) {
System.err.println("登录失败:" + e.getMessage());
return AjaxResult.error("登录失败,请稍后重试");
}
}
/**
* 参数校验方法仅返回错误信息补充userType校验
*/
private AjaxResult validateLoginParam(LoginBody dto, boolean needDecryptPhone) {
if (dto == null) {
return AjaxResult.error(ParamErrorConstants.PARAM_NULL_MSG);
}
if (StringUtils.isEmpty(dto.getCode())) {
return AjaxResult.error(ParamErrorConstants.CODE_EMPTY_MSG);
}
String userType = dto.getUserType();
if (StringUtils.isEmpty(userType) ||
!StringUtil.IS_COMPANY_USER.equals(userType) &&
!StringUtil.IS_JOB_REQUEST_USER.equals(userType)) {
return AjaxResult.error(ParamErrorConstants.USER_TYPE_INVALID_MSG);
}
if (needDecryptPhone) {
if (StringUtils.isEmpty(dto.getEncryptedData())) {
return AjaxResult.error(ParamErrorConstants.ENCRYPTED_DATA_EMPTY_MSG);
}
if (StringUtils.isEmpty(dto.getIv())) {
return AjaxResult.error(ParamErrorConstants.IV_EMPTY_MSG);
}
}
return null;
}
/**
* 处理老用户登录日志用println
*/
@Transactional(rollbackFor = Exception.class)
public AjaxResult handleExistingUser(AppUser existingUser, String userType) {
AjaxResult ajax = AjaxResult.success();
updateAppUserCommon(existingUser, null, null, userType);
String token = loginUserIdApp(existingUser);
ajax.put(Constants.TOKEN, token);
ajax.put("isNewUser", false);
ajax.put("idCard", existingUser.getIdCard());
ajax.put("isCompanyUser", existingUser.getIsCompanyUser());
System.out.println("老用户登录成功openid:" + existingUser.getOpenid() + "===========");
System.out.println(ParamErrorConstants.LOG_AJAX_RETURN + JSON.toJSONString(ajax));
return ajax;
}
/**
* 处理手机号已绑定的用户
*/
@Transactional(rollbackFor = Exception.class)
public AjaxResult handlePhoneBoundUser(AppUser phoneUser, String openid, String unionid, String userType) {
AjaxResult ajax = AjaxResult.success();
if (StringUtils.hasText(phoneUser.getOpenid()) && !openid.equals(phoneUser.getOpenid())) {
System.out.printf("手机号绑定冲突phone:%s, oldOpenid:%s, newOpenid:%s%n",
phoneUser.getPhone(), phoneUser.getOpenid(), openid);
return AjaxResult.error("该手机号已绑定其他微信账号");
}
//修改用户信息
updateAppUserCommon(phoneUser, openid, unionid, userType);
phoneUser.setOpenid(openid);
phoneUser.setUnionid(unionid);
phoneUser.setIsCompanyUser(userType);
String token = loginUserIdApp(phoneUser);
ajax.put(Constants.TOKEN, token);
ajax.put("isNewUser", false);
ajax.put("idCard", phoneUser.getIdCard());
ajax.put("isCompanyUser", phoneUser.getIsCompanyUser());
System.out.println("手机号绑定用户登录成功phone:" + phoneUser.getPhone());
System.out.println(ParamErrorConstants.LOG_AJAX_RETURN + JSON.toJSONString(ajax));
return ajax;
}
/**
* 处理新用户注册
*/
@Transactional(rollbackFor = Exception.class)
public AjaxResult handleNewUser(String openid, String unionid, String phone, String userType) {
AjaxResult ajax = AjaxResult.success();
AppUser newUser = new AppUser();
newUser.setOpenid(openid);
newUser.setUnionid(unionid);
newUser.setPhone(phone);
newUser.setIsCompanyUser(userType);
appUserService.insertAppUser(newUser);
String token = loginUserIdApp(newUser);
ajax.put(Constants.TOKEN, token);
ajax.put("isNewUser", true);
ajax.put("idCard", null);
ajax.put("isCompanyUser", userType);
System.out.printf("新用户创建成功openid:%s, phone:%s%n", openid, phone);
System.out.println(ParamErrorConstants.LOG_AJAX_RETURN + JSON.toJSONString(ajax));
return ajax;
}
/**
* 抽取用户更新公共方法
*/
private void updateAppUserCommon(AppUser targetUser, String openid, String unionid, String userType) {
AppUser updateParm = new AppUser();
updateParm.setUserId(targetUser.getUserId());
String currentRole = targetUser.getIsCompanyUser();
if (!StringUtil.IS_GRID_USER.equals(currentRole) && !StringUtil.IS_INTERNAL_USER.equals(currentRole)) {
updateParm.setIsCompanyUser(userType);
targetUser.setIsCompanyUser(userType);
}else{
System.out.printf("用户角色不允许修改openid:%s, 当前角色:%s, 传入角色:%s%n",
targetUser.getOpenid(), currentRole, userType);
}
if (StringUtils.isNotBlank(openid)) {
updateParm.setOpenid(openid);
targetUser.setOpenid(openid);
}
if (StringUtils.isNotBlank(unionid)) {
updateParm.setUnionid(unionid);
targetUser.setUnionid(unionid);
}
appUserService.updateAppUser(updateParm);
}
/**
* 注册
* @param registerBody
* @return
*/
public String registerAppUser(RegisterBody registerBody) {
AppUser appUser=appUserService.registerAppUser(registerBody);
//AppUser appUser=appUserService.registerAppUser(registerBody);
AppUser appUser=appUserService.registerAppUserNew(registerBody);
return loginUserIdApp(appUser);
}
/**
* 手机号验证登录
* @return
*/
public AjaxResult phoneLogin(LoginBody loginBody){
AppUser appUser=appUserService.getPhone(loginBody.getUsername());
if(appUser==null){
return AjaxResult.error("未查询到您的注册信息,请先完成注册后再登录~");
}
if(!SiteSecurityUtils.matchesPassword(loginBody.getPassword(),appUser.getYtjPassword())){
return AjaxResult.error("您输入的密码有误,请核对后重新尝试~!");
}
return getAjax(appUser);
}
/**
* 身份证号登录
* @param loginBody
* @return
*/
public AjaxResult idCardLogin(LoginBody loginBody){
AppUser appUser=appUserService.selectAppuserByIdcard(loginBody.getIdCard());
if(appUser==null){
return AjaxResult.error("未查询到您的注册信息,请先完成注册后再登录~");
}
return getAjax(appUser);
}
/**
* 获取ajax
* @param appUser
* @return
*/
public AjaxResult getAjax(AppUser appUser){
AjaxResult ajax = AjaxResult.success();
String token=loginUserIdApp(appUser);
ajax.put(Constants.TOKEN, token);
ajax.put("isNewUser", false);
ajax.put("idCard",appUser.getIdCard());
ajax.put("isCompanyUser",appUser.getIsCompanyUser());
return ajax;
}
}

View File

@@ -53,8 +53,8 @@ public class UserDetailsServiceImpl implements UserDetailsService
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException(MessageUtils.message("user.blocked"));
}
passwordService.validate(user);
////单点跳过验证密码阶段
//passwordService.validate(user);
return createLoginUser(user);
}

View File

@@ -29,7 +29,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectJobVo"/>
<where>
<if test="jobName != null and jobName != ''">
AND job_name like concat('%', #{jobName}, '%')
AND job_name like concat('%', cast(#{jobName, jdbcType=VARCHAR} as varchar), '%')
</if>
<if test="jobGroup != null and jobGroup != ''">
AND job_group = #{jobGroup}

View File

@@ -129,4 +129,11 @@ public interface SysUserMapper
public SysUser checkEmailUnique(String email);
AppUser selectAppUserById(long id);
/**
* 通过身份证查询信息
* @param idCard
* @return
*/
SysUser selectUserByIdCard(String idCard);
}

View File

@@ -207,4 +207,6 @@ public interface ISysUserService
public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
AppUser selectAppUserById(long id);
SysUser selectUserByIdCard(String idCard);
}

View File

@@ -554,4 +554,9 @@ public class SysUserServiceImpl implements ISysUserService
public AppUser selectAppUserById(long id) {
return userMapper.selectAppUserById(id);
}
@Override
public SysUser selectUserByIdCard(String idCard) {
return userMapper.selectUserByIdCard(idCard);
}
}

Some files were not shown because too many files have changed in this diff Show More