mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-11-13 09:46:09 +08:00
回调管理
This commit is contained in:
24
sop-notify/pom.xml
Normal file
24
sop-notify/pom.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<artifactId>sop-parent</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>sop-notify</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>sop-notify-api</module>
|
||||
<module>sop-notify-service</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
31
sop-notify/sop-notify-api/pom.xml
Normal file
31
sop-notify/sop-notify-api/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<artifactId>sop-notify-api</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>2.0.1.Final</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.36</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.gitee.sop.notify.api;
|
||||
|
||||
import com.gitee.sop.notify.api.req.NotifyRequest;
|
||||
import com.gitee.sop.notify.api.resp.NotifyResponse;
|
||||
|
||||
/**
|
||||
* 回调接口
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
public interface NotifyService {
|
||||
|
||||
/**
|
||||
* 回调
|
||||
*
|
||||
* @param request 参数
|
||||
* @return 返回结果
|
||||
*/
|
||||
NotifyResponse notify(NotifyRequest request);
|
||||
|
||||
/**
|
||||
* 回调立即发送
|
||||
*
|
||||
* @param notifyId notifyId
|
||||
* @return 返回结果
|
||||
*/
|
||||
NotifyResponse notifyImmediately(Long notifyId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.gitee.sop.notify.api.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Data
|
||||
public class NotifyRequest implements Serializable {
|
||||
private static final long serialVersionUID = -4018307141661725928L;
|
||||
|
||||
/**
|
||||
* appId
|
||||
*/
|
||||
@NotBlank(message = "appId必填")
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* apiName
|
||||
*/
|
||||
@NotBlank(message = "apiName必填")
|
||||
private String apiName;
|
||||
|
||||
/**
|
||||
* version
|
||||
*/
|
||||
@NotBlank(message = "version必填")
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
@NotBlank(message = "charset必填")
|
||||
private String charset;
|
||||
|
||||
/**
|
||||
* token,没有返回null
|
||||
*/
|
||||
private String appAuthToken;
|
||||
|
||||
/**
|
||||
* 客户端ip
|
||||
*/
|
||||
private String clientIp;
|
||||
|
||||
/**
|
||||
* 回调地址
|
||||
*/
|
||||
private String notifyUrl;
|
||||
|
||||
/**
|
||||
* 业务参数
|
||||
*/
|
||||
@NotNull(message = "bizParams必填")
|
||||
private Map<String, Object> bizParams;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.gitee.sop.notify.api.resp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Data
|
||||
public class NotifyResponse implements Serializable {
|
||||
private static final long serialVersionUID = 5813802354743928430L;
|
||||
|
||||
/**
|
||||
* 返回请求id
|
||||
*/
|
||||
private Long notifyId;
|
||||
|
||||
private Boolean success = true;
|
||||
|
||||
private String msg;
|
||||
|
||||
public static NotifyResponse success(Long notifyId) {
|
||||
NotifyResponse notifyResponse = new NotifyResponse();
|
||||
notifyResponse.setNotifyId(notifyId);
|
||||
notifyResponse.setSuccess(true);
|
||||
notifyResponse.setMsg("");
|
||||
return notifyResponse;
|
||||
}
|
||||
|
||||
public static NotifyResponse error(String msg) {
|
||||
NotifyResponse notifyResponse = new NotifyResponse();
|
||||
notifyResponse.setNotifyId(null);
|
||||
notifyResponse.setSuccess(false);
|
||||
notifyResponse.setMsg(msg);
|
||||
return notifyResponse;
|
||||
}
|
||||
}
|
||||
154
sop-notify/sop-notify-service/pom.xml
Normal file
154
sop-notify/sop-notify-service/pom.xml
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<artifactId>sop-notify</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>sop-notify-service</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<!-- dubbo版本 -->
|
||||
<dubbo.version>3.2.16</dubbo.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<artifactId>sop-notify-api</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<artifactId>sdk-java</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.gitee.durcframework</groupId>
|
||||
<artifactId>fastmybatis-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.oschina.durcframework</groupId>
|
||||
<artifactId>http-helper</artifactId>
|
||||
</dependency>
|
||||
<!-- sop接入依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<artifactId>sop-spring-boot-starter</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- nacos注册中心 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-nacos-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- zookeeper注册中心 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.34</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-bom</artifactId>
|
||||
<version>${dubbo.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 打包时跳过测试 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.12.4</version>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- 文档推送 -->
|
||||
<plugin>
|
||||
<groupId>com.ly.smart-doc</groupId>
|
||||
<artifactId>smart-doc-maven-plugin</artifactId>
|
||||
<version>3.0.9</version>
|
||||
<configuration>
|
||||
<!--指定生成文档的使用的配置文件-->
|
||||
<configFile>./src/main/resources/smart-doc.json</configFile>
|
||||
<!--指定项目名称-->
|
||||
<projectName>${project.artifactId}</projectName>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<artifactId>sop-service-support</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>maven_central</id>
|
||||
<name>Maven Central</name>
|
||||
<url>https://repo.maven.apache.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.gitee.sop.notify;
|
||||
|
||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableDubbo
|
||||
@EnableScheduling
|
||||
public class SopNotifyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SopNotifyApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.gitee.sop.notify.dao.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.PkStrategy;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:notify_info
|
||||
* 备注:回调信息
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "notify_info", pk = @Pk(name = "id", strategy = PkStrategy.INCREMENT))
|
||||
@Data
|
||||
public class NotifyInfo {
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* app_id
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* api_name
|
||||
*/
|
||||
private String apiName;
|
||||
|
||||
/**
|
||||
* api_version
|
||||
*/
|
||||
private String apiVersion;
|
||||
|
||||
/**
|
||||
* 回调url
|
||||
*/
|
||||
private String notifyUrl;
|
||||
|
||||
/**
|
||||
* 最近一次发送时间
|
||||
*/
|
||||
private LocalDateTime lastSendTime;
|
||||
|
||||
/**
|
||||
* 下一次发送时间
|
||||
*/
|
||||
private LocalDateTime nextSendTime;
|
||||
|
||||
/**
|
||||
* 已发送次数
|
||||
*/
|
||||
private Integer sendCnt;
|
||||
|
||||
/**
|
||||
* 发送内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 状态,1-发送成功,2-发送失败,3-重试结束
|
||||
*/
|
||||
private Integer notifyStatus;
|
||||
|
||||
/**
|
||||
* 失败原因
|
||||
*/
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 返回结果
|
||||
*/
|
||||
private String resultContent;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
private LocalDateTime addTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
private Long addBy;
|
||||
|
||||
/**
|
||||
* 修改人id
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.gitee.sop.notify.dao.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Mapper
|
||||
public interface IsvMapper {
|
||||
|
||||
String getPrivatePlatformKey(String appId);
|
||||
|
||||
String getNotifyUrl(String appId);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.gitee.sop.notify.dao.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.BaseMapper;
|
||||
import com.gitee.sop.notify.dao.entity.NotifyInfo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Mapper
|
||||
public interface NotifyInfoMapper extends BaseMapper<NotifyInfo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.gitee.sop.notify.dubbo;
|
||||
|
||||
import com.gitee.sop.notify.api.NotifyService;
|
||||
import com.gitee.sop.notify.api.req.NotifyRequest;
|
||||
import com.gitee.sop.notify.api.resp.NotifyResponse;
|
||||
import com.gitee.sop.notify.service.NotifyBizService;
|
||||
import com.gitee.sop.notify.service.bo.NotifyBO;
|
||||
import com.gitee.sop.sdk.sign.SopSignException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@DubboService(validation = "true")
|
||||
@Slf4j
|
||||
public class NotifyServiceImpl implements NotifyService {
|
||||
|
||||
@Autowired
|
||||
private NotifyBizService notifyBizService;
|
||||
|
||||
@Override
|
||||
public NotifyResponse notify(NotifyRequest request) {
|
||||
NotifyBO notifyBO = new NotifyBO();
|
||||
BeanUtils.copyProperties(request, notifyBO);
|
||||
try {
|
||||
Long notifyId = notifyBizService.notify(notifyBO);
|
||||
return NotifyResponse.success(notifyId);
|
||||
} catch (SopSignException e) {
|
||||
log.error("回调异常,服务端签名失败, request={}", request, e);
|
||||
return NotifyResponse.error(e.getErrMsg());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotifyResponse notifyImmediately(Long notifyId) {
|
||||
try {
|
||||
notifyBizService.notifyImmediately(notifyId);
|
||||
return NotifyResponse.success(notifyId);
|
||||
} catch (Exception e) {
|
||||
log.error("回调异常, notifyId={}", notifyId, e);
|
||||
return NotifyResponse.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.gitee.sop.notify.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum NotifyStatusEnum {
|
||||
|
||||
// 状态,1-发送成功,2-发送失败,3-重试结束
|
||||
SEND_SUCCESS(1, "发送成功"),
|
||||
SEND_FAIL(2, "发送失败"),
|
||||
RETRY_OVER(3, "重试结束");
|
||||
|
||||
private final Integer value;
|
||||
|
||||
private final String description;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.gitee.sop.notify.schedule;
|
||||
|
||||
import com.gitee.sop.notify.service.NotifyBizService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Component
|
||||
public class NotifySchedule {
|
||||
|
||||
@Autowired
|
||||
private NotifyBizService notifyBizService;
|
||||
|
||||
/**
|
||||
* 每分钟执行一次
|
||||
*/
|
||||
@Scheduled(cron = "0 0/1 * * * ?")
|
||||
public void run() {
|
||||
notifyBizService.retry(LocalDateTime.now());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.gitee.sop.notify.service;
|
||||
|
||||
import com.gitee.sop.notify.dao.mapper.IsvMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Service
|
||||
public class IsvService {
|
||||
|
||||
@Autowired
|
||||
private IsvMapper isvMapper;
|
||||
|
||||
public String getPrivatePlatformKey(String appId) {
|
||||
return isvMapper.getPrivatePlatformKey(appId);
|
||||
}
|
||||
|
||||
public String getNotifyUrl(String appId) {
|
||||
return isvMapper.getNotifyUrl(appId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package com.gitee.sop.notify.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.fastmybatis.core.support.LambdaService;
|
||||
import com.gitee.httphelper.HttpHelper;
|
||||
import com.gitee.httphelper.result.ResponseResult;
|
||||
import com.gitee.sop.notify.dao.entity.NotifyInfo;
|
||||
import com.gitee.sop.notify.dao.mapper.NotifyInfoMapper;
|
||||
import com.gitee.sop.notify.enums.NotifyStatusEnum;
|
||||
import com.gitee.sop.notify.service.bo.NotifyBO;
|
||||
import com.gitee.sop.sdk.sign.SignUtil;
|
||||
import com.gitee.sop.sdk.sign.SopSignException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* 回调业务逻辑处理
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class NotifyBizService implements LambdaService<NotifyInfo, NotifyInfoMapper> {
|
||||
|
||||
// 对应第1,2,3...次尝试
|
||||
// 即1分钟后进行第一次尝试,如果失败,5分钟后进行第二次尝试
|
||||
@Value("${sop.notify.time-level:1m,5m,10m,30m,1h,2h,5h}")
|
||||
private String timeLevel;
|
||||
|
||||
@Autowired
|
||||
private IsvService isvService;
|
||||
|
||||
/**
|
||||
* 第一次发送
|
||||
*
|
||||
* @param notifyBO 回调内容
|
||||
* @return 返回回调id
|
||||
* @throws SopSignException 异常处理
|
||||
*/
|
||||
public Long notify(NotifyBO notifyBO) throws SopSignException {
|
||||
NotifyInfo notifyInfo = buildRecord(notifyBO);
|
||||
return doNotify(notifyBO, notifyInfo);
|
||||
}
|
||||
|
||||
public void notifyImmediately(Long notifyId) throws SopSignException {
|
||||
NotifyInfo notifyInfo = this.getById(notifyId);
|
||||
String content = notifyInfo.getContent();
|
||||
NotifyBO notifyBO = JSON.parseObject(content, NotifyBO.class);
|
||||
// 发送请求
|
||||
doNotify(notifyBO, notifyInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重试
|
||||
*
|
||||
* @param now 当前时间
|
||||
*/
|
||||
public void retry(LocalDateTime now) {
|
||||
LocalDateTime nextTime = now.withSecond(0).withNano(0);
|
||||
List<NotifyInfo> list = this.query()
|
||||
.eq(NotifyInfo::getNextSendTime, nextTime)
|
||||
.eq(NotifyInfo::getNotifyStatus, NotifyStatusEnum.SEND_FAIL.getValue())
|
||||
.list();
|
||||
if (list.isEmpty()) {
|
||||
log.info("[notify]无重试记录");
|
||||
return;
|
||||
}
|
||||
|
||||
for (NotifyInfo notifyInfo : list) {
|
||||
retry(notifyInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void retry(NotifyInfo notifyInfo) {
|
||||
String content = notifyInfo.getContent();
|
||||
NotifyBO notifyBO = JSON.parseObject(content, NotifyBO.class);
|
||||
try {
|
||||
log.info("[notify]开始重试, notifyId={}", notifyInfo.getId());
|
||||
if (Objects.equals(notifyInfo.getNotifyStatus(), NotifyStatusEnum.RETRY_OVER.getValue())) {
|
||||
log.warn("重试次数已用尽, notifyId={}", notifyInfo.getId());
|
||||
return;
|
||||
}
|
||||
// 发送请求
|
||||
doNotify(notifyBO, notifyInfo);
|
||||
} catch (SopSignException e) {
|
||||
log.error("[notify]重试签名错误,notifyId={}", notifyInfo.getId(), e);
|
||||
throw new RuntimeException("重试失败,签名错误");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建下一次重试时间
|
||||
*
|
||||
* @param currentSendCnt 当前发送次数
|
||||
* @return 返回null表示重试次数用完
|
||||
*/
|
||||
private LocalDateTime buildNextSendTime(Integer currentSendCnt) {
|
||||
String[] split = timeLevel.split(",");
|
||||
if (currentSendCnt >= split.length) {
|
||||
return null;
|
||||
}
|
||||
// 1m
|
||||
String exp = split[currentSendCnt - 1];
|
||||
// 秒,毫秒归零f
|
||||
LocalDateTime time = LocalDateTime.now().withSecond(0).withNano(0);
|
||||
// 最后一个字符,如:m,h,d
|
||||
char ch = exp.charAt(exp.length() - 1);
|
||||
int value = NumberUtils.toInt(exp.substring(0, exp.length() - 1));
|
||||
switch (String.valueOf(ch).toLowerCase()) {
|
||||
case "m":
|
||||
return time.plusMinutes(value);
|
||||
case "h":
|
||||
return time.plusHours(value);
|
||||
case "d":
|
||||
return time.plusDays(value);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Long doNotify(NotifyBO notifyBO, NotifyInfo notifyInfo) throws SopSignException {
|
||||
notifyInfo.setSendCnt(notifyInfo.getSendCnt() + 1);
|
||||
notifyInfo.setLastSendTime(LocalDateTime.now());
|
||||
notifyInfo.setNotifyUrl(buildNotifyUrl(notifyBO, notifyInfo));
|
||||
|
||||
String notifyUrl = notifyInfo.getNotifyUrl();
|
||||
// 构建请求参数
|
||||
Map<String, String> params = buildParams(notifyBO);
|
||||
try {
|
||||
if (StringUtils.isBlank(notifyUrl)) {
|
||||
throw new RuntimeException("回调接口不能为空");
|
||||
}
|
||||
|
||||
String json = JSON.toJSONString(params);
|
||||
log.info("发送回调请求,notifyUrl={}, content={}", notifyUrl, json);
|
||||
ResponseResult responseResult = HttpHelper.postJson(notifyUrl, json)
|
||||
.execute();
|
||||
|
||||
// 这里判断收到200认为请求成功
|
||||
int status = responseResult.getStatus();
|
||||
String resultContent = responseResult.asString();
|
||||
notifyInfo.setResultContent(resultContent);
|
||||
if (status == HttpStatus.SC_OK) {
|
||||
// 更新状态
|
||||
notifyInfo.setNotifyStatus(NotifyStatusEnum.SEND_SUCCESS.getValue());
|
||||
notifyInfo.setErrorMsg("");
|
||||
} else {
|
||||
// 回调失败
|
||||
log.error("回调状态非200:{}, result={}", status, resultContent);
|
||||
throw new RuntimeException(resultContent);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("回调请求失败, notifyUrl={}, params={}, notifyBO={}", notifyUrl, params, notifyBO, e);
|
||||
notifyInfo.setNotifyStatus(NotifyStatusEnum.SEND_FAIL.getValue());
|
||||
notifyInfo.setErrorMsg(e.getMessage());
|
||||
|
||||
LocalDateTime nextSendTime = buildNextSendTime(notifyInfo.getSendCnt());
|
||||
notifyInfo.setNextSendTime(nextSendTime);
|
||||
|
||||
if (nextSendTime == null) {
|
||||
log.error("回调请求次数达到上线, notifyUrl={}, params={}", notifyUrl, params);
|
||||
notifyInfo.setNotifyStatus(NotifyStatusEnum.RETRY_OVER.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
this.saveOrUpdate(notifyInfo);
|
||||
|
||||
return notifyInfo.getId();
|
||||
}
|
||||
|
||||
private Map<String, String> buildParams(NotifyBO notifyBO) throws SopSignException {
|
||||
// 公共请求参数
|
||||
Map<String, String> params = new HashMap<>();
|
||||
String appId = notifyBO.getAppId();
|
||||
params.put("app_id", appId);
|
||||
params.put("method", notifyBO.getApiName());
|
||||
params.put("format", "json");
|
||||
params.put("charset", notifyBO.getCharset());
|
||||
params.put("sign_type", "RSA2");
|
||||
params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
|
||||
params.put("version", notifyBO.getVersion());
|
||||
|
||||
// 业务参数
|
||||
Map<String, Object> bizContent = notifyBO.getBizParams();
|
||||
|
||||
params.put("biz_content", JSON.toJSONString(bizContent));
|
||||
String content = SignUtil.getSignContent(params);
|
||||
|
||||
String privateKey = isvService.getPrivatePlatformKey(appId);
|
||||
String sign = SignUtil.rsa256Sign(content, privateKey, notifyBO.getCharset());
|
||||
params.put("sign", sign);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private String buildNotifyUrl(NotifyBO notifyBO, NotifyInfo notifyInfo) {
|
||||
String savedUrl = notifyInfo.getNotifyUrl();
|
||||
if (StringUtils.isNotBlank(savedUrl)) {
|
||||
return savedUrl;
|
||||
}
|
||||
String notifyUrl = notifyBO.getNotifyUrl();
|
||||
if (StringUtils.isBlank(notifyUrl)) {
|
||||
notifyUrl = isvService.getNotifyUrl(notifyBO.getAppId());
|
||||
}
|
||||
return notifyUrl;
|
||||
}
|
||||
|
||||
private NotifyInfo buildRecord(NotifyBO notifyBO) {
|
||||
NotifyInfo notifyInfo = new NotifyInfo();
|
||||
notifyInfo.setAppId(notifyBO.getAppId());
|
||||
notifyInfo.setApiName(notifyBO.getApiName());
|
||||
notifyInfo.setApiVersion(notifyBO.getVersion());
|
||||
notifyInfo.setSendCnt(0);
|
||||
notifyInfo.setContent(JSON.toJSONString(notifyBO));
|
||||
notifyInfo.setNotifyStatus(0);
|
||||
notifyInfo.setErrorMsg("");
|
||||
notifyInfo.setRemark(notifyBO.getRemark());
|
||||
notifyInfo.setAddTime(LocalDateTime.now());
|
||||
notifyInfo.setUpdateTime(LocalDateTime.now());
|
||||
notifyInfo.setAddBy(0L);
|
||||
notifyInfo.setUpdateBy(0L);
|
||||
|
||||
return notifyInfo;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.gitee.sop.notify.service.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Data
|
||||
public class NotifyBO {
|
||||
|
||||
/**
|
||||
* appId
|
||||
*/
|
||||
@NotBlank(message = "appId必填")
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* apiName
|
||||
*/
|
||||
@NotBlank(message = "apiName必填")
|
||||
private String apiName;
|
||||
|
||||
/**
|
||||
* version
|
||||
*/
|
||||
@NotBlank(message = "version必填")
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* token,没有返回null
|
||||
*/
|
||||
private String appAuthToken;
|
||||
|
||||
/**
|
||||
* 客户端ip
|
||||
*/
|
||||
private String clientIp;
|
||||
|
||||
/**
|
||||
* 回调地址
|
||||
*/
|
||||
@NotBlank(message = "notifyUrl必填")
|
||||
private String notifyUrl;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private String charset;
|
||||
|
||||
/**
|
||||
* 业务参数
|
||||
*/
|
||||
@NotBlank(message = "bizParams必填")
|
||||
private Map<String, Object> bizParams;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
mybatis.print-sql=true
|
||||
|
||||
# mysql config
|
||||
mysql.host=127.0.0.1:3306
|
||||
mysql.db=sop
|
||||
mysql.username=root
|
||||
mysql.password=12345678
|
||||
@@ -0,0 +1,9 @@
|
||||
dubbo.registry.address=nacos://localhost:8848
|
||||
|
||||
mybatis.print-sql=true
|
||||
|
||||
# mysql config
|
||||
mysql.host=127.0.0.1:3306
|
||||
mysql.db=sop
|
||||
mysql.username=root
|
||||
mysql.password=root
|
||||
47
sop-notify/sop-notify-service/src/main/resources/application.properties
Executable file
47
sop-notify/sop-notify-service/src/main/resources/application.properties
Executable file
@@ -0,0 +1,47 @@
|
||||
server.port=8085
|
||||
spring.profiles.active=dev
|
||||
|
||||
spring.application.name=sop-notify
|
||||
|
||||
dubbo.protocol.name=dubbo
|
||||
dubbo.protocol.port=-1
|
||||
dubbo.application.qos-enable=false
|
||||
dubbo.consumer.check=false
|
||||
# ### register config see:https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/registry/overview/
|
||||
# ------
|
||||
# nacos://localhost:8848 Cluster config:nacos://localhost:8848?backup=localshot:8846,localshot:8847
|
||||
# zookeeper://localhost:2181 Cluster config:zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181
|
||||
# redis://localhost:6379 Cluster config:redis://10.20.153.10:6379?backup=10.20.153.11:6379,10.20.153.12:6379
|
||||
# ------
|
||||
dubbo.registry.address=zookeeper://localhost:2181
|
||||
|
||||
####### mysql config #######
|
||||
mysql.host=127.0.0.1:3306
|
||||
mysql.db=sop
|
||||
mysql.username=
|
||||
mysql.password=
|
||||
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
spring.datasource.url=jdbc:mysql://${mysql.host}/${mysql.db}?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
|
||||
spring.datasource.username=${mysql.username}
|
||||
spring.datasource.password=${mysql.password}
|
||||
|
||||
####### mybatis config #######
|
||||
mybatis.fill.com.gitee.fastmybatis.core.support.LocalDateTimeFillInsert=add_time
|
||||
mybatis.fill.com.gitee.fastmybatis.core.support.LocalDateTimeFillUpdate=update_time
|
||||
# mybatis config file
|
||||
mybatis.config-location=classpath:mybatis/mybatisConfig.xml
|
||||
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
|
||||
|
||||
# log level
|
||||
logging.level.com.gitee.sop=info
|
||||
# log path
|
||||
logging.file.name=logs/sop-notify.log
|
||||
# print SQL
|
||||
logging.level.com.gitee.sop.notify.dao=error
|
||||
logging.level.com.gitee.fastmybatis=info
|
||||
mybatis.print-sql=false
|
||||
|
||||
# \u5BF9\u5E94\u7B2C1\uFF0C2\uFF0C3...\u6B21\u5C1D\u8BD5
|
||||
# \u53731\u5206\u949F\u540E\u8FDB\u884C\u7B2C\u4E00\u6B21\u5C1D\u8BD5\uFF0C\u5982\u679C\u5931\u8D25\uFF0C5\u5206\u949F\u540E\u8FDB\u884C\u7B2C\u4E8C\u6B21\u5C1D\u8BD5
|
||||
sop.notify.time-level:1m,5m,10m,30m,1h,2h,5h
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="com.gitee.sop.notify.dao.mapper.IsvMapper">
|
||||
|
||||
<select id="getPrivatePlatformKey" resultType="String">
|
||||
select t2.private_key_platform
|
||||
from isv_info t inner join isv_keys t2 on t.id = t2.isv_id
|
||||
where app_id=#{appId}
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<select id="getNotifyUrl" resultType="String">
|
||||
select t.notify_url
|
||||
from isv_info t
|
||||
where app_id=#{appId}
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
26
sop-notify/sop-notify-service/src/main/resources/mybatis/mybatisConfig.xml
Executable file
26
sop-notify/sop-notify-service/src/main/resources/mybatis/mybatisConfig.xml
Executable file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
|
||||
<configuration>
|
||||
<settings>
|
||||
<!-- 全局映射器启用缓存 -->
|
||||
<setting name="cacheEnabled" value="true" />
|
||||
<!-- 查询时,关闭关联对象即时加载以提高性能 -->
|
||||
<setting name="lazyLoadingEnabled" value="true" />
|
||||
<!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->
|
||||
<setting name="multipleResultSetsEnabled" value="true" />
|
||||
<!-- 允许使用列标签代替列名 -->
|
||||
<setting name="useColumnLabel" value="true" />
|
||||
<!-- 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->
|
||||
<setting name="useGeneratedKeys" value="false" />
|
||||
<!-- 对于批量更新操作缓存SQL以提高性能:BATCH -->
|
||||
<setting name="defaultExecutorType" value="SIMPLE" />
|
||||
<!-- 超时设置 -->
|
||||
<setting name="defaultStatementTimeout" value="25000" />
|
||||
</settings>
|
||||
|
||||
<plugins>
|
||||
<plugin interceptor="com.gitee.fastmybatis.core.support.plugin.SqlFormatterPlugin">
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user