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.KYNTService; 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.web.bind.annotation.*; import java.util.*; import java.util.concurrent.TimeUnit; @Slf4j @RestController @RequestMapping("/nt") public class KYNTController extends DDCallbackController { @Autowired private KYNTService kyntService; @Autowired private DDConf ddConf; @Value("${dingtalk_nt.token}") private String token; @Value("${dingtalk_nt.aesKey}") private String aesKey; @Value("${dingtalk_nt.appKey}") private String appKey; @GetMapping("/test") public McR test() { log.info("11111111"); return McR.success(); } //获取在职员工userId列表 @GetMapping("/getEmployeeUserId") McR getEmployeeUserId() { List result = kyntService.getEmployeeUserId(); return McR.success(result); } //获取员工花名册信息 @PostMapping("/getEmployeeRosterInfo") McR getEmployeeRosterInfo(@RequestBody Map map) { List result = kyntService.getEmployeeRosterInfo(map); return McR.success(result); } //计算并设置员工年假数 @PostMapping("/getEmployeeAnnualLeaveNum") McR getEmployeeAnnualLeaveNum(@RequestBody Map map) { kyntService.getEmployeeAnnualLeaveNum(map); return McR.success(); } //每年1月1日 01:00定时更新员工年假数 @Scheduled(cron = "0 0 1 1 1 ? ") @GetMapping("/cronUpdateEmployeeAnnualLeaveNum") McR cronUpdateEmployeeAnnualLeaveNum(){ System.out.println("定时更新员工年假数开始执行"+new Date()); return kyntService.updateEmployeeAnnualLeaveNum(); } @PostMapping("/getUserLeaveInfo") McR getUserLeaveInfo(@RequestBody Map map) { String userId = map.get("userId").toString(); Map result = kyntService.getUserLeaveInfo(userId); return McR.success(result); } //保存10s内已处理的回调事件 private Map eventList = new HashMap<>(); //钉钉事件回调 @SneakyThrows @RequestMapping(value = "/callback", method = RequestMethod.POST) 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)); // 检查回调事件是否已经处理过,如果是,则忽略该回调 if (isCallbackProcessed(decryptMsg)) { log.info("----- [DD]该回调事件已处理过 忽略该回调 -----"); return success; } // 业务处理代码... 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 if (Objects.nonNull(eventJson.get("userid"))){ //通讯录事件返回的userId userId = eventJson.get("userid").toString(); }else { log.error("[DD]人事档案变动回调, 未获取到userId"); return success; } log.info("员工userId:"+userId); Map map = new HashMap(); map.put("userid_list", userId); //更新员工年假余额 log.info("----- [DD]更新员工年假余额 -----"); kyntService.getEmployeeAnnualLeaveNum(map); // 将回调事件和当前时间戳添加到已处理集合中 long currentTime = System.currentTimeMillis(); eventList.put(decryptMsg, currentTime); return success; } log.info("----- [DD]已注册, 未处理的其它回调 -----, eventType:{}, eventJson:{}",eventType, eventJson); return success; } /** * 检查该回调事件在10s内是否处理过,应对钉钉瞬间重复回调 * * @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); } }