mirror of
https://gitee.com/egzosn/pay-java-parent.git
synced 2026-05-13 09:18:37 +08:00
Merge remote-tracking branch 'origin/develop' into develop
# Conflicts: # pay-java-demo/src/main/java/in/egan/pay/demo/controller/PayController.java
This commit is contained in:
@@ -1,381 +1,396 @@
|
||||
|
||||
### 快速入门
|
||||
#####1.支付整合配置
|
||||
```java
|
||||
|
||||
|
||||
/**
|
||||
* 支付类型
|
||||
* @author egan
|
||||
* @email egzosn@gmail.com
|
||||
* @date 2016/11/20 0:30
|
||||
*/
|
||||
public enum PayType implements BasePayType{
|
||||
aliPay{
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage();
|
||||
aliPayConfigStorage.setPartner(apyAccount.getPartner());
|
||||
aliPayConfigStorage.setAliPublicKey(apyAccount.getPublicKey());
|
||||
aliPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
aliPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
aliPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
|
||||
aliPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
aliPayConfigStorage.setSeller(apyAccount.getSeller());
|
||||
aliPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
aliPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
aliPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new AliPayService(aliPayConfigStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
return AliTransactionType.valueOf(transactionType);
|
||||
}
|
||||
|
||||
|
||||
},wxPay {
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage();
|
||||
wxPayConfigStorage.setMchId(apyAccount.getPartner());
|
||||
wxPayConfigStorage.setAppSecret(apyAccount.getPublicKey());
|
||||
wxPayConfigStorage.setKeyPublic(apyAccount.getPublicKey());
|
||||
wxPayConfigStorage.setAppid(apyAccount.getAppid());
|
||||
wxPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
wxPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
wxPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
wxPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
wxPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
wxPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new WxPayService(wxPayConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型获取交易类型
|
||||
* @param transactionType 类型值
|
||||
* @see WxTransactionType
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
|
||||
return WxTransactionType.valueOf(transactionType);
|
||||
}
|
||||
},youdianPay {
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
// TODO 2017/1/23 14:12 author: egan 集群的话,友店可能会有bug。暂未测试集群环境
|
||||
WxYouDianPayConfigStorage wxPayConfigStorage = new WxYouDianPayConfigStorage();
|
||||
wxPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
wxPayConfigStorage.setKeyPublic(apyAccount.getPublicKey());
|
||||
// wxPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
// wxPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
|
||||
wxPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
wxPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
wxPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
wxPayConfigStorage.setSeller(apyAccount.getSeller());
|
||||
wxPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new WxYouDianPayService(wxPayConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型获取交易类型
|
||||
* @param transactionType 类型值
|
||||
* @see YoudianTransactionType
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
|
||||
return YoudianTransactionType.valueOf(transactionType);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract PayService getPayService(ApyAccount apyAccount);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付响应对象
|
||||
* @author: egan
|
||||
* @email egzosn@gmail.com
|
||||
* @date 2016/11/18 0:34
|
||||
*/
|
||||
public class PayResponse {
|
||||
@Resource
|
||||
private AutowireCapableBeanFactory spring;
|
||||
|
||||
private PayConfigStorage storage;
|
||||
|
||||
private PayService service;
|
||||
|
||||
private PayMessageRouter router;
|
||||
|
||||
public PayResponse() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化支付配置
|
||||
* @param apyAccount 账户信息
|
||||
* @see ApyAccount 对应表结构详情--》 pay-java-demo/resources/apy_account.sql
|
||||
*/
|
||||
public void init(ApyAccount apyAccount) {
|
||||
|
||||
//根据不同的账户类型 初始化支付配置
|
||||
this.service = apyAccount.getPayType().getPayService(apyAccount);
|
||||
this.storage = service.getPayConfigStorage();
|
||||
|
||||
buildRouter(apyAccount.getPayId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 配置路由
|
||||
* @param payId 指定账户id,用户多微信支付多支付宝支付
|
||||
*/
|
||||
private void buildRouter(Integer payId) {
|
||||
router = new PayMessageRouter(this.service);
|
||||
router
|
||||
.rule()
|
||||
.async(false)
|
||||
.msgType(MsgType.text.name()) //消息类型
|
||||
.event(PayType.aliPay.name()) //支付账户事件类型
|
||||
.interceptor(new AliPayMessageInterceptor()) //拦截器
|
||||
.handler(autowire(new AliPayMessageHandler(payId))) //处理器
|
||||
.end()
|
||||
.rule()
|
||||
.async(false)
|
||||
.msgType(MsgType.xml.name())
|
||||
.event(PayType.wxPay.name())
|
||||
.handler(autowire(new WxPayMessageHandler(payId)))
|
||||
.end()
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
private PayMessageHandler autowire(PayMessageHandler handler) {
|
||||
spring.autowireBean(handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
public PayConfigStorage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public PayService getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
public PayMessageRouter getRouter() {
|
||||
return router;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#####2.支付处理器与拦截器简单实现
|
||||
|
||||
```java
|
||||
/**
|
||||
* 微信支付回调处理器
|
||||
* Created by ZaoSheng on 2016/6/1.
|
||||
*/
|
||||
public class WxPayMessageHandler extends BasePayMessageHandler {
|
||||
public WxPayMessageHandler(Integer payId) {
|
||||
super(payId);
|
||||
}
|
||||
@Override
|
||||
public PayOutMessage handle(PayMessage payMessage, Map<String, Object> context, PayService payService) throws PayErrorException {
|
||||
//交易状态
|
||||
if ("SUCCESS".equals(payMessage.getPayMessage().get("result_code"))){
|
||||
/////这里进行成功的处理
|
||||
|
||||
return payService.getPayOutMessage("SUCCESS", "OK");
|
||||
}
|
||||
|
||||
return payService.getPayOutMessage("FAIL", "失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付宝回调信息拦截器
|
||||
* @author: egan
|
||||
* @email egzosn@gmail.com
|
||||
* @date 2017/1/18 19:28
|
||||
*/
|
||||
public class AliPayMessageInterceptor implements PayMessageInterceptor {
|
||||
/**
|
||||
* 拦截支付消息
|
||||
*
|
||||
* @param payMessage 支付回调消息
|
||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
|
||||
* @param payService
|
||||
* @return true代表OK,false代表不OK并直接中断对应的支付处理器
|
||||
* @see PayMessageHandler 支付处理器
|
||||
*/
|
||||
@Override
|
||||
public boolean intercept(PayMessage payMessage, Map<String, Object> context, PayService payService) throws PayErrorException {
|
||||
|
||||
//这里进行拦截器处理,自行实现
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
#####3.支付响应PayResponse的获取
|
||||
|
||||
|
||||
```java
|
||||
|
||||
|
||||
public class ApyAccountService {
|
||||
|
||||
|
||||
@Inject
|
||||
private ApyAccountDao dao;
|
||||
|
||||
@Inject
|
||||
private AutowireCapableBeanFactory spring;
|
||||
|
||||
private final static Map<Integer, PayResponse> payResponses = new HashMap<Integer, PayResponse>();
|
||||
|
||||
|
||||
/**
|
||||
* 获取支付响应
|
||||
* @param id 账户id
|
||||
* @return
|
||||
*/
|
||||
public PayResponse getPayResponse(Integer id) {
|
||||
|
||||
PayResponse payResponse = payResponses.get(id);
|
||||
if (payResponse == null) {
|
||||
ApyAccount apyAccount = dao.get(id);
|
||||
if (apyAccount == null) {
|
||||
throw new IllegalArgumentException ("无法查询");
|
||||
}
|
||||
payResponse = new PayResponse();
|
||||
spring.autowireBean(payResponse);
|
||||
payResponse.init(apyAccount);
|
||||
payResponses.put(id, payResponse);
|
||||
// 查询
|
||||
}
|
||||
return payResponse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
#####4.根据账户id与业务id,组拼订单信息(支付宝、微信支付订单)获取支付信息所需的数据
|
||||
|
||||
```java
|
||||
|
||||
/**
|
||||
* 跳到支付页面
|
||||
* 针对实时支付,即时付款
|
||||
*
|
||||
* @param payId 账户id
|
||||
* @param transactionType 交易类型, 这个针对于每一个 支付类型的对应的几种交易方式
|
||||
* @param bankType 针对刷卡支付,卡的类型,类型值
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "toPay.html", produces = "text/html;charset=UTF-8")
|
||||
public String toPay( Integer payId, String transactionType, String bankType, BigDecimal price) {
|
||||
//获取对应的支付账户操作工具(可根据账户id)
|
||||
PayResponse payResponse = service.getPayResponse(payId);
|
||||
|
||||
PayOrder order = new PayOrder("订单title", "摘要", null == price ? new BigDecimal(0.01) : price, UUID.randomUUID().toString().replace("-", ""), PayType.valueOf(payResponse.getStorage().getPayType()).getTransactionType(transactionType));
|
||||
|
||||
//此处只有刷卡支付(银行卡支付)时需要
|
||||
if (StringUtils.isNotEmpty(bankType)){
|
||||
order.setBankType(bankType);
|
||||
}
|
||||
Map orderInfo = payResponse.getService().orderInfo(order);
|
||||
return payResponse.getService().buildRequest(orderInfo, MethodType.POST);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取二维码图像
|
||||
* 二维码支付
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "toQrPay.jpg", produces = "image/jpeg;charset=UTF-8")
|
||||
public byte[] toWxQrPay(Integer payId, String transactionType, BigDecimal price) throws IOException {
|
||||
//获取对应的支付账户操作工具(可根据账户id)
|
||||
PayResponse payResponse = service.getPayResponse(payId);
|
||||
//获取订单信息
|
||||
Map<String, Object> orderInfo = payResponse.getService().orderInfo(new PayOrder("订单title", "摘要", null == price ? new BigDecimal(0.01) : price, UUID.randomUUID().toString().replace("-", ""), PayType.valueOf(payResponse.getStorage().getPayType()).getTransactionType(transactionType)));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(payResponse.getService().genQrPay(orderInfo), "JPEG", baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 获取支付预订单信息
|
||||
* @param payId 支付账户id
|
||||
* @param transactionType 交易类型
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("getOrderInfo")
|
||||
public Map<String, Object> getOrderInfo(Integer payId, String transactionType, BigDecimal price){
|
||||
//获取对应的支付账户操作工具(可根据账户id)
|
||||
PayResponse payResponse = service.getPayResponse(payId);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("code", 0);
|
||||
PayOrder order = new PayOrder("订单title", "摘要", null == price ? new BigDecimal(0.01) : price, UUID.randomUUID().toString().replace("-", ""), PayType.valueOf(payResponse.getStorage().getPayType()).getTransactionType(transactionType));
|
||||
data.put("orderInfo", payResponse.getService().orderInfo(order));
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
#####5.支付回调
|
||||
```java
|
||||
|
||||
|
||||
/**
|
||||
* 支付回调地址
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "payBack{payId}.json")
|
||||
public String payBack(HttpServletRequest request, @PathVariable Integer payId) throws IOException {
|
||||
//根据账户id,获取对应的支付账户操作工具
|
||||
PayResponse payResponse = service.getPayResponse(payId);
|
||||
PayConfigStorage storage = payResponse.getStorage();
|
||||
//获取支付方返回的对应参数
|
||||
Map<String, String> params = payResponse.getService().getParameter2Map(request.getParameterMap(), request.getInputStream());
|
||||
if (null == params){
|
||||
return payResponse.getService().getPayOutMessage("fail","失败").toMessage();
|
||||
}
|
||||
|
||||
//校验
|
||||
if (payResponse.getService().verify(params)){
|
||||
PayMessage message = new PayMessage(params, storage.getPayType(), storage.getMsgType().name());
|
||||
PayOutMessage outMessage = payResponse.getRouter().route(message);
|
||||
return outMessage.toMessage();
|
||||
}
|
||||
|
||||
return payResponse.getService().getPayOutMessage("fail","失败").toMessage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
### 快速入门
|
||||
#####1.支付整合配置
|
||||
```java
|
||||
|
||||
|
||||
/**
|
||||
* 支付类型
|
||||
* @author egan
|
||||
* @email egzosn@gmail.com
|
||||
* @date 2016/11/20 0:30
|
||||
*/
|
||||
public enum PayType implements BasePayType {
|
||||
|
||||
aliPay{
|
||||
/**
|
||||
* @see in.egan.pay.ali.before.api.AliPayService 支付宝暂时请用这个2016年版本的,17年更新的版本暂时未进行测试,开发者可自行测试,可以的话反馈到我这边
|
||||
* @param apyAccount
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage();
|
||||
aliPayConfigStorage.setPid(apyAccount.getPartner());
|
||||
aliPayConfigStorage.setAppId(apyAccount.getAppid());
|
||||
aliPayConfigStorage.setAliPublicKey(apyAccount.getPublicKey());
|
||||
aliPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
aliPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
aliPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
|
||||
aliPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
aliPayConfigStorage.setSeller(apyAccount.getSeller());
|
||||
aliPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
aliPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
aliPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new AliPayService(aliPayConfigStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
// in.egan.pay.ali.before.bean.AliTransactionType 支付宝暂时用2016年版本的,17年更新的版本暂时未进行测试,开发者可自行测试,可以的话反馈到我这边
|
||||
return AliTransactionType.valueOf(transactionType);
|
||||
}
|
||||
|
||||
|
||||
},wxPay {
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage();
|
||||
wxPayConfigStorage.setMchId(apyAccount.getPartner());
|
||||
wxPayConfigStorage.setAppSecret(apyAccount.getPublicKey());
|
||||
wxPayConfigStorage.setKeyPublic(apyAccount.getPublicKey());
|
||||
wxPayConfigStorage.setAppid(apyAccount.getAppid());
|
||||
wxPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
wxPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
wxPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
wxPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
wxPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
wxPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new WxPayService(wxPayConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型获取交易类型
|
||||
* @param transactionType 类型值
|
||||
* @see WxTransactionType
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
|
||||
return WxTransactionType.valueOf(transactionType);
|
||||
}
|
||||
},youdianPay {
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
// TODO 2017/1/23 14:12 author: egan 集群的话,友店可能会有bug。暂未测试集群环境
|
||||
WxYouDianPayConfigStorage wxPayConfigStorage = new WxYouDianPayConfigStorage();
|
||||
wxPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
wxPayConfigStorage.setKeyPublic(apyAccount.getPublicKey());
|
||||
// wxPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
// wxPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
|
||||
wxPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
wxPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
wxPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
wxPayConfigStorage.setSeller(apyAccount.getSeller());
|
||||
wxPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new WxYouDianPayService(wxPayConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型获取交易类型
|
||||
* @param transactionType 类型值
|
||||
* @see YoudianTransactionType
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
|
||||
return YoudianTransactionType.valueOf(transactionType);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract PayService getPayService(ApyAccount apyAccount);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付响应对象
|
||||
* @author: egan
|
||||
* @email egzosn@gmail.com
|
||||
* @date 2016/11/18 0:34
|
||||
*/
|
||||
public class PayResponse {
|
||||
@Resource
|
||||
private AutowireCapableBeanFactory spring;
|
||||
|
||||
private PayConfigStorage storage;
|
||||
|
||||
private PayService service;
|
||||
|
||||
private PayMessageRouter router;
|
||||
|
||||
public PayResponse() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化支付配置
|
||||
* @param apyAccount 账户信息
|
||||
* @see ApyAccount 对应表结构详情--》 pay-java-demo/resources/apy_account.sql
|
||||
*/
|
||||
public void init(ApyAccount apyAccount) {
|
||||
|
||||
//根据不同的账户类型 初始化支付配置
|
||||
this.service = apyAccount.getPayType().getPayService(apyAccount);
|
||||
this.storage = service.getPayConfigStorage();
|
||||
|
||||
buildRouter(apyAccount.getPayId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 配置路由
|
||||
* @param payId 指定账户id,用户多微信支付多支付宝支付
|
||||
*/
|
||||
private void buildRouter(Integer payId) {
|
||||
router = new PayMessageRouter(this.service);
|
||||
router
|
||||
.rule()
|
||||
.async(false)
|
||||
.msgType(MsgType.text.name()) //消息类型
|
||||
.payType(PayType.aliPay.name()) //支付账户事件类型
|
||||
.transactionType(AliTransactionType.UNAWARE.name())//交易类型,有关回调的可在这处理
|
||||
.interceptor(new AliPayMessageInterceptor(payId)) //拦截器
|
||||
.handler(autowire(new AliPayMessageHandler(payId))) //处理器
|
||||
.end()
|
||||
.rule()
|
||||
.async(false)
|
||||
.msgType(MsgType.xml.name())
|
||||
.payType(PayType.wxPay.name())
|
||||
.handler(autowire(new WxPayMessageHandler(payId)))
|
||||
.end()
|
||||
.rule()
|
||||
.async(false)
|
||||
.msgType(MsgType.json.name())
|
||||
.payType(PayType.youdianPay.name())
|
||||
.handler(autowire(new YouDianPayMessageHandler(payId)))
|
||||
.end()
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
private PayMessageHandler autowire(PayMessageHandler handler) {
|
||||
spring.autowireBean(handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
public PayConfigStorage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public PayService getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
public PayMessageRouter getRouter() {
|
||||
return router;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#####2.支付处理器与拦截器简单实现
|
||||
|
||||
```java
|
||||
/**
|
||||
* 微信支付回调处理器
|
||||
* Created by ZaoSheng on 2016/6/1.
|
||||
*/
|
||||
public class WxPayMessageHandler extends BasePayMessageHandler {
|
||||
public WxPayMessageHandler(Integer payId) {
|
||||
super(payId);
|
||||
}
|
||||
@Override
|
||||
public PayOutMessage handle(PayMessage payMessage, Map<String, Object> context, PayService payService) throws PayErrorException {
|
||||
//交易状态
|
||||
if ("SUCCESS".equals(payMessage.getPayMessage().get("result_code"))){
|
||||
/////这里进行成功的处理
|
||||
|
||||
return payService.getPayOutMessage("SUCCESS", "OK");
|
||||
}
|
||||
|
||||
return payService.getPayOutMessage("FAIL", "失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付宝回调信息拦截器
|
||||
* @author: egan
|
||||
* @email egzosn@gmail.com
|
||||
* @date 2017/1/18 19:28
|
||||
*/
|
||||
public class AliPayMessageInterceptor implements PayMessageInterceptor {
|
||||
/**
|
||||
* 拦截支付消息
|
||||
*
|
||||
* @param payMessage 支付回调消息
|
||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
|
||||
* @param payService
|
||||
* @return true代表OK,false代表不OK并直接中断对应的支付处理器
|
||||
* @see PayMessageHandler 支付处理器
|
||||
*/
|
||||
@Override
|
||||
public boolean intercept(PayMessage payMessage, Map<String, Object> context, PayService payService) throws PayErrorException {
|
||||
|
||||
//这里进行拦截器处理,自行实现
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
#####3.支付响应PayResponse的获取
|
||||
|
||||
|
||||
```java
|
||||
|
||||
|
||||
public class ApyAccountService {
|
||||
|
||||
|
||||
@Inject
|
||||
private ApyAccountDao dao;
|
||||
|
||||
@Inject
|
||||
private AutowireCapableBeanFactory spring;
|
||||
|
||||
private final static Map<Integer, PayResponse> payResponses = new HashMap<Integer, PayResponse>();
|
||||
|
||||
|
||||
/**
|
||||
* 获取支付响应
|
||||
* @param id 账户id
|
||||
* @return
|
||||
*/
|
||||
public PayResponse getPayResponse(Integer id) {
|
||||
|
||||
PayResponse payResponse = payResponses.get(id);
|
||||
if (payResponse == null) {
|
||||
ApyAccount apyAccount = dao.get(id);
|
||||
if (apyAccount == null) {
|
||||
throw new IllegalArgumentException ("无法查询");
|
||||
}
|
||||
payResponse = new PayResponse();
|
||||
spring.autowireBean(payResponse);
|
||||
payResponse.init(apyAccount);
|
||||
payResponses.put(id, payResponse);
|
||||
// 查询
|
||||
}
|
||||
return payResponse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
#####4.根据账户id与业务id,组拼订单信息(支付宝、微信支付订单)获取支付信息所需的数据
|
||||
|
||||
```java
|
||||
|
||||
/**
|
||||
* 跳到支付页面
|
||||
* 针对实时支付,即时付款
|
||||
*
|
||||
* @param payId 账户id
|
||||
* @param transactionType 交易类型, 这个针对于每一个 支付类型的对应的几种交易方式
|
||||
* @param bankType 针对刷卡支付,卡的类型,类型值
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "toPay.html", produces = "text/html;charset=UTF-8")
|
||||
public String toPay( Integer payId, String transactionType, String bankType, BigDecimal price) {
|
||||
//获取对应的支付账户操作工具(可根据账户id)
|
||||
PayResponse payResponse = service.getPayResponse(payId);
|
||||
|
||||
PayOrder order = new PayOrder("订单title", "摘要", null == price ? new BigDecimal(0.01) : price, UUID.randomUUID().toString().replace("-", ""), PayType.valueOf(payResponse.getStorage().getPayType()).getTransactionType(transactionType));
|
||||
|
||||
//此处只有刷卡支付(银行卡支付)时需要
|
||||
if (StringUtils.isNotEmpty(bankType)){
|
||||
order.setBankType(bankType);
|
||||
}
|
||||
Map orderInfo = payResponse.getService().orderInfo(order);
|
||||
return payResponse.getService().buildRequest(orderInfo, MethodType.POST);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取二维码图像
|
||||
* 二维码支付
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "toQrPay.jpg", produces = "image/jpeg;charset=UTF-8")
|
||||
public byte[] toWxQrPay(Integer payId, String transactionType, BigDecimal price) throws IOException {
|
||||
//获取对应的支付账户操作工具(可根据账户id)
|
||||
PayResponse payResponse = service.getPayResponse(payId);
|
||||
//获取订单信息
|
||||
Map<String, Object> orderInfo = payResponse.getService().orderInfo(new PayOrder("订单title", "摘要", null == price ? new BigDecimal(0.01) : price, UUID.randomUUID().toString().replace("-", ""), PayType.valueOf(payResponse.getStorage().getPayType()).getTransactionType(transactionType)));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(payResponse.getService().genQrPay(orderInfo), "JPEG", baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 获取支付预订单信息
|
||||
* @param payId 支付账户id
|
||||
* @param transactionType 交易类型
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("getOrderInfo")
|
||||
public Map<String, Object> getOrderInfo(Integer payId, String transactionType, BigDecimal price){
|
||||
//获取对应的支付账户操作工具(可根据账户id)
|
||||
PayResponse payResponse = service.getPayResponse(payId);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("code", 0);
|
||||
PayOrder order = new PayOrder("订单title", "摘要", null == price ? new BigDecimal(0.01) : price, UUID.randomUUID().toString().replace("-", ""), PayType.valueOf(payResponse.getStorage().getPayType()).getTransactionType(transactionType));
|
||||
data.put("orderInfo", payResponse.getService().orderInfo(order));
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
#####5.支付回调
|
||||
```java
|
||||
|
||||
|
||||
/**
|
||||
* 支付回调地址
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "payBack{payId}.json")
|
||||
public String payBack(HttpServletRequest request, @PathVariable Integer payId) throws IOException {
|
||||
//根据账户id,获取对应的支付账户操作工具
|
||||
PayResponse payResponse = service.getPayResponse(payId);
|
||||
PayConfigStorage storage = payResponse.getStorage();
|
||||
//获取支付方返回的对应参数
|
||||
Map<String, String> params = payResponse.getService().getParameter2Map(request.getParameterMap(), request.getInputStream());
|
||||
if (null == params){
|
||||
return payResponse.getService().getPayOutMessage("fail","失败").toMessage();
|
||||
}
|
||||
|
||||
//校验
|
||||
if (payResponse.getService().verify(params)){
|
||||
PayMessage message = new PayMessage(params, storage.getPayType(), storage.getMsgType().name());
|
||||
PayOutMessage outMessage = payResponse.getRouter().route(message);
|
||||
return outMessage.toMessage();
|
||||
}
|
||||
|
||||
return payResponse.getService().getPayOutMessage("fail","失败").toMessage();
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
@@ -2,11 +2,6 @@
|
||||
package in.egan.pay.demo.controller;
|
||||
|
||||
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
import com.alipay.api.request.AlipayTradeQueryRequest;
|
||||
import com.alipay.api.response.AlipayTradeQueryResponse;
|
||||
import in.egan.pay.ali.before.bean.AliTransactionType;
|
||||
import in.egan.pay.common.api.Callback;
|
||||
import in.egan.pay.common.bean.*;
|
||||
|
||||
@@ -1,111 +1,117 @@
|
||||
package in.egan.pay.demo.entity;
|
||||
|
||||
import in.egan.pay.ali.api.AliPayConfigStorage;
|
||||
import in.egan.pay.ali.before.api.AliPayService;
|
||||
import in.egan.pay.ali.before.bean.AliTransactionType;
|
||||
import in.egan.pay.common.api.PayService;
|
||||
import in.egan.pay.common.bean.BasePayType;
|
||||
import in.egan.pay.common.bean.TransactionType;
|
||||
import in.egan.pay.wx.api.WxPayConfigStorage;
|
||||
import in.egan.pay.wx.api.WxPayService;
|
||||
import in.egan.pay.wx.bean.WxTransactionType;
|
||||
import in.egan.pay.wx.youdian.api.WxYouDianPayConfigStorage;
|
||||
import in.egan.pay.wx.youdian.api.WxYouDianPayService;
|
||||
import in.egan.pay.wx.youdian.bean.YoudianTransactionType;
|
||||
|
||||
|
||||
/**
|
||||
* 支付类型
|
||||
* @author egan
|
||||
* @email egzosn@gmail.com
|
||||
* @date 2016/11/20 0:30
|
||||
*/
|
||||
public enum PayType implements BasePayType {
|
||||
|
||||
|
||||
aliPay{
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage();
|
||||
aliPayConfigStorage.setPid(apyAccount.getPartner());
|
||||
aliPayConfigStorage.setAppId(apyAccount.getAppid());
|
||||
aliPayConfigStorage.setAliPublicKey(apyAccount.getPublicKey());
|
||||
aliPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
aliPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
aliPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
|
||||
aliPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
aliPayConfigStorage.setSeller(apyAccount.getSeller());
|
||||
aliPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
aliPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
aliPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new AliPayService(aliPayConfigStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
return AliTransactionType.valueOf(transactionType);
|
||||
}
|
||||
|
||||
|
||||
},wxPay {
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage();
|
||||
wxPayConfigStorage.setMchId(apyAccount.getPartner());
|
||||
wxPayConfigStorage.setAppSecret(apyAccount.getPublicKey());
|
||||
wxPayConfigStorage.setKeyPublic(apyAccount.getPublicKey());
|
||||
wxPayConfigStorage.setAppid(apyAccount.getAppid());
|
||||
wxPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
wxPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
wxPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
wxPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
wxPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
wxPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new WxPayService(wxPayConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型获取交易类型
|
||||
* @param transactionType 类型值
|
||||
* @see WxTransactionType
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
|
||||
return WxTransactionType.valueOf(transactionType);
|
||||
}
|
||||
},youdianPay {
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
// TODO 2017/1/23 14:12 author: egan 集群的话,友店可能会有bug。暂未测试集群环境
|
||||
WxYouDianPayConfigStorage wxPayConfigStorage = new WxYouDianPayConfigStorage();
|
||||
wxPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
wxPayConfigStorage.setKeyPublic(apyAccount.getPublicKey());
|
||||
// wxPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
// wxPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
|
||||
wxPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
wxPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
wxPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
wxPayConfigStorage.setSeller(apyAccount.getSeller());
|
||||
wxPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new WxYouDianPayService(wxPayConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型获取交易类型
|
||||
* @param transactionType 类型值
|
||||
* @see YoudianTransactionType
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
|
||||
return YoudianTransactionType.valueOf(transactionType);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract PayService getPayService(ApyAccount apyAccount);
|
||||
|
||||
|
||||
}
|
||||
package in.egan.pay.demo.entity;
|
||||
|
||||
import in.egan.pay.ali.api.AliPayConfigStorage;
|
||||
import in.egan.pay.ali.before.api.AliPayService;
|
||||
import in.egan.pay.ali.before.bean.AliTransactionType;
|
||||
import in.egan.pay.common.api.PayService;
|
||||
import in.egan.pay.common.bean.BasePayType;
|
||||
import in.egan.pay.common.bean.TransactionType;
|
||||
import in.egan.pay.wx.api.WxPayConfigStorage;
|
||||
import in.egan.pay.wx.api.WxPayService;
|
||||
import in.egan.pay.wx.bean.WxTransactionType;
|
||||
import in.egan.pay.wx.youdian.api.WxYouDianPayConfigStorage;
|
||||
import in.egan.pay.wx.youdian.api.WxYouDianPayService;
|
||||
import in.egan.pay.wx.youdian.bean.YoudianTransactionType;
|
||||
|
||||
|
||||
/**
|
||||
* 支付类型
|
||||
* @author egan
|
||||
* @email egzosn@gmail.com
|
||||
* @date 2016/11/20 0:30
|
||||
*/
|
||||
public enum PayType implements BasePayType {
|
||||
|
||||
|
||||
aliPay{
|
||||
/**
|
||||
* @see in.egan.pay.ali.before.api.AliPayService 支付宝暂时请用这个2016年版本的,17年更新的版本暂时未进行测试,开发者可自行测试,可以的话反馈到我这边
|
||||
* @param apyAccount
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage();
|
||||
aliPayConfigStorage.setPid(apyAccount.getPartner());
|
||||
aliPayConfigStorage.setAppId(apyAccount.getAppid());
|
||||
aliPayConfigStorage.setAliPublicKey(apyAccount.getPublicKey());
|
||||
aliPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
aliPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
aliPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
|
||||
aliPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
aliPayConfigStorage.setSeller(apyAccount.getSeller());
|
||||
aliPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
aliPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
aliPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new AliPayService(aliPayConfigStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
// in.egan.pay.ali.before.bean.AliTransactionType 支付宝暂时用2016年版本的,17年更新的版本暂时未进行测试,开发者可自行测试,可以的话反馈到我这边
|
||||
return AliTransactionType.valueOf(transactionType);
|
||||
}
|
||||
|
||||
|
||||
},wxPay {
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage();
|
||||
wxPayConfigStorage.setMchId(apyAccount.getPartner());
|
||||
wxPayConfigStorage.setAppSecret(apyAccount.getPublicKey());
|
||||
wxPayConfigStorage.setKeyPublic(apyAccount.getPublicKey());
|
||||
wxPayConfigStorage.setAppid(apyAccount.getAppid());
|
||||
wxPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
wxPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
wxPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
wxPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
wxPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
wxPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new WxPayService(wxPayConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型获取交易类型
|
||||
* @param transactionType 类型值
|
||||
* @see WxTransactionType
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
|
||||
return WxTransactionType.valueOf(transactionType);
|
||||
}
|
||||
},youdianPay {
|
||||
@Override
|
||||
public PayService getPayService(ApyAccount apyAccount) {
|
||||
// TODO 2017/1/23 14:12 author: egan 集群的话,友店可能会有bug。暂未测试集群环境
|
||||
WxYouDianPayConfigStorage wxPayConfigStorage = new WxYouDianPayConfigStorage();
|
||||
wxPayConfigStorage.setKeyPrivate(apyAccount.getPrivateKey());
|
||||
wxPayConfigStorage.setKeyPublic(apyAccount.getPublicKey());
|
||||
// wxPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
|
||||
// wxPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
|
||||
wxPayConfigStorage.setSignType(apyAccount.getSignType());
|
||||
wxPayConfigStorage.setPayType(apyAccount.getPayType().toString());
|
||||
wxPayConfigStorage.setMsgType(apyAccount.getMsgType());
|
||||
wxPayConfigStorage.setSeller(apyAccount.getSeller());
|
||||
wxPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
|
||||
return new WxYouDianPayService(wxPayConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型获取交易类型
|
||||
* @param transactionType 类型值
|
||||
* @see YoudianTransactionType
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public TransactionType getTransactionType(String transactionType) {
|
||||
|
||||
return YoudianTransactionType.valueOf(transactionType);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract PayService getPayService(ApyAccount apyAccount);
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user