package com.malk.kaiyue.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.malk.controller.DDCallbackController; import com.malk.kaiyue.service.KYCDService; import com.malk.server.common.McR; import com.malk.server.dingtalk.DDConf; import com.malk.server.dingtalk.crypto.DingCallbackCrypto; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.*; import java.text.ParseException; import java.util.*; import java.util.concurrent.TimeUnit; @Slf4j @RestController @RequestMapping("/cd") @Component public class KYCDController extends DDCallbackController { @Autowired private KYCDService kycdService; @Autowired private DDConf ddConf; @Value("${dingtalk_cd.token}") private String token; @Value("${dingtalk_cd.aesKey}") private String aesKey; @Value("${dingtalk_cd.appKey}") private String appKey; @PostMapping("/test") McR test(){ log.info("11111"); return McR.success(); } //获取在职员工userId列表 @GetMapping("/getEmployeeUserId") McR getEmployeeUserId() { List userIdList = kycdService.getEmployeeUserId(); return McR.success(userIdList); } //获取员工花名册信息 @PostMapping("/getEmployeeRosterInfo") McR getEmployeeRosterInfo(@RequestBody Map map) { List result = kycdService.getEmployeeRosterInfo(map); return McR.success(result); } //计算并设置员工年假数 @PostMapping("/getEmployeeAnnualLeaveNum") McR getEmployeeAnnualLeaveNum(@RequestBody Map map) { return kycdService.getEmployeeAnnualLeaveNum(map); } //获取员工真实假期余额 @PostMapping("/getUserLeaveInfo") McR getUserLeaveInfo(@RequestBody Map map) { String userId = map.get("userId").toString(); Map result = kycdService.getUserLeaveInfo(userId); return McR.success(result); } //每年1月1日 00:00定时更新员工年假数 @Scheduled(cron = "0 0 0 1 1 ? ") @GetMapping("/grantEmployeeAnnualLeave") McR grantEmployeeAnnualLeave() { System.out.println("年初发放员工年假开始执行"+new Date()); return kycdService.grantEmployeeAnnualLeave(); } //保存十分钟内已处理的回调事件 private Map eventList = new HashMap<>(); @SneakyThrows public synchronized Map invokeCallback(@RequestParam(value = "signature", required = false) String signature, @RequestParam(value = "timestamp", required = false) String timestamp, @RequestParam(value = "nonce", required = false) String nonce, @RequestBody(required = false) JSONObject json) { DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(token, aesKey, appKey); // 处理回调消息,得到回调事件decryptMsg... final String decryptMsg = callbackCrypto.getDecryptMsg(signature, timestamp, nonce, json.getString("encrypt")); JSONObject eventJson = JSON.parseObject(decryptMsg); Map success = callbackCrypto.getEncryptedMap(DDConf.CALLBACK_RESPONSE, System.currentTimeMillis(), DingCallbackCrypto.Utils.getRandomStr(8)); // 业务处理代码... String eventType = eventJson.getString("EventType"); if (DDConf.CALLBACK_CHECK.equals(eventType)) { log.info("----- [DD]验证注册 -----"); return success; } // [回调任务执行逻辑: 异步] 钉钉超时3s未返回会被记录为失败, 可通过失败接口获取记录 if (Arrays.asList(DDConf.HRM_USER_RECORD_CHANGE).contains(eventType)) { log.info("[DD]人事档案变动回调, eventType:{}, eventJson:{}",eventType, eventJson); //获取员工userId String userId = ""; if (Objects.nonNull(eventJson.get("staffId"))){ //人事档案返回的userId userId = eventJson.get("staffId").toString(); }else { log.error("[DD]人事档案变动回调, 未获取到userId"); return success; } log.info("员工userId:"+userId); Map map = new HashMap(); map.put("userid_list", userId); //更新员工年假余额 log.info("----- [DD]更新员工年假余额 -----"); kycdService.getEmployeeAnnualLeaveNum(map); return success; } log.info("----- [DD]已注册, 未处理的其它回调 -----, eventType:{}, eventJson:{}",eventType, eventJson); return success; } /** * 检查该回调事件在十分钟内是否处理过,应对钉钉瞬间重复回调 * * @param decryptMsg 回调事件 * @return 是否处理过 */ private boolean isCallbackProcessed(String decryptMsg) { // 清理超过十分钟的回调事件 long currentTime = System.currentTimeMillis(); long expirationTime = currentTime - TimeUnit.MINUTES.toMillis(10); eventList.entrySet().removeIf(entry -> entry.getValue() < expirationTime); return eventList.containsKey(decryptMsg); } }