ylb-支付服务pay

2023-10-21 11:20
文章标签 服务 支付 pay ylb

本文主要是介绍ylb-支付服务pay,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

总览:
在这里插入图片描述
在这里插入图片描述

1、工具类(签名工具类Pkipair和http工具类HttpUtil)

在pay模块util包下,创建签名工具类Pkipair和http工具类HttpUtil:

package com.bjpowernode.util;import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;public class Pkipair {/*生成签名*/public String signMsg( String signMsg) {String base64 = "";try {KeyStore ks = KeyStore.getInstance("PKCS12");//商户私钥文件String file = Pkipair.class.getResource("10012140356.pfx").getPath().replaceAll("%20", " ");System.out.println(file);FileInputStream ksfis = new FileInputStream(file);BufferedInputStream ksbufin = new BufferedInputStream(ksfis);char[] keyPwd = "123456".toCharArray();ks.load(ksbufin, keyPwd);PrivateKey priK = (PrivateKey) ks.getKey("test-alias", keyPwd);Signature signature = Signature.getInstance("SHA256withRSA");signature.initSign(priK);signature.update(signMsg.getBytes("utf-8"));sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();base64 = encoder.encode(signature.sign());} catch(FileNotFoundException e){e.printStackTrace();}catch (Exception ex) {ex.printStackTrace();}return base64;}/*验签的方法*/public boolean enCodeByCer( String val, String msg) {boolean flag = false;try {//快钱的公钥文件String file = Pkipair.class.getResource("99bill[1].cert.rsa.20140803.cer").toURI().getPath();System.out.println(file);                       //  99bill.cert.rsa.20140803.cerFileInputStream inStream = new FileInputStream(file);CertificateFactory cf = CertificateFactory.getInstance("X.509");X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);PublicKey pk = cert.getPublicKey();Signature signature = Signature.getInstance("SHA256withRSA");signature.initVerify(pk);signature.update(val.getBytes());sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();System.out.println(new String(decoder.decodeBuffer(msg)));flag = signature.verify(decoder.decodeBuffer(msg));System.out.println(flag);} catch (Exception e) {e.printStackTrace();System.out.println("no");}return flag;}}
package com.bjpowernode.util;import java.net.SocketTimeoutException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;/*** HttpUtil 工具类*/
public class HttpUtil {private static final Log LOGGER = LogFactory.getLog(HttpUtil.class);private static PoolingHttpClientConnectionManager connManager;private static RequestConfig requestConfig;static{try {SSLContext sslcontext = createIgnoreVerifySSL();SSLContext sslContext = SSLContext.getInstance("TLSv1.2");sslContext.init(null, null, null);SSLContext.setDefault(sslContext);Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("http", PlainConnectionSocketFactory.INSTANCE).register("https", new SSLConnectionSocketFactory(sslcontext)).build();connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);// 连接池超时时间使用connect超时时间requestConfig = RequestConfig.custom().setConnectionRequestTimeout(1000).setConnectTimeout(1000).setSocketTimeout(5000).build();} catch (Exception e) {LOGGER.error(" [XPAY-SDK] init connectionManager or requestConfig error !!! ",e);e.printStackTrace();}}public static String doPostJsonRequest(String reqeustString, String url,int connectTimeout, int socketTimeOut) throws Exception {CloseableHttpResponse response = null;try {changeRequestConfig(connectTimeout,socketTimeOut);CloseableHttpClient httpclient = HttpClients.createDefault();HttpPost httpPost = new HttpPost(url);httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");httpPost.setConfig(requestConfig);httpPost.setEntity(new StringEntity(reqeustString, ContentType.APPLICATION_JSON));response = httpclient.execute(httpPost);// get http status codeint resStatu = response.getStatusLine().getStatusCode();String responseString = null;if (resStatu == HttpStatus.SC_OK) {responseString = EntityUtils.toString(response.getEntity());} else {throw new Exception(url + ",the statusCode is " + resStatu);}return responseString;} catch (ConnectTimeoutException e) {e.printStackTrace();} catch (SocketTimeoutException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();} finally {if (response != null) {try {EntityUtils.consume(response.getEntity());response.close();} catch (Exception e) {e.printStackTrace();}}}return url;}/*** 绕过验证** @return* @throws NoSuchAlgorithmException* @throws KeyManagementException*/private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {SSLContext sc = SSLContext.getInstance("TLSv1.2");// 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法X509TrustManager trustManager = new X509TrustManager() {public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,String paramString) throws CertificateException {}public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,String paramString) throws CertificateException {}public java.security.cert.X509Certificate[] getAcceptedIssuers() {return null;}};sc.init(null, new TrustManager[] { trustManager }, null);return sc;}public static String doPostJsonRequestByHttps(String reqeustString, String url,int connectTimeout, int socketTimeOut) {long startTime = System.currentTimeMillis();CloseableHttpResponse response = null;String responseString = null;try {changeRequestConfig(connectTimeout,socketTimeOut);CloseableHttpClient httpsClient = HttpClients.custom().setConnectionManager(connManager).build();HttpPost httpPost = new HttpPost(url);httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");httpPost.setConfig(requestConfig);httpPost.setEntity(new StringEntity(reqeustString, ContentType.APPLICATION_JSON));response = httpsClient.execute(httpPost);// get http status codeint resStatu = response.getStatusLine().getStatusCode();responseString = null;if (resStatu == HttpStatus.SC_OK) {responseString = EntityUtils.toString(response.getEntity());} else {throw new Exception(url + ",the statusCode is " + resStatu);}LOGGER.info(String.format("response data : [ %s ] , time consuming : [ %s ] ms !! ",responseString,(System.currentTimeMillis()- startTime)));return responseString;}catch (ConnectTimeoutException e) {e.printStackTrace();} catch (SocketTimeoutException e) {e.printStackTrace();}catch (Exception e) {e.printStackTrace();}finally {if (response != null) {try {EntityUtils.consume(response.getEntity());response.close();} catch (Exception e) {e.printStackTrace();}}}return responseString;}/*** 修改默认超时时间* @param connectionTime* @param soTimeout*/private static void changeRequestConfig(int connectionTime,int soTimeout){if(connectionTime != requestConfig.getConnectionRequestTimeout()|| soTimeout != requestConfig.getSocketTimeout()){requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionTime).setConnectTimeout(connectionTime).setSocketTimeout(soTimeout).build();}}
}

2、service处理(KuaiQianService)

在pay模块service包下,创建KuaiQianService:
1、获取用户信息(queryUser)
2、生成快钱支付接口的数据 Map是发送给快钱的所有请求参数(generateFormData)
3、创建充值记录(addRecharge)
4、生成订单号orderId(generateOrderId)
5、把订单号,存放到redis(addOrderIdToRedis)
6、处理异步通知(kqNotify)
7、调用快钱的查询接口(handleQueryOrder)

package com.bjpowernode.pay.service;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bjpowernode.api.model.RechargeRecord;
import com.bjpowernode.api.model.User;
import com.bjpowernode.api.service.RechargeService;
import com.bjpowernode.api.service.UserService;
import com.bjpowernode.common.constants.RedisKey;
import com.bjpowernode.common.constants.YLBConstant;
import com.bjpowernode.util.HttpUtil;
import com.bjpowernode.util.Pkipair;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;@Service
public class KuiQianService {@DubboReference(interfaceClass = UserService.class,version = "1.0")private UserService userService;@DubboReference(interfaceClass = RechargeService.class,version = "1.0")private RechargeService rechargeService;@Resourceprivate StringRedisTemplate stringRedisTemplate;/*获取用户信息*/public User queryUser(Integer uid){User user = userService.queryById(uid);return user;}/*生成快钱支付接口的数据  Map是发送给快钱的所有请求参数*/public Map<String,String> generateFormData(Integer uid, String phone, BigDecimal rechargeMoney) {Map<String,String> data = new HashMap<>();//人民币网关账号,该账号为11位人民币网关商户编号+01,该参数必填。String merchantAcctId = "1001214035601";////编码方式,1代表 UTF-8; 2 代表 GBK; 3代表 GB2312 默认为1,该参数必填。String inputCharset = "1";//接收支付结果的页面地址,该参数一般置为空即可。String pageUrl = "";//服务器接收支付结果的后台地址,该参数务必填写,不能为空。String bgUrl = "http://451627p2o2.qicp.vip/pay/kq/rece/notify";//网关版本,固定值:v2.0,该参数必填。String version =  "v2.0";//语言种类,1代表中文显示,2代表英文显示。默认为1,该参数必填。String language =  "1";//签名类型,该值为4,代表PKI加密方式,该参数必填。String signType =  "4";//支付人姓名,可以为空。String payerName= "";//支付人联系类型,1 代表电子邮件方式;2 代表手机联系方式。可以为空。String payerContactType =  "2";//支付人联系方式,与payerContactType设置对应,payerContactType为1,则填写邮箱地址;payerContactType为2,则填写手机号码。可以为空。String payerContact =  phone;//指定付款人,可以为空String payerIdType =  "3";//付款人标识,可以为空String payerId =  String.valueOf(uid);//付款人IP,可以为空String payerIP =  "";//商户订单号,以下采用时间来定义订单号,商户可以根据自己订单号的定义规则来定义该值,不能为空。String orderId = "KQ"+generateOrderId();//订单金额,金额以“分”为单位,商户测试以1分测试即可,切勿以大金额测试。该参数必填。//0.01 * 100 == 1.00  100000*100 = 10000000 , 科学计数法  1 * 10^7String orderAmount = rechargeMoney.multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString();//订单提交时间,格式:yyyyMMddHHmmss,如:20071117020101,不能为空。String orderTime = new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());//快钱时间戳,格式:yyyyMMddHHmmss,如:20071117020101, 可以为空String orderTimestamp = orderTime;//商品名称,可以为空。String productName= "动力理财产品";//商品数量,可以为空。String productNum = "1";//商品代码,可以为空。String productId = "10000";//商品描述,可以为空。String productDesc = "购买产品";//扩展字段1,商户可以传递自己需要的参数,支付完快钱会原值返回,可以为空。String ext1 = "";//扩展自段2,商户可以传递自己需要的参数,支付完快钱会原值返回,可以为空。String ext2 = "";//支付方式,一般为00,代表所有的支付方式。如果是银行直连商户,该值为10-1或10-2,必填。String payType = "00";//银行代码,如果payType为00,该值可以为空;如果payType为10-1或10-2,该值必须填写,具体请参考银行列表。String bankId = "";//同一订单禁止重复提交标志,实物购物车填1,虚拟产品用0。1代表只能提交一次,0代表在支付不成功情况下可以再提交。可为空。String redoFlag = "0";//快钱合作伙伴的帐户号,即商户编号,可为空。String pid = "";// signMsg 签名字符串 不可空,生成加密签名串String signMsgVal = "";signMsgVal = appendParam(signMsgVal, "inputCharset", inputCharset,data);signMsgVal = appendParam(signMsgVal, "pageUrl", pageUrl,data);signMsgVal = appendParam(signMsgVal, "bgUrl", bgUrl,data);signMsgVal = appendParam(signMsgVal, "version", version,data);signMsgVal = appendParam(signMsgVal, "language", language,data);signMsgVal = appendParam(signMsgVal, "signType", signType,data);signMsgVal = appendParam(signMsgVal, "merchantAcctId",merchantAcctId,data);signMsgVal = appendParam(signMsgVal, "payerName", payerName,data);signMsgVal = appendParam(signMsgVal, "payerContactType",payerContactType,data);signMsgVal = appendParam(signMsgVal, "payerContact", payerContact,data);signMsgVal = appendParam(signMsgVal, "payerIdType", payerIdType,data);signMsgVal = appendParam(signMsgVal, "payerId", payerId,data);signMsgVal = appendParam(signMsgVal, "payerIP", payerIP,data);signMsgVal = appendParam(signMsgVal, "orderId", orderId,data);signMsgVal = appendParam(signMsgVal, "orderAmount", orderAmount,data);signMsgVal = appendParam(signMsgVal, "orderTime", orderTime,data);signMsgVal = appendParam(signMsgVal, "orderTimestamp", orderTimestamp,data);signMsgVal = appendParam(signMsgVal, "productName", productName,data);signMsgVal = appendParam(signMsgVal, "productNum", productNum,data);signMsgVal = appendParam(signMsgVal, "productId", productId,data);signMsgVal = appendParam(signMsgVal, "productDesc", productDesc,data);signMsgVal = appendParam(signMsgVal, "ext1", ext1,data);signMsgVal = appendParam(signMsgVal, "ext2", ext2,data);signMsgVal = appendParam(signMsgVal, "payType", payType,data);signMsgVal = appendParam(signMsgVal, "bankId", bankId,data);signMsgVal = appendParam(signMsgVal, "redoFlag", redoFlag,data);signMsgVal = appendParam(signMsgVal, "pid", pid,data);System.out.println(signMsgVal);Pkipair pki = new Pkipair();//生成签名串String signMsg = pki.signMsg(signMsgVal);//需要signMsgdata.put("signMsg",signMsg);return data;}/*创建充值记录*/public boolean addRecharge(Integer uid, BigDecimal rechargeMoney, String orderId) {RechargeRecord record = new RechargeRecord();record.setChannel("KQ");record.setRechargeDesc("快钱充值");record.setRechargeMoney(rechargeMoney);record.setRechargeNo(orderId);record.setRechargeStatus(YLBConstant.RECHARGE_STATUS_PROCESSING);record.setRechargeTime(new Date());record.setUid(uid);int rows = rechargeService.addRechargeRecord(record);return rows > 0;}/**************辅助工具方法***********************************/private String appendParam(String returns, String paramId, String paramValue,Map<String,String> data) {if (returns != "") {if (paramValue != "" && paramValue != null) {returns += "&" + paramId + "=" + paramValue;}} else {if (paramValue != "" && paramValue != null) {returns = paramId + "=" + paramValue;}}if( data != null ){data.put(paramId,paramValue);}return returns;}//生成orderIdprivate String generateOrderId(){//唯一值。1. 使用数据库的自增主键//       2. 使用redis的自增// orderId = 时间戳 +  redis的自增String key = RedisKey.KEY_RECHARGE_ORDERID;Long incr = stringRedisTemplate.boundValueOps(key).increment();String orderId = DateFormatUtils.format(new Date(),"yyyyMMddHHmmssSSS") + incr;return orderId;}/*把订单号,存放到redis*/public void addOrderIdToRedis(String orderId) {String key  = RedisKey.KEY_ORDERID_SET;stringRedisTemplate.boundZSetOps(key).add(orderId, new Date().getTime());}/*处理异步通知*/public void kqNotify(HttpServletRequest request) {String merchantAcctId = request.getParameter("merchantAcctId");String version = request.getParameter("version");String language = request.getParameter("language");String signType = request.getParameter("signType");String payType = request.getParameter("payType");String bankId = request.getParameter("bankId");String orderId = request.getParameter("orderId");String orderTime = request.getParameter("orderTime");String orderAmount = request.getParameter("orderAmount");String bindCard = request.getParameter("bindCard");if(request.getParameter("bindCard")!=null){bindCard = request.getParameter("bindCard");}String bindMobile="";if(request.getParameter("bindMobile")!=null){bindMobile = request.getParameter("bindMobile");}String dealId = request.getParameter("dealId");String bankDealId = request.getParameter("bankDealId");String dealTime = request.getParameter("dealTime");String payAmount = request.getParameter("payAmount");String fee = request.getParameter("fee");String ext1 = request.getParameter("ext1");String ext2 = request.getParameter("ext2");String payResult = request.getParameter("payResult");String aggregatePay = request.getParameter("aggregatePay");String errCode = request.getParameter("errCode");String signMsg = request.getParameter("signMsg");//拼接签名计算的串String merchantSignMsgVal = "";merchantSignMsgVal = appendParam(merchantSignMsgVal,"merchantAcctId", merchantAcctId,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "version",version,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "language",language,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "signType",signType,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "payType",payType,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "bankId",bankId,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderId",orderId,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderTime",orderTime,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderAmount",orderAmount,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "bindCard",bindCard,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "bindMobile",bindMobile,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "dealId",dealId,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "bankDealId",bankDealId,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "dealTime",dealTime,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "payAmount",payAmount,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "fee", fee,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "ext1", ext1,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "ext2", ext2,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "payResult",payResult,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "aggregatePay",aggregatePay,null);merchantSignMsgVal = appendParam(merchantSignMsgVal, "errCode",errCode,null);Pkipair pki = new Pkipair();boolean flag = pki.enCodeByCer(merchantSignMsgVal, signMsg);System.out.println("flag==="+flag);if( flag ){/*** 可以处理业务逻辑* 1.判断商户是商家自己的吗* 2.判断订单在商家是否存在,是否处理过* 3.判断金额是否一致* 4.如果成功,更新用户的资金* 5.修改充值表的记录状态* 6.删除redis中的处理过的订单号*/if("1001214035601".equals(merchantAcctId)){int rechargeResult  =  rechargeService.handleKQNotify(orderId,payAmount,payResult);System.out.println("订单"+orderId+",充值处理结果:"+rechargeResult);} else {System.out.println("订单"+orderId+",充值处理结果:商家号不正确");}} else {System.out.println("订单"+orderId+"验签失败,不能处理");}//删除redis中的订单记录stringRedisTemplate.boundZSetOps(RedisKey.KEY_ORDERID_SET).remove(orderId);}/*调用快钱的查询接口*/public void handleQueryOrder() {//1.从redis获取订单号Set<String> orders = stringRedisTemplate.boundZSetOps(RedisKey.KEY_ORDERID_SET).range(0, -1);//2.循环订单号orders.forEach( orderId -> {//3.每个订单,调用查询接口doQuery(orderId);});}private void doQuery(String orderId){Map<String, Object> request = new HashMap<String, Object>();//固定值:1代表UTF-8;String inputCharset = "1";//固定值:v2.0 必填String version = "v2.0";//1代表Md5,2 代表PKI加密方式  必填String signType = "2";//人民币账号 membcode+01  必填String merchantAcctId = "1001214035601";//固定值:0 按商户订单号单笔查询,1 按交易结束时间批量查询必填String queryType = "0";//固定值:1	代表简单查询 必填String queryMode = "1";//数字串,格式为:年[4 位]月[2 位]日[2 位]时[2 位]分[2 位]秒[2位],例如:20071117020101String startTime = "";数字串,格式为:年[4 位]月[2 位]日[2 位]时[2 位]分[2 位]秒[2位],例如:20071117020101String endTime = "";String requestPage = "";String key = "27YKWKBKHT2IZSQ4";request.put("inputCharset", inputCharset);request.put("version", version);request.put("signType", signType);request.put("merchantAcctId", merchantAcctId);request.put("queryType", queryType);request.put("queryMode", queryMode);request.put("startTime", startTime);request.put("endTime", endTime);request.put("requestPage", requestPage);request.put("orderId", orderId);String message="";message = appendParam(message,"inputCharset",inputCharset,null);message = appendParam(message,"version",version,null);message = appendParam(message,"signType",signType,null);message = appendParam(message,"merchantAcctId",merchantAcctId,null);message = appendParam(message,"queryType",queryType,null);message = appendParam(message,"queryMode",queryMode,null);message = appendParam(message,"startTime",startTime,null);message = appendParam(message,"endTime",endTime,null);message = appendParam(message,"requestPage",requestPage,null);message = appendParam(message,"orderId",orderId,null);message = appendParam(message,"key",key,null);Pkipair pki = new Pkipair();String sign = pki.signMsg(message);request.put("signMsg", sign);System.out.println("请求json串===" + JSON.toJSONString(request));//sandbox提交地址String reqUrl = "https://sandbox.99bill.com/gatewayapi/gatewayOrderQuery.do";String response = "";try {response = HttpUtil.doPostJsonRequestByHttps(JSON.toJSONString(request), reqUrl, 3000, 8000);//解析responseif(StringUtils.isNotBlank(response)){Object detailObject = JSONObject.parseObject(response).get("orderDetail");System.out.println("detailObject===="+detailObject);if( detailObject != null){//把查询的Object转为JSONArrayJSONArray array = (JSONArray)detailObject;JSONObject detailJsonObject = array.getJSONObject(0);if( detailJsonObject != null){//处理充值结果,和异步通知一样int result = rechargeService.handleKQNotify(detailJsonObject.getString("orderId"),detailJsonObject.getString("payAmount"),detailJsonObject.getString("payResult"));System.out.println("处理的订单号是:"+orderId+",处理结果:"+result);}}}//删除redis中的订单stringRedisTemplate.boundZSetOps(RedisKey.KEY_ORDERID_SET).remove(orderId);} catch (Exception e) {e.printStackTrace();return;}}
}

其中:

3、service处理(RechargeService)

1、在api模块下的service包,充值接口RechargeService添加:(创建充值记录方法addRechargeRecord 和 处理后续充值方法handleKQNotify)

package com.bjpowernode.api.service;import com.bjpowernode.api.model.RechargeRecord;import java.util.List;/*** 充值接口*/
public interface RechargeService {/*根据userID查询它的充值记录*/List<RechargeRecord> queryByUid(Integer uid,Integer pageNo, Integer pageSize);/*创建充值记录*/int addRechargeRecord(RechargeRecord record);/*处理后续充值*/int handleKQNotify(String orderId, String payAmount, String payResult);
}

2、实现这个接口方法,在dataservice模块service包下,实现类RechargeServiceImpl添加:(创建充值记录addRechargeRecord 和 处理后续充值handleKQNotify):

package com.bjpowernode.dataservice.service;import com.bjpowernode.api.model.RechargeRecord;
import com.bjpowernode.api.service.RechargeService;
import com.bjpowernode.common.constants.YLBConstant;
import com.bjpowernode.common.util.CommonUtil;
import com.bjpowernode.dataservice.mapper.FinanceAccountMapper;
import com.bjpowernode.dataservice.mapper.RechargeRecordMapper;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;@DubboService(interfaceClass = RechargeService.class,version = "1.0")
public class RechargeServiceImpl implements RechargeService {@Resourceprivate RechargeRecordMapper rechargeMapper;@Resourceprivate FinanceAccountMapper accountMapper;/*根据userID查询它的充值记录*/@Overridepublic List<RechargeRecord> queryByUid(Integer uid, Integer pageNo, Integer pageSize) {List<RechargeRecord> records  = new ArrayList<>();if( uid != null && uid > 0 ){pageNo  = CommonUtil.defaultPageNo(pageNo);pageSize = CommonUtil.defaultPageSize(pageSize);int offset = (pageNo -1 ) * pageSize;records = rechargeMapper.selectByUid(uid, offset, pageSize);}return records;}/*创建充值记录*/@Overridepublic int addRechargeRecord(RechargeRecord record) {return rechargeMapper.insertSelective(record);}/*处理后续充值*/@Transactional(rollbackFor = Exception.class)@Overridepublic synchronized int handleKQNotify(String orderId, String payAmount, String payResult) {int result = 0;//订单不存在int rows =  0;//1.查询订单RechargeRecord record = rechargeMapper.selectByRechargeNo(orderId);if(record != null ){if( record.getRechargeStatus() == YLBConstant.RECHARGE_STATUS_PROCESSING){//2.判断金额是否一致String fen = record.getRechargeMoney().multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString();if( fen.equals(payAmount)){//金额一致if("10".equals(payResult)){//成功rows = accountMapper.updateAvailableMoneyByRecharge(record.getUid(),record.getRechargeMoney());if(rows < 1 ){throw new RuntimeException("充值更新资金账号失败");}//更新充值记录的状态rows = rechargeMapper.updateStatus(record.getId(),YLBConstant.RECHARGE_STATUS_SUCCESS);if( rows < 1) {throw new RuntimeException("充值更新充值记录状态失败");}result  = 1;//成功} else {//充值失败//更新充值记录的状态rows = rechargeMapper.updateStatus(record.getId(),YLBConstant.RECHARGE_STATUS_FAIL);if( rows < 1) {throw new RuntimeException("充值更新充值记录状态失败");}result = 2;//充值结果是失败的}} else {result = 4;//金额不一样}} else {result = 3;//订单已经处理过了}}return result;}
}

其中:
1、根据订单号,查询记录selectByRechargeNo(需要在dataservice模块mapper包下的RechargeRecordMapper接口添加方法,并在resources/mappers/RechargeRecordMapper.xml编写SQL语句):

    RechargeRecord selectByRechargeNo(@Param("rechargeNo") String orderId);
  <!--根据订单号,查询记录--><select id="selectByRechargeNo" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from b_recharge_recordwhere recharge_no = #{rechargeNo} for update</select>

2、充值更新金额updateAvailableMoneyByRecharge(需要在dataservice模块mapper包下的FinanceAccountMapper接口添加方法,并在resources/mappers/FinanceAccountMapper.xml编写SQL语句):

    /*充值更新金额*/int updateAvailableMoneyByRecharge(@Param("uid") Integer uid, @Param("rechargeMoney") BigDecimal rechargeMoney);
  <!--充值更新金额--><update id="updateAvailableMoneyByRecharge">update  u_finance_account set  available_money = available_money + #{rechargeMoney}where uid = #{uid}</update>

3、更新充值记录状态updateStatus(需要在dataservice模块mapper包下的RechargeRecordMapper接口添加方法,并在resources/mappers/RechargeRecordMapper.xml编写SQL语句):

    /*更新状态*/int updateStatus(@Param("id") Integer id, @Param("newStatus") int rechargeStatusSuccess);
  <!--更新状态--><update id="updateStatus">update b_recharge_record set  recharge_status = #{newStatus} where id = #{id}</update>

4、controller处理

在pay模块controller包下,创建接受请求的KuaiQianController:
一、(接收来自vue项目的支付充值请求)
1、检查uid是否是有效的用户(用户存在,且充值金额充足),并查询用户(kQService.queryUser(uid))
2、创建快钱支付接口需要的请求参数(kQService.generateFormData(uid,user.getPhone(),rechargeMoney))
3、创建充值记录(kQService.addRecharge(uid,rechargeMoney,data.get(“orderId”)))
4、把订单号存放到redis(kQService.addOrderIdToRedis(data.get(“orderId”)))
5、提交支付请求给快钱的form页面(thymeleaf)(view = “kqForm”;)
二、(接收快钱给商家的支付结果 , 快钱以get方式,发送请求给商家)
三、从定时任务,调用的接口

package com.bjpowernode.pay.controller;import com.bjpowernode.api.model.User;
import com.bjpowernode.pay.service.KuiQianService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Map;@Controller
@RequestMapping("/kq")
public class KuaiQianController {@Resourceprivate KuiQianService kQService;/*接收来自vue项目的支付充值请求*/@GetMapping("/rece/recharge")public String receFrontRechargeKQ(Integer uid,BigDecimal rechargeMoney,Model model){//默认是错误视图String view="err";if(uid != null && uid > 0 &&rechargeMoney != null && rechargeMoney.doubleValue() > 0 ){//1.检查uid是否是有效的用户try{User user = kQService.queryUser(uid);if(user != null ){//创建快钱支付接口需要的请求参数Map<String,String> data = kQService.generateFormData(uid,user.getPhone(),rechargeMoney);model.addAllAttributes(data);//创建充值记录kQService.addRecharge(uid,rechargeMoney,data.get("orderId"));//把订单号存放到rediskQService.addOrderIdToRedis(data.get("orderId"));//提交支付请求给快钱的form页面(thymeleaf)view  = "kqForm";}}catch (Exception e){e.printStackTrace();}}return view;}//接收快钱给商家的支付结果 , 快钱以get方式,发送请求给商家@GetMapping("/rece/notify")@ResponseBodypublic String payResultNotify(HttpServletRequest request){System.out.println("=================接收快钱的异步通知=============");kQService.kqNotify(request);return "<result>1</result><redirecturl>http://localhost:8080/</redirecturl>";}//从定时任务,调用的接口@GetMapping("/rece/query")@ResponseBodypublic String queryKQOrder(){kQService.handleQueryOrder();return "接收了查询的请求";}
}

其中:

静态页面

1、在pay模块,resources/template下,创建两个页面:err.html和kqForm.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>请求错误</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form name="kqPay" action="https://sandbox.99bill.com/gateway/recvMerchantInfoAction.htm" method="get"><input type="hidden" name="inputCharset" th:value="${inputCharset}" /><input type="hidden" name="pageUrl" th:value="${pageUrl}" /><input type="hidden" name="bgUrl" th:value="${bgUrl}" /><input type="hidden" name="version" th:value="${version}" /><input type="hidden" name="language" th:value="${language}" /><input type="hidden" name="signType" th:value="${signType}" /><input type="hidden" name="signMsg" th:value="${signMsg}" /><input type="hidden" name="merchantAcctId" th:value="${merchantAcctId}" /><input type="hidden" name="payerName" th:value="${payerName}" /><input type="hidden" name="payerContactType" th:value="${payerContactType}" /><input type="hidden" name="payerContact" th:value="${payerContact}" /><input type="hidden" name="payerIdType" th:value="${payerIdType}" /><input type="hidden" name="payerId" th:value="${payerId}" /><input type="hidden" name="payerIP" th:value="${payerIP}" /><input type="hidden" name="orderId" th:value="${orderId}" /><input type="hidden" name="orderAmount" th:value="${orderAmount}" /><input type="hidden" name="orderTime" th:value="${orderTime}" /><input type="hidden" name="orderTimestamp" th:value="${orderTimestamp}" /><input type="hidden" name="productName" th:value="${productName}" /><input type="hidden" name="productNum" th:value="${productNum}" /><input type="hidden" name="productId" th:value="${productId}" /><input type="hidden" name="productDesc" th:value="${productDesc}" /><input type="hidden" name="ext1" th:value="${ext1}" /><input type="hidden" name="ext2" th:value="${ext2}" /><input type="hidden" name="payType" th:value="${payType}" /><input type="hidden" name="bankId" th:value="${bankId}" /><input type="hidden" name="redoFlag" th:value="${redoFlag}" /><input type="hidden" name="pid" th:value="${pid}" /><!-- <input type="submit" name="submit" th:value="提交到快钱">--></form><script>document.forms[0].submit();</script>
</body>
</html>

这篇关于ylb-支付服务pay的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/254061

相关文章

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

基于SpringBoot的宠物服务系统+uniapp小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统+原生微信小程序+LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统+LW参考示例 3.基于SpringBoot+Vue的企业人事管理系统+LW参考示例 4.基于SSM的高校实验室管理系统+LW参考示例 5.基于SpringBoot的二手数码回收系统+原生微信小程序+LW参考示例 6.基于SSM的民宿预订管理系统+LW参考示例 7.基于

Golang支持平滑升级的HTTP服务

前段时间用Golang在做一个HTTP的接口,因编译型语言的特性,修改了代码需要重新编译可执行文件,关闭正在运行的老程序,并启动新程序。对于访问量较大的面向用户的产品,关闭、重启的过程中势必会出现无法访问的情况,从而影响用户体验。 使用Golang的系统包开发HTTP服务,是无法支持平滑升级(优雅重启)的,本文将探讨如何解决该问题。 一、平滑升级(优雅重启)的一般思路 一般情况下,要实现平滑

Golang服务平滑重启

与重载配置相同的是我们也需要通过信号来通知server重启,但关键在于平滑重启,如果只是简单的重启,只需要kill掉,然后再拉起即可。平滑重启意味着server升级的时候可以不用停止业务。 我们先来看下Github上有没有相应的库解决这个问题,然后找到了如下三个库: facebookgo/grace - Graceful restart & zero downtime deploy for G

Java后端微服务架构下的API限流策略:Guava RateLimiter

Java后端微服务架构下的API限流策略:Guava RateLimiter 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 在微服务架构中,API限流是保护服务不受过度使用和拒绝服务攻击的重要手段。Guava RateLimiter是Google开源的Java库中的一个组件,提供了简单易用的限流功能。 API限流概述 API限流通过控制请求的速率来防止

【微服务】Ribbon(负载均衡,服务调用)+ OpenFeign(服务发现,远程调用)【详解】

文章目录 1.Ribbon(负载均衡,服务调用)1.1问题引出1.2 Ribbon负载均衡1.3 RestTemplate整合Ribbon1.4 指定Ribbon负载均衡策略1.4.1 配置文件1.4.2 配置类1.4.3 定义Ribbon客户端配置1.4.4 自定义负载均衡策略 2.OpenFeign面向接口的服务调用(服务发现,远程调用)2.1 OpenFeign的使用2.1 .1创建

java后端服务监控与告警:Prometheus与Grafana集成

Java后端服务监控与告警:Prometheus与Grafana集成 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 在现代的微服务架构中,监控和告警是确保服务稳定性的关键组成部分。Prometheus和Grafana是两个强大的工具,它们可以集成在一起,为Java后端服务提供实时监控和可视化告警。 服务监控的重要性 服务监控可以帮助我们实时了解服务的健

OpenStack离线Train版安装系列—3控制节点-Keystone认证服务组件

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

OpenStack离线Train版安装系列—10.控制节点-Heat服务组件

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版