From 761a2f08d443c50fbb526b6644ba56b421b6c697 Mon Sep 17 00:00:00 2001 From: DB <2502523450@qq.com> Date: Thu, 29 Feb 2024 15:18:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AF=B7=E6=B1=82=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cpop/core/utils/CpopSignatureUtils.java | 133 ++++++++++++++++++ .../java/com/cpop/core/utils/RsaUtils.java | 12 +- .../business/bo/EasyLearnUnionPayBo.java | 2 +- .../framework/enums/EasyLearnPayPayEnum.java | 2 +- .../java/com/cpop/oam/web/CpopApiTests.java | 22 +++ .../oam/business/bo/ApiTenantRequest.java | 93 ++++++++++++ .../framework/tasks/OamScheduledTasks.java | 47 +++++++ .../tasks/WorkOrderPauseRecoverTask.java | 24 ++++ .../backstage/BackstageBrandController.java | 2 +- 9 files changed, 332 insertions(+), 5 deletions(-) create mode 100644 Cpop-Core/src/main/java/com/cpop/core/utils/CpopSignatureUtils.java create mode 100644 Cpop-Oam/src/main/java/com/cpop/oam/business/bo/ApiTenantRequest.java diff --git a/Cpop-Core/src/main/java/com/cpop/core/utils/CpopSignatureUtils.java b/Cpop-Core/src/main/java/com/cpop/core/utils/CpopSignatureUtils.java new file mode 100644 index 0000000..2f1cb58 --- /dev/null +++ b/Cpop-Core/src/main/java/com/cpop/core/utils/CpopSignatureUtils.java @@ -0,0 +1,133 @@ +package com.cpop.core.utils; + +import com.alibaba.fastjson2.JSONObject; +import com.cpop.core.base.entity.CpopSignBase; +import okhttp3.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.DigestUtils; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author DB + * @version 1.0.0 + * @since 2024-02-28 14:50 + */ +@Component +public class CpopSignatureUtils { + + @Autowired + private RsaUtils rsaUtils; + + private static final Map APP_IDS = new HashMap() {{ + //数币 + put("1688842965582499840", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmsFHkB4iIdVSgaz8u8QG66wiZupgSbu2T/ml/kdPm2vemsKgvEqUqp1gR6ulfHcPF8otjVbjiE8q8oR70XfxFIREbomTUmpsOzurLFrAmVhyvu6/tY23/txjQoeeH/tlCy7Lq/TL1AqPKyBcGzsQ4yInpIgRWpXz7fmJCTRw07tyE+4lpXBqiaLdWrkkGG00LnHQAOfcUoXf0TdxFPSfRHiBikfbkmgeVoU66RGlUEXU2esTY2nYGvFn+FqWsNkGEnn2YxIqgbQQ1zNX33+FWBlba1WdQtc8mTJAleaPGXmFnQiEMb55b7xVPjyyCWt6aRwl97KQgtCmfsoPZUWwQQIDAQAB"}); + //系统 + put("100", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvDdtx3eLzoUbm0qr8xv4XXew0raUsv98eOmdxS4jDgFkajzK3H02fnWg99y2CRcZNnEFA6MlE/0RrAuWnuIehazQBR5dpnzoOht4WweRO0DEciRTdQ5Uf5T4YOlwmNKhE2S9jsmBP8X5Gi2r65G4miBG8r4AJJ9Pxtq8fjZUkCpKrk3y167mSunDUtZZOAimQ7W235Oh7fIqOSNQN+KxvhFSkiSqFIaXjDY50eONdSBaPYV1NsbW5A6VHrsvcG/2uzcEAfINFoRsmF9SxsckvnVsVfKgN+ONvnQdFmAJaiwtXJ9eJ4TfMt+HPTZk8pMfAUEj8vfz/98g39kKY42b2QIDAQAB"}); + }}; + + /** + * 发送签名http请求 + * @author DB + * @since 2024/2/28 + * @param url 路径 + * @param data 数据 + * @param appid appid + * @return Response + */ + public JSONObject sendSignaturePost(String url, Object data, String appid) throws IOException, IllegalAccessException { + OkHttpClient client = new OkHttpClient().newBuilder().build(); + MediaType mediaType = MediaType.Companion.parse("application/json;charset=utf-8"); + RequestBody body = RequestBody.Companion.create(JSONObject.toJSONString(data), mediaType); + String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); + String signType = "RSA"; + CpopSignBase cpopSignBase = new CpopSignBase(); + cpopSignBase.setSignType(signType); + cpopSignBase.setDateTime(now); + cpopSignBase.setAppId(appid); + cpopSignBase.setSignature(md5(data, appid)); + Request request = new Request + .Builder() + .url(url) + .post(body) + .addHeader("Content-Type", "application/json") + .addHeader("appId", appid) + .addHeader("signature", signature(cpopSignBase,APP_IDS.get(appid)[0])) + .addHeader("dateTime", now) + .addHeader("signType", signType) + .build(); + Response response = null; + try { + response = client.newCall(request).execute(); + return JSONObject.parseObject(response.body().string()); + } finally { + assert response != null; + response.close(); + } + } + + private String md5(Object object, String appId) throws IllegalAccessException { + //验签拼接字段 + List signString = new ArrayList(); + //获取父类(公共类必传属性) + Field[] fatherFields = object.getClass().getSuperclass().getDeclaredFields(); + for (Field field : fatherFields) { + field.setAccessible(true); + signString.add(field.getName() + "=" + field.get(object)); + } + //可能为空参 + Field[] fields = object.getClass().getDeclaredFields(); + if (fields.length > 0) { + for (Field field : fields) { + field.setAccessible(true); + if (null == field.get(object)) { + signString.add(field.getName() + "="); + } else { + signString.add(field.getName() + "=" + field.get(object)); + } + } + } + //按照字母排序 + String sign = signString.stream().sorted().collect(Collectors.joining("&")) + appId; + return DigestUtils.md5DigestAsHex(sign.getBytes()); + } + + /** + * 签名 + * + * @param data 数据 + * @return String + * @author DB + * @since 2024/2/28 + */ + private String signature(CpopSignBase data, String publicKey) { + return rsaUtils.encrypt(JSONObject.toJSONString(data), stringToPublicKey(publicKey)); + } + + private PublicKey stringToPublicKey(String publicKey) { + byte[] decode = Base64.getDecoder().decode(publicKey); + X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decode); + //返回转换指定算法的KeyFactory对象 + KeyFactory keyFactory = null; + try { + keyFactory = KeyFactory.getInstance("RSA"); + //根据PKCS8编码密钥规范产生私钥对象 + return keyFactory.generatePublic(x509EncodedKeySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new RuntimeException(e); + } + } +} diff --git a/Cpop-Core/src/main/java/com/cpop/core/utils/RsaUtils.java b/Cpop-Core/src/main/java/com/cpop/core/utils/RsaUtils.java index e0f833a..ac59ab7 100644 --- a/Cpop-Core/src/main/java/com/cpop/core/utils/RsaUtils.java +++ b/Cpop-Core/src/main/java/com/cpop/core/utils/RsaUtils.java @@ -169,8 +169,7 @@ public class RsaUtils { * @param source 源数据 * @return 加密后的字符串 */ - public String encrypt(String source) { - Key publicKey = getKeyFromFile(keyPairConfig.getPublicKeyFile()); + public String encrypt(String source, Key publicKey) { Base64.Encoder encoder = Base64.getEncoder(); String encryptSource = null; try { @@ -187,6 +186,15 @@ public class RsaUtils { return encryptSource; } + /** + * 加密方法 + * @param source 源数据 + * @return 加密后的字符串 + */ + public String encrypt(String source) { + return encrypt(source, getKeyFromFile(keyPairConfig.getPublicKeyFile())); + } + /** * 解密方法 * @param source 密文 diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/bo/EasyLearnUnionPayBo.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/bo/EasyLearnUnionPayBo.java index 5be9b87..979089c 100644 --- a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/bo/EasyLearnUnionPayBo.java +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/bo/EasyLearnUnionPayBo.java @@ -64,7 +64,7 @@ public class EasyLearnUnionPayBo { /** * 订单类型 */ - @NotNull(message = "联合支付类型不能为空") + @NotBlank(message = "联合支付类型不能为空") @ApiModelProperty(value = "联合支付类型(WX_PAY:微信支付;PREPAYMENT:预付;REPAYMENT:还款;MEMBER:会员)",required = true) private String easyLearnUnionPay; diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/framework/enums/EasyLearnPayPayEnum.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/framework/enums/EasyLearnPayPayEnum.java index d3e9724..424d987 100644 --- a/Cpop-Jambox/src/main/java/com/cpop/jambox/framework/enums/EasyLearnPayPayEnum.java +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/framework/enums/EasyLearnPayPayEnum.java @@ -51,7 +51,7 @@ public enum EasyLearnPayPayEnum { } /** - * 分账比例 + * 订单类型 */ private Integer orderType; diff --git a/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopApiTests.java b/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopApiTests.java index edc0a96..1edd043 100644 --- a/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopApiTests.java +++ b/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopApiTests.java @@ -3,14 +3,22 @@ package com.cpop.oam.web; import com.alibaba.fastjson.JSONObject; import com.cpop.api.tencent.location.handler.TencentLocationHandler; import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler; +import com.cpop.core.annontation.StringArrayConvert; +import com.cpop.core.utils.CpopSignatureUtils; import com.cpop.core.utils.RsaUtils; import com.cpop.core.utils.SpringUtils; +import com.cpop.oam.business.bo.ApiTenantRequest; import com.cpop.pay.framewok.handler.ecpp.EcppHandler; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.experimental.Accessors; +import okhttp3.Response; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @@ -60,4 +68,18 @@ public class CpopApiTests { JSONObject geocoder = SpringUtils.getBean(TencentLocationHandler.class).geocoder("114.4246835", "23.12707132", "UGLBZ-LBF3I-ETCGO-UUH5X-QDV45-3LFKA"); System.out.println(geocoder); } + + /** + * 新增租户 + * @author DB + * @since 2024/2/28 + */ + @Test + public void insertTenant() throws IOException, IllegalAccessException { + com.alibaba.fastjson2.JSONObject jsonObject = SpringUtils.getBean(CpopSignatureUtils.class).sendSignaturePost("http://localhost:9440/Jambox-System/api/tenant/insertTenant", + new ApiTenantRequest().setName("测试租户").setIsSuper(false), "100"); + System.out.println(jsonObject); + } + + } diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/business/bo/ApiTenantRequest.java b/Cpop-Oam/src/main/java/com/cpop/oam/business/bo/ApiTenantRequest.java new file mode 100644 index 0000000..1c0961d --- /dev/null +++ b/Cpop-Oam/src/main/java/com/cpop/oam/business/bo/ApiTenantRequest.java @@ -0,0 +1,93 @@ +package com.cpop.oam.business.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDate; + +/** + * @author DB + * @version 1.0.0 + * @since 2024-02-28 16:50 + */ +@Data +@Accessors(chain = true) +public class ApiTenantRequest { + + /** + * 主键 + */ + private String id; + + /** + * 租户名 + */ + private String name; + + /** + * 是否是超管 + */ + private Boolean isSuper; + + /** + * 外部id + */ + private String outId; + + /** + * logo + */ + private String logo; + + /** + * 排序 + */ + private Integer orderNo; + + /** + * 手机号 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 地址 + */ + private String address; + + /** + * 用户名 + */ + private String username; + + /** + * 密码 + */ + private String password; + + /** + * 昵称 + */ + private String nickname; + + /** + * 状态(0:停用;1:启用) + */ + private Boolean status; + + /** + * 到期日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private LocalDate maturityDate; + + /** + * 加密签名 + */ + private String signature; +} diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/OamScheduledTasks.java b/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/OamScheduledTasks.java index b24ca33..b6e3c4c 100644 --- a/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/OamScheduledTasks.java +++ b/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/OamScheduledTasks.java @@ -1,7 +1,9 @@ package com.cpop.oam.framework.tasks; +import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler; import com.cpop.common.utils.StringUtils; import com.cpop.common.utils.bean.BeanUtils; +import com.cpop.core.base.exception.ServiceException; import com.cpop.core.base.table.SysConfig; import com.cpop.core.service.CoreService; import com.cpop.core.service.RedisService; @@ -14,7 +16,9 @@ import com.cpop.oam.business.entity.table.DataImportTableDef; import com.cpop.oam.business.mapper.ClueMapper; import com.cpop.oam.business.service.*; import com.cpop.oam.business.vo.SignGoalConfigInfoVo; +import com.cpop.oam.business.vo.StaffInfoVo; import com.cpop.oam.framework.constant.OamConfigKey; +import com.cpop.oam.framework.constant.WebHookKeyConstant; import com.cpop.oam.framework.enums.OamConfigEnum; import com.mybatisflex.core.row.Db; import com.mybatisflex.core.update.UpdateChain; @@ -25,6 +29,7 @@ import org.springframework.context.annotation.Profile; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.transaction.annotation.Transactional; +import java.io.IOException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; @@ -212,4 +217,46 @@ public class OamScheduledTasks { } } } + + /** + * 任务逾期提醒 + * @author DB + * @since 2023/12/11 + */ + @Scheduled(cron = "0 30 9 * * *") + public void taskOverdueRemind() { + log.info("==============开始检查即将逾期任务==========="); + TaskService taskService = SpringUtils.getBean(TaskService.class); + //进行中的任务提醒任务负责人 + List dealTasks = taskService.queryChain().where(TASK.TASK_STATUS.eq(2)).and(TASK.TASK_TYPE.in(0, 1)).and(TASK.EXPECTED_COMPLETION_DATE.eq(LocalDate.now())).list(); + if (!dealTasks.isEmpty()) { + dealTasks.forEach(item->{ + ArrayList phoneList = new ArrayList<>(); + StaffInfoVo staffInfo = SpringUtils.getBean(StaffService.class).getStaffInfo(item.getResponsibleStaffId()); + phoneList.add(staffInfo.getPhoneNumber()); + try { + SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.ORDER_INFO_BOT, phoneList, + "==========您有一个任务今天即将到期,请及时处理==========\n" + item.getTaskContent(), + false); + } catch (IOException e) { + throw new ServiceException("发送消息通知失败!"); + } + }); + } + List testTasks = taskService.queryChain().where(TASK.TASK_STATUS.eq(3)).and(TASK.TASK_TYPE.in(0, 1)).and(TASK.EXPECTED_COMPLETION_DATE.eq(LocalDate.now().minusDays(1))).list(); + if (!testTasks.isEmpty()) { + String testStaffPhones = SpringUtils.getBean(RedisService.class).getCacheObject(OamConfigKey.OAM_CONFIG_KEY + OamConfigEnum.TEST_STAFF_PHONE.getKey()); + testTasks.forEach(item->{ + ArrayList phoneList = new ArrayList<>(); + phoneList.add(testStaffPhones); + try { + SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.ORDER_INFO_BOT, phoneList, + "==========您有一个测试任务今天即将到期,请及时处理==========\n" + item.getTaskContent(), + false); + } catch (IOException e) { + throw new ServiceException("发送消息通知失败!"); + } + }); + } + } } diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/WorkOrderPauseRecoverTask.java b/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/WorkOrderPauseRecoverTask.java index 2dca877..99d5c94 100644 --- a/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/WorkOrderPauseRecoverTask.java +++ b/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/WorkOrderPauseRecoverTask.java @@ -1,15 +1,24 @@ package com.cpop.oam.framework.tasks; +import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler; +import com.cpop.core.base.exception.ServiceException; import com.cpop.core.utils.SpringUtils; import com.cpop.oam.business.entity.Task; import com.cpop.oam.business.entity.TaskWorkOrder; +import com.cpop.oam.business.service.StaffService; import com.cpop.oam.business.service.TaskService; import com.cpop.oam.business.service.TaskWorkOrderService; +import com.cpop.oam.business.vo.StaffInfoVo; +import com.cpop.oam.framework.constant.WebHookKeyConstant; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + import static com.cpop.oam.business.entity.table.TaskTableDef.TASK; /** @@ -32,6 +41,21 @@ public class WorkOrderPauseRecoverTask implements Job { Task task = taskService.getById(taskWorkOrder.getTaskId()); if (task.getTaskStatus() == 5) { taskService.updateChain().set(TASK.TASK_STATUS, 2).where(TASK.ID.eq(taskWorkOrder.getTaskId())).update(); + // 发送消息通知 + List phoneList = new ArrayList(); + StaffInfoVo responsibleStaff = SpringUtils.getBean(StaffService.class).getStaffInfo(task.getResponsibleStaffId()); + StaffInfoVo recordStaff = SpringUtils.getBean(StaffService.class).getStaffInfo(task.getRecordStaffId()); + phoneList.add(responsibleStaff.getPhoneNumber()); + phoneList.add(recordStaff.getPhoneNumber()); + try { + SpringUtils.getBean(WebHookSendHandler.class) + .webHookSendText(WebHookKeyConstant.ORDER_INFO_BOT, + phoneList, + "==========您有一条工单已经到期,请及时处理==========\n" + task.getTaskContent(), + false); + } catch (IOException e) { + throw new ServiceException("发送消息通知失败!"); + } } } } diff --git a/Cpop-System/src/main/java/com/cpop/system/business/controller/backstage/BackstageBrandController.java b/Cpop-System/src/main/java/com/cpop/system/business/controller/backstage/BackstageBrandController.java index e5edb3f..08173cc 100644 --- a/Cpop-System/src/main/java/com/cpop/system/business/controller/backstage/BackstageBrandController.java +++ b/Cpop-System/src/main/java/com/cpop/system/business/controller/backstage/BackstageBrandController.java @@ -75,7 +75,7 @@ public class BackstageBrandController { Row row = Db.selectOneByQuery("cp_j_brand_extend", QueryWrapper.create().where("brand_id = ?", bo.getId())); if (row != null){ CloudBrandDto cloudBrandDto = new CloudBrandDto(); - cloudBrandDto.setBrandCloudId(row.getString("brand_cloud_id")); + cloudBrandDto.setBrandCloudId(row.getString("brandCloudId")); cloudBrandDto.setBrandName(bo.getBrandName()); SpringUtils.getBean(CloudBrandHandler.class).updateBrand(cloudBrandDto); }