feat: 增加系统接口回调和系统任务

This commit is contained in:
TS-QD1 2025-02-19 20:01:08 +08:00
parent a6b5a24cf8
commit d456bfe4ff
12 changed files with 549 additions and 8 deletions

View File

@ -1,4 +1,12 @@
# 账号自动解锁
# 增加微信支付回调
微信支付增加支付成功后系统回调通知
# 增加系统任务
quartz系统任务
# 账号自动解锁(已上线)
说明
@ -10,8 +18,8 @@
1. 一个账号可以有两个邀请码,一个邀请码用于其他账号关联,另一个邀请码是关联其他账号。
2. 邀请码的获取有两种方式:
1. 由管理员直接生成
2. 自己发起申请,管理员审核通过后生成
1. 由管理员直接生成
2. 自己发起申请,管理员审核通过后生成
3. 生成邀请码时,必须设置金额和邀请码返利比例
变更的表

View File

@ -5,8 +5,10 @@ import cn.com.tenlion.operator.enums.ReconciliationStatusEnum;
import cn.com.tenlion.operator.enums.ThirdPartyEnum;
import cn.com.tenlion.operator.pojo.dtos.accountbank.AccountBankDTO;
import cn.com.tenlion.operator.pojo.dtos.accountrecharge.AccountRechargeDTO;
import cn.com.tenlion.operator.properties.SystemApiPathProperties;
import cn.com.tenlion.operator.service.accountbank.IAccountBankService;
import cn.com.tenlion.operator.service.accountrecharge.IAccountRechargeService;
import cn.com.tenlion.operator.service.sys.callback.SysCallbackService;
import cn.com.tenlion.operator.util.UserUtil;
import cn.com.tenlion.operator.util.pay.ALiPay;
import cn.com.tenlion.operator.util.pay.PayResultDTO;
@ -48,15 +50,16 @@ public class AccountController extends DefaultBaseController {
@Autowired
private IAccountService accountService;
@Autowired
private IUserBaseService iUserBaseService;
@Autowired
private IAccountBankService iAccountBankService;
@Autowired
private IAccountRechargeService iAccountRechargeService;
@Autowired
private SysCallbackService sysCallbackService;
@Autowired
private SystemApiPathProperties systemApiPathProperties;
@ApiOperation(value = "支付宝支付成功后回调", notes = "支付宝支付成功后回调")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@ -93,9 +96,10 @@ public class AccountController extends DefaultBaseController {
JSONObject selfData = JSON.parseObject(dto.getSelfData());
if (selfData.containsKey("type") && StringUtils.equals("PROJ_PKG", selfData.getString("type"))) {
LOG.debug("通知付打包款成功");
sysCallbackService.save("项目打包付款成功", systemApiPathProperties.getCopyright() + "api/pay/pkg-pay-success/proj-id/" + selfData.getString("projId"), null);
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,24 @@
package cn.com.tenlion.operator.dao.sys.callback;
import cn.com.tenlion.operator.pojo.pos.sys.callback.SysCallbackPO;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository
public interface ISysCallbackDao {
void save(Map<String, Object> params);
void remove(Map<String, Object> params);
void update(Map<String, Object> params);
void updateStatus(Map<String, Object> params);
SysCallbackPO getPO(Map<String, Object> params);
List<SysCallbackPO> listPO(Map<String, Object> params);
}

View File

@ -0,0 +1,8 @@
package cn.com.tenlion.operator.enums;
public enum SysCallbackStatusEnum {
SUCCESS,
UN_SUCCESS
}

View File

@ -0,0 +1,106 @@
package cn.com.tenlion.operator.pojo.pos.sys.callback;
import cn.com.tenlion.operator.enums.SysCallbackStatusEnum;
public class SysCallbackPO {
private String callbackId;
private String name;
private String url;
private String jsonBody;
private SysCallbackStatusEnum status;
private Integer failCount;
private String gmtCreate;
private String creator;
private String gmtModified;
private String modifier;
private Integer isDelete;
public String getCallbackId() {
return callbackId == null ? "" : callbackId.trim();
}
public void setCallbackId(String callbackId) {
this.callbackId = callbackId;
}
public String getName() {
return name == null ? "" : name.trim();
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url == null ? "" : url.trim();
}
public void setUrl(String url) {
this.url = url;
}
public String getJsonBody() {
return jsonBody == null ? "" : jsonBody.trim();
}
public void setJsonBody(String jsonBody) {
this.jsonBody = jsonBody;
}
public SysCallbackStatusEnum getStatus() {
return status;
}
public void setStatus(SysCallbackStatusEnum status) {
this.status = status;
}
public Integer getFailCount() {
return failCount == null ? 0 : failCount;
}
public void setFailCount(Integer failCount) {
this.failCount = failCount;
}
public String getGmtCreate() {
return gmtCreate == null ? "" : gmtCreate.trim();
}
public void setGmtCreate(String gmtCreate) {
this.gmtCreate = gmtCreate;
}
public String getCreator() {
return creator == null ? "" : creator.trim();
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getGmtModified() {
return gmtModified == null ? "" : gmtModified.trim();
}
public void setGmtModified(String gmtModified) {
this.gmtModified = gmtModified;
}
public String getModifier() {
return modifier == null ? "" : modifier.trim();
}
public void setModifier(String modifier) {
this.modifier = modifier;
}
public Integer getIsDelete() {
return isDelete == null ? 0 : isDelete;
}
public void setIsDelete(Integer isDelete) {
this.isDelete = isDelete;
}
}

View File

@ -0,0 +1,85 @@
package cn.com.tenlion.operator.service.sys.callback;
import cn.com.tenlion.operator.dao.sys.callback.ISysCallbackDao;
import cn.com.tenlion.operator.enums.SysCallbackStatusEnum;
import cn.com.tenlion.operator.pojo.pos.sys.callback.SysCallbackPO;
import cn.com.tenlion.operator.service.sys.task.SysTaskService;
import com.alibaba.fastjson.JSONObject;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.map.HashMapUtil;
import ink.wgink.util.thread.CachedThreadPoolUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
@Service
public class SysCallbackService extends DefaultBaseService {
@Autowired
private ISysCallbackDao sysCallbackDao;
@Autowired
private SysTaskService sysTaskService;
public void save(String name, String url, JSONObject jsonBody) {
String callbackId = UUIDUtil.getUUID();
String jsonBodyString = jsonBody == null ? "" : jsonBody.toJSONString();
Map<String, Object> params = getHashMap(3);
params.put("callbackId", callbackId);
params.put("name", name);
params.put("url", url);
params.put("jsonBody", jsonBodyString);
params.put("status", SysCallbackStatusEnum.UN_SUCCESS);
params.put("failCount", 0);
setSaveInfoByUserId(params, "1");
sysCallbackDao.save(params);
sysTaskService.runCallbackTask(callbackId);
}
public void remove(List<String> callbackIds) {
Map<String, Object> params = getHashMap(2);
params.put("callbackIds", callbackIds);
setUpdateInfo(params);
sysCallbackDao.remove(params);
}
public void update(String callbackId, SysCallbackPO sysCallbackPO) {
Map<String, Object> params = HashMapUtil.beanToMap(sysCallbackPO);
setUpdateInfo(params);
params.put("callbackId", callbackId);
sysCallbackDao.update(params);
}
public void update(String callbackId, SysCallbackStatusEnum status, int failCount) {
Map<String, Object> params = getHashMap(3);
params.put("callbackId", callbackId);
params.put("status", status);
params.put("failCount", failCount);
setUpdateInfoByUserId(params, "1");
sysCallbackDao.update(params);
}
public SysCallbackPO getPO(String callbackId) {
Map<String, Object> params = getHashMap(2);
params.put("callbackId", callbackId);
return sysCallbackDao.getPO(params);
}
public List<SysCallbackPO> listPO(Map<String, Object> params) {
return sysCallbackDao.listPO(params);
}
public List<SysCallbackPO> listPOByStatus(SysCallbackStatusEnum status) {
Map<String, Object> params = getHashMap(2);
params.put("status", status.name());
return sysCallbackDao.listPO(params);
}
}

View File

@ -0,0 +1,66 @@
package cn.com.tenlion.operator.service.sys.callback;
import cn.com.tenlion.operator.enums.SysCallbackStatusEnum;
import cn.com.tenlion.operator.pojo.pos.sys.callback.SysCallbackPO;
import cn.com.tenlion.operator.service.sys.task.SysTaskService;
import com.alibaba.fastjson.JSONObject;
import ink.wgink.exceptions.base.SystemException;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class SysCallbackTask implements Job {
private static final Logger LOG = LoggerFactory.getLogger(SysCallbackTask.class);
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
SysCallbackService sysCallbackService = (SysCallbackService) mergedJobDataMap.get("sysCallbackService");
SysTaskService sysTaskService = (SysTaskService) mergedJobDataMap.get("sysTaskService");
SysCallbackPO sysCallbackPO = (SysCallbackPO) mergedJobDataMap.get("sysCallbackPO");
try {
URL url = new URL(sysCallbackPO.getUrl());
LOG.debug("回调地址:{}", url);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
httpURLConnection.setConnectTimeout(3000);
httpURLConnection.connect();
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
String line;
StringBuilder resultSB = new StringBuilder();
while ((line = reader.readLine()) != null) { // 循环从流中读取
resultSB.append(line);
}
reader.close();
httpURLConnection.disconnect();
if (!resultSB.toString().startsWith("{") && !resultSB.toString().endsWith("}")) {
throw new SystemException("返回结果不是JSON对象");
}
LOG.debug("回调成功");
sysCallbackService.update(sysCallbackPO.getCallbackId(), SysCallbackStatusEnum.SUCCESS, sysCallbackPO.getFailCount());
} else {
httpURLConnection.disconnect();
throw new SystemException("回调状态码不是200");
}
} catch (Exception e) {
LOG.error("回调异常: {}", e.getMessage(), e);
sysCallbackService.update(sysCallbackPO.getCallbackId(), SysCallbackStatusEnum.UN_SUCCESS, sysCallbackPO.getFailCount() + 1);
sysTaskService.runCallbackTask(sysCallbackPO.getCallbackId());
}
}
}

View File

@ -0,0 +1,78 @@
package cn.com.tenlion.operator.service.sys.task;
import cn.com.tenlion.operator.pojo.pos.sys.callback.SysCallbackPO;
import cn.com.tenlion.operator.service.sys.callback.SysCallbackService;
import cn.com.tenlion.operator.service.sys.callback.SysCallbackTask;
import com.google.gson.LongSerializationPolicy;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.util.UUIDUtil;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Service
public class SysTaskService extends DefaultBaseService {
private static Scheduler scheduler = null;
@Autowired
@Lazy
private SysCallbackService sysCallbackService;
public SysTaskService() {
try {
scheduler = StdSchedulerFactory.getDefaultScheduler();
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
public void runCallbackTask(String callbackId) {
SysCallbackPO sysCallbackPO = sysCallbackService.getPO(callbackId);
if (sysCallbackPO == null) {
LOG.debug("回调任务不存在");
return;
}
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("sysCallbackPO", sysCallbackPO);
jobDataMap.put("sysCallbackService", sysCallbackService);
jobDataMap.put("sysTaskService", this);
JobDetail jobDetail = JobBuilder.newJob(SysCallbackTask.class).usingJobData(jobDataMap).build();
try {
// 15103060120300
long waitTime;
if (sysCallbackPO.getFailCount() == 0) {
waitTime = 0;
} else if (sysCallbackPO.getFailCount() == 1) {
waitTime = 1;
} else if (sysCallbackPO.getFailCount() == 2) {
waitTime = 5;
} else if (sysCallbackPO.getFailCount() == 3) {
waitTime = 10;
} else if (sysCallbackPO.getFailCount() == 4) {
waitTime = 30;
} else if (sysCallbackPO.getFailCount() == 5) {
waitTime = 60;
} else if (sysCallbackPO.getFailCount() == 6) {
waitTime = 120;
} else {
waitTime = 300;
}
Date startDate = new Date(System.currentTimeMillis() + waitTime * 1000);
TriggerKey triggerKey = new TriggerKey(UUIDUtil.getUUID(), "SYS_CALLBACK_TASK");
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).startAt(startDate).build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,32 @@
package cn.com.tenlion.operator.startup;
import cn.com.tenlion.operator.enums.SysCallbackStatusEnum;
import cn.com.tenlion.operator.pojo.pos.sys.callback.SysCallbackPO;
import cn.com.tenlion.operator.service.sys.callback.SysCallbackService;
import cn.com.tenlion.operator.service.sys.task.SysTaskService;
import ink.wgink.interfaces.start.IApplicationStart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class SystemStart implements IApplicationStart {
private static final Logger LOG = LoggerFactory.getLogger(SystemStart.class);
@Autowired
private SysCallbackService sysCallbackService;
@Autowired
private SysTaskService sysTaskService;
@Override
public void run() throws Exception {
List<SysCallbackPO> sysCallbackPOS = sysCallbackService.listPOByStatus(SysCallbackStatusEnum.UN_SUCCESS);
for (SysCallbackPO sysCallbackPO : sysCallbackPOS) {
sysTaskService.runCallbackTask(sysCallbackPO.getCallbackId());
}
}
}

View File

@ -175,7 +175,7 @@ pay:
# 单笔最大金额
max-money: 20000
# 单笔最小金额
min-money: 0.1
min-money: 0.01
ali-pay:
# 应用ID
# 西藏 app-id: 2021004137636507

View File

@ -0,0 +1,127 @@
<?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="cn.com.tenlion.operator.dao.sys.callback.ISysCallbackDao">
<resultMap id="sysCallbackPO" type="cn.com.tenlion.operator.pojo.pos.sys.callback.SysCallbackPO">
<id column="callback_id" property="callbackId"/>
<result column="name" property="name"/>
<result column="url" property="url"/>
<result column="json_body" property="jsonBody"/>
<result column="status" property="status"/>
<result column="fail_count" property="failCount"/>
<result column="gmt_create" property="gmtCreate"/>
<result column="creator" property="creator"/>
<result column="gmt_modified" property="gmtModified"/>
<result column="modifier" property="modifier"/>
<result column="is_delete" property="isDelete"/>
</resultMap>
<insert id="save" parameterType="map">
INSERT INTO sys_callback (callback_id, name, url, json_body, status, fail_count, gmt_create, creator, gmt_modified, modifier, is_delete)
VALUES (#{callbackId}, #{name}, #{url}, #{jsonBody}, #{status}, #{failCount}, #{gmtCreate}, #{creator}, #{gmtModified}, #{modifier}, #{isDelete})
</insert>
<update id="remove" parameterType="map">
UPDATE sys_callback
SET
is_delete = #{isDelete},
gmt_modified = #{gmtModified},
modifier = #{modifier}
WHERE
<if test="callbackIds != null and callbackIds.size >0">
callback_id IN
<foreach collection="callbackIds" item="callbackId" index="index" open="(" close=")" separator=",">
#{callbackId}
</foreach>
</if>
</update>
<update id="update" parameterType="map">
UPDATE sys_callback
SET
<if test="name != null">
name = #{name},
</if>
<if test="url != null">
url = #{url},
</if>
<if test="jsonBody != null">
json_body = #{jsonBody},
</if>
<if test="status != null">
status = #{status},
</if>
<if test="failCount!= null">
fail_count = #{failCount},
</if>
gmt_modified = #{gmtModified},
modifier = #{modifier}
WHERE
callback_id = #{callbackId}
</update>
<update id="updateStatus" parameterType="map">
UPDATE sys_callback
SET
<if test="failCount != null">
fail_count = #{failCount},
</if>
status = #{status},
gmt_modified = #{gmtModified},
modifier = #{modifier}
WHERE
callback_id = #{callbackId}
</update>
<select id="getPO" parameterType="map" resultMap="sysCallbackPO">
SELECT
callback_id,
name,
url,
json_body,
status,
fail_count,
gmt_create,
creator,
gmt_modified,
modifier,
is_delete
FROM
sys_callback
WHERE
is_delete = 0
AND
callback_id = #{callbackId}
</select>
<select id="listPO" parameterType="map" resultMap="sysCallbackPO">
SELECT
callback_id,
name,
url,
json_body,
status,
fail_count,
gmt_create,
creator,
gmt_modified,
modifier,
is_delete
FROM
sys_callback
WHERE
is_delete = 0
<if test="callbackIds != null and callbackIds.size > 0">
AND
callback_id IN
<foreach collection="callbackIds" item="callbackId" index="index" open="(" close=")" separator=",">
#{callbackId}
</foreach>
</if>
<if test="status != null and status != ''">
AND
status = #{status}
</if>
</select>
</mapper>

View File

@ -0,0 +1,3 @@
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 10
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore