Commit de3de82d authored by dingzhiwei's avatar dingzhiwei
Browse files

初始化Jeepay项目

parent 40dcaf4a
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.ctrl.scanimg;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController;
import com.jeequan.jeepay.pay.util.CodeImgUtil;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/*
* jeepay 扫描图片生成器
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:28
*/
@RestController
@RequestMapping("/api/scan")
public class ScanImgController extends AbstractPayOrderController {
/** 返回 图片地址信息 **/
@RequestMapping("/imgs/{aesStr}.png")
public void qrImgs(@PathVariable("aesStr") String aesStr) throws Exception {
String str = JeepayKit.aesDecode(aesStr);
int width = getValIntegerDefault("width", 200);
int height = getValIntegerDefault("height", 200);
CodeImgUtil.writeQrCode(response.getOutputStream(), str, width, height);
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.exception;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import lombok.Getter;
/*
* 请求渠道侧异常 exception
* 抛出此异常: 仅支持: 未知状态(需查单) 和 系统内异常
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:28
*/
@Getter
public class ChannelException extends RuntimeException{
private static final long serialVersionUID = 1L;
private ChannelRetMsg channelRetMsg;
/** 业务自定义异常 **/
private ChannelException(ChannelRetMsg channelRetMsg) {
super(channelRetMsg != null ? channelRetMsg.getChannelErrMsg() : null);
this.channelRetMsg = channelRetMsg;
}
/** 未知状态 **/
public static ChannelException unknown(String channelErrMsg){
return new ChannelException(ChannelRetMsg.sysError(channelErrMsg));
}
/** 系统内异常 **/
public static ChannelException sysError(String channelErrMsg){
return new ChannelException(ChannelRetMsg.sysError(channelErrMsg));
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.model;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayRequest;
import com.alipay.api.AlipayResponse;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.exception.ChannelException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/*
* 支付宝Client 包装类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:28
*/
@Slf4j
@Data
@AllArgsConstructor
public class AlipayClientWrapper {
//默认为 不使用证书方式
private Byte useCert = CS.NO;
/** 缓存支付宝client 对象 **/
private AlipayClient alipayClient;
/** 封装支付宝接口调用函数 **/
public <T extends AlipayResponse> T execute(AlipayRequest<T> request){
try {
T alipayResp = null;
if(useCert != null && useCert == CS.YES){ //证书加密方式
alipayResp = alipayClient.certificateExecute(request);
}else{ //key 或者 空都为默认普通加密方式
alipayResp = alipayClient.execute(request);
}
//判断返回的值: // TODO
return alipayResp;
} catch (AlipayApiException e) { // 调起接口前出现异常,如私钥问题。 调起后出现验签异常等。
log.error("调起支付宝execute[AlipayApiException]异常!", e);
//如果数据返回出现验签异常,则需要抛出: UNKNOWN 异常。
throw ChannelException.sysError(e.getMessage());
} catch (Exception e) {
log.error("调起支付宝execute[Exception]异常!", e);
throw ChannelException.sysError("调用支付宝client服务异常");
}
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.model;
import com.jeequan.jeepay.core.entity.IsvInfo;
import com.jeequan.jeepay.core.model.params.IsvParams;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/*
* Isv支付参数信息 放置到内存, 避免多次查询操作
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:28
*/
@Data
public class IsvConfigContext {
/** isv信息缓存 */
private String isvNo;
private IsvInfo isvInfo;
/** 商户支付配置信息缓存 */
private Map<String, IsvParams> isvParamsMap = new HashMap<>();
/** 缓存支付宝client 对象 **/
private AlipayClientWrapper alipayClientWrapper;
/** 缓存 wxServiceWrapper 对象 **/
private WxServiceWrapper wxServiceWrapper;
/** 获取isv配置信息 **/
public IsvParams getIsvParamsByIfCode(String ifCode){
return isvParamsMap.get(ifCode);
}
/** 获取isv配置信息 **/
public <T> T getIsvParamsByIfCode(String ifCode, Class<? extends IsvParams> cls){
return (T)isvParamsMap.get(ifCode);
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.model;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.model.params.IsvsubMchParams;
import com.jeequan.jeepay.core.model.params.NormalMchParams;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/*
* 商户支付参数信息
* 用户 放置到内存, 避免多次查询操作
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:29
*/
@Data
public class MchConfigContext {
/** 商户信息缓存 */
private String mchNo;
private Byte mchType;
private MchInfo mchInfo;
/** 商户支付配置信息缓存 */
private Map<String, NormalMchParams> normalMchParamsMap = new HashMap<>();
private Map<String, IsvsubMchParams> isvsubMchParamsMap = new HashMap<>();
/** 放置所属服务商的信息 **/
private IsvConfigContext isvConfigContext;
/** 缓存支付宝client 对象 **/
private AlipayClientWrapper alipayClientWrapper;
/** 缓存 wxServiceWrapper 对象 **/
private WxServiceWrapper wxServiceWrapper;
/** 获取普通商户配置信息 **/
public NormalMchParams getNormalMchParamsByIfCode(String ifCode){
return normalMchParamsMap.get(ifCode);
}
/** 获取isv配置信息 **/
public <T> T getNormalMchParamsByIfCode(String ifCode, Class<? extends NormalMchParams> cls){
return (T)normalMchParamsMap.get(ifCode);
}
/** 获取特约商户配置信息 **/
public IsvsubMchParams getIsvsubMchParamsByIfCode(String ifCode){
return isvsubMchParamsMap.get(ifCode);
}
/** 获取isv配置信息 **/
public <T> T getIsvsubMchParamsByIfCode(String ifCode, Class<? extends IsvsubMchParams> cls){
return (T)isvsubMchParamsMap.get(ifCode);
}
/** 是否为 服务商特约商户 **/
public boolean isIsvsubMch(){
return this.mchType == MchInfo.TYPE_ISVSUB;
}
public AlipayClientWrapper getAlipayClientWrapper(){
return isIsvsubMch() ? isvConfigContext.getAlipayClientWrapper(): alipayClientWrapper;
}
public WxServiceWrapper getWxServiceWrapper(){
return isIsvsubMch() ? isvConfigContext.getWxServiceWrapper(): wxServiceWrapper;
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.model;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.AllArgsConstructor;
import lombok.Data;
import me.chanjar.weixin.mp.api.WxMpService;
/*
* wxService 包装类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:30
*/
@Data
@AllArgsConstructor
public class WxServiceWrapper {
/** 缓存微信API版本 **/
private String apiVersion;
/** 缓存 wxPayService 对象 **/
private WxPayService wxPayService;
/** 缓存 wxJavaService 对象 **/
private WxMpService wxMpService;
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/*
* MQ 线程池配置
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:33
*/
@Configuration
@EnableAsync
public class MqThreadExecutor {
public static final String EXECUTOR_PAYORDER_MCH_NOTIFY = "mqQueue4PayOrderMchNotifyExecutor";
/*
* 功能描述:
* 支付结果通知到商户的异步执行器 (由于量大, 单独新建一个线程池处理, 之前的不做变动 )
* 20, 300, 10, 60 该配置: 同一时间最大并发量300,(已经验证通过, 商户都可以收到请求消息)
* 缓存队列尽量减少,否则将堵塞在队列中无法执行。 corePoolSize 根据机器的配置进行添加。此处设置的为20
*/
@Bean
public Executor mqQueue4PayOrderMchNotifyExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20); // 线程池维护线程的最少数量
executor.setMaxPoolSize(300); // 线程池维护线程的最大数量
executor.setQueueCapacity(10); // 缓存队列
executor.setThreadNamePrefix("payOrderMchNotifyExecutor-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //对拒绝task的处理策略
executor.setKeepAliveSeconds(60); // 允许的空闲时间
executor.initialize();
return executor;
}
}
\ No newline at end of file
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq.queue;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.service.ChannelOrderReissueService;
import com.jeequan.jeepay.service.impl.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.ScheduledMessage;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import javax.jms.TextMessage;
/*
* 上游渠道订单轮询查单
* 如:微信的条码支付,没有回调接口, 需要轮询查单完成交易结果通知。
*
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:30
*/
@Slf4j
@Component
public class MqQueue4ChannelOrderQuery extends ActiveMQQueue{
@Autowired private JmsTemplate jmsTemplate;
@Autowired private PayOrderService payOrderService;
@Autowired private ChannelOrderReissueService channelOrderReissueService;
public static final String buildMsg(String payOrderId, int count){
return payOrderId + "," + count;
}
/** 构造函数 */
public MqQueue4ChannelOrderQuery(){
super(CS.MQ.QUEUE_CHANNEL_ORDER_QUERY);
}
/** 发送MQ消息 **/
public void send(String msg) {
this.jmsTemplate.convertAndSend(this, msg);
}
/** 发送MQ消息 **/
public void send(String msg, long delay) {
jmsTemplate.send(this, session -> {
TextMessage tm = session.createTextMessage(msg);
tm.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, delay);
tm.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 1*1000);
tm.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, 1);
return tm;
});
}
/** 接收 更新系统配置项的消息 **/
@JmsListener(destination = CS.MQ.QUEUE_CHANNEL_ORDER_QUERY)
public void receive(String msg) {
String [] arr = msg.split(",");
String payOrderId = arr[0];
int currentCount = Integer.parseInt(arr[1]);
log.info("接收轮询查单通知MQ, payOrderId={}, count={}", payOrderId, currentCount);
currentCount++ ;
PayOrder payOrder = payOrderService.getById(payOrderId);
if(payOrder == null) {
log.warn("查询支付订单为空,payOrderId={}", payOrderId);
return;
}
if(payOrder.getState() != PayOrder.STATE_ING) {
log.warn("订单状态不是支付中,不需查询渠道.payOrderId={}", payOrderId);
return;
}
ChannelRetMsg channelRetMsg = channelOrderReissueService.processPayOrder(payOrder);
//返回null 可能为接口报错等, 需要再次轮询
if(channelRetMsg == null || channelRetMsg.getChannelState() == null || channelRetMsg.getChannelState().equals(ChannelRetMsg.ChannelState.WAITING)){
//最多查询6次
if(currentCount <= 6){
send(buildMsg(payOrderId, currentCount), 5 * 1000); //延迟5s再次查询
}else{
//TODO 调用【撤销订单】接口
}
}else{ //其他状态, 不需要再次轮询。
}
return;
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq.queue;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchNotifyRecord;
import com.jeequan.jeepay.pay.mq.config.MqThreadExecutor;
import com.jeequan.jeepay.service.impl.MchNotifyRecordService;
import com.jeequan.jeepay.service.impl.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.ScheduledMessage;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.jms.Queue;
import javax.jms.TextMessage;
/*
* 商户订单回调MQ通知
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Slf4j
@Component
public class MqQueue4PayOrderMchNotify {
@Bean("mqQueue4PayOrderMchNotifyInner")
public Queue mqQueue4PayOrderMchNotifyInner(){
return new ActiveMQQueue(CS.MQ.QUEUE_PAYORDER_MCH_NOTIFY);
}
@Lazy
@Autowired
@Qualifier("mqQueue4PayOrderMchNotifyInner")
private Queue mqQueue4PayOrderMchNotifyInner;
@Autowired private JmsTemplate jmsTemplate;
@Autowired private MchNotifyRecordService mchNotifyRecordService;
@Autowired private PayOrderService payOrderService;
public MqQueue4PayOrderMchNotify(){
super();
}
/** 发送MQ消息 **/
public void send(String msg) {
this.jmsTemplate.convertAndSend(mqQueue4PayOrderMchNotifyInner, msg);
}
/** 发送MQ消息 **/
public void send(String msg, long delay) {
jmsTemplate.send(mqQueue4PayOrderMchNotifyInner, session -> {
TextMessage tm = session.createTextMessage(msg);
tm.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, delay);
tm.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 1*1000);
tm.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, 1);
return tm;
});
}
/** 接收 更新系统配置项的消息 **/
@Async(MqThreadExecutor.EXECUTOR_PAYORDER_MCH_NOTIFY)
@JmsListener(destination = CS.MQ.QUEUE_PAYORDER_MCH_NOTIFY)
public void receive(String msg) {
log.info("接收商户通知MQ, msg={}", msg);
Long notifyId = Long.parseLong(msg);
MchNotifyRecord record = mchNotifyRecordService.getById(notifyId);
if(record == null || record.getState() != MchNotifyRecord.STATE_ING){
log.info("查询通知记录不存在或状态不是通知中");
return ;
}
if( record.getNotifyCount() >= 6 ){
log.info("已达到最大发送次数");
return ;
}
//1. (发送结果最多6次)
Integer currentCount = record.getNotifyCount() + 1;
String notifyUrl = record.getNotifyUrl();
String res = "";
try {
res = HttpUtil.createPost(notifyUrl).timeout(20000).execute().body();
} catch (HttpException e) {
log.error("http error", e);
}
if(currentCount == 1){ //第一次通知: 更新为已通知
payOrderService.updateNotifySent(record.getOrderId());
}
//通知成功
if("SUCCESS".equalsIgnoreCase(res)){
mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_SUCCESS, res);
return ;
}
//响应结果为异常
if( currentCount >= 6 ){
mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_FAIL, res);
return ;
}
// 继续发送MQ 延迟发送
mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_ING, res);
// 通知延时次数
// 1 2 3 4 5 6
// 0 30 60 90 120 150
send(msg, currentCount * 30 * 1000);
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq.topic;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.stereotype.Component;
import javax.jms.ConnectionFactory;
/*
* JMS消息配置项
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:31
*/
@Component
public class JMSConfig {
/** 新增jmsListenerContainer, 用于接收topic类型的消息 **/
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainer(ConnectionFactory factory){
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setPubSubDomain(true);
bean.setConnectionFactory(factory);
return bean;
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq.topic;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.service.ConfigContextService;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
/*
* 更改ISV信息
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:31
*/
@Slf4j
@Component
public class MqTopic4ModifyIsvInfo extends ActiveMQTopic{
@Autowired private ConfigContextService configContextService;
public MqTopic4ModifyIsvInfo(){
super(CS.MQ.TOPIC_MODIFY_ISV_INFO);
}
/** 接收 更新系统配置项的消息 **/
@JmsListener(destination = CS.MQ.TOPIC_MODIFY_ISV_INFO, containerFactory = "jmsListenerContainer")
public void receive(String isvNo) {
log.info("重置ISV信息, msg={}", isvNo);
configContextService.initIsvConfigContext(isvNo);
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq.topic;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.service.ConfigContextService;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
/*
* 更改商户信息
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:31
*/
@Slf4j
@Component
public class MqTopic4ModifyMchInfo extends ActiveMQTopic{
@Autowired private ConfigContextService configContextService;
public MqTopic4ModifyMchInfo(){
super(CS.MQ.TOPIC_MODIFY_MCH_INFO);
}
/** 接收 更新系统配置项的消息 **/
@JmsListener(destination = CS.MQ.TOPIC_MODIFY_MCH_INFO, containerFactory = "jmsListenerContainer")
public void receive(String mchNo) {
log.info("重置商户信息, msg={}", mchNo);
configContextService.initMchConfigContext(mchNo);
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.mq.topic;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.service.impl.SysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
/*
* 更改系统配置参数
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:35
*/
@Slf4j
@Component
public class MqTopic4ModifySysConfig extends ActiveMQTopic{
@Autowired private SysConfigService sysConfigService;
public MqTopic4ModifySysConfig(){
super(CS.MQ.TOPIC_MODIFY_SYS_CONFIG);
}
/** 接收 更新系统配置项的消息 **/
@JmsListener(destination = CS.MQ.TOPIC_MODIFY_SYS_CONFIG, containerFactory = "jmsListenerContainer")
public void receive(String msg) {
log.info("成功接收更新系统配置的订阅通知, msg={}", msg);
sysConfigService.initDBConfig(msg);
log.info("系统配置静态属性已重置");
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.rqrs;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/*
* 基础请求参数
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:39
*/
@Data
public abstract class AbstractRQ implements Serializable {
/** 版本号 **/
@NotBlank(message="版本号不能为空")
protected String version;
/** 签名类型 **/
@NotBlank(message="签名类型不能为空")
protected String signType;
/** 签名值 **/
@NotBlank(message="签名值不能为空")
protected String sign;
/** 接口请求时间 **/
@NotBlank(message="时间戳不能为空")
protected String reqTime;
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.rqrs;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import java.io.Serializable;
/*
* 接口抽象RS对象, 本身无需实例化
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:39
*/
@Data
public abstract class AbstractRS implements Serializable {
public String toJSONString(){
return JSON.toJSONString(this);
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.rqrs;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/*
* 商户获取渠道用户ID 请求参数对象
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:40
*/
@Data
public class ChannelUserIdRQ extends AbstractRQ{
/** 商户号 **/
@NotBlank(message="商户号不能为空")
private String mchNo;
/** 接口代码, AUTO表示:自动获取 **/
@NotBlank(message="接口代码不能为空")
private String ifCode;
/** 回调地址 **/
@NotBlank(message="回调地址不能为空")
private String redirectUrl;
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.rqrs;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/*
* 查询订单请求参数对象
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:40
*/
@Data
public class QueryPayOrderRQ extends AbstractRQ{
/** 商户号 **/
@NotBlank(message="商户号不能为空")
private String mchNo;
/** 商户订单号 **/
private String mchOrderNo;
/** 支付系统订单号 **/
private String payOrderId;
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.rqrs;
import com.jeequan.jeepay.core.entity.PayOrder;
import lombok.Data;
import org.springframework.beans.BeanUtils;
/*
* 查询订单 响应参数
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:40
*/
@Data
public class QueryPayOrderRS extends AbstractRS{
/**
* 支付订单号
*/
private String payOrderId;
/**
* 商户号
*/
private String mchNo;
/**
* 商户订单号
*/
private String mchOrderNo;
/**
* 支付接口代码
*/
private String ifCode;
/**
* 支付方式代码
*/
private String wayCode;
/**
* 支付金额,单位分
*/
private Long amount;
/**
* 三位货币代码,人民币:cny
*/
private String currency;
/**
* 支付状态: 0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭
*/
private Byte state;
/**
* 客户端IP
*/
private String clientIp;
/**
* 商品标题
*/
private String subject;
/**
* 商品描述信息
*/
private String body;
/**
* 渠道订单号
*/
private String channelOrderNo;
/**
* 渠道支付错误码
*/
private String errCode;
/**
* 渠道支付错误描述
*/
private String errMsg;
/**
* 商户扩展参数
*/
private String extParam;
/**
* 订单支付成功时间
*/
private Long successTime;
/**
* 创建时间
*/
private Long createdAt;
public static QueryPayOrderRS buildByPayOrder(PayOrder payOrder){
if(payOrder == null){
return null;
}
QueryPayOrderRS result = new QueryPayOrderRS();
BeanUtils.copyProperties(payOrder, result);
result.setSuccessTime(payOrder.getSuccessTime() == null ? null : payOrder.getSuccessTime().getTime());
result.setCreatedAt(payOrder.getCreatedAt() == null ? null : payOrder.getCreatedAt().getTime());
return result;
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.rqrs.msg;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import java.io.Serializable;
/*
* 上游渠道侧响应信息包装类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:31
*/
@Slf4j
@Data
public class ChannelRetMsg implements Serializable {
/** 上游渠道返回状态 **/
private ChannelState channelState;
/** 渠道订单号 **/
private String channelOrderId;
/** 渠道用户标识 **/
private String channelUserId;
/** 渠道错误码 **/
private String channelErrCode;
/** 渠道错误描述 **/
private String channelErrMsg;
/** 渠道支付数据包, 一般用于支付订单的继续支付操作 **/
private String channelAttach;
/** 上游渠道返回的原始报文, 一般用于[运营平台的查询上游结果]功能 **/
private String channelOriginResponse;
/** 是否需要轮询查单(比如微信条码支付) 默认不查询订单 **/
private boolean isNeedQuery = false;
/** 响应结果(一般用于回调接口返回给上游数据 ) **/
private ResponseEntity responseEntity;
//渠道状态枚举值
public enum ChannelState {
CONFIRM_SUCCESS, //接口正确返回: 业务状态已经明确成功
CONFIRM_FAIL, //接口正确返回: 业务状态已经明确失败
WAITING, //接口正确返回: 上游处理中, 需通过定时查询/回调进行下一步处理
UNKNOWN, //接口超时,或网络异常等请求, 或者返回结果的签名失败: 状态不明确 ( 上游接口变更, 暂时无法确定状态值 )
API_RET_ERROR, //渠道侧出现异常( 接口返回了异常状态 )
SYS_ERROR //本系统出现不可预知的异常
}
//静态初始函数
public ChannelRetMsg(){}
public ChannelRetMsg(ChannelState channelState, String channelOrderId, String channelErrCode, String channelErrMsg) {
this.channelState = channelState;
this.channelOrderId = channelOrderId;
this.channelErrCode = channelErrCode;
this.channelErrMsg = channelErrMsg;
}
/** 明确成功 **/
public static ChannelRetMsg confirmSuccess(String channelOrderId){
return new ChannelRetMsg(ChannelState.CONFIRM_SUCCESS, channelOrderId, null, null);
}
/** 明确失败 **/
public static ChannelRetMsg confirmFail(String channelOrderId, String channelErrCode, String channelErrMsg){
return new ChannelRetMsg(ChannelState.CONFIRM_FAIL, channelOrderId, channelErrCode, channelErrMsg);
}
/** 明确失败 **/
public static ChannelRetMsg confirmFail(String channelOrderId){
return new ChannelRetMsg(ChannelState.CONFIRM_FAIL, channelOrderId, null, null);
}
/** 明确失败 **/
public static ChannelRetMsg confirmFail(){
return new ChannelRetMsg(ChannelState.CONFIRM_FAIL, null, null, null);
}
/** 处理中 **/
public static ChannelRetMsg waiting(){
return new ChannelRetMsg(ChannelState.WAITING, null, null, null);
}
/** 异常的情况 **/
public static ChannelRetMsg sysError(String channelErrMsg){
return new ChannelRetMsg(ChannelState.SYS_ERROR, null, null, "系统:" + channelErrMsg);
}
/** 状态未知的情况 **/
public static ChannelRetMsg unknown(){
return new ChannelRetMsg(ChannelState.UNKNOWN, null, null, null);
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.rqrs.payorder;
import lombok.Data;
/*
* 通用支付数据RQ
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:31
*/
@Data
public class CommonPayDataRQ extends UnifiedOrderRQ {
/** 请求参数: 支付数据包类型 **/
private String payDataType;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment