提交 0758a0da 编写于 作者: terrfly's avatar terrfly

添加支付测试ctrl; 添加webSocket监听推送到端程序;

上级 ff0623cc
......@@ -95,6 +95,12 @@
<artifactId>jeepay-sdk-java</artifactId>
</dependency>
<!-- webSocket -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
</dependencies>
<!-- 作为可执行jar -->
......
/*
* 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.mch.ctrl.paytest;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.JeepayClient;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchPayPassage;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.exception.JeepayException;
import com.jeequan.jeepay.mch.ctrl.CommonCtrl;
import com.jeequan.jeepay.model.PayOrderCreateReqModel;
import com.jeequan.jeepay.request.PayOrderCreateRequest;
import com.jeequan.jeepay.response.PayOrderCreateResponse;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchPayPassageService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.HashSet;
import java.util.Set;
/*
* 支付测试类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/22 9:43
*/
@RestController
@RequestMapping("/api/paytest")
public class PaytestController extends CommonCtrl {
@Autowired private MchAppService mchAppService;
@Autowired private MchPayPassageService mchPayPassageService;
@Autowired private SysConfigService sysConfigService;
/** 查询商户对应应用下支持的支付方式 **/
@PreAuthorize("hasAuthority('ENT_MCH_PAY_TEST_PAYWAY_LIST')")
@GetMapping("/payways/{appId}")
public ApiRes payWayList(@PathVariable("appId") String appId) {
Set<String> payWaySet = new HashSet<>();
mchPayPassageService.list(
MchPayPassage.gw().select(MchPayPassage::getWayCode)
.eq(MchPayPassage::getMchNo, getCurrentMchNo())
.eq(MchPayPassage::getAppId, appId)
.eq(MchPayPassage::getState, CS.PUB_USABLE)
).stream().forEach(r -> payWaySet.add(r.getWayCode()));
return ApiRes.ok(payWaySet);
}
/** 调起下单接口 **/
@PreAuthorize("hasAuthority('ENT_MCH_PAY_TEST_DO')")
@PostMapping("/payOrders")
public ApiRes doPay() {
//获取请求参数
String appId = getValStringRequired("appId");
Long amount = getRequiredAmountL("amount");
String mchOrderNo = getValStringRequired("mchOrderNo");
String wayCode = getValStringRequired("wayCode");
// 前端明确了支付参数的类型 payDataType
String payDataType = getValString("payDataType");
String authCode = getValString("authCode");
MchApp mchApp = mchAppService.getById(appId);
if(mchApp == null || mchApp.getState() != CS.PUB_USABLE || !mchApp.getAppId().equals(appId)){
throw new BizException("商户应用不存在或不可用");
}
PayOrderCreateRequest request = new PayOrderCreateRequest();
PayOrderCreateReqModel model = new PayOrderCreateReqModel();
request.setBizModel(model);
model.setMchNo(getCurrentMchNo()); // 商户号
model.setAppId(appId);
model.setMchOrderNo(mchOrderNo);
model.setWayCode(wayCode);
model.setAmount(amount);
model.setCurrency("CNY");
model.setClientIp(getClientIp());
model.setSubject(getCurrentMchNo() + "商户联调");
model.setBody(getCurrentMchNo() + "商户联调");
model.setNotifyUrl(sysConfigService.getDBApplicationConfig().getMchSiteUrl() + "/api/anon/paytestNotify/payOrder"); //回调地址
//设置扩展参数
JSONObject extParams = new JSONObject();
if(StringUtils.isNotEmpty(payDataType)) extParams.put("payDataType", payDataType.trim());
if(StringUtils.isNotEmpty(authCode)) extParams.put("authCode", authCode.trim());
model.setChannelExtra(extParams.toString());
JeepayClient jeepayClient = new JeepayClient(sysConfigService.getDBApplicationConfig().getPaySiteUrl(), mchApp.getAppSecret());
try {
PayOrderCreateResponse response = jeepayClient.execute(request);
if(response.getCode() != 0){
throw new BizException(response.getMsg());
}
return ApiRes.ok(response.get());
} catch (JeepayException e) {
throw new BizException(e.getMessage());
}
}
}
/*
* 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.mch.ctrl.paytest;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.model.OriginalRes;
import com.jeequan.jeepay.mch.ctrl.CommonCtrl;
import com.jeequan.jeepay.mch.websocket.server.WsPayOrderServer;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchPayPassageService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import com.jeequan.jeepay.util.JeepayKit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/*
* 支付测试 - 回调函数
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/22 14:22
*/
@RestController
@RequestMapping("/api/anon/paytestNotify")
public class PaytestNotifyController extends CommonCtrl {
@Autowired private MchAppService mchAppService;
@RequestMapping("/payOrder")
public void payOrderNotify() throws IOException {
//请求参数
JSONObject params = getReqParamJSON();
String mchNo = params.getString("mchNo");
String appId = params.getString("appId");
String sign = params.getString("sign");
MchApp mchApp = mchAppService.getById(appId);
if(mchApp == null || !mchApp.getMchNo().equals(mchNo)){
response.getWriter().print("app is not exists");
return;
}
params.remove("sign");
if(!JeepayKit.getSign(params, mchApp.getAppSecret()).equalsIgnoreCase(sign)){
response.getWriter().print("sign fail");
return;
}
JSONObject msg = new JSONObject();
msg.put("state", params.getIntValue("state"));
msg.put("errCode", params.getString("errCode"));
msg.put("errMsg", params.getString("errMsg"));
//推送到前端
WsPayOrderServer.sendMsgByOrderId(params.getString("payOrderId"), msg.toJSONString());
response.getWriter().print("SUCCESS");
}
}
/*
* 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.mch.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/*
* 开启WebSocket支持
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/22 12:57
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
/*
* 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.mch.websocket.server;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/*
* WebSocket服务类
* /ws/payOrder/{訂單ID}/{客戶端自定義ID}
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/22 12:57
*/
@ServerEndpoint("/api/anon/ws/payOrder/{payOrderId}/{cid}")
@Component
public class WsPayOrderServer {
private final static Logger logger = LoggerFactory.getLogger(WsPayOrderServer.class);
//当前在线客户端 数量
private static int onlineClientSize = 0;
// payOrderId 与 WsPayOrderServer 存储关系, ConcurrentHashMap保证线程安全
private static Map<String, Set<WsPayOrderServer>> wsOrderIdMap = new ConcurrentHashMap<>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//客户端自定义ID
private String cid = "";
//支付订单号
private String payOrderId = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("payOrderId") String payOrderId, @PathParam("cid") String cid) {
try {
//设置当前属性
this.cid = cid;
this.payOrderId = payOrderId;
this.session = session;
Set<WsPayOrderServer> wsServerSet = wsOrderIdMap.get(payOrderId);
if(wsServerSet == null) wsServerSet = new CopyOnWriteArraySet<>();
wsServerSet.add(this);
wsOrderIdMap.put(payOrderId, wsServerSet);
addOnlineCount(); //在线数加1
logger.info("cid[{}],payOrderId[{}]连接开启监听!当前在线人数为{}", cid, payOrderId, onlineClientSize);
} catch (Exception e) {
logger.error("ws监听异常cid[{}],payOrderId[{}]", cid, payOrderId, e);
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
Set wsSet = wsOrderIdMap.get(this.payOrderId);
wsSet.remove(this);
if(wsSet.isEmpty()) wsOrderIdMap.remove(this.payOrderId);
subOnlineCount(); //在线数减1
logger.info("cid[{}],payOrderId[{}]连接关闭!当前在线人数为{}", cid, payOrderId, onlineClientSize);
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
logger.error("ws发生错误", error);
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 根据订单ID,推送消息
* 捕捉所有的异常,避免影响业务。
* @param payOrderId
*/
public static void sendMsgByOrderId(String payOrderId, String msg) {
try {
logger.info("推送ws消息到浏览器, payOrderId={},msg={}", payOrderId, msg);
Set<WsPayOrderServer> wsSet = wsOrderIdMap.get(payOrderId);
if(wsSet == null || wsSet.isEmpty()){
logger.info("payOrderId[{}] 无ws监听客户端", payOrderId);
return ;
}
for (WsPayOrderServer item : wsSet) {
try {
item.sendMessage(msg);
} catch (Exception e) {
logger.info("推送设备消息时异常,payOrderId={}, cid={}", payOrderId, item.cid, e);
continue;
}
}
} catch (Exception e) {
logger.info("推送消息时异常,payOrderId={}", payOrderId, e);
}
}
public static synchronized int getOnlineClientSize() {
return onlineClientSize;
}
public static synchronized void addOnlineCount() {
onlineClientSize++;
}
public static synchronized void subOnlineCount() {
onlineClientSize--;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册