package com.kingdee.eas.custom.sendmessage.utils; import com.alibaba.fastjson.JSONObject; import com.kingdee.bos.BOSException; import com.kingdee.bos.Context; import com.kingdee.bos.ctrl.swing.StringUtils; import com.kingdee.bos.metadata.entity.EntityViewInfo; import com.kingdee.bos.metadata.entity.FilterInfo; import com.kingdee.bos.metadata.entity.FilterItemInfo; import com.kingdee.bos.metadata.entity.SelectorItemCollection; import com.kingdee.bos.metadata.query.util.CompareType; import com.kingdee.eas.basedata.person.PersonInfo; import com.kingdee.eas.common.EASBizException; import com.kingdee.eas.custom.logs.IMessageLogs; import com.kingdee.eas.custom.logs.MessageLogsFactory; import com.kingdee.eas.custom.logs.MessageLogsInfo; import com.kingdee.eas.custom.logs.app.SendStatusEnum; import com.kingdee.eas.custom.sendmessage.handler.ResignCertificationBillHRListHandlerEx; import com.kingdee.eas.hr.affair.*; import com.kingdee.eas.hr.ats.AtsUtil; import com.kingdee.eas.hr.emp.IPersonContactMethod; import com.kingdee.eas.hr.emp.PersonContactMethodFactory; import com.kingdee.eas.hr.emp.PersonContactMethodInfo; import com.kingdee.shr.base.syssetting.exception.SHRWebException; import com.kingdee.shr.base.syssetting.exception.ShrWebBizException; import com.kingdee.shr.certificationservice.*; import okhttp3.*; import org.apache.commons.codec.digest.DigestUtils; import org.apache.log4j.Logger; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.FileInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.TimeUnit; /** * @author qingwu * @date 2024/11/19 * @apiNote */ public class SendMessageUtil { private static Logger logger = Logger.getLogger(ResignCertificationBillHRListHandlerEx.class); private Properties propt = new Properties(); public SendMessageUtil() throws BOSException { String syncOAConfigPath = System.getProperty("EAS_HOME") + "/server/properties/gyt/sendMessage.properties"; try { propt.load(Files.newBufferedReader(Paths.get(syncOAConfigPath), StandardCharsets.UTF_8)); //propt.load(new FileInputStream(syncOAConfigPath)); } catch (IOException e) { e.printStackTrace(); String errorMsg = "获取配置文件报错,请检查配置:" + syncOAConfigPath + " " + e.getMessage(); throw new BOSException(errorMsg); } } /** * 发送消息 * * @throws SHRWebException */ public void sendMessage(Context ctx, String billId) throws ShrWebBizException, BOSException, EASBizException { MessageLogsInfo messageLogsInfo = new MessageLogsInfo(); IMessageLogs iMessageLogs = MessageLogsFactory.getLocalInstance(ctx); //成功条数 int seccuss = 0; //失败条数 int error = 0; try { Set setBillId = AtsUtil.toSet(billId); //总条数 messageLogsInfo.setCount(setBillId.size()); //hr单据证明 IHRCertificationBill ihrCertificationBill = HRCertificationBillFactory.getLocalInstance(ctx); SelectorItemCollection sic = new SelectorItemCollection(); sic.add("*"); sic.add("person.name"); sic.add("person.number"); sic.add("person.id"); sic.add("certificationTemplet.name"); sic.add("certificationTemplet.number"); sic.add("certificationTemplet.id"); sic.add("certificationTemplet.certificationBillType.name"); sic.add("certificationTemplet.certificationBillType.number"); sic.add("certificationTemplet.certificationBillType.id"); sic.add("certificationTemplet.templateId"); FilterInfo filterInfo = new FilterInfo(); filterInfo.getFilterItems().add(new FilterItemInfo("id", setBillId, CompareType.INCLUDE)); EntityViewInfo entityViewInfo = EntityViewInfo.getInstance(filterInfo, sic, null); HRCertificationBillCollection hrCertificationBillCollection = ihrCertificationBill.getHRCertificationBillCollection(entityViewInfo); for (int i = 0; i < hrCertificationBillCollection.size(); i++) { HRCertificationBillInfo hrCertificationBillInfo = hrCertificationBillCollection.get(i); //手机号 String callPhone = hrCertificationBillInfo.getCallPhone(); //证明模板 CertificationTempletInfo certificationTemplet = hrCertificationBillInfo.getCertificationTemplet(); String templateName = certificationTemplet.getName(); String templateId = (String) certificationTemplet.get("templateId"); //证明模板 HRCertificationBillTypeInfo certificationBillType = certificationTemplet.getCertificationBillType(); //模版名称 messageLogsInfo.setReserved1(templateName); messageLogsInfo.setReserved2(certificationBillType.getName()); if (StringUtils.isEmpty(templateId)) { throw new ShrWebBizException(templateName + "模板的消息id为空,请问维护!!"); } String md5Sign = null; //过滤封装手机号 //Map phoneMap = disposeCollFillterPhone(hrCertificationBillCollection, messageLogsInfo); //密钥 String appSecret = propt.getProperty("appSecret"); //uuid String uuid = UUID.randomUUID().toString(); System.out.println("uuid---" + uuid); //应用类型 String appType = propt.getProperty("appType"); //应用id String appId = propt.getProperty("appId"); //url String url = propt.getProperty("url"); String signName = propt.getProperty("signName"); logger.error("url---" + url); //时间戳 Date date = new Date(); String time = String.valueOf(date.getTime()); messageLogsInfo.setTime(date); logger.error("time---" + time); //参数 JSONObject params = new JSONObject(); params.put("appId", appId); params.put("templateId", templateId); params.put("signName", signName); //批量发送才需要这个参数 //params.put("phone", phone); params.put("phone", "15574198273"); params.put("appId", appId); //消息模板 Map resultMap = SaveFileForDisk.getPDFInfo(ctx, hrCertificationBillInfo); JSONObject param = getTemplate(ctx, templateId, callPhone, resultMap.get("urlPath"), messageLogsInfo); params.put("params", param); //请求参数 JSONObject jsonObject = new JSONObject(); //jsonObject.put("params", params.toString()); jsonObject.put("time", time); jsonObject.put("uuid", uuid); jsonObject.put("phones", callPhone); md5Sign = md5Sign(appSecret, url, params, appType, time, uuid, jsonObject); jsonObject.put("md5Sign", md5Sign); jsonObject.put("resultMap", resultMap); messageLogsInfo.setRequestParams(resultMap.get("urlPath")); messageLogsInfo.setRequestParams(jsonObject.toString()); logger.error("md5Sign---" + md5Sign); logger.error("params---" + params); Response resultResponse = sendMeesage(params, appType, appId, uuid, md5Sign, time); String body = resultResponse.body().string(); logger.error("body---" + body); JSONObject result = JSONObject.parseObject(body); String code = result.get("code").toString(); if (!code.equals("200")) { error++; messageLogsInfo.setStatus(SendStatusEnum.fail); } else { seccuss++; messageLogsInfo.setStatus(SendStatusEnum.succeed); } //返回结果 messageLogsInfo.setResult(body); messageLogsInfo.setSuccessNum(seccuss); messageLogsInfo.setFailNum(error); iMessageLogs.save(messageLogsInfo); } } catch (Exception e) { error++; //返回结果 messageLogsInfo.setFailNum(error); messageLogsInfo.setResult(e.getMessage()); messageLogsInfo.setStatus(SendStatusEnum.fail); iMessageLogs.save(messageLogsInfo); e.printStackTrace(); throw new ShrWebBizException(e); } } /*** * 获取消息模板 * @param ctx * @param templateId * @param phone * @return */ public JSONObject getTemplate(Context ctx, String templateId, String phone, String urlPath, MessageLogsInfo messageLogsInfo) throws BOSException { JSONObject param = new JSONObject(); IPersonContactMethod iPersonContactMethod = PersonContactMethodFactory.getLocalInstance(ctx); PersonContactMethodInfo personContactMethodInfo = iPersonContactMethod .getPersonContactMethodCollection("select * ,person.* where nCell = '" + phone + "'").get(0); PersonInfo person = personContactMethodInfo.getPerson(); messageLogsInfo.setPerson(person); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); //SHR发送电子证明 if (templateId.equals("MSG_2411190001")) { param.put("name", person.getName()); param.put("urlPath", urlPath); } //SHR发送离职通知 if (templateId.equals("MSG_2411200002")) { IResignBizBillEntry iResignBizBillEntry = ResignBizBillEntryFactory.getLocalInstance(ctx); ResignBizBillEntryInfo resignBizBillEntryInfo = iResignBizBillEntry .getResignBizBillEntryCollection("where person = '" + person.getId().toString() + "'").get(0); Date bizDate = resignBizBillEntryInfo.getBizDate(); String lzDate = format.format(bizDate); param.put("name", person.getName()); param.put("lzDate", lzDate); param.put("urlPath", urlPath); } return param; } /** * 通过模板id 分组过滤手机号以及校验是否有模板Id未维护 * * @param hrCertificationBillCollection * @return */ public Map disposeCollFillterPhone(HRCertificationBillCollection hrCertificationBillCollection, MessageLogsInfo messageLogsInfo) throws ShrWebBizException { Map certificationBillTypeMap = new HashMap<>(); for (int i = 0; i < hrCertificationBillCollection.size(); i++) { HRCertificationBillInfo hrCertificationBillInfo = hrCertificationBillCollection.get(i); //手机号 String callPhone = hrCertificationBillInfo.getCallPhone(); //证明模板 CertificationTempletInfo certificationTemplet = hrCertificationBillInfo.getCertificationTemplet(); String templateName = certificationTemplet.getName(); String templateId = (String) certificationTemplet.get("templateId"); //证明模板 HRCertificationBillTypeInfo certificationBillType = certificationTemplet.getCertificationBillType(); //模版名称 messageLogsInfo.setReserved1(templateName); messageLogsInfo.setReserved2(certificationBillType.getName()); if (StringUtils.isEmpty(templateId)) { throw new ShrWebBizException(templateName + "模板的消息id为空,请问维护!!"); } if (!certificationBillTypeMap.containsKey(templateId)) { certificationBillTypeMap.put(templateId, new HashSet<>()); } certificationBillTypeMap.get(templateId).add(callPhone); } Map phoneMap = new HashMap(); // 遍历输出结果map certificationBillTypeMap.forEach((templateId, callPhoneSet) -> { //多个人的手机号 用逗号隔开 //String phones = deleteCharAt(callPhoneSet); phoneMap.put(templateId, callPhoneSet); }); return phoneMap; } /** * 处理集合 封装数据 * * @param set * @return */ public String deleteCharAt(Set set) { StringBuilder callPhoneBuilder = new StringBuilder(); for (String phone : set) { callPhoneBuilder.append(phone).append(","); } callPhoneBuilder.deleteCharAt(callPhoneBuilder.lastIndexOf(",")); return callPhoneBuilder.toString(); } /** * 发送信息 * * @param params * @param appType * @param appId * @param uuid * @param md5Sign * @throws IOException */ private Response sendMeesage(JSONObject params, String appType, String appId, String uuid, String md5Sign, String time) throws IOException { //发送请求 OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, params.toString()); Request request = new Request.Builder() //.url(propt.getProperty("sendMessageTaskUrl")) //批量发送消息 .url(propt.getProperty("sendMessageUrl")) .post(body) //X-*-Sign 指定的算法,可选范围目前只有 md5,后续如有必要会增添其他算法 .addHeader("X-message-Algorithm", "md5") //时间戳,请求时间,防止重放攻击,目前后台最多延时 15 分钟 .addHeader("X-message-Time", time) //终端应用类型,比如小程序设置为 1、WEB 端设置为 2、APP 端设 置为 3,建议设置 2 .addHeader("X-message-AppType", appType) //应用唯一标识,用于判断是那个应用调用消息中心 .addHeader("X-message-AppID", appId) //随机码,防止重放攻击,延时时间之内不能重复,客户端可以采 用 UUID 生成 .addHeader("X-message-Nonce", uuid) //签名 Sign,具体说明看下文 //MD5( APPSECRET+路径+参数 +X-*-AppType +X-*-Time +X-*-Nonce ) .addHeader("X-message-Sign", md5Sign) .addHeader("Content-Type", "application/json") .addHeader("User-Agent", "PostmanRuntime-ApipostRuntime/1.1.0") .addHeader("Connection", "keep-alive") .addHeader("Accept", "*/*") .build(); return client.newCall(request).execute(); } /** * 获取 sign * * @param appSecret 密钥 * @param url url * @param params 参数 * @param appType 类型 建议为2 * @param appTime 时间戳 * @param nonce 随机码 * @return */ public String md5Sign(String appSecret, String url, Map params, String appType, String appTime, String nonce, JSONObject jsonObject) { //System.out.println(params.toString()); String code = appSecret + url + params.toString() + appType + appTime + nonce; logger.error("code---" + code); jsonObject.put("code", code); return DigestUtils.md5Hex(code).toLowerCase(); } /** * aes加密 * * @param phone * @param appSecret * @return * @throws Exception */ public static String encrypt(String phone, String appSecret) throws Exception { // 将自定义的字符串密钥转换为字节数组,注意要确保长度符合要求(AES 128位对应16字节等) byte[] keyBytes = appSecret.getBytes(StandardCharsets.UTF_8); // 如果密钥长度不符合要求,这里可以进行适当处理,比如截取或填充等,示例采用简单截取到16字节长度(仅针对128位AES示例) if (keyBytes.length > 16) { keyBytes = java.util.Arrays.copyOf(keyBytes, 16); } else if (keyBytes.length < 16) { byte[] newKeyBytes = new byte[16]; System.arraycopy(keyBytes, 0, newKeyBytes, 0, keyBytes.length); keyBytes = newKeyBytes; } SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); byte[] encryptedBytes = cipher.doFinal(phone.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encryptedBytes); } }