diff --git a/pom.xml b/pom.xml index 24b1c48..6b8a7b9 100755 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ xxpay-shop xxpay4spring-cloud xxpay4dubbo + xxpay4spring-boot diff --git a/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IMchInfoService.java b/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IMchInfoService.java index 8d61b21..d166ca2 100644 --- a/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IMchInfoService.java +++ b/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IMchInfoService.java @@ -9,6 +9,6 @@ import java.util.Map; */ public interface IMchInfoService { - public Map selectMchInfo(String jsonParam); + Map selectMchInfo(String jsonParam); } diff --git a/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IPayChannelService.java b/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IPayChannelService.java index fffc3d0..8fdbc95 100644 --- a/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IPayChannelService.java +++ b/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IPayChannelService.java @@ -9,6 +9,6 @@ import java.util.Map; */ public interface IPayChannelService { - public Map selectPayChannel(String jsonParam); + Map selectPayChannel(String jsonParam); } diff --git a/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IPayOrderService.java b/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IPayOrderService.java index f5734e2..52a378d 100644 --- a/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IPayOrderService.java +++ b/xxpay4dubbo/xxpay4dubbo-api/src/main/java/org/xxpay/dubbo/api/service/IPayOrderService.java @@ -9,20 +9,20 @@ import java.util.Map; */ public interface IPayOrderService { - public Map createPayOrder(String jsonParam); + Map createPayOrder(String jsonParam); - public Map selectPayOrder(String jsonParam); + Map selectPayOrder(String jsonParam); - public Map selectPayOrderByMchIdAndPayOrderId(String jsonParam); + Map selectPayOrderByMchIdAndPayOrderId(String jsonParam); - public Map selectPayOrderByMchIdAndMchOrderNo(String jsonParam); + Map selectPayOrderByMchIdAndMchOrderNo(String jsonParam); - public Map updateStatus4Ing(String jsonParam); + Map updateStatus4Ing(String jsonParam); - public Map updateStatus4Success(String jsonParam); + Map updateStatus4Success(String jsonParam); - public Map updateStatus4Complete(String jsonParam); + Map updateStatus4Complete(String jsonParam); - public Map updateNotify(String jsonParam); + Map updateNotify(String jsonParam); } diff --git a/xxpay4dubbo/xxpay4dubbo-service/pom.xml b/xxpay4dubbo/xxpay4dubbo-service/pom.xml index c747764..b58c56c 100755 --- a/xxpay4dubbo/xxpay4dubbo-service/pom.xml +++ b/xxpay4dubbo/xxpay4dubbo-service/pom.xml @@ -35,6 +35,10 @@ org.springframework.boot spring-boot-starter-activemq + + org.apache.activemq + activemq-pool + org.mybatis.spring.boot mybatis-spring-boot-starter diff --git a/xxpay4dubbo/xxpay4dubbo-service/src/main/java/org/xxpay/dubbo/service/channel/alipay/AlipayConfig.java b/xxpay4dubbo/xxpay4dubbo-service/src/main/java/org/xxpay/dubbo/service/channel/alipay/AlipayConfig.java index 0dbf617..840f86a 100644 --- a/xxpay4dubbo/xxpay4dubbo-service/src/main/java/org/xxpay/dubbo/service/channel/alipay/AlipayConfig.java +++ b/xxpay4dubbo/xxpay4dubbo-service/src/main/java/org/xxpay/dubbo/service/channel/alipay/AlipayConfig.java @@ -2,10 +2,8 @@ package org.xxpay.dubbo.service.channel.alipay; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; import org.springframework.util.Assert; /** diff --git a/xxpay4dubbo/xxpay4dubbo-service/src/main/java/org/xxpay/dubbo/service/impl/NotifyPayServiceImpl.java b/xxpay4dubbo/xxpay4dubbo-service/src/main/java/org/xxpay/dubbo/service/impl/NotifyPayServiceImpl.java index 7ccc905..5470a1a 100644 --- a/xxpay4dubbo/xxpay4dubbo-service/src/main/java/org/xxpay/dubbo/service/impl/NotifyPayServiceImpl.java +++ b/xxpay4dubbo/xxpay4dubbo-service/src/main/java/org/xxpay/dubbo/service/impl/NotifyPayServiceImpl.java @@ -1,7 +1,6 @@ package org.xxpay.dubbo.service.impl; import com.alibaba.dubbo.config.annotation.Service; -import com.alibaba.fastjson.JSONObject; import com.alipay.api.AlipayApiException; import com.alipay.api.internal.util.AlipaySignature; import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; @@ -15,7 +14,10 @@ import org.springframework.util.StringUtils; import org.xxpay.common.constant.PayConstant; import org.xxpay.common.domain.BaseParam; import org.xxpay.common.enumm.RetEnum; -import org.xxpay.common.util.*; +import org.xxpay.common.util.JsonUtil; +import org.xxpay.common.util.MyLog; +import org.xxpay.common.util.ObjectValidUtil; +import org.xxpay.common.util.RpcUtil; import org.xxpay.dal.dao.model.PayChannel; import org.xxpay.dal.dao.model.PayOrder; import org.xxpay.dubbo.api.service.INotifyPayService; diff --git a/xxpay4spring-boot/pom.xml b/xxpay4spring-boot/pom.xml new file mode 100755 index 0000000..48b5ed4 --- /dev/null +++ b/xxpay4spring-boot/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + org.xxpay + xxpay4spring-boot + 1.0.0 + jar + xxpay4spring-boot + xxpay4spring-boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.6.RELEASE + + + + UTF-8 + UTF-8 + 1.8 + 1.5.6.RELEASE + 1.0.0 + + + + + org.xxpay + xxpay-dal + 1.0.0 + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 1.3.0 + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-freemarker + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-configuration-processor + + + org.springframework.boot + spring-boot-starter-activemq + + + org.apache.activemq + activemq-pool + + + + com.github.binarywang + weixin-java-pay + 2.8.0 + + + + com.alipay + sdk + 1.5 + system + ${basedir}/src/main/webapp/WEB-INF/lib/alipay-sdk-java20170818173712.jar + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + ${project.name} + + + + + + \ No newline at end of file diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/XxPayBootAppliaction.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/XxPayBootAppliaction.java new file mode 100755 index 0000000..8cc697b --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/XxPayBootAppliaction.java @@ -0,0 +1,16 @@ +package org.xxpay.boot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +/** + * + */ +@SpringBootApplication +@ComponentScan(basePackages={"org.xxpay"}) +public class XxPayBootAppliaction { + public static void main(String[] args) { + SpringApplication.run(XxPayBootAppliaction.class, args); + } +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/Notify4AliPayController.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/Notify4AliPayController.java new file mode 100644 index 0000000..9ac6478 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/Notify4AliPayController.java @@ -0,0 +1,75 @@ +package org.xxpay.boot.ctrl; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.xxpay.boot.web.NotifyPayService; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.util.MyLog; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * @Description: 接收处理支付宝通知 + * @author dingzhiwei jmdhappy@126.com + * @date 2017-07-05 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +@RestController +public class Notify4AliPayController { + + private static final MyLog _log = MyLog.getLog(Notify4AliPayController.class); + + @Autowired + private NotifyPayService notifyPayService; + + /** + * 支付宝移动支付后台通知响应 + * @param request + * @return + * @throws ServletException + * @throws IOException + */ + @RequestMapping(value = "/notify/pay/aliPayNotifyRes.htm") + @ResponseBody + public String aliPayNotifyRes(HttpServletRequest request) throws ServletException, IOException { + _log.info("====== 开始接收支付宝支付回调通知 ======"); + String notifyRes = doAliPayRes(request); + _log.info("响应给支付宝:{}", notifyRes); + _log.info("====== 完成接收支付宝支付回调通知 ======"); + return notifyRes; + } + + public String doAliPayRes(HttpServletRequest request) throws ServletException, IOException { + String logPrefix = "【支付宝支付回调通知】"; + //获取支付宝POST过来反馈信息 + Map params = new HashMap(); + Map requestParams = request.getParameterMap(); + for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { + String name = (String) iter.next(); + String[] values = (String[]) requestParams.get(name); + String valueStr = ""; + for (int i = 0; i < values.length; i++) { + valueStr = (i == values.length - 1) ? valueStr + values[i] + : valueStr + values[i] + ","; + } + //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化 + //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk"); + params.put(name, valueStr); + } + _log.info("{}通知请求数据:reqStr={}", logPrefix, params); + if(params.isEmpty()) { + _log.error("{}请求参数为空", logPrefix); + return PayConstant.RETURN_ALIPAY_VALUE_FAIL; + } + return notifyPayService.doAliPayNotify(params); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/Notify4WxPayController.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/Notify4WxPayController.java new file mode 100644 index 0000000..36707ff --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/Notify4WxPayController.java @@ -0,0 +1,54 @@ +package org.xxpay.boot.ctrl; + +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.xxpay.boot.web.NotifyPayService; +import org.xxpay.common.util.MyLog; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * @Description: 接收处理微信通知 + * @author dingzhiwei jmdhappy@126.com + * @date 2017-07-05 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +@RestController +public class Notify4WxPayController { + + private static final MyLog _log = MyLog.getLog(Notify4WxPayController.class); + + @Autowired + private NotifyPayService notifyPayService; + + /** + * 微信支付(统一下单接口)后台通知响应 + * @param request + * @return + * @throws ServletException + * @throws IOException + */ + @RequestMapping("/notify/pay/wxPayNotifyRes.htm") + @ResponseBody + public String wxPayNotifyRes(HttpServletRequest request) throws ServletException, IOException { + _log.info("====== 开始接收微信支付回调通知 ======"); + String notifyRes = doWxPayRes(request); + _log.info("响应给微信:{}", notifyRes); + _log.info("====== 完成接收微信支付回调通知 ======"); + return notifyRes; + } + + public String doWxPayRes(HttpServletRequest request) throws ServletException, IOException { + String logPrefix = "【微信支付回调通知】"; + String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding()); + _log.info("{}通知请求数据:reqStr={}", logPrefix, xmlResult); + return notifyPayService.doWxPayNotify(xmlResult); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/PayOrderController.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/PayOrderController.java new file mode 100644 index 0000000..877c0d1 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/PayOrderController.java @@ -0,0 +1,268 @@ +package org.xxpay.boot.ctrl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.xxpay.boot.web.MchInfoService; +import org.xxpay.boot.web.PayChannelService; +import org.xxpay.boot.web.PayOrderService; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.util.MyLog; +import org.xxpay.common.util.MySeq; +import org.xxpay.common.util.XXPayUtil; + +/** + * @Description: 支付订单,包括:统一下单,订单查询,补单等接口 + * @author dingzhiwei jmdhappy@126.com + * @date 2017-07-05 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +@RestController +public class PayOrderController { + + private final MyLog _log = MyLog.getLog(PayOrderController.class); + + @Autowired + private PayOrderService payOrderService; + + @Autowired + private PayChannelService payChannelService; + + @Autowired + private MchInfoService mchInfoService; + + /** + * 统一下单接口: + * 1)先验证接口参数以及签名信息 + * 2)验证通过创建支付订单 + * 3)根据商户选择渠道,调用支付服务进行下单 + * 4)返回下单数据 + * @param params + * @return + */ + @RequestMapping(value = "/api/pay/create_order") + public String payOrder(@RequestParam String params) { + _log.info("###### 开始接收商户统一下单请求 ######"); + String logPrefix = "【商户统一下单】"; + try { + JSONObject po = JSONObject.parseObject(params); + JSONObject payContext = new JSONObject(); + JSONObject payOrder = null; + // 验证参数有效性 + Object object = validateParams(po, payContext); + if (object instanceof String) { + _log.info("{}参数校验不通过:{}", logPrefix, object); + return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, object.toString(), null, null)); + } + if (object instanceof JSONObject) payOrder = (JSONObject) object; + if(payOrder == null) return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "支付中心下单失败", null, null)); + int result = payOrderService.createPayOrder(payOrder); + _log.info("{}创建支付订单,结果:{}", logPrefix, result); + if(result != 1) { + return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "创建支付订单失败", null, null)); + } + String channelId = payOrder.getString("channelId"); + switch (channelId) { + case PayConstant.PAY_CHANNEL_WX_APP : + return payOrderService.doWxPayReq(PayConstant.WxConstant.TRADE_TYPE_APP, payOrder, payContext.getString("resKey")); + case PayConstant.PAY_CHANNEL_WX_JSAPI : + return payOrderService.doWxPayReq(PayConstant.WxConstant.TRADE_TYPE_JSPAI, payOrder, payContext.getString("resKey")); + case PayConstant.PAY_CHANNEL_WX_NATIVE : + return payOrderService.doWxPayReq(PayConstant.WxConstant.TRADE_TYPE_NATIVE, payOrder, payContext.getString("resKey")); + case PayConstant.PAY_CHANNEL_WX_MWEB : + return payOrderService.doWxPayReq(PayConstant.WxConstant.TRADE_TYPE_MWEB, payOrder, payContext.getString("resKey")); + case PayConstant.PAY_CHANNEL_ALIPAY_MOBILE : + return payOrderService.doAliPayReq(channelId, payOrder, payContext.getString("resKey")); + case PayConstant.PAY_CHANNEL_ALIPAY_PC : + return payOrderService.doAliPayReq(channelId, payOrder, payContext.getString("resKey")); + case PayConstant.PAY_CHANNEL_ALIPAY_WAP : + return payOrderService.doAliPayReq(channelId, payOrder, payContext.getString("resKey")); + case PayConstant.PAY_CHANNEL_ALIPAY_QR : + return payOrderService.doAliPayReq(channelId, payOrder, payContext.getString("resKey")); + default: + return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "不支持的支付渠道类型[channelId="+channelId+"]", null, null)); + } + }catch (Exception e) { + _log.error(e, ""); + return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "支付中心系统异常", null, null)); + } + } + + /** + * 验证创建订单请求参数,参数通过返回JSONObject对象,否则返回错误文本信息 + * @param params + * @return + */ + private Object validateParams(JSONObject params, JSONObject payContext) { + // 验证请求参数,参数有问题返回错误提示 + String errorMessage; + // 支付参数 + String mchId = params.getString("mchId"); // 商户ID + String mchOrderNo = params.getString("mchOrderNo"); // 商户订单号 + String channelId = params.getString("channelId"); // 渠道ID + String amount = params.getString("amount"); // 支付金额(单位分) + String currency = params.getString("currency"); // 币种 + String clientIp = params.getString("clientIp"); // 客户端IP + String device = params.getString("device"); // 设备 + String extra = params.getString("extra"); // 特定渠道发起时额外参数 + String param1 = params.getString("param1"); // 扩展参数1 + String param2 = params.getString("param2"); // 扩展参数2 + String notifyUrl = params.getString("notifyUrl"); // 支付结果回调URL + String sign = params.getString("sign"); // 签名 + String subject = params.getString("subject"); // 商品主题 + String body = params.getString("body"); // 商品描述信息 + // 验证请求参数有效性(必选项) + if(StringUtils.isBlank(mchId)) { + errorMessage = "request params[mchId] error."; + return errorMessage; + } + if(StringUtils.isBlank(mchOrderNo)) { + errorMessage = "request params[mchOrderNo] error."; + return errorMessage; + } + if(StringUtils.isBlank(channelId)) { + errorMessage = "request params[channelId] error."; + return errorMessage; + } + if(!NumberUtils.isNumber(amount)) { + errorMessage = "request params[amount] error."; + return errorMessage; + } + if(StringUtils.isBlank(currency)) { + errorMessage = "request params[currency] error."; + return errorMessage; + } + if(StringUtils.isBlank(notifyUrl)) { + errorMessage = "request params[notifyUrl] error."; + return errorMessage; + } + if(StringUtils.isBlank(subject)) { + errorMessage = "request params[subject] error."; + return errorMessage; + } + if(StringUtils.isBlank(body)) { + errorMessage = "request params[body] error."; + return errorMessage; + } + // 根据不同渠道,判断extra参数 + if(PayConstant.PAY_CHANNEL_WX_JSAPI.equalsIgnoreCase(channelId)) { + if(StringUtils.isEmpty(extra)) { + errorMessage = "request params[extra] error."; + return errorMessage; + } + JSONObject extraObject = JSON.parseObject(extra); + String openId = extraObject.getString("openId"); + if(StringUtils.isBlank(openId)) { + errorMessage = "request params[extra.openId] error."; + return errorMessage; + } + }else if(PayConstant.PAY_CHANNEL_WX_NATIVE.equalsIgnoreCase(channelId)) { + if(StringUtils.isEmpty(extra)) { + errorMessage = "request params[extra] error."; + return errorMessage; + } + JSONObject extraObject = JSON.parseObject(extra); + String productId = extraObject.getString("productId"); + if(StringUtils.isBlank(productId)) { + errorMessage = "request params[extra.productId] error."; + return errorMessage; + } + }else if(PayConstant.PAY_CHANNEL_WX_MWEB.equalsIgnoreCase(channelId)) { + if(StringUtils.isEmpty(extra)) { + errorMessage = "request params[extra] error."; + return errorMessage; + } + JSONObject extraObject = JSON.parseObject(extra); + String productId = extraObject.getString("sceneInfo"); + if(StringUtils.isBlank(productId)) { + errorMessage = "request params[extra.sceneInfo] error."; + return errorMessage; + } + if(StringUtils.isBlank(clientIp)) { + errorMessage = "request params[clientIp] error."; + return errorMessage; + } + } + + // 签名信息 + if (StringUtils.isEmpty(sign)) { + errorMessage = "request params[sign] error."; + return errorMessage; + } + + // 查询商户信息 + JSONObject mchInfo = mchInfoService.getByMchId(mchId); + if(mchInfo == null) { + errorMessage = "Can't found mchInfo[mchId="+mchId+"] record in db."; + return errorMessage; + } + if(mchInfo.getByte("state") != 1) { + errorMessage = "mchInfo not available [mchId="+mchId+"] record in db."; + return errorMessage; + } + + String reqKey = mchInfo.getString("reqKey"); + if (StringUtils.isBlank(reqKey)) { + errorMessage = "reqKey is null[mchId="+mchId+"] record in db."; + return errorMessage; + } + payContext.put("resKey", mchInfo.getString("resKey")); + + // 查询商户对应的支付渠道 + JSONObject payChannel = payChannelService.getByMchIdAndChannelId(mchId, channelId); + if(payChannel == null) { + errorMessage = "Can't found payChannel[channelId="+channelId+",mchId="+mchId+"] record in db."; + return errorMessage; + } + if(payChannel.getByte("state") != 1) { + errorMessage = "channel not available [channelId="+channelId+",mchId="+mchId+"]"; + return errorMessage; + } + + // 验证签名数据 + boolean verifyFlag = XXPayUtil.verifyPaySign(params, reqKey); + if(!verifyFlag) { + errorMessage = "Verify XX pay sign failed."; + return errorMessage; + } + // 验证参数通过,返回JSONObject对象 + JSONObject payOrder = new JSONObject(); + payOrder.put("payOrderId", MySeq.getPay()); + payOrder.put("mchId", mchId); + payOrder.put("mchOrderNo", mchOrderNo); + payOrder.put("channelId", channelId); + payOrder.put("amount", Long.parseLong(amount)); + payOrder.put("currency", currency); + payOrder.put("clientIp", clientIp); + payOrder.put("device", device); + payOrder.put("subject", subject); + payOrder.put("body", body); + payOrder.put("extra", extra); + payOrder.put("channelMchId", payChannel.getString("channelMchId")); + payOrder.put("param1", param1); + payOrder.put("param2", param2); + payOrder.put("notifyUrl", notifyUrl); + return payOrder; + } + + String getJsonParam(String[] names, Object[] values) { + JSONObject jsonParam = new JSONObject(); + for (int i = 0; i < names.length; i++) { + jsonParam.put(names[i], values[i]); + } + return jsonParam.toJSONString(); + } + + String getJsonParam(String name, Object value) { + JSONObject jsonParam = new JSONObject(); + jsonParam.put(name, value); + return jsonParam.toJSONString(); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/QueryPayOrderController.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/QueryPayOrderController.java new file mode 100644 index 0000000..3ac2424 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/ctrl/QueryPayOrderController.java @@ -0,0 +1,135 @@ +package org.xxpay.boot.ctrl; + +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.xxpay.boot.web.MchInfoService; +import org.xxpay.boot.web.PayOrderService; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.util.MyLog; +import org.xxpay.common.util.XXPayUtil; + +import java.util.Map; + +/** + * @Description: 支付订单查询 + * @author dingzhiwei jmdhappy@126.com + * @date 2017-08-31 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +@RestController +public class QueryPayOrderController { + + private final MyLog _log = MyLog.getLog(QueryPayOrderController.class); + + @Autowired + private PayOrderService payOrderService; + + @Autowired + private MchInfoService mchInfoService; + + /** + * 查询支付订单接口: + * 1)先验证接口参数以及签名信息 + * 2)根据参数查询订单 + * 3)返回订单数据 + * @param params + * @return + */ + @RequestMapping(value = "/api/pay/query_order") + public String queryPayOrder(@RequestParam String params) { + _log.info("###### 开始接收商户查询支付订单请求 ######"); + String logPrefix = "【商户支付订单查询】"; + try { + JSONObject po = JSONObject.parseObject(params); + JSONObject payContext = new JSONObject(); + // 验证参数有效性 + String errorMessage = validateParams(po, payContext); + if (!"success".equalsIgnoreCase(errorMessage)) { + _log.warn(errorMessage); + return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, errorMessage, null, null)); + } + _log.debug("请求参数及签名校验通过"); + String mchId = po.getString("mchId"); // 商户ID + String mchOrderNo = po.getString("mchOrderNo"); // 商户订单号 + String payOrderId = po.getString("payOrderId"); // 支付订单号 + String executeNotify = po.getString("executeNotify"); // 是否执行回调 + JSONObject payOrder = payOrderService.queryPayOrder(mchId, payOrderId, mchOrderNo, executeNotify); + _log.info("{}查询支付订单,结果:{}", logPrefix, payOrder); + if (payOrder == null) { + return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "支付订单不存在", null, null)); + } + Map map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null); + map.put("result", payOrder); + _log.info("###### 商户查询订单处理完成 ######"); + return XXPayUtil.makeRetData(map, payContext.getString("resKey")); + }catch (Exception e) { + _log.error(e, ""); + return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "支付中心系统异常", null, null)); + } + } + + /** + * 验证创建订单请求参数,参数通过返回JSONObject对象,否则返回错误文本信息 + * @param params + * @return + */ + private String validateParams(JSONObject params, JSONObject payContext) { + // 验证请求参数,参数有问题返回错误提示 + String errorMessage; + // 支付参数 + String mchId = params.getString("mchId"); // 商户ID + String mchOrderNo = params.getString("mchOrderNo"); // 商户订单号 + String payOrderId = params.getString("payOrderId"); // 支付订单号 + + String sign = params.getString("sign"); // 签名 + + // 验证请求参数有效性(必选项) + if(StringUtils.isBlank(mchId)) { + errorMessage = "request params[mchId] error."; + return errorMessage; + } + if(StringUtils.isBlank(mchOrderNo) && StringUtils.isBlank(payOrderId)) { + errorMessage = "request params[mchOrderNo or payOrderId] error."; + return errorMessage; + } + + // 签名信息 + if (StringUtils.isEmpty(sign)) { + errorMessage = "request params[sign] error."; + return errorMessage; + } + + // 查询商户信息 + JSONObject mchInfo = mchInfoService.getByMchId(mchId); + if(mchInfo == null) { + errorMessage = "Can't found mchInfo[mchId="+mchId+"] record in db."; + return errorMessage; + } + if(mchInfo.getByte("state") != 1) { + errorMessage = "mchInfo not available [mchId="+mchId+"] record in db."; + return errorMessage; + } + + String reqKey = mchInfo.getString("reqKey"); + if (StringUtils.isBlank(reqKey)) { + errorMessage = "reqKey is null[mchId="+mchId+"] record in db."; + return errorMessage; + } + payContext.put("resKey", mchInfo.getString("resKey")); + + // 验证签名数据 + boolean verifyFlag = XXPayUtil.verifyPaySign(params, reqKey); + if(!verifyFlag) { + errorMessage = "Verify XX pay sign failed."; + return errorMessage; + } + + return "success"; + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/BaseService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/BaseService.java new file mode 100644 index 0000000..89b205e --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/BaseService.java @@ -0,0 +1,119 @@ +package org.xxpay.boot.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.dal.dao.mapper.MchInfoMapper; +import org.xxpay.dal.dao.mapper.PayChannelMapper; +import org.xxpay.dal.dao.mapper.PayOrderMapper; +import org.xxpay.dal.dao.model.*; + +import java.util.List; + +/** + * @author: dingzhiwei + * @date: 17/9/9 + * @description: + */ +@Service +public class BaseService { + + @Autowired + private PayOrderMapper payOrderMapper; + + @Autowired + private MchInfoMapper mchInfoMapper; + + @Autowired + private PayChannelMapper payChannelMapper; + + + public MchInfo baseSelectMchInfo(String mchId) { + return mchInfoMapper.selectByPrimaryKey(mchId); + } + + public PayChannel baseSelectPayChannel(String mchId, String channelId) { + PayChannelExample example = new PayChannelExample(); + PayChannelExample.Criteria criteria = example.createCriteria(); + criteria.andChannelIdEqualTo(channelId); + criteria.andMchIdEqualTo(mchId); + List payChannelList = payChannelMapper.selectByExample(example); + if(CollectionUtils.isEmpty(payChannelList)) return null; + return payChannelList.get(0); + } + + public int baseCreatePayOrder(PayOrder payOrder) { + return payOrderMapper.insertSelective(payOrder); + } + + public PayOrder baseSelectPayOrder(String payOrderId) { + return payOrderMapper.selectByPrimaryKey(payOrderId); + } + + public PayOrder baseSelectPayOrderByMchIdAndPayOrderId(String mchId, String payOrderId) { + PayOrderExample example = new PayOrderExample(); + PayOrderExample.Criteria criteria = example.createCriteria(); + criteria.andMchIdEqualTo(mchId); + criteria.andPayOrderIdEqualTo(payOrderId); + List payOrderList = payOrderMapper.selectByExample(example); + return CollectionUtils.isEmpty(payOrderList) ? null : payOrderList.get(0); + } + + public PayOrder baseSelectPayOrderByMchIdAndMchOrderNo(String mchId, String mchOrderNo) { + PayOrderExample example = new PayOrderExample(); + PayOrderExample.Criteria criteria = example.createCriteria(); + criteria.andMchIdEqualTo(mchId); + criteria.andMchOrderNoEqualTo(mchOrderNo); + List payOrderList = payOrderMapper.selectByExample(example); + return CollectionUtils.isEmpty(payOrderList) ? null : payOrderList.get(0); + } + + public int baseUpdateStatus4Ing(String payOrderId, String channelOrderNo) { + PayOrder payOrder = new PayOrder(); + payOrder.setStatus(PayConstant.PAY_STATUS_PAYING); + if(channelOrderNo != null) payOrder.setChannelOrderNo(channelOrderNo); + payOrder.setPaySuccTime(System.currentTimeMillis()); + PayOrderExample example = new PayOrderExample(); + PayOrderExample.Criteria criteria = example.createCriteria(); + criteria.andPayOrderIdEqualTo(payOrderId); + criteria.andStatusEqualTo(PayConstant.PAY_STATUS_INIT); + return payOrderMapper.updateByExampleSelective(payOrder, example); + } + + public int baseUpdateStatus4Success(String payOrderId) { + PayOrder payOrder = new PayOrder(); + payOrder.setPayOrderId(payOrderId); + payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS); + payOrder.setPaySuccTime(System.currentTimeMillis()); + PayOrderExample example = new PayOrderExample(); + PayOrderExample.Criteria criteria = example.createCriteria(); + criteria.andPayOrderIdEqualTo(payOrderId); + criteria.andStatusEqualTo(PayConstant.PAY_STATUS_PAYING); + return payOrderMapper.updateByExampleSelective(payOrder, example); + } + + public int baseUpdateStatus4Complete(String payOrderId) { + PayOrder payOrder = new PayOrder(); + payOrder.setPayOrderId(payOrderId); + payOrder.setStatus(PayConstant.PAY_STATUS_COMPLETE); + PayOrderExample example = new PayOrderExample(); + PayOrderExample.Criteria criteria = example.createCriteria(); + criteria.andPayOrderIdEqualTo(payOrderId); + criteria.andStatusEqualTo(PayConstant.PAY_STATUS_SUCCESS); + return payOrderMapper.updateByExampleSelective(payOrder, example); + } + + public int baseUpdateNotify(String payOrderId, byte count) { + PayOrder newPayOrder = new PayOrder(); + newPayOrder.setNotifyCount(count); + newPayOrder.setLastNotifyTime(System.currentTimeMillis()); + newPayOrder.setPayOrderId(payOrderId); + return payOrderMapper.updateByPrimaryKeySelective(newPayOrder); + } + + public int baseUpdateNotify(PayOrder payOrder) { + return payOrderMapper.updateByPrimaryKeySelective(payOrder); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IMchInfoService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IMchInfoService.java new file mode 100644 index 0000000..80ab116 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IMchInfoService.java @@ -0,0 +1,14 @@ +package org.xxpay.boot.service; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/8 + * @description: + */ +public interface IMchInfoService { + + Map selectMchInfo(String jsonParam); + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/INotifyPayService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/INotifyPayService.java new file mode 100644 index 0000000..01fbd1d --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/INotifyPayService.java @@ -0,0 +1,17 @@ +package org.xxpay.boot.service; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/10 + * @description: + */ +public interface INotifyPayService { + + Map doAliPayNotify(String jsonParam); + + Map doWxPayNotify(String jsonParam); + + Map sendBizPayNotify(String jsonParam); +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannel4AliService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannel4AliService.java new file mode 100644 index 0000000..535bb0b --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannel4AliService.java @@ -0,0 +1,20 @@ +package org.xxpay.boot.service; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/10 + * @description: + */ +public interface IPayChannel4AliService { + + Map doAliPayWapReq(String jsonParam); + + Map doAliPayPcReq(String jsonParam); + + Map doAliPayMobileReq(String jsonParam); + + Map doAliPayQrReq(String jsonParam); + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannel4WxService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannel4WxService.java new file mode 100644 index 0000000..c007803 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannel4WxService.java @@ -0,0 +1,14 @@ +package org.xxpay.boot.service; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/9 + * @description: + */ +public interface IPayChannel4WxService { + + Map doWxPayReq(String jsonParam); + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannelService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannelService.java new file mode 100644 index 0000000..3776c0e --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayChannelService.java @@ -0,0 +1,14 @@ +package org.xxpay.boot.service; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/8 + * @description: + */ +public interface IPayChannelService { + + Map selectPayChannel(String jsonParam); + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayOrderService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayOrderService.java new file mode 100644 index 0000000..c2a9738 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/IPayOrderService.java @@ -0,0 +1,28 @@ +package org.xxpay.boot.service; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/8 + * @description: + */ +public interface IPayOrderService { + + Map createPayOrder(String jsonParam); + + Map selectPayOrder(String jsonParam); + + Map selectPayOrderByMchIdAndPayOrderId(String jsonParam); + + Map selectPayOrderByMchIdAndMchOrderNo(String jsonParam); + + Map updateStatus4Ing(String jsonParam); + + Map updateStatus4Success(String jsonParam); + + Map updateStatus4Complete(String jsonParam); + + Map updateNotify(String jsonParam); + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/Notify4BasePay.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/Notify4BasePay.java new file mode 100644 index 0000000..f215e2d --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/Notify4BasePay.java @@ -0,0 +1,120 @@ +package org.xxpay.boot.service; + +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.util.MyLog; +import org.xxpay.common.util.PayDigestUtil; +import org.xxpay.common.util.XXPayUtil; +import org.xxpay.dal.dao.model.MchInfo; +import org.xxpay.dal.dao.model.PayOrder; +import org.xxpay.boot.service.mq.Mq4PayNotify; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; + +/** + * @Description: 支付通知处理基类 + * @author dingzhiwei jmdhappy@126.com + * @date 2017-07-05 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +@Component +public class Notify4BasePay extends BaseService { + + private static final MyLog _log = MyLog.getLog(Notify4BasePay.class); + + @Autowired + private Mq4PayNotify mq4PayNotify; + + /** + * 创建响应URL + * @param payOrder + * @param backType 1:前台页面;2:后台接口 + * @return + */ + public String createNotifyUrl(PayOrder payOrder, String backType) { + String mchId = payOrder.getMchId(); + MchInfo mchInfo = super.baseSelectMchInfo(mchId); + String resKey = mchInfo.getResKey(); + Map paramMap = new HashMap<>(); + paramMap.put("payOrderId", payOrder.getPayOrderId() == null ? "" : payOrder.getPayOrderId()); // 支付订单号 + paramMap.put("mchId", payOrder.getMchId() == null ? "" : payOrder.getMchId()); // 商户ID + paramMap.put("mchOrderNo", payOrder.getMchOrderNo() == null ? "" : payOrder.getMchOrderNo()); // 商户订单号 + paramMap.put("channelId", payOrder.getChannelId() == null ? "" : payOrder.getChannelId()); // 渠道ID + paramMap.put("amount", payOrder.getAmount() == null ? "" : payOrder.getAmount()); // 支付金额 + paramMap.put("currency", payOrder.getCurrency() == null ? "" : payOrder.getCurrency()); // 货币类型 + paramMap.put("status", payOrder.getStatus() == null ? "" : payOrder.getStatus()); // 支付状态 + paramMap.put("clientIp", payOrder.getClientIp()==null ? "" : payOrder.getClientIp()); // 客户端IP + paramMap.put("device", payOrder.getDevice()==null ? "" : payOrder.getDevice()); // 设备 + paramMap.put("subject", payOrder.getSubject()==null ? "" : payOrder.getSubject()); // 商品标题 + paramMap.put("channelOrderNo", payOrder.getChannelOrderNo()==null ? "" : payOrder.getChannelOrderNo()); // 渠道订单号 + paramMap.put("param1", payOrder.getParam1()==null ? "" : payOrder.getParam1()); // 扩展参数1 + paramMap.put("param2", payOrder.getParam2()==null ? "" : payOrder.getParam2()); // 扩展参数2 + paramMap.put("paySuccTime", payOrder.getPaySuccTime()==null ? "" : payOrder.getPaySuccTime()); // 支付成功时间 + paramMap.put("backType", backType==null ? "" : backType); + // 先对原文签名 + String reqSign = PayDigestUtil.getSign(paramMap, resKey); + paramMap.put("sign", reqSign); // 签名 + // 签名后再对有中文参数编码 + try { + paramMap.put("device", URLEncoder.encode(payOrder.getDevice()==null ? "" : payOrder.getDevice(), PayConstant.RESP_UTF8)); + paramMap.put("subject", URLEncoder.encode(payOrder.getSubject()==null ? "" : payOrder.getSubject(), PayConstant.RESP_UTF8)); + paramMap.put("param1", URLEncoder.encode(payOrder.getParam1()==null ? "" : payOrder.getParam1(), PayConstant.RESP_UTF8)); + paramMap.put("param2", URLEncoder.encode(payOrder.getParam2()==null ? "" : payOrder.getParam2(), PayConstant.RESP_UTF8)); + }catch (UnsupportedEncodingException e) { + _log.error("URL Encode exception.", e); + return null; + } + String param = XXPayUtil.genUrlParams(paramMap); + StringBuffer sb = new StringBuffer(); + sb.append(payOrder.getNotifyUrl()).append("?").append(param); + return sb.toString(); + } + + /** + * 处理支付结果前台页面跳转 + */ + public boolean doPage(PayOrder payOrder) { + String redirectUrl = createNotifyUrl(payOrder, "1"); + _log.info("redirect to respUrl:"+redirectUrl); + // 前台跳转业务系统 + /*try { + response.sendRedirect(redirectUrl); + } catch (IOException e) { + _log.error("XxPay sendRedirect exception. respUrl="+redirectUrl, e); + return false; + }*/ + return true; + } + + /** + * 处理支付结果后台服务器通知 + */ + public void doNotify(PayOrder payOrder) { + _log.info(">>>>>> PAY开始回调通知业务系统 <<<<<<"); + // 发起后台通知业务系统 + JSONObject object = createNotifyInfo(payOrder); + try { + mq4PayNotify.send(object.toJSONString()); + } catch (Exception e) { + _log.error("payOrderId={},sendMessage error.", payOrder != null ? payOrder.getPayOrderId() : "", e); + } + _log.info(">>>>>> PAY回调通知业务系统完成 <<<<<<"); + } + + public JSONObject createNotifyInfo(PayOrder payOrder) { + JSONObject object = new JSONObject(); + object.put("method", "GET"); + object.put("url", createNotifyUrl(payOrder, "2")); + object.put("orderId", payOrder.getPayOrderId()); + object.put("count", payOrder.getNotifyCount()); + object.put("createTime", System.currentTimeMillis()); + return object; + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/alipay/AlipayConfig.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/alipay/AlipayConfig.java new file mode 100644 index 0000000..e63d27b --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/alipay/AlipayConfig.java @@ -0,0 +1,115 @@ +package org.xxpay.boot.service.channel.alipay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +/** + * @author: dingzhiwei + * @date: 17/8/21 + * @description: + */ +@Component +@ConfigurationProperties(prefix="config.ali") +public class AlipayConfig { + + // 商户appid + private String app_id; + // 私钥 pkcs8格式的 + private String rsa_private_key; + // 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 + + private String notify_url; + // 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址 + + private String return_url; + // 请求网关地址 + private String url = "https://openapi.alipay.com/gateway.do"; + + // 编码 + public static String CHARSET = "UTF-8"; + // 返回格式 + public static String FORMAT = "json"; + // 支付宝公钥 + public String alipay_public_key; + // RSA2 + public static String SIGNTYPE = "RSA2"; + + // 是否沙箱环境,1:沙箱,0:正式环境 + private Short isSandbox = 0; + + /** + * 初始化支付宝配置 + * @param configParam + * @return + */ + public AlipayConfig init(String configParam) { + Assert.notNull(configParam, "init alipay config error"); + JSONObject paramObj = JSON.parseObject(configParam); + this.setApp_id(paramObj.getString("appid")); + this.setRsa_private_key(paramObj.getString("private_key")); + this.setAlipay_public_key(paramObj.getString("alipay_public_key")); + this.setIsSandbox(paramObj.getShortValue("isSandbox")); + if(this.getIsSandbox() == 1) this.setUrl("https://openapi.alipaydev.com/gateway.do"); + return this; + } + + public String getApp_id() { + return app_id; + } + + public void setApp_id(String app_id) { + this.app_id = app_id; + } + + public String getRsa_private_key() { + return rsa_private_key; + } + + public void setRsa_private_key(String rsa_private_key) { + this.rsa_private_key = rsa_private_key; + } + + public String getNotify_url() { + return notify_url; + } + + public void setNotify_url(String notify_url) { + this.notify_url = notify_url; + } + + public String getReturn_url() { + return return_url; + } + + public void setReturn_url(String return_url) { + this.return_url = return_url; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Short getIsSandbox() { + return isSandbox; + } + + public void setIsSandbox(Short isSandbox) { + this.isSandbox = isSandbox; + } + + public String getAlipay_public_key() { + return alipay_public_key; + } + + public void setAlipay_public_key(String alipay_public_key) { + this.alipay_public_key = alipay_public_key; + } +} + diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/wechat/WxPayProperties.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/wechat/WxPayProperties.java new file mode 100755 index 0000000..56d3b42 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/wechat/WxPayProperties.java @@ -0,0 +1,35 @@ +package org.xxpay.boot.service.channel.wechat; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * User: rizenguo + * Date: 2014/10/29 + * Time: 14:40 + * 这里放置各种配置数据 + */ +@Component +@ConfigurationProperties(prefix="config.wx") +public class WxPayProperties { + + private String certRootPath; + + private String notifyUrl; + + public String getCertRootPath() { + return certRootPath; + } + + public void setCertRootPath(String certRootPath) { + this.certRootPath = certRootPath; + } + + public String getNotifyUrl() { + return notifyUrl; + } + + public void setNotifyUrl(String notifyUrl) { + this.notifyUrl = notifyUrl; + } +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/wechat/WxPayUtil.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/wechat/WxPayUtil.java new file mode 100644 index 0000000..ae598e3 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/channel/wechat/WxPayUtil.java @@ -0,0 +1,50 @@ +package org.xxpay.boot.service.channel.wechat; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.config.WxPayConfig; + +import java.io.File; + +/** + * @author: dingzhiwei + * @date: 17/8/25 + * @description: + */ +public class WxPayUtil { + + /** + * 获取微信支付配置 + * @param configParam + * @param tradeType + * @param certRootPath + * @param notifyUrl + * @return + */ + public static WxPayConfig getWxPayConfig(String configParam, String tradeType, String certRootPath, String notifyUrl) { + WxPayConfig wxPayConfig = new WxPayConfig(); + JSONObject paramObj = JSON.parseObject(configParam); + wxPayConfig.setMchId(paramObj.getString("mchId")); + wxPayConfig.setAppId(paramObj.getString("appId")); + wxPayConfig.setKeyPath(certRootPath + File.separator + paramObj.getString("certLocalPath")); + wxPayConfig.setMchKey(paramObj.getString("key")); + wxPayConfig.setNotifyUrl(notifyUrl); + wxPayConfig.setTradeType(tradeType); + return wxPayConfig; + } + + /** + * 获取微信支付配置 + * @param configParam + * @return + */ + public static WxPayConfig getWxPayConfig(String configParam) { + WxPayConfig wxPayConfig = new WxPayConfig(); + JSONObject paramObj = JSON.parseObject(configParam); + wxPayConfig.setMchId(paramObj.getString("mchId")); + wxPayConfig.setAppId(paramObj.getString("appId")); + wxPayConfig.setMchKey(paramObj.getString("key")); + return wxPayConfig; + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/MchInfoServiceImpl.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/MchInfoServiceImpl.java new file mode 100644 index 0000000..4d79efa --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/MchInfoServiceImpl.java @@ -0,0 +1,44 @@ +package org.xxpay.boot.service.impl; + +import org.springframework.stereotype.Service; +import org.xxpay.boot.service.BaseService; +import org.xxpay.boot.service.IMchInfoService; +import org.xxpay.common.domain.BaseParam; +import org.xxpay.common.enumm.RetEnum; +import org.xxpay.common.util.JsonUtil; +import org.xxpay.common.util.MyLog; +import org.xxpay.common.util.ObjectValidUtil; +import org.xxpay.common.util.RpcUtil; +import org.xxpay.dal.dao.model.MchInfo; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/8 + * @description: + */ +@Service +public class MchInfoServiceImpl extends BaseService implements IMchInfoService { + + private static final MyLog _log = MyLog.getLog(MchInfoServiceImpl.class); + + @Override + public Map selectMchInfo(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("查询商户信息失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String mchId = baseParam.isNullValue("mchId") ? null : bizParamMap.get("mchId").toString(); + if (ObjectValidUtil.isInvalid(mchId)) { + _log.warn("查询商户信息失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + MchInfo mchInfo = super.baseSelectMchInfo(mchId); + if(mchInfo == null) return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_DATA_NOT_EXISTS); + String jsonResult = JsonUtil.object2Json(mchInfo); + return RpcUtil.createBizResult(baseParam, jsonResult); + } +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/NotifyPayServiceImpl.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/NotifyPayServiceImpl.java new file mode 100644 index 0000000..3003f73 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/NotifyPayServiceImpl.java @@ -0,0 +1,294 @@ +package org.xxpay.boot.service.impl; + +import com.alipay.api.AlipayApiException; +import com.alipay.api.internal.util.AlipaySignature; +import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import org.xxpay.boot.service.INotifyPayService; +import org.xxpay.boot.service.Notify4BasePay; +import org.xxpay.boot.service.channel.alipay.AlipayConfig; +import org.xxpay.boot.service.channel.wechat.WxPayUtil; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.domain.BaseParam; +import org.xxpay.common.enumm.RetEnum; +import org.xxpay.common.util.JsonUtil; +import org.xxpay.common.util.MyLog; +import org.xxpay.common.util.ObjectValidUtil; +import org.xxpay.common.util.RpcUtil; +import org.xxpay.dal.dao.model.PayChannel; +import org.xxpay.dal.dao.model.PayOrder; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/10 + * @description: + */ +@Service +public class NotifyPayServiceImpl extends Notify4BasePay implements INotifyPayService { + + private static final MyLog _log = MyLog.getLog(NotifyPayServiceImpl.class); + + @Autowired + private AlipayConfig alipayConfig; + + @Override + public Map doAliPayNotify(String jsonParam) { + String logPrefix = "【处理支付宝支付回调】"; + _log.info("====== 开始处理支付宝支付回调通知 ======"); + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("处理支付宝支付回调失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + Map params = baseParam.isNullValue("params") ? null : (Map) bizParamMap.get("params"); + if (ObjectValidUtil.isInvalid(params)) { + _log.warn("处理支付宝支付回调失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + Map payContext = new HashMap(); + PayOrder payOrder; + payContext.put("parameters", params); + if(!verifyAliPayParams(payContext)) { + return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_PAY_NOTIFY_VERIFY_FAIL); + } + _log.info("{}验证支付通知数据及签名通过", logPrefix); + String trade_status = params.get("trade_status").toString(); // 交易状态 + // 支付状态成功或者完成 + if (trade_status.equals(PayConstant.AlipayConstant.TRADE_STATUS_SUCCESS) || + trade_status.equals(PayConstant.AlipayConstant.TRADE_STATUS_FINISHED)) { + int updatePayOrderRows; + payOrder = (PayOrder)payContext.get("payOrder"); + byte payStatus = payOrder.getStatus(); // 0:订单生成,1:支付中,-1:支付失败,2:支付成功,3:业务处理完成,-2:订单过期 + if (payStatus != PayConstant.PAY_STATUS_SUCCESS && payStatus != PayConstant.PAY_STATUS_COMPLETE) { + updatePayOrderRows = super.baseUpdateStatus4Success(payOrder.getPayOrderId()); + if (updatePayOrderRows != 1) { + _log.error("{}更新支付状态失败,将payOrderId={},更新payStatus={}失败", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS); + _log.info("{}响应给支付宝结果:{}", logPrefix, PayConstant.RETURN_ALIPAY_VALUE_FAIL); + return RpcUtil.createBizResult(baseParam, PayConstant.RETURN_ALIPAY_VALUE_FAIL); + } + _log.info("{}更新支付状态成功,将payOrderId={},更新payStatus={}成功", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS); + payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS); + } + }else{ + // 其他状态 + _log.info("{}支付状态trade_status={},不做业务处理", logPrefix, trade_status); + _log.info("{}响应给支付宝结果:{}", logPrefix, PayConstant.RETURN_ALIPAY_VALUE_SUCCESS); + return RpcUtil.createBizResult(baseParam, PayConstant.RETURN_ALIPAY_VALUE_SUCCESS); + } + doNotify(payOrder); + _log.info("====== 完成处理支付宝支付回调通知 ======"); + return RpcUtil.createBizResult(baseParam, PayConstant.RETURN_ALIPAY_VALUE_SUCCESS); + } + + @Override + public Map doWxPayNotify(String jsonParam) { + String logPrefix = "【处理微信支付回调】"; + _log.info("====== 开始处理微信支付回调通知 ======"); + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + try { + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("处理微信支付回调失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createBizResult(baseParam, WxPayNotifyResponse.fail(RetEnum.RET_PARAM_NOT_FOUND.getMessage())); + //return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String xmlResult = baseParam.isNullValue("xmlResult") ? null : bizParamMap.get("xmlResult").toString(); + if (ObjectValidUtil.isInvalid(xmlResult)) { + _log.warn("处理微信支付回调失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createBizResult(baseParam, WxPayNotifyResponse.fail(RetEnum.RET_PARAM_INVALID.getMessage())); + //return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + WxPayService wxPayService = new WxPayServiceImpl(); + WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlResult); + Map payContext = new HashMap(); + payContext.put("parameters", result); + // 验证业务数据是否正确,验证通过后返回PayOrder和WxPayConfig对象 + if(!verifyWxPayParams(payContext)) { + return RpcUtil.createBizResult(baseParam, WxPayNotifyResponse.fail((String) payContext.get("retMsg"))); + } + PayOrder payOrder = (PayOrder) payContext.get("payOrder"); + WxPayConfig wxPayConfig = (WxPayConfig) payContext.get("wxPayConfig"); + wxPayService.setConfig(wxPayConfig); + // 这里做了签名校验(这里又做了一次xml转换对象,可以考虑优化) + wxPayService.parseOrderNotifyResult(xmlResult); + // 处理订单 + byte payStatus = payOrder.getStatus(); // 0:订单生成,1:支付中,-1:支付失败,2:支付成功,3:业务处理完成,-2:订单过期 + if (payStatus != PayConstant.PAY_STATUS_SUCCESS && payStatus != PayConstant.PAY_STATUS_COMPLETE) { + int updatePayOrderRows = super.baseUpdateStatus4Success(payOrder.getPayOrderId()); + if (updatePayOrderRows != 1) { + _log.error("{}更新支付状态失败,将payOrderId={},更新payStatus={}失败", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS); + return RpcUtil.createBizResult(baseParam, WxPayNotifyResponse.fail("处理订单失败")); + } + _log.error("{}更新支付状态成功,将payOrderId={},更新payStatus={}成功", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS); + payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS); + } + // 业务系统后端通知 + doNotify(payOrder); + _log.info("====== 完成处理微信支付回调通知 ======"); + return RpcUtil.createBizResult(baseParam, WxPayNotifyResponse.success("OK")); + } catch (WxPayException e) { + //出现业务错误 + _log.error(e, "微信回调结果异常,异常原因"); + _log.info("{}请求数据result_code=FAIL", logPrefix); + _log.info("err_code:", e.getErrCode()); + _log.info("err_code_des:", e.getErrCodeDes()); + return RpcUtil.createBizResult(baseParam, WxPayNotifyResponse.fail(e.getMessage())); + } catch (Exception e) { + _log.error(e, "微信回调结果异常,异常原因"); + return RpcUtil.createBizResult(baseParam, WxPayNotifyResponse.fail(e.getMessage())); + } + } + + @Override + public Map sendBizPayNotify(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("发送业务支付通知失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String payOrderId = baseParam.isNullValue("payOrderId") ? null : bizParamMap.get("payOrderId").toString(); + if(ObjectValidUtil.isInvalid(payOrderId)) { + _log.warn("发送业务支付通知失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + PayOrder payOrder = super.baseSelectPayOrder(payOrderId); + if(payOrder == null) return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_DATA_NOT_EXISTS); + try { + // 发送业务支付通知 + super.doNotify(payOrder); + }catch (Exception e) { + return RpcUtil.createBizResult(baseParam, 0); + } + return RpcUtil.createBizResult(baseParam, 1); + } + + + /** + * 验证支付宝支付通知参数 + * @return + */ + public boolean verifyAliPayParams(Map payContext) { + Map params = (Map)payContext.get("parameters"); + String out_trade_no = params.get("out_trade_no"); // 商户订单号 + String total_amount = params.get("total_amount"); // 支付金额 + if (StringUtils.isEmpty(out_trade_no)) { + _log.error("AliPay Notify parameter out_trade_no is empty. out_trade_no={}", out_trade_no); + payContext.put("retMsg", "out_trade_no is empty"); + return false; + } + if (StringUtils.isEmpty(total_amount)) { + _log.error("AliPay Notify parameter total_amount is empty. total_fee={}", total_amount); + payContext.put("retMsg", "total_amount is empty"); + return false; + } + String errorMessage; + // 查询payOrder记录 + String payOrderId = out_trade_no; + PayOrder payOrder = super.baseSelectPayOrder(payOrderId); + if (payOrder == null) { + _log.error("Can't found payOrder form db. payOrderId={}, ", payOrderId); + payContext.put("retMsg", "Can't found payOrder"); + return false; + } + // 查询payChannel记录 + String mchId = payOrder.getMchId(); + String channelId = payOrder.getChannelId(); + PayChannel payChannel = super.baseSelectPayChannel(mchId, channelId); + if(payChannel == null) { + _log.error("Can't found payChannel form db. mchId={} channelId={}, ", payOrderId, mchId, channelId); + payContext.put("retMsg", "Can't found payChannel"); + return false; + } + boolean verify_result = false; + try { + verify_result = AlipaySignature.rsaCheckV1(params, alipayConfig.init(payChannel.getParam()).getAlipay_public_key(), AlipayConfig.CHARSET, "RSA2"); + } catch (AlipayApiException e) { + _log.error(e, "AlipaySignature.rsaCheckV1 error"); + } + + // 验证签名 + if (!verify_result) { + errorMessage = "rsaCheckV1 failed."; + _log.error("AliPay Notify parameter {}", errorMessage); + payContext.put("retMsg", errorMessage); + return false; + } + + // 核对金额 + long aliPayAmt = new BigDecimal(total_amount).movePointRight(2).longValue(); + long dbPayAmt = payOrder.getAmount().longValue(); + if (dbPayAmt != aliPayAmt) { + _log.error("db payOrder record payPrice not equals total_amount. total_amount={},payOrderId={}", total_amount, payOrderId); + payContext.put("retMsg", ""); + return false; + } + payContext.put("payOrder", payOrder); + return true; + } + + /** + * 验证微信支付通知参数 + * @return + */ + public boolean verifyWxPayParams(Map payContext) { + WxPayOrderNotifyResult params = (WxPayOrderNotifyResult)payContext.get("parameters"); + + //校验结果是否成功 + if (!PayConstant.RETURN_VALUE_SUCCESS.equalsIgnoreCase(params.getResultCode()) + || !PayConstant.RETURN_VALUE_SUCCESS.equalsIgnoreCase(params.getResultCode())) { + _log.error("returnCode={},resultCode={},errCode={},errCodeDes={}", params.getReturnCode(), params.getResultCode(), params.getErrCode(), params.getErrCodeDes()); + payContext.put("retMsg", "notify data failed"); + return false; + } + + Integer total_fee = params.getTotalFee(); // 总金额 + String out_trade_no = params.getOutTradeNo(); // 商户系统订单号 + + // 查询payOrder记录 + String payOrderId = out_trade_no; + PayOrder payOrder = super.baseSelectPayOrder(payOrderId); + if (payOrder==null) { + _log.error("Can't found payOrder form db. payOrderId={}, ", payOrderId); + payContext.put("retMsg", "Can't found payOrder"); + return false; + } + + // 查询payChannel记录 + String mchId = payOrder.getMchId(); + String channelId = payOrder.getChannelId(); + PayChannel payChannel = super.baseSelectPayChannel(mchId, channelId); + if(payChannel == null) { + _log.error("Can't found payChannel form db. mchId={} channelId={}, ", payOrderId, mchId, channelId); + payContext.put("retMsg", "Can't found payChannel"); + return false; + } + payContext.put("wxPayConfig", WxPayUtil.getWxPayConfig(payChannel.getParam())); + + // 核对金额 + long wxPayAmt = new BigDecimal(total_fee).longValue(); + long dbPayAmt = payOrder.getAmount().longValue(); + if (dbPayAmt != wxPayAmt) { + _log.error("db payOrder record payPrice not equals total_fee. total_fee={},payOrderId={}", total_fee, payOrderId); + payContext.put("retMsg", "total_fee is not the same"); + return false; + } + + payContext.put("payOrder", payOrder); + return true; + } + + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannel4AliServiceImpl.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannel4AliServiceImpl.java new file mode 100644 index 0000000..63f39f7 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannel4AliServiceImpl.java @@ -0,0 +1,287 @@ +package org.xxpay.boot.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.domain.AlipayTradeAppPayModel; +import com.alipay.api.domain.AlipayTradePagePayModel; +import com.alipay.api.domain.AlipayTradePrecreateModel; +import com.alipay.api.domain.AlipayTradeWapPayModel; +import com.alipay.api.request.AlipayTradeAppPayRequest; +import com.alipay.api.request.AlipayTradePagePayRequest; +import com.alipay.api.request.AlipayTradePrecreateRequest; +import com.alipay.api.request.AlipayTradeWapPayRequest; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.xxpay.boot.service.BaseService; +import org.xxpay.boot.service.IPayChannel4AliService; +import org.xxpay.boot.service.channel.alipay.AlipayConfig; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.domain.BaseParam; +import org.xxpay.common.enumm.RetEnum; +import org.xxpay.common.util.*; +import org.xxpay.dal.dao.model.PayChannel; +import org.xxpay.dal.dao.model.PayOrder; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/10 + * @description: + */ +@Service +public class PayChannel4AliServiceImpl extends BaseService implements IPayChannel4AliService { + + private static final MyLog _log = MyLog.getLog(PayChannel4AliServiceImpl.class); + + @Autowired + private AlipayConfig alipayConfig; + + @Override + public Map doAliPayWapReq(String jsonParam) { + String logPrefix = "【支付宝WAP支付下单】"; + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + JSONObject payOrderObj = baseParam.isNullValue("payOrder") ? null : JSONObject.parseObject(bizParamMap.get("payOrder").toString()); + PayOrder payOrder = BeanConvertUtils.map2Bean(payOrderObj, PayOrder.class); + if (ObjectValidUtil.isInvalid(payOrder)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + String payOrderId = payOrder.getPayOrderId(); + String mchId = payOrder.getMchId(); + String channelId = payOrder.getChannelId(); + PayChannel payChannel = super.baseSelectPayChannel(mchId, channelId); + alipayConfig.init(payChannel.getParam()); + AlipayClient client = new DefaultAlipayClient(alipayConfig.getUrl(), alipayConfig.getApp_id(), alipayConfig.getRsa_private_key(), AlipayConfig.FORMAT, AlipayConfig.CHARSET, alipayConfig.getAlipay_public_key(), AlipayConfig.SIGNTYPE); + AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest(); + // 封装请求支付信息 + AlipayTradeWapPayModel model=new AlipayTradeWapPayModel(); + model.setOutTradeNo(payOrderId); + model.setSubject(payOrder.getSubject()); + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getAmount().toString())); + model.setBody(payOrder.getBody()); + model.setProductCode("QUICK_WAP_PAY"); + // 获取objParams参数 + String objParams = payOrder.getExtra(); + if (StringUtils.isNotEmpty(objParams)) { + try { + JSONObject objParamsJson = JSON.parseObject(objParams); + if(StringUtils.isNotBlank(objParamsJson.getString("quit_url"))) { + model.setQuitUrl(objParamsJson.getString("quit_url")); + } + } catch (Exception e) { + _log.error("{}objParams参数格式错误!", logPrefix); + } + } + alipay_request.setBizModel(model); + // 设置异步通知地址 + alipay_request.setNotifyUrl(alipayConfig.getNotify_url()); + // 设置同步地址 + alipay_request.setReturnUrl(alipayConfig.getReturn_url()); + String payUrl = null; + try { + payUrl = client.pageExecute(alipay_request).getBody(); + } catch (AlipayApiException e) { + e.printStackTrace(); + } + _log.info("{}生成跳转路径:payUrl={}", logPrefix, payUrl); + super.baseUpdateStatus4Ing(payOrderId, null); + _log.info("{}生成请求支付宝数据,req={}", logPrefix, alipay_request.getBizModel()); + _log.info("###### 商户统一下单处理完成 ######"); + Map map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null); + map.put("payOrderId", payOrderId); + map.put("payUrl", payUrl); + return RpcUtil.createBizResult(baseParam, map); + } + + @Override + public Map doAliPayPcReq(String jsonParam) { + String logPrefix = "【支付宝PC支付下单】"; + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + JSONObject payOrderObj = baseParam.isNullValue("payOrder") ? null : JSONObject.parseObject(bizParamMap.get("payOrder").toString()); + PayOrder payOrder = BeanConvertUtils.map2Bean(payOrderObj, PayOrder.class); + if (ObjectValidUtil.isInvalid(payOrder)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + String payOrderId = payOrder.getPayOrderId(); + String mchId = payOrder.getMchId(); + String channelId = payOrder.getChannelId(); + PayChannel payChannel = super.baseSelectPayChannel(mchId, channelId); + alipayConfig.init(payChannel.getParam()); + AlipayClient client = new DefaultAlipayClient(alipayConfig.getUrl(), alipayConfig.getApp_id(), alipayConfig.getRsa_private_key(), AlipayConfig.FORMAT, AlipayConfig.CHARSET, alipayConfig.getAlipay_public_key(), AlipayConfig.SIGNTYPE); + AlipayTradePagePayRequest alipay_request = new AlipayTradePagePayRequest(); + // 封装请求支付信息 + AlipayTradePagePayModel model=new AlipayTradePagePayModel(); + model.setOutTradeNo(payOrderId); + model.setSubject(payOrder.getSubject()); + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getAmount().toString())); + model.setBody(payOrder.getBody()); + model.setProductCode("FAST_INSTANT_TRADE_PAY"); + // 获取objParams参数 + String objParams = payOrder.getExtra(); + String qr_pay_mode = "2"; + String qrcode_width = "200"; + if (StringUtils.isNotEmpty(objParams)) { + try { + JSONObject objParamsJson = JSON.parseObject(objParams); + qr_pay_mode = ObjectUtils.toString(objParamsJson.getString("qr_pay_mode"), "2"); + qrcode_width = ObjectUtils.toString(objParamsJson.getString("qrcode_width"), "200"); + } catch (Exception e) { + _log.error("{}objParams参数格式错误!", logPrefix); + } + } + model.setQrPayMode(qr_pay_mode); + model.setQrcodeWidth(Long.parseLong(qrcode_width)); + alipay_request.setBizModel(model); + // 设置异步通知地址 + alipay_request.setNotifyUrl(alipayConfig.getNotify_url()); + // 设置同步地址 + alipay_request.setReturnUrl(alipayConfig.getReturn_url()); + String payUrl = null; + try { + payUrl = client.pageExecute(alipay_request).getBody(); + } catch (AlipayApiException e) { + e.printStackTrace(); + } + _log.info("{}生成跳转路径:payUrl={}", logPrefix, payUrl); + super.baseUpdateStatus4Ing(payOrderId, null); + _log.info("{}生成请求支付宝数据,req={}", logPrefix, alipay_request.getBizModel()); + _log.info("###### 商户统一下单处理完成 ######"); + Map map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null); + map.put("payOrderId", payOrderId); + map.put("payUrl", payUrl); + return RpcUtil.createBizResult(baseParam, map); + } + + @Override + public Map doAliPayMobileReq(String jsonParam) { + String logPrefix = "【支付宝APP支付下单】"; + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + JSONObject payOrderObj = baseParam.isNullValue("payOrder") ? null : JSONObject.parseObject(bizParamMap.get("payOrder").toString()); + PayOrder payOrder = BeanConvertUtils.map2Bean(payOrderObj, PayOrder.class); + if (ObjectValidUtil.isInvalid(payOrder)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + String payOrderId = payOrder.getPayOrderId(); + String mchId = payOrder.getMchId(); + String channelId = payOrder.getChannelId(); + PayChannel payChannel = super.baseSelectPayChannel(mchId, channelId); + alipayConfig.init(payChannel.getParam()); + AlipayClient client = new DefaultAlipayClient(alipayConfig.getUrl(), alipayConfig.getApp_id(), alipayConfig.getRsa_private_key(), AlipayConfig.FORMAT, AlipayConfig.CHARSET, alipayConfig.getAlipay_public_key(), AlipayConfig.SIGNTYPE); + AlipayTradeAppPayRequest alipay_request = new AlipayTradeAppPayRequest(); + // 封装请求支付信息 + AlipayTradeAppPayModel model=new AlipayTradeAppPayModel(); + model.setOutTradeNo(payOrderId); + model.setSubject(payOrder.getSubject()); + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getAmount().toString())); + model.setBody(payOrder.getBody()); + model.setProductCode("QUICK_MSECURITY_PAY"); + alipay_request.setBizModel(model); + // 设置异步通知地址 + alipay_request.setNotifyUrl(alipayConfig.getNotify_url()); + // 设置同步地址 + alipay_request.setReturnUrl(alipayConfig.getReturn_url()); + String payParams = null; + try { + payParams = client.sdkExecute(alipay_request).getBody(); + } catch (AlipayApiException e) { + e.printStackTrace(); + } + super.baseUpdateStatus4Ing(payOrderId, null); + _log.info("{}生成请求支付宝数据,payParams={}", logPrefix, payParams); + _log.info("###### 商户统一下单处理完成 ######"); + Map map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null); + map.put("payOrderId", payOrderId); + map.put("payParams", payParams); + return RpcUtil.createBizResult(baseParam, map); + } + + @Override + public Map doAliPayQrReq(String jsonParam) { + String logPrefix = "【支付宝当面付之扫码支付下单】"; + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + JSONObject payOrderObj = baseParam.isNullValue("payOrder") ? null : JSONObject.parseObject(bizParamMap.get("payOrder").toString()); + PayOrder payOrder = BeanConvertUtils.map2Bean(payOrderObj, PayOrder.class); + if (ObjectValidUtil.isInvalid(payOrder)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + String payOrderId = payOrder.getPayOrderId(); + String mchId = payOrder.getMchId(); + String channelId = payOrder.getChannelId(); + PayChannel payChannel = super.baseSelectPayChannel(mchId, channelId); + alipayConfig.init(payChannel.getParam()); + AlipayClient client = new DefaultAlipayClient(alipayConfig.getUrl(), alipayConfig.getApp_id(), alipayConfig.getRsa_private_key(), AlipayConfig.FORMAT, AlipayConfig.CHARSET, alipayConfig.getAlipay_public_key(), AlipayConfig.SIGNTYPE); + AlipayTradePrecreateRequest alipay_request = new AlipayTradePrecreateRequest(); + // 封装请求支付信息 + AlipayTradePrecreateModel model=new AlipayTradePrecreateModel(); + model.setOutTradeNo(payOrderId); + model.setSubject(payOrder.getSubject()); + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getAmount().toString())); + model.setBody(payOrder.getBody()); + // 获取objParams参数 + String objParams = payOrder.getExtra(); + if (StringUtils.isNotEmpty(objParams)) { + try { + JSONObject objParamsJson = JSON.parseObject(objParams); + if(StringUtils.isNotBlank(objParamsJson.getString("discountable_amount"))) { + //可打折金额 + model.setDiscountableAmount(objParamsJson.getString("discountable_amount")); + } + if(StringUtils.isNotBlank(objParamsJson.getString("undiscountable_amount"))) { + //不可打折金额 + model.setUndiscountableAmount(objParamsJson.getString("undiscountable_amount")); + } + } catch (Exception e) { + _log.error("{}objParams参数格式错误!", logPrefix); + } + } + alipay_request.setBizModel(model); + // 设置异步通知地址 + alipay_request.setNotifyUrl(alipayConfig.getNotify_url()); + // 设置同步地址 + alipay_request.setReturnUrl(alipayConfig.getReturn_url()); + String payUrl = null; + try { + payUrl = client.execute(alipay_request).getBody(); + } catch (AlipayApiException e) { + e.printStackTrace(); + } + _log.info("{}生成跳转路径:payUrl={}", logPrefix, payUrl); + super.baseUpdateStatus4Ing(payOrderId, null); + _log.info("{}生成请求支付宝数据,req={}", logPrefix, alipay_request.getBizModel()); + _log.info("###### 商户统一下单处理完成 ######"); + Map map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null); + map.put("payOrderId", payOrderId); + map.put("payUrl", payUrl); + return RpcUtil.createBizResult(baseParam, map); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannel4WxServiceImpl.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannel4WxServiceImpl.java new file mode 100644 index 0000000..1e13657 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannel4WxServiceImpl.java @@ -0,0 +1,198 @@ +package org.xxpay.boot.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import com.github.binarywang.wxpay.util.SignUtils; +import org.springframework.stereotype.Service; +import org.xxpay.boot.service.BaseService; +import org.xxpay.boot.service.IPayChannel4WxService; +import org.xxpay.boot.service.channel.wechat.WxPayProperties; +import org.xxpay.boot.service.channel.wechat.WxPayUtil; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.domain.BaseParam; +import org.xxpay.common.enumm.RetEnum; +import org.xxpay.common.util.*; +import org.xxpay.dal.dao.model.PayChannel; +import org.xxpay.dal.dao.model.PayOrder; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +/** + * @Description: 支付渠道接口:微信 + * @author dingzhiwei jmdhappy@126.com + * @date 2017-09-05 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +@Service +public class PayChannel4WxServiceImpl extends BaseService implements IPayChannel4WxService { + + private final MyLog _log = MyLog.getLog(PayChannel4WxServiceImpl.class); + + @Resource + private WxPayProperties wxPayProperties; + + public Map doWxPayReq(String jsonParam) { + String logPrefix = "【微信支付统一下单】"; + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + try{ + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + JSONObject payOrderObj = baseParam.isNullValue("payOrder") ? null : JSONObject.parseObject(bizParamMap.get("payOrder").toString()); + String tradeType = baseParam.isNullValue("tradeType") ? null : bizParamMap.get("tradeType").toString(); + PayOrder payOrder = BeanConvertUtils.map2Bean(payOrderObj, PayOrder.class); + if (ObjectValidUtil.isInvalid(payOrder, tradeType)) { + _log.warn("{}失败, {}. jsonParam={}", logPrefix, RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + String mchId = payOrder.getMchId(); + String channelId = payOrder.getChannelId(); + PayChannel payChannel = super.baseSelectPayChannel(mchId, channelId); + WxPayConfig wxPayConfig = WxPayUtil.getWxPayConfig(payChannel.getParam(), tradeType, wxPayProperties.getCertRootPath(), wxPayProperties.getNotifyUrl()); + WxPayService wxPayService = new WxPayServiceImpl(); + wxPayService.setConfig(wxPayConfig); + WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = buildUnifiedOrderRequest(payOrder, wxPayConfig); + String payOrderId = payOrder.getPayOrderId(); + WxPayUnifiedOrderResult wxPayUnifiedOrderResult; + try { + wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest); + _log.info("{} >>> 下单成功", logPrefix); + Map map = new HashMap<>(); + map.put("payOrderId", payOrderId); + map.put("prepayId", wxPayUnifiedOrderResult.getPrepayId()); + int result = super.baseUpdateStatus4Ing(payOrderId, wxPayUnifiedOrderResult.getPrepayId()); + _log.info("更新第三方支付订单号:payOrderId={},prepayId={},result={}", payOrderId, wxPayUnifiedOrderResult.getPrepayId(), result); + switch (tradeType) { + case PayConstant.WxConstant.TRADE_TYPE_NATIVE : { + map.put("codeUrl", wxPayUnifiedOrderResult.getCodeURL()); // 二维码支付链接 + break; + } + case PayConstant.WxConstant.TRADE_TYPE_APP : { + Map payInfo = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonceStr = String.valueOf(System.currentTimeMillis()); + // APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数 + String appId = wxPayConfig.getAppId(); + Map configMap = new HashMap<>(); + // 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改 + String partnerId = wxPayConfig.getMchId(); + configMap.put("prepayid", wxPayUnifiedOrderResult.getPrepayId()); + configMap.put("partnerid", partnerId); + String packageValue = "Sign=WXPay"; + configMap.put("package", packageValue); + configMap.put("timestamp", timestamp); + configMap.put("noncestr", nonceStr); + configMap.put("appid", appId); + // 此map用于客户端与微信服务器交互 + payInfo.put("sign", SignUtils.createSign(configMap, wxPayConfig.getMchKey(), null)); + payInfo.put("prepayId", wxPayUnifiedOrderResult.getPrepayId()); + payInfo.put("partnerId", partnerId); + payInfo.put("appId", appId); + payInfo.put("packageValue", packageValue); + payInfo.put("timeStamp", timestamp); + payInfo.put("nonceStr", nonceStr); + map.put("payParams", payInfo); + break; + } + case PayConstant.WxConstant.TRADE_TYPE_JSPAI : { + Map payInfo = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonceStr = String.valueOf(System.currentTimeMillis()); + payInfo.put("appId", wxPayUnifiedOrderResult.getAppid()); + // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 + payInfo.put("timeStamp", timestamp); + payInfo.put("nonceStr", nonceStr); + payInfo.put("package", "prepay_id=" + wxPayUnifiedOrderResult.getPrepayId()); + payInfo.put("signType", WxPayConstants.SignType.MD5); + payInfo.put("paySign", SignUtils.createSign(payInfo, wxPayConfig.getMchKey(), null)); + map.put("payParams", payInfo); + break; + } + case PayConstant.WxConstant.TRADE_TYPE_MWEB : { + map.put("payUrl", wxPayUnifiedOrderResult.getMwebUrl()); // h5支付链接地址 + break; + } + } + return RpcUtil.createBizResult(baseParam, map); + } catch (WxPayException e) { + _log.error(e, "下单失败"); + //出现业务错误 + _log.info("{}下单返回失败", logPrefix); + _log.info("err_code:{}", e.getErrCode()); + _log.info("err_code_des:{}", e.getErrCodeDes()); + + return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_WX_PAY_CREATE_FAIL); + + // return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_FAIL, "0111", "调用微信支付失败," + e.getErrCode() + ":" + e.getErrCodeDes()), resKey); + } + }catch (Exception e) { + _log.error(e, "微信支付统一下单异常"); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_WX_PAY_CREATE_FAIL); + + //return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "", PayConstant.RETURN_VALUE_FAIL, PayEnum.ERR_0001)); + } + } + + /** + * 构建微信统一下单请求数据 + * @param payOrder + * @param wxPayConfig + * @return + */ + WxPayUnifiedOrderRequest buildUnifiedOrderRequest(PayOrder payOrder, WxPayConfig wxPayConfig) { + String tradeType = wxPayConfig.getTradeType(); + String payOrderId = payOrder.getPayOrderId(); + Integer totalFee = payOrder.getAmount().intValue();// 支付金额,单位分 + String deviceInfo = payOrder.getDevice(); + String body = payOrder.getBody(); + String detail = null; + String attach = null; + String outTradeNo = payOrderId; + String feeType = "CNY"; + String spBillCreateIP = payOrder.getClientIp(); + String timeStart = null; + String timeExpire = null; + String goodsTag = null; + String notifyUrl = wxPayConfig.getNotifyUrl(); + String productId = null; + if(tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_NATIVE)) productId = JSON.parseObject(payOrder.getExtra()).getString("productId"); + String limitPay = null; + String openId = null; + if(tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_JSPAI)) openId = JSON.parseObject(payOrder.getExtra()).getString("openId"); + String sceneInfo = null; + if(tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_MWEB)) sceneInfo = JSON.parseObject(payOrder.getExtra()).getString("sceneInfo"); + // 微信统一下单请求对象 + WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); + request.setDeviceInfo(deviceInfo); + request.setBody(body); + request.setDetail(detail); + request.setAttach(attach); + request.setOutTradeNo(outTradeNo); + request.setFeeType(feeType); + request.setTotalFee(totalFee); + request.setSpbillCreateIp(spBillCreateIP); + request.setTimeStart(timeStart); + request.setTimeExpire(timeExpire); + request.setGoodsTag(goodsTag); + request.setNotifyURL(notifyUrl); + request.setTradeType(tradeType); + request.setProductId(productId); + request.setLimitPay(limitPay); + request.setOpenid(openId); + request.setSceneInfo(sceneInfo); + + return request; + } +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannelServiceImpl.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannelServiceImpl.java new file mode 100644 index 0000000..f6e07df --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayChannelServiceImpl.java @@ -0,0 +1,45 @@ +package org.xxpay.boot.service.impl; + +import org.springframework.stereotype.Service; +import org.xxpay.boot.service.BaseService; +import org.xxpay.boot.service.IPayChannelService; +import org.xxpay.common.domain.BaseParam; +import org.xxpay.common.enumm.RetEnum; +import org.xxpay.common.util.JsonUtil; +import org.xxpay.common.util.MyLog; +import org.xxpay.common.util.ObjectValidUtil; +import org.xxpay.common.util.RpcUtil; +import org.xxpay.dal.dao.model.PayChannel; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/8 + * @description: + */ +@Service +public class PayChannelServiceImpl extends BaseService implements IPayChannelService { + + private static final MyLog _log = MyLog.getLog(PayChannelServiceImpl.class); + + @Override + public Map selectPayChannel(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("查询支付渠道信息失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String mchId = baseParam.isNullValue("mchId") ? null : bizParamMap.get("mchId").toString(); + String channelId = baseParam.isNullValue("channelId") ? null : bizParamMap.get("channelId").toString(); + if (ObjectValidUtil.isInvalid(mchId, channelId)) { + _log.warn("查询支付渠道信息失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + PayChannel payChannel = super.baseSelectPayChannel(mchId, channelId); + if(payChannel == null) return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_DATA_NOT_EXISTS); + String jsonResult = JsonUtil.object2Json(payChannel); + return RpcUtil.createBizResult(baseParam, jsonResult); + } +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayOrderServiceImpl.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayOrderServiceImpl.java new file mode 100644 index 0000000..5c5cf42 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/impl/PayOrderServiceImpl.java @@ -0,0 +1,174 @@ +package org.xxpay.boot.service.impl; + +import com.alibaba.fastjson.JSONObject; +import org.springframework.stereotype.Service; +import org.xxpay.boot.service.BaseService; +import org.xxpay.boot.service.IPayOrderService; +import org.xxpay.common.domain.BaseParam; +import org.xxpay.common.enumm.RetEnum; +import org.xxpay.common.util.*; +import org.xxpay.dal.dao.model.PayOrder; + +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/8 + * @description: + */ +@Service +public class PayOrderServiceImpl extends BaseService implements IPayOrderService { + + private static final MyLog _log = MyLog.getLog(PayOrderServiceImpl.class); + + @Override + public Map createPayOrder(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("新增支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + JSONObject payOrderObj = baseParam.isNullValue("payOrder") ? null : JSONObject.parseObject(bizParamMap.get("payOrder").toString()); + if(payOrderObj == null) { + _log.warn("新增支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + PayOrder payOrder = BeanConvertUtils.map2Bean(payOrderObj, PayOrder.class); + if(payOrder == null) { + _log.warn("新增支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + int result = super.baseCreatePayOrder(payOrder); + return RpcUtil.createBizResult(baseParam, result); + } + + @Override + public Map selectPayOrder(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("根据支付订单号查询支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String payOrderId = baseParam.isNullValue("payOrderId") ? null : bizParamMap.get("payOrderId").toString(); + if (ObjectValidUtil.isInvalid(payOrderId)) { + _log.warn("根据支付订单号查询支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + PayOrder payOrder = super.baseSelectPayOrder(payOrderId); + if(payOrder == null) return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_DATA_NOT_EXISTS); + String jsonResult = JsonUtil.object2Json(payOrder); + return RpcUtil.createBizResult(baseParam, jsonResult); + } + + @Override + public Map selectPayOrderByMchIdAndPayOrderId(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("根据商户号和支付订单号查询支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String mchId = baseParam.isNullValue("mchId") ? null : bizParamMap.get("mchId").toString(); + String payOrderId = baseParam.isNullValue("payOrderId") ? null : bizParamMap.get("payOrderId").toString(); + if (ObjectValidUtil.isInvalid(mchId, payOrderId)) { + _log.warn("根据商户号和支付订单号查询支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + PayOrder payOrder = super.baseSelectPayOrderByMchIdAndPayOrderId(mchId, payOrderId); + if(payOrder == null) return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_DATA_NOT_EXISTS); + String jsonResult = JsonUtil.object2Json(payOrder); + return RpcUtil.createBizResult(baseParam, jsonResult); + } + + @Override + public Map selectPayOrderByMchIdAndMchOrderNo(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("根据商户号和商户订单号查询支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String mchId = baseParam.isNullValue("mchId") ? null : bizParamMap.get("mchId").toString(); + String mchOrderNo = baseParam.isNullValue("mchOrderNo") ? null : bizParamMap.get("mchOrderNo").toString(); + if (ObjectValidUtil.isInvalid(mchId, mchOrderNo)) { + _log.warn("根据商户号和商户订单号查询支付订单失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + PayOrder payOrder = super.baseSelectPayOrderByMchIdAndMchOrderNo(mchId, mchOrderNo); + if(payOrder == null) return RpcUtil.createFailResult(baseParam, RetEnum.RET_BIZ_DATA_NOT_EXISTS); + String jsonResult = JsonUtil.object2Json(payOrder); + return RpcUtil.createBizResult(baseParam, jsonResult); + } + + @Override + public Map updateStatus4Ing(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("修改支付订单状态为支付中失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String payOrderId = baseParam.isNullValue("payOrderId") ? null : bizParamMap.get("payOrderId").toString(); + String channelOrderNo = baseParam.isNullValue("channelOrderNo") ? null : bizParamMap.get("channelOrderNo").toString(); + if (ObjectValidUtil.isInvalid(payOrderId, channelOrderNo)) { + _log.warn("修改支付订单状态为支付中失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + int result = super.baseUpdateStatus4Ing(payOrderId, channelOrderNo); + return RpcUtil.createBizResult(baseParam, result); + } + + @Override + public Map updateStatus4Success(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("修改支付订单状态为支付成功失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String payOrderId = baseParam.isNullValue("payOrderId") ? null : bizParamMap.get("payOrderId").toString(); + if (ObjectValidUtil.isInvalid(payOrderId)) { + _log.warn("修改支付订单状态为支付成功失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + int result = super.baseUpdateStatus4Success(payOrderId); + return RpcUtil.createBizResult(baseParam, result); + } + + @Override + public Map updateStatus4Complete(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("修改支付订单状态为支付完成失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String payOrderId = baseParam.isNullValue("payOrderId") ? null : bizParamMap.get("payOrderId").toString(); + if (ObjectValidUtil.isInvalid(payOrderId)) { + _log.warn("修改支付订单状态为支付完成失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + int result = super.baseUpdateStatus4Complete(payOrderId); + return RpcUtil.createBizResult(baseParam, result); + } + + @Override + public Map updateNotify(String jsonParam) { + BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class); + Map bizParamMap = baseParam.getBizParamMap(); + if (ObjectValidUtil.isInvalid(bizParamMap)) { + _log.warn("修改支付订单通知次数失败, {}. jsonParam={}", RetEnum.RET_PARAM_NOT_FOUND.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_NOT_FOUND); + } + String payOrderId = baseParam.isNullValue("payOrderId") ? null : bizParamMap.get("payOrderId").toString(); + Byte count = baseParam.isNullValue("count") ? null : Byte.parseByte(bizParamMap.get("count").toString()); + if (ObjectValidUtil.isInvalid(payOrderId, count)) { + _log.warn("修改支付订单通知次数失败, {}. jsonParam={}", RetEnum.RET_PARAM_INVALID.getMessage(), jsonParam); + return RpcUtil.createFailResult(baseParam, RetEnum.RET_PARAM_INVALID); + } + int result = super.baseUpdateNotify(payOrderId, count); + return RpcUtil.createBizResult(baseParam, result); + } +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/mq/Mq4PayNotify.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/mq/Mq4PayNotify.java new file mode 100644 index 0000000..59de5be --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/mq/Mq4PayNotify.java @@ -0,0 +1,190 @@ +package org.xxpay.boot.service.mq; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.apache.activemq.ScheduledMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jms.annotation.JmsListener; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.MessageCreator; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.xxpay.common.util.MyLog; +import org.xxpay.boot.service.BaseService; + +import javax.jms.*; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @Description: 业务通知MQ实现 + * @author dingzhiwei jmdhappy@126.com + * @date 2017-07-05 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +@Component +public class Mq4PayNotify extends BaseService { + + @Autowired + private Queue payNotifyQueue; + + @Autowired + private JmsTemplate jmsTemplate; + + private static final MyLog _log = MyLog.getLog(Mq4PayNotify.class); + + public void send(String msg) { + _log.info("发送MQ消息:msg={}", msg); + this.jmsTemplate.convertAndSend(this.payNotifyQueue, msg); + } + + /** + * 发送延迟消息 + * @param msg + * @param delay + */ + public void send(String msg, long delay) { + _log.info("发送MQ延时消息:msg={},delay={}", msg, delay); + jmsTemplate.send(this.payNotifyQueue, new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + 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; + } + }); + } + + private static class TrustAnyTrustManager implements X509TrustManager { + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[] {}; + } + } + + @JmsListener(destination = MqConfig.PAY_NOTIFY_QUEUE_NAME) + public void receive(String msg) { + _log.info("do notify task, msg={}", msg); + JSONObject msgObj = JSON.parseObject(msg); + String respUrl = msgObj.getString("url"); + String orderId = msgObj.getString("orderId"); + int count = msgObj.getInteger("count"); + if(StringUtils.isEmpty(respUrl)) { + _log.warn("notify url is empty. respUrl={}", respUrl); + return; + } + try { + StringBuffer sb = new StringBuffer(); + URL console = new URL(respUrl); + _log.info("==>MQ通知业务系统开始[orderId:{}][count:{}][time:{}]", orderId, count, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + if("https".equals(console.getProtocol())) { + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, + new java.security.SecureRandom()); + HttpsURLConnection con = (HttpsURLConnection) console.openConnection(); + con.setSSLSocketFactory(sc.getSocketFactory()); + con.setRequestMethod("POST"); + con.setDoInput(true); + con.setDoOutput(true); + con.setUseCaches(false); + con.setConnectTimeout(10 * 1000); + con.setReadTimeout(5 * 1000); + con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()), 1024*1024); + while (true) { + String line = in.readLine(); + if (line == null) { + break; + } + sb.append(line); + } + in.close(); + }else if("http".equals(console.getProtocol())) { + HttpURLConnection con = (HttpURLConnection) console.openConnection(); + con.setRequestMethod("POST"); + con.setDoInput(true); + con.setDoOutput(true); + con.setUseCaches(false); + con.setConnectTimeout(10 * 1000); + con.setReadTimeout(5 * 1000); + con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()), 1024*1024); + while (true) { + String line = in.readLine(); + if (line == null) { + break; + } + sb.append(line); + } + in.close(); + }else { + _log.error("not do protocol. protocol=%s", console.getProtocol()); + return; + } + _log.info("<==MQ通知业务系统结束[orderId:{}][count:{}][time:{}]", orderId, count, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + // 验证结果 + _log.info("notify response , OrderID={}", orderId); + if(sb.toString().trim().equalsIgnoreCase("success")){ + //_log.info("{} notify success, url:{}", _notifyInfo.getBusiId(), respUrl); + //修改订单表 + try { + int result = super.baseUpdateStatus4Complete(orderId); + _log.info("修改payOrderId={},订单状态为处理完成->{}", orderId, result == 1 ? "成功" : "失败"); + } catch (Exception e) { + _log.error(e, "修改订单状态为处理完成异常"); + } + // 修改通知次数 + try { + int result = super.baseUpdateNotify(orderId, (byte) 1); + _log.info("修改payOrderId={},通知业务系统次数->{}", orderId, result == 1 ? "成功" : "失败"); + }catch (Exception e) { + _log.error(e, "修改通知次数异常"); + } + return ; // 通知成功结束 + }else { + // 通知失败,延时再通知 + int cnt = count+1; + _log.info("notify count={}", cnt); + // 修改通知次数 + try { + int result = super.baseUpdateNotify(orderId, (byte) cnt); + _log.info("修改payOrderId={},通知业务系统次数->{}", orderId, result == 1 ? "成功" : "失败"); + }catch (Exception e) { + _log.error(e, "修改通知次数异常"); + } + + if (cnt > 5) { + _log.info("notify count>5 stop. url={}", respUrl); + return ; + } + msgObj.put("count", cnt); + this.send(msgObj.toJSONString(), cnt * 60 * 1000); + } + _log.warn("notify failed. url:{}, response body:{}", respUrl, sb.toString()); + } catch(Exception e) { + _log.info("<==MQ通知业务系统结束[orderId:{}][count:{}][time:{}]", orderId, count, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + _log.error(e, "notify exception. url:%s", respUrl); + } + + } +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/mq/MqConfig.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/mq/MqConfig.java new file mode 100644 index 0000000..de1511e --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/service/mq/MqConfig.java @@ -0,0 +1,26 @@ +package org.xxpay.boot.service.mq; + +import org.apache.activemq.command.ActiveMQQueue; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.jms.Queue; + +/** + * @Description: + * @author dingzhiwei jmdhappy@126.com + * @date 2017-07-05 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +@Configuration +public class MqConfig { + + public static final String PAY_NOTIFY_QUEUE_NAME = "pay.notify.queue"; + + @Bean + public Queue payNotifyQueue() { + return new ActiveMQQueue(PAY_NOTIFY_QUEUE_NAME); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/MchInfoService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/MchInfoService.java new file mode 100644 index 0000000..5b592a3 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/MchInfoService.java @@ -0,0 +1,32 @@ +package org.xxpay.boot.web; + +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.xxpay.common.util.RpcUtil; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/9 + * @description: + */ +@Service +public class MchInfoService { + + @Autowired + private RpcCommonService rpcCommonService; + + public JSONObject getByMchId(String mchId) { + Map paramMap = new HashMap<>(); + paramMap.put("mchId", mchId); + String jsonParam = RpcUtil.createBaseParam(paramMap); + Map result = rpcCommonService.rpcMchInfoService.selectMchInfo(jsonParam); + String s = RpcUtil.mkRet(result); + if(s==null) return null; + return JSONObject.parseObject(s); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/NotifyPayService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/NotifyPayService.java new file mode 100644 index 0000000..6eced88 --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/NotifyPayService.java @@ -0,0 +1,43 @@ +package org.xxpay.boot.web; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.util.RpcUtil; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/10 + * @description: + */ +@Service +public class NotifyPayService { + + @Autowired + private RpcCommonService rpcCommonService; + + public String doAliPayNotify(Map params) { + Map paramMap = new HashMap<>(); + paramMap.put("params", params); + String jsonParam = RpcUtil.createBaseParam(paramMap); + Map result = rpcCommonService.rpcNotifyPayService.doAliPayNotify(jsonParam); + String s = RpcUtil.mkRet(result); + if(s == null) { + return PayConstant.RETURN_ALIPAY_VALUE_FAIL; + } + return s; + } + + public String doWxPayNotify(String xmlResult) { + Map paramMap = new HashMap<>(); + paramMap.put("xmlResult", xmlResult); + String jsonParam = RpcUtil.createBaseParam(paramMap); + // 返回给微信的数据格式已经有service处理(包括正确与错误),肯定会返回result + Map result = rpcCommonService.rpcNotifyPayService.doWxPayNotify(jsonParam); + return RpcUtil.mkRet(result); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/PayChannelService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/PayChannelService.java new file mode 100644 index 0000000..60939da --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/PayChannelService.java @@ -0,0 +1,33 @@ +package org.xxpay.boot.web; + +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.xxpay.common.util.RpcUtil; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/9 + * @description: + */ +@Service +public class PayChannelService { + + @Autowired + private RpcCommonService rpcCommonService; + + public JSONObject getByMchIdAndChannelId(String mchId, String channelId) { + Map paramMap = new HashMap<>(); + paramMap.put("mchId", mchId); + paramMap.put("channelId", channelId); + String jsonParam = RpcUtil.createBaseParam(paramMap); + Map result = rpcCommonService.rpcPayChannelService.selectPayChannel(jsonParam); + String s = RpcUtil.mkRet(result); + if(s == null) return null; + return JSONObject.parseObject(s); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/PayOrderService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/PayOrderService.java new file mode 100644 index 0000000..fb2eedc --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/PayOrderService.java @@ -0,0 +1,113 @@ +package org.xxpay.boot.web; + +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.xxpay.common.constant.PayConstant; +import org.xxpay.common.util.MyLog; +import org.xxpay.common.util.RpcUtil; +import org.xxpay.common.util.XXPayUtil; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author: dingzhiwei + * @date: 17/9/9 + * @description: + */ +@Service +public class PayOrderService { + + private static final MyLog _log = MyLog.getLog(PayOrderService.class); + + @Autowired + private RpcCommonService rpcCommonService; + + public int createPayOrder(JSONObject payOrder) { + Map paramMap = new HashMap<>(); + paramMap.put("payOrder", payOrder); + String jsonParam = RpcUtil.createBaseParam(paramMap); + Map result = rpcCommonService.rpcPayOrderService.createPayOrder(jsonParam); + String s = RpcUtil.mkRet(result); + if(s == null) return 0; + return Integer.parseInt(s); + } + + public JSONObject queryPayOrder(String mchId, String payOrderId, String mchOrderNo, String executeNotify) { + Map paramMap = new HashMap<>(); + Map result; + if(StringUtils.isNotBlank(payOrderId)) { + paramMap.put("mchId", mchId); + paramMap.put("payOrderId", payOrderId); + String jsonParam = RpcUtil.createBaseParam(paramMap); + result = rpcCommonService.rpcPayOrderService.selectPayOrderByMchIdAndPayOrderId(jsonParam); + }else { + paramMap.put("mchId", mchId); + paramMap.put("mchOrderNo", mchOrderNo); + String jsonParam = RpcUtil.createBaseParam(paramMap); + result = rpcCommonService.rpcPayOrderService.selectPayOrderByMchIdAndMchOrderNo(jsonParam); + } + String s = RpcUtil.mkRet(result); + if(s == null) return null; + boolean isNotify = Boolean.parseBoolean(executeNotify); + JSONObject payOrder = JSONObject.parseObject(s); + if(isNotify) { + paramMap = new HashMap<>(); + paramMap.put("payOrderId", payOrderId); + String jsonParam = RpcUtil.createBaseParam(paramMap); + result = rpcCommonService.rpcNotifyPayService.sendBizPayNotify(jsonParam); + s = RpcUtil.mkRet(result); + _log.info("业务查单完成,并再次发送业务支付通知.发送结果:{}", s); + } + return payOrder; + } + + public String doWxPayReq(String tradeType, JSONObject payOrder, String resKey) { + Map paramMap = new HashMap<>(); + paramMap.put("tradeType", tradeType); + paramMap.put("payOrder", payOrder); + String jsonParam = RpcUtil.createBaseParam(paramMap); + Map result = rpcCommonService.rpcPayChannel4WxService.doWxPayReq(jsonParam); + String s = RpcUtil.mkRet(result); + if(s == null) { + return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_FAIL, "0111", "调用微信支付失败"), resKey); + } + Map map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null); + map.putAll((Map) result.get("bizResult")); + return XXPayUtil.makeRetData(map, resKey); + } + + public String doAliPayReq(String channelId, JSONObject payOrder, String resKey) { + Map paramMap = new HashMap<>(); + paramMap.put("payOrder", payOrder); + String jsonParam = RpcUtil.createBaseParam(paramMap); + Map result; + switch (channelId) { + case PayConstant.PAY_CHANNEL_ALIPAY_MOBILE : + result = rpcCommonService.rpcPayChannel4AliService.doAliPayMobileReq(jsonParam); + break; + case PayConstant.PAY_CHANNEL_ALIPAY_PC : + result = rpcCommonService.rpcPayChannel4AliService.doAliPayPcReq(jsonParam); + break; + case PayConstant.PAY_CHANNEL_ALIPAY_WAP : + result = rpcCommonService.rpcPayChannel4AliService.doAliPayWapReq(jsonParam); + break; + case PayConstant.PAY_CHANNEL_ALIPAY_QR : + result = rpcCommonService.rpcPayChannel4AliService.doAliPayQrReq(jsonParam); + break; + default: + result = null; + break; + } + String s = RpcUtil.mkRet(result); + if(s == null) { + return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_FAIL, "0111", "调用支付宝支付失败"), resKey); + } + Map map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null); + map.putAll((Map) result.get("bizResult")); + return XXPayUtil.makeRetData(map, resKey); + } + +} diff --git a/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/RpcCommonService.java b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/RpcCommonService.java new file mode 100644 index 0000000..b4ad50a --- /dev/null +++ b/xxpay4spring-boot/src/main/java/org/xxpay/boot/web/RpcCommonService.java @@ -0,0 +1,33 @@ +package org.xxpay.boot.web; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.xxpay.boot.service.*; + +/** + * @author: dingzhiwei + * @date: 17/9/10 + * @description: + */ +@Service +public class RpcCommonService { + + @Autowired + public IMchInfoService rpcMchInfoService; + + @Autowired + public IPayChannelService rpcPayChannelService; + + @Autowired + public IPayOrderService rpcPayOrderService; + + @Autowired + public IPayChannel4WxService rpcPayChannel4WxService; + + @Autowired + public IPayChannel4AliService rpcPayChannel4AliService; + + @Autowired + public INotifyPayService rpcNotifyPayService; + +} diff --git a/xxpay4spring-boot/src/main/webapp/WEB-INF/lib/alipay-sdk-java20170818173712.jar b/xxpay4spring-boot/src/main/webapp/WEB-INF/lib/alipay-sdk-java20170818173712.jar new file mode 100755 index 0000000..6cc1c44 Binary files /dev/null and b/xxpay4spring-boot/src/main/webapp/WEB-INF/lib/alipay-sdk-java20170818173712.jar differ diff --git a/xxpay4spring-cloud/xxpay-service/pom.xml b/xxpay4spring-cloud/xxpay-service/pom.xml index 20019d7..92d8833 100644 --- a/xxpay4spring-cloud/xxpay-service/pom.xml +++ b/xxpay4spring-cloud/xxpay-service/pom.xml @@ -27,6 +27,10 @@ org.springframework.boot spring-boot-starter-activemq + + org.apache.activemq + activemq-pool + org.mybatis.spring.boot mybatis-spring-boot-starter