SendMessageUtil.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. package com.kingdee.eas.custom.sendmessage.utils;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.kingdee.bos.BOSException;
  4. import com.kingdee.bos.Context;
  5. import com.kingdee.bos.ctrl.swing.StringUtils;
  6. import com.kingdee.bos.metadata.entity.EntityViewInfo;
  7. import com.kingdee.bos.metadata.entity.FilterInfo;
  8. import com.kingdee.bos.metadata.entity.FilterItemInfo;
  9. import com.kingdee.bos.metadata.entity.SelectorItemCollection;
  10. import com.kingdee.bos.metadata.query.util.CompareType;
  11. import com.kingdee.eas.basedata.person.PersonInfo;
  12. import com.kingdee.eas.common.EASBizException;
  13. import com.kingdee.eas.custom.logs.IMessageLogs;
  14. import com.kingdee.eas.custom.logs.MessageLogsFactory;
  15. import com.kingdee.eas.custom.logs.MessageLogsInfo;
  16. import com.kingdee.eas.custom.logs.app.SendStatusEnum;
  17. import com.kingdee.eas.custom.sendmessage.handler.ResignCertificationBillHRListHandlerEx;
  18. import com.kingdee.eas.hr.affair.*;
  19. import com.kingdee.eas.hr.ats.AtsUtil;
  20. import com.kingdee.eas.hr.emp.IPersonContactMethod;
  21. import com.kingdee.eas.hr.emp.PersonContactMethodFactory;
  22. import com.kingdee.eas.hr.emp.PersonContactMethodInfo;
  23. import com.kingdee.shr.base.syssetting.exception.SHRWebException;
  24. import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
  25. import com.kingdee.shr.certificationservice.*;
  26. import okhttp3.*;
  27. import org.apache.commons.codec.digest.DigestUtils;
  28. import org.apache.log4j.Logger;
  29. import javax.crypto.Cipher;
  30. import javax.crypto.spec.SecretKeySpec;
  31. import java.io.FileInputStream;
  32. import java.io.IOException;
  33. import java.nio.charset.StandardCharsets;
  34. import java.nio.file.Files;
  35. import java.nio.file.Paths;
  36. import java.text.SimpleDateFormat;
  37. import java.util.*;
  38. import java.util.concurrent.TimeUnit;
  39. /**
  40. * @author qingwu
  41. * @date 2024/11/19
  42. * @apiNote
  43. */
  44. public class SendMessageUtil {
  45. private static Logger logger =
  46. Logger.getLogger(ResignCertificationBillHRListHandlerEx.class);
  47. private Properties propt = new Properties();
  48. public SendMessageUtil() throws BOSException {
  49. String syncOAConfigPath = System.getProperty("EAS_HOME") + "/server/properties/gyt/sendMessage.properties";
  50. try {
  51. propt.load(Files.newBufferedReader(Paths.get(syncOAConfigPath), StandardCharsets.UTF_8));
  52. //propt.load(new FileInputStream(syncOAConfigPath));
  53. } catch (IOException e) {
  54. e.printStackTrace();
  55. String errorMsg = "获取配置文件报错,请检查配置:" + syncOAConfigPath + " " + e.getMessage();
  56. throw new BOSException(errorMsg);
  57. }
  58. }
  59. /**
  60. * 发送消息
  61. *
  62. * @throws SHRWebException
  63. */
  64. public void sendMessage(Context ctx, String billId) throws ShrWebBizException, BOSException, EASBizException {
  65. MessageLogsInfo messageLogsInfo = new MessageLogsInfo();
  66. IMessageLogs iMessageLogs = MessageLogsFactory.getLocalInstance(ctx);
  67. //成功条数
  68. int seccuss = 0;
  69. //失败条数
  70. int error = 0;
  71. try {
  72. Set<String> setBillId = AtsUtil.toSet(billId);
  73. //总条数
  74. messageLogsInfo.setCount(setBillId.size());
  75. //hr单据证明
  76. IHRCertificationBill ihrCertificationBill = HRCertificationBillFactory.getLocalInstance(ctx);
  77. SelectorItemCollection sic = new SelectorItemCollection();
  78. sic.add("*");
  79. sic.add("person.name");
  80. sic.add("person.number");
  81. sic.add("person.id");
  82. sic.add("certificationTemplet.name");
  83. sic.add("certificationTemplet.number");
  84. sic.add("certificationTemplet.id");
  85. sic.add("certificationTemplet.certificationBillType.name");
  86. sic.add("certificationTemplet.certificationBillType.number");
  87. sic.add("certificationTemplet.certificationBillType.id");
  88. sic.add("certificationTemplet.templateId");
  89. FilterInfo filterInfo = new FilterInfo();
  90. filterInfo.getFilterItems().add(new FilterItemInfo("id", setBillId, CompareType.INCLUDE));
  91. EntityViewInfo entityViewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
  92. HRCertificationBillCollection hrCertificationBillCollection = ihrCertificationBill.getHRCertificationBillCollection(entityViewInfo);
  93. for (int i = 0; i < hrCertificationBillCollection.size(); i++) {
  94. HRCertificationBillInfo hrCertificationBillInfo = hrCertificationBillCollection.get(i);
  95. //手机号
  96. String callPhone = hrCertificationBillInfo.getCallPhone();
  97. //证明模板
  98. CertificationTempletInfo certificationTemplet = hrCertificationBillInfo.getCertificationTemplet();
  99. String templateName = certificationTemplet.getName();
  100. String templateId = (String) certificationTemplet.get("templateId");
  101. //证明模板
  102. HRCertificationBillTypeInfo certificationBillType = certificationTemplet.getCertificationBillType();
  103. //模版名称
  104. messageLogsInfo.setReserved1(templateName);
  105. messageLogsInfo.setReserved2(certificationBillType.getName());
  106. if (StringUtils.isEmpty(templateId)) {
  107. throw new ShrWebBizException(templateName + "模板的消息id为空,请问维护!!");
  108. }
  109. String md5Sign = null;
  110. //过滤封装手机号
  111. //Map<String, Set> phoneMap = disposeCollFillterPhone(hrCertificationBillCollection, messageLogsInfo);
  112. //密钥
  113. String appSecret = propt.getProperty("appSecret");
  114. //uuid
  115. String uuid = UUID.randomUUID().toString();
  116. System.out.println("uuid---" + uuid);
  117. //应用类型
  118. String appType = propt.getProperty("appType");
  119. //应用id
  120. String appId = propt.getProperty("appId");
  121. //url
  122. String url = propt.getProperty("url");
  123. String signName = propt.getProperty("signName");
  124. logger.error("url---" + url);
  125. //时间戳
  126. Date date = new Date();
  127. String time = String.valueOf(date.getTime());
  128. messageLogsInfo.setTime(date);
  129. logger.error("time---" + time);
  130. //参数
  131. JSONObject params = new JSONObject();
  132. params.put("appId", appId);
  133. params.put("templateId", templateId);
  134. params.put("signName", signName);
  135. //批量发送才需要这个参数
  136. //params.put("phone", phone);
  137. params.put("phone", "15574198273");
  138. params.put("appId", appId);
  139. //消息模板
  140. Map<String, String> resultMap = SaveFileForDisk.getPDFInfo(ctx, hrCertificationBillInfo);
  141. JSONObject param = getTemplate(ctx, templateId, callPhone, resultMap.get("urlPath"), messageLogsInfo);
  142. params.put("params", param);
  143. //请求参数
  144. JSONObject jsonObject = new JSONObject();
  145. //jsonObject.put("params", params.toString());
  146. jsonObject.put("time", time);
  147. jsonObject.put("uuid", uuid);
  148. jsonObject.put("phones", callPhone);
  149. md5Sign = md5Sign(appSecret, url, params, appType, time, uuid, jsonObject);
  150. jsonObject.put("md5Sign", md5Sign);
  151. jsonObject.put("resultMap", resultMap);
  152. messageLogsInfo.setRequestParams(resultMap.get("urlPath"));
  153. messageLogsInfo.setRequestParams(jsonObject.toString());
  154. logger.error("md5Sign---" + md5Sign);
  155. logger.error("params---" + params);
  156. Response resultResponse = sendMeesage(params, appType, appId, uuid, md5Sign, time);
  157. String body = resultResponse.body().string();
  158. logger.error("body---" + body);
  159. JSONObject result = JSONObject.parseObject(body);
  160. String code = result.get("code").toString();
  161. if (!code.equals("200")) {
  162. error++;
  163. messageLogsInfo.setStatus(SendStatusEnum.fail);
  164. } else {
  165. seccuss++;
  166. messageLogsInfo.setStatus(SendStatusEnum.succeed);
  167. }
  168. //返回结果
  169. messageLogsInfo.setResult(body);
  170. messageLogsInfo.setSuccessNum(seccuss);
  171. messageLogsInfo.setFailNum(error);
  172. iMessageLogs.save(messageLogsInfo);
  173. }
  174. } catch (Exception e) {
  175. error++;
  176. //返回结果
  177. messageLogsInfo.setFailNum(error);
  178. messageLogsInfo.setResult(e.getMessage());
  179. messageLogsInfo.setStatus(SendStatusEnum.fail);
  180. iMessageLogs.save(messageLogsInfo);
  181. e.printStackTrace();
  182. throw new ShrWebBizException(e);
  183. }
  184. }
  185. /***
  186. * 获取消息模板
  187. * @param ctx
  188. * @param templateId
  189. * @param phone
  190. * @return
  191. */
  192. public JSONObject getTemplate(Context ctx, String templateId, String phone, String urlPath, MessageLogsInfo messageLogsInfo) throws BOSException {
  193. JSONObject param = new JSONObject();
  194. IPersonContactMethod iPersonContactMethod = PersonContactMethodFactory.getLocalInstance(ctx);
  195. PersonContactMethodInfo personContactMethodInfo = iPersonContactMethod
  196. .getPersonContactMethodCollection("select * ,person.* where nCell = '" + phone + "'").get(0);
  197. PersonInfo person = personContactMethodInfo.getPerson();
  198. messageLogsInfo.setPerson(person);
  199. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
  200. //SHR发送电子证明
  201. if (templateId.equals("MSG_2411190001")) {
  202. param.put("name", person.getName());
  203. param.put("urlPath", urlPath);
  204. }
  205. //SHR发送离职通知
  206. if (templateId.equals("MSG_2411200002")) {
  207. IResignBizBillEntry iResignBizBillEntry = ResignBizBillEntryFactory.getLocalInstance(ctx);
  208. ResignBizBillEntryInfo resignBizBillEntryInfo = iResignBizBillEntry
  209. .getResignBizBillEntryCollection("where person = '" + person.getId().toString() + "'").get(0);
  210. Date bizDate = resignBizBillEntryInfo.getBizDate();
  211. String lzDate = format.format(bizDate);
  212. param.put("name", person.getName());
  213. param.put("lzDate", lzDate);
  214. param.put("urlPath", urlPath);
  215. }
  216. return param;
  217. }
  218. /**
  219. * 通过模板id 分组过滤手机号以及校验是否有模板Id未维护
  220. *
  221. * @param hrCertificationBillCollection
  222. * @return
  223. */
  224. public Map disposeCollFillterPhone(HRCertificationBillCollection hrCertificationBillCollection, MessageLogsInfo messageLogsInfo) throws ShrWebBizException {
  225. Map<String, Set> certificationBillTypeMap = new HashMap<>();
  226. for (int i = 0; i < hrCertificationBillCollection.size(); i++) {
  227. HRCertificationBillInfo hrCertificationBillInfo = hrCertificationBillCollection.get(i);
  228. //手机号
  229. String callPhone = hrCertificationBillInfo.getCallPhone();
  230. //证明模板
  231. CertificationTempletInfo certificationTemplet = hrCertificationBillInfo.getCertificationTemplet();
  232. String templateName = certificationTemplet.getName();
  233. String templateId = (String) certificationTemplet.get("templateId");
  234. //证明模板
  235. HRCertificationBillTypeInfo certificationBillType = certificationTemplet.getCertificationBillType();
  236. //模版名称
  237. messageLogsInfo.setReserved1(templateName);
  238. messageLogsInfo.setReserved2(certificationBillType.getName());
  239. if (StringUtils.isEmpty(templateId)) {
  240. throw new ShrWebBizException(templateName + "模板的消息id为空,请问维护!!");
  241. }
  242. if (!certificationBillTypeMap.containsKey(templateId)) {
  243. certificationBillTypeMap.put(templateId, new HashSet<>());
  244. }
  245. certificationBillTypeMap.get(templateId).add(callPhone);
  246. }
  247. Map<String, Set> phoneMap = new HashMap<String, Set>();
  248. // 遍历输出结果map
  249. certificationBillTypeMap.forEach((templateId, callPhoneSet) -> {
  250. //多个人的手机号 用逗号隔开
  251. //String phones = deleteCharAt(callPhoneSet);
  252. phoneMap.put(templateId, callPhoneSet);
  253. });
  254. return phoneMap;
  255. }
  256. /**
  257. * 处理集合 封装数据
  258. *
  259. * @param set
  260. * @return
  261. */
  262. public String deleteCharAt(Set<String> set) {
  263. StringBuilder callPhoneBuilder = new StringBuilder();
  264. for (String phone : set) {
  265. callPhoneBuilder.append(phone).append(",");
  266. }
  267. callPhoneBuilder.deleteCharAt(callPhoneBuilder.lastIndexOf(","));
  268. return callPhoneBuilder.toString();
  269. }
  270. /**
  271. * 发送信息
  272. *
  273. * @param params
  274. * @param appType
  275. * @param appId
  276. * @param uuid
  277. * @param md5Sign
  278. * @throws IOException
  279. */
  280. private Response sendMeesage(JSONObject params, String appType, String appId, String uuid, String md5Sign, String time) throws IOException {
  281. //发送请求
  282. OkHttpClient client = new OkHttpClient.Builder()
  283. .connectTimeout(30, TimeUnit.SECONDS)
  284. .writeTimeout(30, TimeUnit.SECONDS)
  285. .readTimeout(30, TimeUnit.SECONDS)
  286. .build();
  287. MediaType mediaType = MediaType.parse("application/json");
  288. RequestBody body = RequestBody.create(mediaType, params.toString());
  289. Request request = new Request.Builder()
  290. //.url(propt.getProperty("sendMessageTaskUrl")) //批量发送消息
  291. .url(propt.getProperty("sendMessageUrl"))
  292. .post(body)
  293. //X-*-Sign 指定的算法,可选范围目前只有 md5,后续如有必要会增添其他算法
  294. .addHeader("X-message-Algorithm", "md5")
  295. //时间戳,请求时间,防止重放攻击,目前后台最多延时 15 分钟
  296. .addHeader("X-message-Time", time)
  297. //终端应用类型,比如小程序设置为 1、WEB 端设置为 2、APP 端设 置为 3,建议设置 2
  298. .addHeader("X-message-AppType", appType)
  299. //应用唯一标识,用于判断是那个应用调用消息中心
  300. .addHeader("X-message-AppID", appId)
  301. //随机码,防止重放攻击,延时时间之内不能重复,客户端可以采 用 UUID 生成
  302. .addHeader("X-message-Nonce", uuid)
  303. //签名 Sign,具体说明看下文
  304. //MD5( APPSECRET+路径+参数 +X-*-AppType +X-*-Time +X-*-Nonce )
  305. .addHeader("X-message-Sign", md5Sign)
  306. .addHeader("Content-Type", "application/json")
  307. .addHeader("User-Agent", "PostmanRuntime-ApipostRuntime/1.1.0")
  308. .addHeader("Connection", "keep-alive")
  309. .addHeader("Accept", "*/*")
  310. .build();
  311. return client.newCall(request).execute();
  312. }
  313. /**
  314. * 获取 sign
  315. *
  316. * @param appSecret 密钥
  317. * @param url url
  318. * @param params 参数
  319. * @param appType 类型 建议为2
  320. * @param appTime 时间戳
  321. * @param nonce 随机码
  322. * @return
  323. */
  324. public String md5Sign(String appSecret, String url, Map params, String appType, String appTime, String nonce, JSONObject jsonObject) {
  325. //System.out.println(params.toString());
  326. String code = appSecret + url + params.toString() + appType + appTime + nonce;
  327. logger.error("code---" + code);
  328. jsonObject.put("code", code);
  329. return DigestUtils.md5Hex(code).toLowerCase();
  330. }
  331. /**
  332. * aes加密
  333. *
  334. * @param phone
  335. * @param appSecret
  336. * @return
  337. * @throws Exception
  338. */
  339. public static String encrypt(String phone, String appSecret) throws Exception {
  340. // 将自定义的字符串密钥转换为字节数组,注意要确保长度符合要求(AES 128位对应16字节等)
  341. byte[] keyBytes = appSecret.getBytes(StandardCharsets.UTF_8);
  342. // 如果密钥长度不符合要求,这里可以进行适当处理,比如截取或填充等,示例采用简单截取到16字节长度(仅针对128位AES示例)
  343. if (keyBytes.length > 16) {
  344. keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
  345. } else if (keyBytes.length < 16) {
  346. byte[] newKeyBytes = new byte[16];
  347. System.arraycopy(keyBytes, 0, newKeyBytes, 0, keyBytes.length);
  348. keyBytes = newKeyBytes;
  349. }
  350. SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
  351. Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  352. cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
  353. byte[] encryptedBytes = cipher.doFinal(phone.getBytes(StandardCharsets.UTF_8));
  354. return Base64.getEncoder().encodeToString(encryptedBytes);
  355. }
  356. }