✨ Introducing new features. #2351 【支付管理】支持YunGouOS 小微商户支付模式
This commit is contained in:
1 parent
821580737c
commit
eb8bd5b2d1
15 files changed
+245
-277
No files matched your search
-27
@@ -1,27 +0,0 @@
|
||||
package com.pig4cloud.pigx.pay.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-06-19
|
||||
*/
|
||||
@Data
|
||||
public class AliPayConfig {
|
||||
|
||||
/**
|
||||
* 订单过期时间
|
||||
*/
|
||||
private String expireTime;
|
||||
|
||||
/**
|
||||
* 前端回调地址
|
||||
*/
|
||||
private String returnUrl;
|
||||
|
||||
/**
|
||||
* 服务端回调地址
|
||||
*/
|
||||
private String notifyUrl;
|
||||
|
||||
}
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
package com.pig4cloud.pigx.pay.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ijpay.alipay.AliPayApiConfig;
|
||||
import com.ijpay.alipay.AliPayApiConfigKit;
|
||||
import com.ijpay.wxpay.WxPayApiConfig;
|
||||
import com.ijpay.wxpay.WxPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.admin.api.feign.RemoteTenantService;
|
||||
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
|
||||
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
|
||||
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantBroker;
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import com.pig4cloud.pigx.pay.service.PayChannelService;
|
||||
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
|
||||
|
||||
import org.springframework.boot.web.context.WebServerInitializedEvent;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-05-31
|
||||
* <p>
|
||||
* 支付参数初始化
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
public class PayConfigParmaInitRunner {
|
||||
|
||||
public static Map<String, WxMpService> mpServiceMap = new HashMap<>();
|
||||
|
||||
private final PayChannelService channelService;
|
||||
|
||||
private final RemoteTenantService tenantService;
|
||||
|
||||
@Async
|
||||
@Order
|
||||
@EventListener({ WebServerInitializedEvent.class })
|
||||
public void initPayConfig() {
|
||||
|
||||
List<PayChannel> channelList = new ArrayList<>();
|
||||
tenantService.list(SecurityConstants.FROM_IN).getData()
|
||||
.forEach(tenant -> TenantBroker.runAs(tenant.getId(), (id) -> {
|
||||
List<PayChannel> payChannelList = channelService.list(
|
||||
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getState, CommonConstants.STATUS_NORMAL));
|
||||
channelList.addAll(payChannelList);
|
||||
}));
|
||||
|
||||
channelList.forEach(channel -> {
|
||||
JSONObject params = JSONUtil.parseObj(channel.getParam());
|
||||
|
||||
// 支付宝支付
|
||||
if (PayChannelNameEnum.ALIPAY_WAP.getName().equals(channel.getChannelId())) {
|
||||
|
||||
AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder().setAppId(channel.getAppId())
|
||||
.setPrivateKey(params.getStr("privateKey")).setCharset(CharsetUtil.UTF_8)
|
||||
.setAliPayPublicKey(params.getStr("publicKey")).setServiceUrl(params.getStr("serviceUrl"))
|
||||
.setSignType("RSA2").build();
|
||||
|
||||
AliPayApiConfigKit.putApiConfig(aliPayApiConfig);
|
||||
log.info("新增支付宝支付参数 {}", aliPayApiConfig);
|
||||
}
|
||||
|
||||
// 微信支付
|
||||
if (PayChannelNameEnum.WEIXIN_MP.getName().equals(channel.getChannelId())) {
|
||||
WxPayApiConfig wx = WxPayApiConfig.builder().appId(channel.getAppId()).mchId(channel.getChannelMchId())
|
||||
.partnerKey(params.getStr("paternerKey")).build();
|
||||
|
||||
String subMchId = params.getStr("subMchId");
|
||||
if (StrUtil.isNotBlank(subMchId)) {
|
||||
wx.setSlAppId(channel.getAppId());
|
||||
wx.setSlMchId(subMchId);
|
||||
}
|
||||
|
||||
WxPayApiConfigKit.putApiConfig(wx);
|
||||
|
||||
WxMpService wxMpService = new WxMpServiceImpl();
|
||||
WxMpDefaultConfigImpl storage = new WxMpDefaultConfigImpl();
|
||||
storage.setAppId(channel.getAppId());
|
||||
storage.setSecret(params.getStr("secret"));
|
||||
storage.setToken(params.getStr("token"));
|
||||
wxMpService.setWxMpConfigStorage(storage);
|
||||
|
||||
mpServiceMap.put(channel.getAppId(), wxMpService);
|
||||
log.info("新增微信支付参数 {} {}", wx, wxMpService);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* redis 监听配置,监听 pay_redis_route_reload_topic,重新加载配置
|
||||
* @param redisConnectionFactory redis 配置
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(redisConnectionFactory);
|
||||
container.addMessageListener((message, bytes) -> {
|
||||
log.warn("接收到Redis 事件 重新加载支付参数事件");
|
||||
initPayConfig();
|
||||
}, new ChannelTopic(CacheConstants.PAY_REDIS_RELOAD_TOPIC));
|
||||
return container;
|
||||
}
|
||||
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package com.pig4cloud.pigx.pay.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-06-19
|
||||
*/
|
||||
@Data
|
||||
public class WxPayConfig {
|
||||
|
||||
/**
|
||||
* 服务端回调地址
|
||||
*/
|
||||
private String notifyUrl;
|
||||
|
||||
/**
|
||||
* 订单过期时间
|
||||
*/
|
||||
private String expireTime;
|
||||
|
||||
}
|
||||
+8
-8
@@ -19,16 +19,21 @@ package com.pig4cloud.pigx.pay.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
|
||||
import com.pig4cloud.pigx.common.core.util.R;
|
||||
import com.pig4cloud.pigx.common.log.annotation.SysLog;
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import com.pig4cloud.pigx.pay.service.PayChannelService;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 渠道
|
||||
@@ -44,8 +49,6 @@ public class PayChannelController {
|
||||
|
||||
private final PayChannelService payChannelService;
|
||||
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param page 分页对象
|
||||
@@ -77,7 +80,6 @@ public class PayChannelController {
|
||||
@PreAuthorize("@pms.hasPermission('pay_paychannel_add')")
|
||||
public R save(@RequestBody PayChannel payChannel) {
|
||||
payChannelService.saveChannel(payChannel);
|
||||
redisTemplate.convertAndSend(CacheConstants.PAY_REDIS_RELOAD_TOPIC, "重新加载支付参数");
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@@ -91,7 +93,6 @@ public class PayChannelController {
|
||||
@PreAuthorize("@pms.hasPermission('pay_paychannel_edit')")
|
||||
public R updateById(@RequestBody PayChannel payChannel) {
|
||||
payChannelService.updateById(payChannel);
|
||||
redisTemplate.convertAndSend(CacheConstants.PAY_REDIS_RELOAD_TOPIC, "重新加载支付参数");
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@@ -105,7 +106,6 @@ public class PayChannelController {
|
||||
@PreAuthorize("@pms.hasPermission('pay_paychannel_del')")
|
||||
public R removeById(@PathVariable Integer id) {
|
||||
payChannelService.removeById(id);
|
||||
redisTemplate.convertAndSend(CacheConstants.PAY_REDIS_RELOAD_TOPIC, "重新加载支付参数");
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
+68
-26
@@ -17,24 +17,37 @@
|
||||
|
||||
package com.pig4cloud.pigx.pay.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.http.ContentType;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ijpay.wxpay.WxPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.common.core.util.R;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.common.log.annotation.SysLog;
|
||||
import com.pig4cloud.pigx.common.security.annotation.Inner;
|
||||
import com.pig4cloud.pigx.pay.config.PayConfigParmaInitRunner;
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.service.PayChannelService;
|
||||
import com.pig4cloud.pigx.pay.service.PayGoodsOrderService;
|
||||
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
|
||||
import com.pig4cloud.pigx.pay.utils.PayConstants;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
|
||||
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Controller;
|
||||
@@ -51,6 +64,7 @@ import java.util.Map;
|
||||
* @author lengleng
|
||||
* @date 2019-05-28 23:58:27
|
||||
*/
|
||||
@Slf4j
|
||||
@Controller
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/goods")
|
||||
@@ -59,37 +73,44 @@ public class PayGoodsOrderController {
|
||||
|
||||
private final PayGoodsOrderService payGoodsOrderService;
|
||||
|
||||
private final PayChannelService channelService;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 商品订单
|
||||
*
|
||||
* @param goods 商品
|
||||
* @param goods 商品
|
||||
* @param response
|
||||
*
|
||||
* AliPayApiConfigKit.setAppId WxPayApiConfigKit.setAppId shezhi
|
||||
*
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Inner(false)
|
||||
@GetMapping(value = {"/buy", "/merge/buy"})
|
||||
@GetMapping("/buy")
|
||||
@SysLog("购买商品")
|
||||
public void buy(PayGoodsOrder goods, HttpServletRequest request, HttpServletResponse response) {
|
||||
String ua = request.getHeader(HttpHeaders.USER_AGENT);
|
||||
|
||||
//服务商 模式
|
||||
if ("/goods/merge/buy".equals(request.getRequestURI())) {
|
||||
Map<String, Object> result = payGoodsOrderService.buy(goods, true);
|
||||
response.setContentType(ContentType.JSON.getValue());
|
||||
response.getWriter().print(objectMapper.writeValueAsString(result));
|
||||
return;
|
||||
}
|
||||
log.info("当前扫码方式 UA:{}", ua);
|
||||
|
||||
if (ua.contains(PayConstants.MICRO_MESSENGER)) {
|
||||
String appId = WxPayApiConfigKit.getWxPayApiConfig().getAppId();
|
||||
String wxUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s"
|
||||
+ "&redirect_uri=http%3a%2f%2fadmin.pig4cloud.com%2fpay%2fgoods%2fwx%3famount%3d"
|
||||
+ "%s&response_type=code&scope=snsapi_base&state=";
|
||||
PayChannel channel = channelService.getOne(
|
||||
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.WEIXIN_MP),
|
||||
false);
|
||||
|
||||
response.sendRedirect(String.format(wxUrl, appId, goods.getAmount(), appId));
|
||||
if (channel == null) {
|
||||
throw new IllegalArgumentException("公众号支付配置不存在");
|
||||
}
|
||||
|
||||
String wxUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s"
|
||||
+ "&redirect_uri=%s&response_type=code&scope=snsapi_base&state=%s";
|
||||
|
||||
String redirectUri = String.format("%s/pay/goods/wx?amount=%s&TENANT-ID=%s", channel.getNotifyUrl(),
|
||||
goods.getAmount(), TenantContextHolder.getTenantId());
|
||||
|
||||
response.sendRedirect(
|
||||
String.format(wxUrl, channel.getAppId(), URLUtil.encode(redirectUri), channel.getAppId()));
|
||||
}
|
||||
|
||||
if (ua.contains(PayConstants.ALIPAY)) {
|
||||
@@ -98,12 +119,20 @@ public class PayGoodsOrderController {
|
||||
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Inner(false)
|
||||
@GetMapping("/merge/buy")
|
||||
@SysLog("聚合支付购买商品")
|
||||
public void mergeBuy(PayGoodsOrder goods, HttpServletResponse response) {
|
||||
Map<String, Object> result = payGoodsOrderService.buy(goods, true);
|
||||
response.setContentType(ContentType.JSON.getValue());
|
||||
response.getWriter().print(objectMapper.writeValueAsString(result));
|
||||
}
|
||||
|
||||
/**
|
||||
* oauth
|
||||
*
|
||||
* @param goods 商品信息
|
||||
* @param state appid
|
||||
* @param code 回调code
|
||||
* @param goods 商品信息
|
||||
* @param code 回调code
|
||||
* @param modelAndView
|
||||
* @return
|
||||
* @throws WxErrorException
|
||||
@@ -111,10 +140,23 @@ public class PayGoodsOrderController {
|
||||
@Inner(false)
|
||||
@SneakyThrows
|
||||
@GetMapping("/wx")
|
||||
public ModelAndView wx(PayGoodsOrder goods, String state, String code, ModelAndView modelAndView) {
|
||||
WxMpService wxMpService = PayConfigParmaInitRunner.mpServiceMap.get(state);
|
||||
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
|
||||
goods.setUserId(wxMpOAuth2AccessToken.getOpenId());
|
||||
public ModelAndView wx(PayGoodsOrder goods, String code, ModelAndView modelAndView) {
|
||||
PayChannel channel = channelService.getOne(
|
||||
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.WEIXIN_MP), false);
|
||||
|
||||
if (channel == null) {
|
||||
throw new IllegalArgumentException("公众号支付配置不存在");
|
||||
}
|
||||
|
||||
JSONObject params = JSONUtil.parseObj(channel.getParam());
|
||||
WxMpService wxMpService = new WxMpServiceImpl();
|
||||
WxMpDefaultConfigImpl storage = new WxMpDefaultConfigImpl();
|
||||
storage.setAppId(channel.getAppId());
|
||||
storage.setSecret(params.getStr("secret"));
|
||||
wxMpService.setWxMpConfigStorage(storage);
|
||||
|
||||
WxMpOAuth2AccessToken mpOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
|
||||
goods.setUserId(mpOAuth2AccessToken.getOpenId());
|
||||
goods.setAmount(goods.getAmount());
|
||||
modelAndView.setViewName("pay");
|
||||
modelAndView.addAllObjects(payGoodsOrderService.buy(goods, false));
|
||||
|
||||
+12
-2
@@ -17,6 +17,8 @@
|
||||
|
||||
package com.pig4cloud.pigx.pay.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
@@ -25,8 +27,6 @@ import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 渠道
|
||||
*
|
||||
@@ -67,6 +67,16 @@ public class PayChannel extends Model<PayChannel> {
|
||||
*/
|
||||
private String channelMchId;
|
||||
|
||||
/**
|
||||
* 前端回调地址
|
||||
*/
|
||||
private String returnUrl;
|
||||
|
||||
/**
|
||||
* 后端回调地址
|
||||
*/
|
||||
private String notifyUrl;
|
||||
|
||||
/**
|
||||
* 渠道状态
|
||||
*/
|
||||
|
||||
+8
@@ -1,5 +1,6 @@
|
||||
package com.pig4cloud.pigx.pay.handler;
|
||||
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
|
||||
|
||||
@@ -11,6 +12,13 @@ import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
|
||||
*/
|
||||
public interface PayOrderHandler {
|
||||
|
||||
/**
|
||||
* 准备支付参数
|
||||
*/
|
||||
default PayChannel preparePayParams() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建商品订单
|
||||
* @param goodsOrder 金额
|
||||
|
||||
+7
@@ -18,10 +18,12 @@
|
||||
package com.pig4cloud.pigx.pay.handler.impl;
|
||||
|
||||
import com.pig4cloud.pigx.common.sequence.sequence.Sequence;
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
|
||||
import com.pig4cloud.pigx.pay.handler.PayOrderHandler;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayGoodsOrderMapper;
|
||||
import com.pig4cloud.pigx.pay.utils.ChannelPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.pay.utils.OrderStatusEnum;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@@ -55,10 +57,15 @@ public abstract class AbstractPayOrderHandler implements PayOrderHandler {
|
||||
*/
|
||||
@Override
|
||||
public Object handle(PayGoodsOrder payGoodsOrder) {
|
||||
PayChannel payChannel = preparePayParams();
|
||||
ChannelPayApiConfigKit.put(payChannel);
|
||||
|
||||
createGoodsOrder(payGoodsOrder);
|
||||
PayTradeOrder tradeOrder = createTradeOrder(payGoodsOrder);
|
||||
Object result = pay(payGoodsOrder, tradeOrder);
|
||||
updateOrder(payGoodsOrder, tradeOrder);
|
||||
// 情况ttl
|
||||
ChannelPayApiConfigKit.remove();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+3
-29
@@ -17,15 +17,12 @@
|
||||
|
||||
package com.pig4cloud.pigx.pay.handler.impl;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.internal.util.AlipaySignature;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ijpay.alipay.AliPayApiConfig;
|
||||
import com.ijpay.alipay.AliPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayNotifyRecord;
|
||||
@@ -40,8 +37,6 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-06-27
|
||||
@@ -100,28 +95,7 @@ public class AlipayPayNotifyCallbackHandler extends AbstractPayNotifyCallbakHand
|
||||
*/
|
||||
@Override
|
||||
public Boolean verifyNotify(Map<String, String> params) {
|
||||
String callReq = MapUtil.join(params, StrUtil.DASHED, StrUtil.DASHED);
|
||||
log.info("支付宝发起回调 报文: {}", callReq);
|
||||
String appId = params.get("app_id");
|
||||
|
||||
if (StrUtil.isBlank(appId)) {
|
||||
log.warn("支付宝回调报文 appid 为空 {}", callReq);
|
||||
return false;
|
||||
}
|
||||
|
||||
AliPayApiConfig apiConfig = AliPayApiConfigKit.getApiConfig(appId);
|
||||
if (apiConfig == null) {
|
||||
log.warn("支付宝回调报文 appid 不合法 {}", callReq);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return AlipaySignature.rsaCheckV1(params, apiConfig.getAliPayPublicKey(), CharsetUtil.UTF_8, "RSA2");
|
||||
}
|
||||
catch (AlipayApiException e) {
|
||||
log.error("支付宝验签失败", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+41
-11
@@ -17,28 +17,36 @@
|
||||
|
||||
package com.pig4cloud.pigx.pay.handler.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.domain.AlipayTradeWapPayModel;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ijpay.alipay.AliPayApi;
|
||||
import com.ijpay.alipay.AliPayApiConfig;
|
||||
import com.ijpay.alipay.AliPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.pay.config.PayCommonProperties;
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayChannelMapper;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayGoodsOrderMapper;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayTradeOrderMapper;
|
||||
import com.pig4cloud.pigx.pay.utils.ChannelPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.pay.utils.OrderStatusEnum;
|
||||
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-05-31
|
||||
@@ -50,16 +58,37 @@ import java.io.IOException;
|
||||
@AllArgsConstructor
|
||||
public class AlipayWapPayOrderHandler extends AbstractPayOrderHandler {
|
||||
|
||||
private final PayCommonProperties payCommonProperties;
|
||||
|
||||
private final PayTradeOrderMapper tradeOrderMapper;
|
||||
|
||||
private final PayGoodsOrderMapper goodsOrderMapper;
|
||||
|
||||
private final PayChannelMapper channelMapper;
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private final HttpServletResponse response;
|
||||
|
||||
/**
|
||||
* 准备支付参数
|
||||
*/
|
||||
@Override
|
||||
public PayChannel preparePayParams() {
|
||||
PayChannel channel = channelMapper.selectOne(
|
||||
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.ALIPAY_WAP.name()));
|
||||
|
||||
if (channel == null) {
|
||||
throw new IllegalArgumentException("支付宝网页支付渠道配置为空");
|
||||
}
|
||||
|
||||
JSONObject params = JSONUtil.parseObj(channel.getParam());
|
||||
AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder().setAppId(channel.getAppId())
|
||||
.setPrivateKey(params.getStr("privateKey")).setCharset(CharsetUtil.UTF_8)
|
||||
.setAliPayPublicKey(params.getStr("publicKey")).setServiceUrl(params.getStr("serviceUrl"))
|
||||
.setSignType("RSA2").build();
|
||||
AliPayApiConfigKit.putApiConfig(aliPayApiConfig);
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建交易订单
|
||||
* @param goodsOrder
|
||||
@@ -74,7 +103,7 @@ public class AlipayWapPayOrderHandler extends AbstractPayOrderHandler {
|
||||
tradeOrder.setChannelMchId(AliPayApiConfigKit.getAliPayApiConfig().getAppId());
|
||||
tradeOrder.setClientIp(ServletUtil.getClientIP(request));
|
||||
tradeOrder.setCurrency("cny");
|
||||
tradeOrder.setExpireTime(Long.parseLong(payCommonProperties.getAliPayConfig().getExpireTime()));
|
||||
tradeOrder.setExpireTime(30L);
|
||||
tradeOrder.setStatus(OrderStatusEnum.INIT.getStatus());
|
||||
tradeOrder.setBody(goodsOrder.getGoodsName());
|
||||
tradeOrderMapper.insert(tradeOrder);
|
||||
@@ -92,15 +121,16 @@ public class AlipayWapPayOrderHandler extends AbstractPayOrderHandler {
|
||||
model.setBody(tradeOrder.getBody());
|
||||
model.setSubject(tradeOrder.getBody());
|
||||
model.setOutTradeNo(tradeOrder.getOrderId());
|
||||
model.setTimeoutExpress(payCommonProperties.getAliPayConfig().getExpireTime() + "m");
|
||||
model.setTimeoutExpress("30m");
|
||||
|
||||
// 分转成元 并且保留两位
|
||||
model.setTotalAmount(NumberUtil.div(tradeOrder.getAmount(), "100", 2).toString());
|
||||
model.setProductCode(goodsOrder.getGoodsId());
|
||||
model.setPassbackParams(String.valueOf(TenantContextHolder.getTenantId()));
|
||||
try {
|
||||
AliPayApi.wapPay(response, model, payCommonProperties.getAliPayConfig().getReturnUrl(),
|
||||
payCommonProperties.getAliPayConfig().getNotifyUrl());
|
||||
log.info("拉起支付宝wap 支付参数 {}", model);
|
||||
AliPayApi.wapPay(response, model, ChannelPayApiConfigKit.get().getReturnUrl(),
|
||||
ChannelPayApiConfigKit.get().getNotifyUrl() + "/pay/notify/ali/callbak");
|
||||
}
|
||||
catch (AlipayApiException e) {
|
||||
log.error("支付宝手机支付失败", e);
|
||||
|
||||
+35
-5
@@ -17,7 +17,14 @@
|
||||
|
||||
package com.pig4cloud.pigx.pay.handler.impl;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.enums.TradeType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
@@ -26,11 +33,13 @@ import com.ijpay.wxpay.WxPayApiConfig;
|
||||
import com.ijpay.wxpay.WxPayApiConfigKit;
|
||||
import com.ijpay.wxpay.model.UnifiedOrderModel;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.pay.config.PayCommonProperties;
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayChannelMapper;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayGoodsOrderMapper;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayTradeOrderMapper;
|
||||
import com.pig4cloud.pigx.pay.utils.ChannelPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.pay.utils.OrderStatusEnum;
|
||||
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -51,14 +60,35 @@ import java.util.Map;
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatMpPayOrderHandler extends AbstractPayOrderHandler {
|
||||
|
||||
private final PayCommonProperties payCommonProperties;
|
||||
|
||||
private final PayTradeOrderMapper tradeOrderMapper;
|
||||
|
||||
private final PayGoodsOrderMapper goodsOrderMapper;
|
||||
|
||||
private final PayChannelMapper channelMapper;
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* 准备支付参数
|
||||
* @return PayChannel
|
||||
*/
|
||||
@Override
|
||||
public PayChannel preparePayParams() {
|
||||
PayChannel channel = channelMapper.selectOne(
|
||||
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.WEIXIN_MP.name()));
|
||||
|
||||
if (channel == null) {
|
||||
throw new IllegalArgumentException("微信公众号支付渠道配置为空");
|
||||
}
|
||||
|
||||
JSONObject params = JSONUtil.parseObj(channel.getParam());
|
||||
WxPayApiConfig wx = WxPayApiConfig.builder().appId(channel.getAppId()).mchId(channel.getChannelMchId())
|
||||
.partnerKey(params.getStr("partnerKey")).build();
|
||||
|
||||
WxPayApiConfigKit.putApiConfig(wx);
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建交易订单
|
||||
* @param goodsOrder
|
||||
@@ -94,12 +124,12 @@ public class WeChatMpPayOrderHandler extends AbstractPayOrderHandler {
|
||||
.mch_id(wxPayApiConfig.getMchId()).nonce_str(WxPayKit.generateStr()).body(goodsOrder.getGoodsName())
|
||||
.attach(TenantContextHolder.getTenantId().toString()).out_trade_no(tradeOrder.getOrderId())
|
||||
.total_fee(goodsOrder.getAmount()).spbill_create_ip(ip)
|
||||
.notify_url(payCommonProperties.getWxPayConfig().getNotifyUrl())
|
||||
.notify_url(ChannelPayApiConfigKit.get().getNotifyUrl() + "/pay/notify/wx/callbak")
|
||||
.trade_type(TradeType.JSAPI.getTradeType()).openid(goodsOrder.getUserId()).build()
|
||||
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
|
||||
|
||||
String xmlResult = WxPayApi.pushOrder(false, params);
|
||||
log.info(xmlResult);
|
||||
log.info("微信统一下单返回 {}", xmlResult);
|
||||
Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);
|
||||
String prepayId = resultMap.get("prepay_id");
|
||||
return WxPayKit.prepayIdCreateSign(prepayId, wxPayApiConfig.getAppId(), wxPayApiConfig.getPartnerKey(),
|
||||
|
||||
+3
-9
@@ -17,11 +17,13 @@
|
||||
|
||||
package com.pig4cloud.pigx.pay.handler.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import com.ijpay.wxpay.WxPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayNotifyRecord;
|
||||
@@ -36,9 +38,6 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-06-27
|
||||
@@ -91,11 +90,6 @@ public class WeChatPayNotifyCallbackHandler extends AbstractPayNotifyCallbakHand
|
||||
*/
|
||||
@Override
|
||||
public Boolean verifyNotify(Map<String, String> params) {
|
||||
if (!WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getApiKey())) {
|
||||
log.warn("微信支付回调验签失败", params);
|
||||
return null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayNotifyRecord;
|
||||
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
|
||||
@@ -46,7 +47,8 @@ public class YungouosMergePayNotifyCallbakHandler extends AbstractPayNotifyCallb
|
||||
*/
|
||||
@Override
|
||||
public void before(Map<String, String> params) {
|
||||
|
||||
Integer tenant = MapUtil.getInt(params, "attach");
|
||||
TenantContextHolder.setTenantId(tenant);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+28
-9
@@ -1,13 +1,18 @@
|
||||
package com.pig4cloud.pigx.pay.handler.impl;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.ijpay.wxpay.WxPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.pay.config.PayCommonProperties;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
|
||||
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayChannelMapper;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayGoodsOrderMapper;
|
||||
import com.pig4cloud.pigx.pay.mapper.PayTradeOrderMapper;
|
||||
import com.pig4cloud.pigx.pay.utils.ChannelPayApiConfigKit;
|
||||
import com.pig4cloud.pigx.pay.utils.OrderStatusEnum;
|
||||
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
|
||||
import com.yungouos.pay.merge.MergePay;
|
||||
@@ -15,8 +20,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2021/1/4
|
||||
@@ -29,17 +32,32 @@ import javax.servlet.http.HttpServletRequest;
|
||||
@RequiredArgsConstructor
|
||||
public class YungouosMergePayOrderHandler extends AbstractPayOrderHandler {
|
||||
|
||||
private final PayCommonProperties commonProperties;
|
||||
|
||||
private final PayTradeOrderMapper tradeOrderMapper;
|
||||
|
||||
private final PayGoodsOrderMapper goodsOrderMapper;
|
||||
|
||||
private final PayChannelMapper channelMapper;
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* 准备支付参数
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public PayChannel preparePayParams() {
|
||||
PayChannel channel = channelMapper.selectOne(
|
||||
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.MERGE_PAY.name()));
|
||||
|
||||
if (channel == null) {
|
||||
throw new IllegalArgumentException("聚合支付渠道配置为空");
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建交易订单
|
||||
*
|
||||
* @param goodsOrder 商品订单
|
||||
* @return
|
||||
*/
|
||||
@@ -49,7 +67,7 @@ public class YungouosMergePayOrderHandler extends AbstractPayOrderHandler {
|
||||
tradeOrder.setOrderId(goodsOrder.getPayOrderId());
|
||||
tradeOrder.setAmount(goodsOrder.getAmount());
|
||||
tradeOrder.setChannelId(PayChannelNameEnum.MERGE_PAY.getName());
|
||||
tradeOrder.setChannelMchId(WxPayApiConfigKit.getWxPayApiConfig().getMchId());
|
||||
tradeOrder.setChannelMchId(ChannelPayApiConfigKit.get().getChannelMchId());
|
||||
tradeOrder.setClientIp(ServletUtil.getClientIP(request));
|
||||
tradeOrder.setCurrency("CNY");
|
||||
tradeOrder.setStatus(OrderStatusEnum.INIT.getStatus());
|
||||
@@ -60,13 +78,14 @@ public class YungouosMergePayOrderHandler extends AbstractPayOrderHandler {
|
||||
|
||||
/**
|
||||
* 调起渠道支付
|
||||
*
|
||||
* @param goodsOrder 商品订单
|
||||
* @param tradeOrder 交易订单
|
||||
* @return obj
|
||||
*/
|
||||
@Override
|
||||
public Object pay(PayGoodsOrder goodsOrder, PayTradeOrder tradeOrder) {
|
||||
PayChannel channel = ChannelPayApiConfigKit.get();
|
||||
|
||||
String money = NumberUtil.div(tradeOrder.getAmount(), "100", 2).toString();
|
||||
return MergePay.nativePay(tradeOrder.getOrderId(), money, "100106279016"
|
||||
, tradeOrder.getBody()
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.pig4cloud.pigx.pay.utils;
|
||||
|
||||
import com.pig4cloud.pigx.pay.entity.PayChannel;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2021/2/2
|
||||
*
|
||||
* 聚合支付配置管理
|
||||
*/
|
||||
@UtilityClass
|
||||
public class ChannelPayApiConfigKit {
|
||||
|
||||
private static final ThreadLocal<PayChannel> TL = new ThreadLocal();
|
||||
|
||||
public PayChannel get() {
|
||||
return TL.get();
|
||||
}
|
||||
|
||||
public void put(PayChannel channel) {
|
||||
TL.set(channel);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
TL.remove();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user