2
0

feat: payment update

This commit is contained in:
zhangsz
2025-01-04 15:12:09 +08:00
parent 35889fe4f7
commit c454de459c
39 changed files with 1955 additions and 868 deletions

View File

@@ -11,12 +11,10 @@
<artifactId>wfc-modules-payment</artifactId>
<properties>
<wfc-modules-payment.version>1.0.0</wfc-modules-payment.version>
<wfc-modules-payment.version>1.0.1</wfc-modules-payment.version>
</properties>
<description>
wfc-modules-payment
</description>
<description>wfc-modules-payment</description>
<dependencies>
@@ -96,6 +94,20 @@
<version>4.11.0.ALL</version>
</dependency>
<!-- for Union Pay -->
<dependency>
<groupId>com.egzosn</groupId>
<artifactId>pay-java-union</artifactId>
<version>2.14.7</version>
</dependency>
<!-- Missing dependency for pay-java-web -->
<dependency>
<groupId>com.egzosn</groupId>
<artifactId>pay-java-web-support</artifactId>
<version>2.14.7</version>
</dependency>
<!-- Swagger 依赖项 -->
<dependency>
<groupId>org.springdoc</groupId>
@@ -103,6 +115,12 @@
<version>1.6.14</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
<build>

View File

@@ -38,12 +38,12 @@ public class WfcPaymentApplication
public static void main(String[] args)
{
SpringApplication.run(WfcPaymentApplication.class, args);
logger.info("(♥◠‿◠)ノ゙ Payment module startup ლ(´ڡ`ლ)゙ \n");
logger.info("(♥◠‿◠)ノ゙ Payment module startup successfully ლ(´ڡ`ლ)゙ \n");
}
@PostConstruct
public void printConfig() {
System.out.println("CCPay URL: " + ccpayConfig.getUrl());
System.out.println("CCPay PaymentURL: " + ccpayConfig.getPaymentUrl());
System.out.println("CCPay API Key: " + ccpayConfig.getApiKey());
System.out.println("CCPay Merchant ID: " + ccpayConfig.getMerchantId());
System.out.println("CCPay Currency: " + ccpayConfig.getCurrency());

View File

@@ -4,7 +4,6 @@ import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@@ -23,13 +22,9 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
public class AlipayController {
@Autowired
private final IAlipayPaymentService alipayPaymentService;
@Autowired
private final IAlipayQueryOrderService alipayQueryService;
@Autowired
private final IAlipayTradeCloseService alipayCloseService;
@Autowired
private final IAlipayRefundService alipayRefundService;
@Operation(summary = "Create Alipay order")

View File

@@ -8,10 +8,15 @@ import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "ccpay")
public class CcpayConfig {
private String url;
private String paymentUrl;
private String tokenUrl;
private String refundUrl;
private String queryUrl;
private String apiKey;
private String merchantId;
private String currency;
private int timeout;
private String callbackUrl;
private String clientId;
private String clientSecret;
}

View File

@@ -5,28 +5,61 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.wfc.payment.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.PaymentResponse;
import org.wfc.payment.ccpay.service.ICcpayPaymentService;
import org.wfc.common.core.constant.HttpStatus;
import org.wfc.payment.ccpay.model.UCreditCardToken;
import org.wfc.payment.ccpay.model.RefundResponse;
import org.wfc.payment.ccpay.model.RefundRequest;
import org.wfc.payment.ccpay.service.IUCreditCardPaymentService;
import org.wfc.payment.ccpay.service.IUCreditCardTokenService;
/**
* Credit card pay controller
* Credit card payment controller
*
*/
@RestController
@RequestMapping("/ccpay")
public class CcpayController {
private final IUCreditCardPaymentService paymentService;
private final IUCreditCardTokenService tokenService;
@Autowired
private ICcpayPaymentService ccpayService;
public CcpayController(IUCreditCardPaymentService paymentService, IUCreditCardTokenService tokenService) {
this.paymentService = paymentService;
this.tokenService = tokenService;
}
@PostMapping("/payOrder")
public ResponseEntity<String> processPayment(@RequestBody PaymentRequest paymentRequest) {
// 调用支付服务处理支付请求
PaymentResponse paymentResult = ccpayService.processPayment(paymentRequest);
if (paymentResult.isSuccess()) {
return ResponseEntity.ok("Payment successful");
public ResponseEntity<PaymentResponse> processPayment(@RequestBody PaymentRequest paymentRequest) {
// 检查用户是否已有支付令牌
UCreditCardToken token = tokenService.getTokenByUserId(paymentRequest.getUserId());
if (token != null) {
// 使用支付令牌进行支付
paymentRequest.setToken(token.getToken());
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Payment failed");
// 用户首次支付,获取支付令牌并存储
String newToken = paymentService.getPaymentToken(paymentRequest);
token = new UCreditCardToken();
token.setUserId(paymentRequest.getUserId());
token.setToken(newToken);
token.setCardLastFour(paymentRequest.getCardLastFour());
token.setCardType(paymentRequest.getCardType());
tokenService.saveToken(token);
paymentRequest.setToken(newToken);
}
PaymentResponse processedPayment = paymentService.processPayment(paymentRequest);
return ResponseEntity.ok(processedPayment);
}
@GetMapping("/queryOrder/{orderId}")
public ResponseEntity<PaymentResponse> queryOrder(@PathVariable Long orderId) {
PaymentResponse paymentResponse = paymentService.queryOrder(orderId);
return ResponseEntity.ok(paymentResponse);
}
@PostMapping("/refundOrder")
public ResponseEntity<RefundResponse> refundOrder(@RequestBody RefundRequest refundRequest) {
RefundResponse refundResponse = paymentService.refundOrder(refundRequest);
return ResponseEntity.ok(refundResponse);
}
}

View File

@@ -0,0 +1,12 @@
package org.wfc.payment.ccpay.exception;
public class RuntimeException extends Exception {
public RuntimeException(String message) {
super(message);
}
public RuntimeException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,15 @@
package org.wfc.payment.ccpay.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.wfc.payment.ccpay.model.UCreditCardPayment;
@Mapper
public interface UCreditCardPaymentMapper {
void insertPayment(UCreditCardPayment payment);
UCreditCardPayment selectPaymentById(@Param("id") Long id);
// 其他需要的方法
}

View File

@@ -0,0 +1,13 @@
package org.wfc.payment.ccpay.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.wfc.payment.ccpay.model.UCreditCardToken;
@Mapper
public interface UCreditCardTokenMapper {
void insertToken(UCreditCardToken token);
UCreditCardToken selectTokenByUserId(@Param("userId") Long userId);
}

View File

@@ -4,9 +4,37 @@ import lombok.Data;
@Data
public class PaymentRequest {
private Long userId;
private String cardNumber;
private String cardLastFour;
private String cardHolderName;
private String expirationDate;
private String cvv;
private double amount;
}
private String token;
private String cardType;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public void setToken(String token) {
this.token = token;
}
public void setCardLastFour() {
this.cardLastFour = cardNumber.substring(cardNumber.length() - 4);
}
public String getCardLastFour() {
return cardLastFour;
}
public String getCardType() {
return cardType;
}
}

View File

@@ -0,0 +1,37 @@
package org.wfc.payment.ccpay.model;
public class RefundRequest {
private String transactionId;
private double amount;
private String reason;
public RefundRequest(String transactionId, double amount, String reason) {
this.transactionId = transactionId;
this.amount = amount;
this.reason = reason;
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}

View File

@@ -0,0 +1,27 @@
package org.wfc.payment.ccpay.model;
public class RefundResponse {
private String status;
private String message;
public RefundResponse(String status, String message) {
this.status = status;
this.message = message;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -0,0 +1,51 @@
package org.wfc.payment.ccpay.model;
import javax.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Entity
@Table(name = "u_credit_card_payment")
public class UCreditCardPayment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "transaction_id", nullable = false)
private String transactionId;
@Column(name = "user_id", nullable = false)
private Long userId;
@Column(name = "order_id", nullable = false)
private Long orderId;
@Column(name = "amount", nullable = false)
private BigDecimal amount;
@Column(name = "currency", nullable = false)
private String currency;
@Column(name = "status", nullable = false)
private String status;
@Column(name = "payment_time", nullable = false)
private LocalDateTime paymentTime;
@Column(name = "card_type")
private String cardType;
@Column(name = "card_holder_name")
private String cardHolderName;
@Column(name = "billing_address")
private String billingAddress;
@Column(name = "card_last_four")
private String cardLastFour;
@Column(name = "gateway_response")
private String gatewayResponse;
// Getters and Setters
}

View File

@@ -0,0 +1,48 @@
package org.wfc.payment.ccpay.model;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "u_credit_card_token")
public class UCreditCardToken {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false)
private Long userId;
@Column(name = "token", nullable = false)
private String token;
@Column(name = "card_last_four")
private String cardLastFour;
@Column(name = "card_type")
private String cardType;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
public void setUserId(Long userId) {
this.userId = userId;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public void setCardLastFour(String cardLastFour) {
this.cardLastFour = cardLastFour;
}
public void setCardType(String cardType) {
this.cardType = cardType;
}
}

View File

@@ -1,8 +0,0 @@
package org.wfc.payment.ccpay.service;
import org.wfc.payment.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.PaymentResponse;
public interface ICcpayPaymentService {
PaymentResponse processPayment(PaymentRequest paymentRequest);
}

View File

@@ -0,0 +1,23 @@
package org.wfc.payment.ccpay.service;
import org.wfc.payment.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.PaymentResponse;
import org.wfc.payment.ccpay.model.RefundRequest;
import org.wfc.payment.ccpay.model.RefundResponse;
import org.wfc.payment.ccpay.model.UCreditCardPayment;
public interface IUCreditCardPaymentService {
PaymentResponse processPayment(PaymentRequest paymentRequest);
PaymentResponse queryOrder(Long orderId);
RefundResponse refundOrder(RefundRequest refundRequest);
void savePayment(UCreditCardPayment payment);
UCreditCardPayment getPaymentById(Long id);
String getPaymentToken(PaymentRequest paymentRequest);
}

View File

@@ -0,0 +1,13 @@
package org.wfc.payment.ccpay.service;
import org.wfc.payment.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.UCreditCardToken;
public interface IUCreditCardTokenService {
void saveToken(UCreditCardToken token);
UCreditCardToken getTokenByUserId(Long userId);
String getPaymentToken(PaymentRequest paymentRequest);
}

View File

@@ -1,61 +0,0 @@
package org.wfc.payment.ccpay.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.wfc.payment.ccpay.config.CcpayConfig;
import org.wfc.payment.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.PaymentResponse;
import org.wfc.payment.ccpay.service.ICcpayPaymentService;
import java.util.HashMap;
import java.util.Map;
@Service
public class CcpayPaymentServiceImpl implements ICcpayPaymentService {
@Autowired
private CcpayConfig ccpayConfig;
@Override
public PaymentResponse processPayment(PaymentRequest paymentRequest) {
RestTemplate restTemplate = new RestTemplate();
PaymentResponse paymentResponse = new PaymentResponse();
try {
// 设置请求头
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer " + ccpayConfig.getApiKey());
headers.put("Content-Type", "application/json");
// 设置请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("merchantId", ccpayConfig.getMerchantId());
requestBody.put("currency", ccpayConfig.getCurrency());
requestBody.put("amount", paymentRequest.getAmount());
requestBody.put("cardNumber", paymentRequest.getCardNumber());
requestBody.put("cardHolderName", paymentRequest.getCardHolderName());
requestBody.put("expirationDate", paymentRequest.getExpirationDate());
requestBody.put("cvv", paymentRequest.getCvv());
requestBody.put("callbackUrl", ccpayConfig.getCallbackUrl());
// 调用第三方支付网关的 API 进行支付处理
PaymentResponse response = restTemplate.postForObject(ccpayConfig.getUrl(), requestBody,
PaymentResponse.class);
if (response != null && response.isSuccess()) {
paymentResponse.setSuccess(true);
paymentResponse.setMessage("Payment successful");
paymentResponse.setTransactionId(response.getTransactionId());
} else {
paymentResponse.setSuccess(false);
paymentResponse.setMessage("Payment failed");
}
} catch (Exception e) {
paymentResponse.setSuccess(false);
paymentResponse.setMessage("Error occurred while processing payment: " + e.getMessage());
}
return paymentResponse;
}
}

View File

@@ -0,0 +1,143 @@
package org.wfc.payment.ccpay.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.core.ParameterizedTypeReference;
import org.wfc.payment.ccpay.config.CcpayConfig;
import org.wfc.payment.ccpay.mapper.UCreditCardPaymentMapper;
import org.wfc.payment.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.PaymentResponse;
import org.wfc.payment.ccpay.model.RefundRequest;
import org.wfc.payment.ccpay.model.RefundResponse;
import org.wfc.payment.ccpay.model.UCreditCardPayment;
import org.wfc.payment.ccpay.service.IUCreditCardPaymentService;
import java.util.HashMap;
import java.util.Map;
@Service
public class UCreditCardPaymentServiceImpl implements IUCreditCardPaymentService {
private final UCreditCardPaymentMapper paymentMapper;
private final CcpayConfig ccpayConfig;
private static final String CONTENT_TYPE_HEADER = "Content-Type";
private static final String APPLICATION_JSON = "application/json";
@Autowired
public UCreditCardPaymentServiceImpl(UCreditCardPaymentMapper paymentMapper, CcpayConfig ccpayConfig) {
this.paymentMapper = paymentMapper;
this.ccpayConfig = ccpayConfig;
}
@Override
public void savePayment(UCreditCardPayment payment) {
paymentMapper.insertPayment(payment);
}
@Override
public UCreditCardPayment getPaymentById(Long id) {
return paymentMapper.selectPaymentById(id);
}
@Override
public String getPaymentToken(PaymentRequest paymentRequest) {
RestTemplate restTemplate = new RestTemplate();
String authUrl = ccpayConfig.getTokenUrl();
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE_HEADER, "application/x-www-form-urlencoded");
// 设置请求体
Map<String, String> requestBody = new HashMap<>();
requestBody.put("grant_type", "client_credentials");
requestBody.put("client_id", ccpayConfig.getClientId());
requestBody.put("client_secret", ccpayConfig.getClientSecret());
// 调用第三方支付网关的 API 获取 token
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
authUrl, HttpMethod.POST, new HttpEntity<>(requestBody, headers),
new ParameterizedTypeReference<Map<String, Object>>() {});
// 从响应中提取 token
Map<String, Object> responseBody = response.getBody();
if (responseBody != null && responseBody.containsKey("access_token")) {
return (String) responseBody.get("access_token");
} else {
throw new IllegalStateException("Failed to obtain access token from third-party gateway");
}
}
@Override
public PaymentResponse processPayment(PaymentRequest paymentRequest) {
RestTemplate restTemplate = new RestTemplate();
PaymentResponse paymentResponse = new PaymentResponse();
try {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE_HEADER, APPLICATION_JSON);
// 设置请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("merchantId", ccpayConfig.getMerchantId());
requestBody.put("currency", ccpayConfig.getCurrency());
requestBody.put("amount", paymentRequest.getAmount());
requestBody.put("cardNumber", paymentRequest.getCardNumber());
requestBody.put("cardHolderName", paymentRequest.getCardHolderName());
requestBody.put("expirationDate", paymentRequest.getExpirationDate());
requestBody.put("cvv", paymentRequest.getCvv());
requestBody.put("callbackUrl", ccpayConfig.getCallbackUrl());
// 调用第三方支付网关的 API 进行支付处理
PaymentResponse response = restTemplate.postForObject(ccpayConfig.getPaymentUrl(), requestBody,
PaymentResponse.class);
if (response != null && response.isSuccess()) {
paymentResponse.setSuccess(true);
paymentResponse.setMessage("Payment successful");
paymentResponse.setTransactionId(response.getTransactionId());
} else {
paymentResponse.setSuccess(false);
paymentResponse.setMessage("Payment failed");
}
} catch (Exception e) {
paymentResponse.setSuccess(false);
paymentResponse.setMessage("Error occurred while processing payment: " + e.getMessage());
}
return paymentResponse;
}
@Override
public PaymentResponse queryOrder(Long orderId) {
// 实现查询订单逻辑
// 例如,调用第三方支付网关的查询订单接口
RestTemplate restTemplate = new RestTemplate();
String queryUrl = ccpayConfig.getQueryUrl() + "/" + orderId;
ResponseEntity<PaymentResponse> response = restTemplate.getForEntity(queryUrl, PaymentResponse.class);
return response.getBody();
}
@Override
public RefundResponse refundOrder(RefundRequest refundRequest) {
// 实现退款逻辑
// 例如,调用第三方支付网关的退款接口
RestTemplate restTemplate = new RestTemplate();
String refundUrl = ccpayConfig.getRefundUrl();
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE_HEADER, APPLICATION_JSON);
HttpEntity<RefundRequest> requestEntity = new HttpEntity<>(refundRequest, headers);
ResponseEntity<RefundResponse> response = restTemplate.postForEntity(refundUrl, requestEntity,
RefundResponse.class);
return response.getBody();
}
}

View File

@@ -0,0 +1,34 @@
package org.wfc.payment.ccpay.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.wfc.payment.ccpay.mapper.UCreditCardTokenMapper;
import org.wfc.payment.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.UCreditCardToken;
import org.wfc.payment.ccpay.service.IUCreditCardTokenService;
@Service
public class UCreditCardTokenServiceImpl implements IUCreditCardTokenService {
private final UCreditCardTokenMapper tokenMapper;
@Autowired
public UCreditCardTokenServiceImpl(UCreditCardTokenMapper tokenMapper) {
this.tokenMapper = tokenMapper;
}
@Override
public void saveToken(UCreditCardToken token) {
tokenMapper.insertToken(token);
}
@Override
public UCreditCardToken getTokenByUserId(Long userId) {
return tokenMapper.selectTokenByUserId(userId);
}
@Override
public String getPaymentToken(PaymentRequest paymentRequest) {
return paymentRequest.getToken();
}
}

View File

@@ -0,0 +1,59 @@
package org.wfc.payment.unionpay.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "unionpay")
public class UnionPayConfig {
private String acpRootCert;
private String acpMiddleCert;
private String keyPrivateCert;
private String keyPrivateCertPwd;
private Boolean certSign;
// Getters and setters
public String getAcpRootCert() {
return acpRootCert;
}
public void setAcpRootCert(String acpRootCert) {
this.acpRootCert = acpRootCert;
}
public String getAcpMiddleCert() {
return acpMiddleCert;
}
public void setAcpMiddleCert(String acpMiddleCert) {
this.acpMiddleCert = acpMiddleCert;
}
public String getKeyPrivateCert() {
return keyPrivateCert;
}
public void setKeyPrivateCert(String keyPrivateCert) {
this.keyPrivateCert = keyPrivateCert;
}
public String getKeyPrivateCertPwd() {
return keyPrivateCertPwd;
}
public void setKeyPrivateCertPwd(String keyPrivateCertPwd) {
this.keyPrivateCertPwd = keyPrivateCertPwd;
}
public Boolean getCertSign() {
return certSign;
}
public void setCertSign(Boolean certSign) {
this.certSign = certSign;
}
}

View File

@@ -0,0 +1,39 @@
package org.wfc.payment.unionpay.config;
import com.egzosn.pay.union.api.UnionPayConfigStorage;
import com.egzosn.pay.union.api.UnionPayService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.egzosn.pay.common.util.sign.SignUtils;
import com.egzosn.pay.common.bean.CertStoreType;
@Configuration
public class UnionPayServiceConfig {
private final UnionPayConfig unionPayConfig;
public UnionPayServiceConfig(UnionPayConfig unionPayConfig) {
this.unionPayConfig = unionPayConfig;
}
@Bean
public UnionPayService unionPayService() {
UnionPayConfigStorage unionPayConfigStorage = new UnionPayConfigStorage();
unionPayConfigStorage.setMerId("700000000000001");
unionPayConfigStorage.setCertSign(unionPayConfig.getCertSign());
unionPayConfigStorage.setAcpMiddleCert(unionPayConfig.getAcpMiddleCert());
unionPayConfigStorage.setAcpRootCert(unionPayConfig.getAcpRootCert());
unionPayConfigStorage.setKeyPrivateCert(unionPayConfig.getKeyPrivateCert());
unionPayConfigStorage.setKeyPrivateCertPwd(unionPayConfig.getKeyPrivateCertPwd());
unionPayConfigStorage.setCertStoreType(CertStoreType.PATH); // 使用文件存储方式
unionPayConfigStorage.setReturnUrl("http://wfc-gateway:8080/payment/unionpay/payBack.json");
unionPayConfigStorage.setNotifyUrl("http://wfc-gateway:8080/payment/unionpay/payBack.json");
unionPayConfigStorage.setSignType(SignUtils.RSA2.name());
unionPayConfigStorage.setPayType("UNION_PAY");
unionPayConfigStorage.setInputCharset("UTF-8");
unionPayConfigStorage.setTest(true);
return new UnionPayService(unionPayConfigStorage);
}
}

View File

@@ -0,0 +1,294 @@
package org.wfc.payment.unionpay.controller;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wfc.payment.unionpay.model.QueryOrder;
import static com.egzosn.pay.union.bean.UnionTransactionType.WEB;
import com.egzosn.pay.common.bean.CertStoreType;
import com.egzosn.pay.common.bean.PayOrder;
import com.egzosn.pay.common.bean.RefundOrder;
import com.egzosn.pay.common.http.HttpConfigStorage;
import com.egzosn.pay.common.util.sign.SignTextUtils;
import com.egzosn.pay.common.util.sign.SignUtils;
import com.egzosn.pay.union.api.UnionPayConfigStorage;
import com.egzosn.pay.union.api.UnionPayService;
import com.egzosn.pay.union.bean.UnionRefundResult;
import com.egzosn.pay.union.bean.UnionTransactionType;
import com.egzosn.pay.common.bean.AssistOrder;
import com.egzosn.pay.web.support.HttpRequestNoticeParams;
import org.wfc.payment.unionpay.config.UnionPayConfig;
/**
* Union pay controller
*
*/
@RestController
@RequestMapping("unionpay")
public class UnionPayController {
private UnionPayService unionPayService = null;
private final UnionPayConfig unionPayConfig;
@Autowired
public UnionPayController(UnionPayService unionPayService, UnionPayConfig unionPayConfig) {
this.unionPayService = unionPayService;
this.unionPayConfig = unionPayConfig;
}
@PostConstruct
public void init() {
// UnionPayConfigStorage unionPayConfigStorage = new UnionPayConfigStorage();
// unionPayConfigStorage.setMerId("700000000000001");
// //是否为证书签名
// unionPayConfigStorage.setCertSign(true);
// //中级证书路径
// unionPayConfigStorage.setAcpMiddleCert(unionPayConfig.getAcpMiddleCert());
// //根证书路径
// unionPayConfigStorage.setAcpRootCert(unionPayConfig.getAcpRootCert());
// // 私钥证书路径
// unionPayConfigStorage.setKeyPrivateCert(unionPayConfig.getKeyPrivateCert());
// //私钥证书对应的密码
// unionPayConfigStorage.setKeyPrivateCertPwd(unionPayConfig.getKeyPrivateCertPwd());
// //设置证书对应的存储方式,这里默认为文件地址
// unionPayConfigStorage.setCertStoreType(CertStoreType.URL);
// //前台通知网址 即SDKConstants.param_frontUrl
// unionPayConfigStorage.setReturnUrl("http://wfc-gateway:8080/payment/unionpay/payBack.json");
// //后台通知地址 即SDKConstants.param_backUrl
// unionPayConfigStorage.setNotifyUrl("http://wfc-gateway:8080/payment/unionpay/payBack.json");
// //加密方式
// unionPayConfigStorage.setSignType(SignUtils.RSA2.name());
// //单一支付可不填
// unionPayConfigStorage.setPayType("UNION_PAY");
// unionPayConfigStorage.setInputCharset("UTF-8");
// //是否为测试账号,沙箱环境
// unionPayConfigStorage.setTest(true);
// unionPayService = new UnionPayService(unionPayConfigStorage);
// //请求连接池配置
// HttpConfigStorage httpConfigStorage = new HttpConfigStorage();
// //最大连接数
// httpConfigStorage.setMaxTotal(20);
// //默认的每个路由的最大连接数
// httpConfigStorage.setDefaultMaxPerRoute(10);
// unionPayService.setRequestTemplateConfigStorage(httpConfigStorage);
}
/**
* ---业务实现例子1---
* 功能生成自动跳转的Html表单
* 业务类型(关键字):网关支付(WEB)/手机网页支付,企业网银支付B2B,
* @param price 金额
* @return 生成自动跳转的Html表单
*/
@RequestMapping(value = "toPay.html", produces = "text/html;charset=UTF-8")
public String toPay( BigDecimal price) {
//网关支付(WEB)/手机网页支付
PayOrder order = new PayOrder("title", "摘要", null == price ? BigDecimal.valueOf(0.01) : price, UUID.randomUUID().toString().replace("-", ""),
WEB);
return unionPayService.toPay(order);
}
/**
* ---业务实现例子2---
* 功能获取调起控件的tn号支付结果等
* 业务类型:手机控件支付产品(WAP),
* @param price 金额
* @return 支付结果
*/
@RequestMapping(value = "toPay.json")
public Map<String, Object> sendHttpRequest( BigDecimal price) {
//手机控件支付产品
PayOrder order = new PayOrder("title", "摘要", null == price ? BigDecimal.valueOf(0.01) : price, UUID.randomUUID().toString().replace("-", "")
,UnionTransactionType.WAP);
return unionPayService.app(order);
}
/**
* APP 获取支付预订单信息
*
* @return 支付预订单信息
*/
@RequestMapping("app")
public Map<String, Object> app() {
Map<String, Object> data = new HashMap<>();
data.put("code", 0);
PayOrder order = new PayOrder("title", "摘要", BigDecimal.valueOf(0.01), SignTextUtils.randomStr());
//App支付
order.setTransactionType(UnionTransactionType.APP);
data.put("orderInfo", unionPayService.app(order));
return data;
}
/**
* 获取二维码图像 APPLY_QR_CODE
* 二维码支付
* @param price 金额
* @return 二维码图像
* @throws IOException IOException
*/
@RequestMapping(value = "toQrPay.jpg", produces = "image/jpeg;charset=UTF-8")
public byte[] toWxQrPay( BigDecimal price) throws IOException {
//获取对应的支付账户操作工具可根据账户id
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(unionPayService.genQrPay( new PayOrder("title", "摘要", null == price ? BigDecimal.valueOf(0.01) : price, System.currentTimeMillis()+"", UnionTransactionType.APPLY_QR_CODE)), "JPEG", baos);
return baos.toByteArray();
}
/**
* 获取二维码地址
* 二维码支付
* @param price 金额
* @return 二维码图像
* @throws IOException IOException
*/
@RequestMapping(value = "getQrPay.json")
public String getQrPay(BigDecimal price) throws IOException {
//获取对应的支付账户操作工具可根据账户id
return unionPayService.getQrPay( new PayOrder("订单title", "摘要", null == price ? BigDecimal.valueOf(0.01) : price, System.currentTimeMillis()+"", UnionTransactionType.APPLY_QR_CODE));
}
/**
* 刷卡付,pos主动扫码付款(条码付) CONSUME
* @param authCode 授权码,条码等
* @param price 金额
* @return 支付结果
*/
@RequestMapping(value = "microPay")
public Map<String, Object> microPay(BigDecimal price, String authCode) {
//获取对应的支付账户操作工具可根据账户id
//条码付
PayOrder order = new PayOrder("egan order", "egan order", null == price ? BigDecimal.valueOf(0.01) : price, SignTextUtils.randomStr(), UnionTransactionType.CONSUME);
//设置授权码,条码等
order.setAuthCode(authCode);
//支付结果
Map<String, Object> params = unionPayService.microPay(order);
//校验
if (unionPayService.verify(params)) {
//支付校验通过后的处理
//......业务逻辑处理块........
}
//这里开发者自行处理
return params;
}
/**
* 支付回调地址 方式一
*
* 方式二,{@link #payBack(HttpServletRequest)} 是属于简化方式, 试用与简单的业务场景
*
* @param request 请求
* @return 是否成功
* @see #payBack(HttpServletRequest)
* @throws IOException IOException
* @deprecated This method is deprecated and will be removed in future versions. Use {@link #payBack(HttpServletRequest)} instead.
*/
@Deprecated
@RequestMapping(value = "payBackBefore.json")
public String payBackBefore(HttpServletRequest request) throws IOException {
//获取支付方返回的对应参数
Map<String, Object> params = unionPayService.getParameter2Map(request.getParameterMap(), request.getInputStream());
if (null == params) {
return unionPayService.getPayOutMessage("fail", "失败").toMessage();
}
//校验
if (unionPayService.verify(params)) {
//这里处理业务逻辑
//......业务逻辑处理块........
return unionPayService.successPayOutMessage(null).toMessage();
}
return unionPayService.getPayOutMessage("fail", "失败").toMessage();
}
/**
* 支付回调地址
*
* @param request 请求
*
* @return 是否成功
*
* 业务处理在对应的PayMessageHandler里面处理在哪里设置PayMessageHandler详情查看{@link com.egzosn.pay.common.api.PayService#setPayMessageHandler(com.egzosn.pay.common.api.PayMessageHandler)}
*
* 如果未设置 {@link com.egzosn.pay.common.api.PayMessageHandler} 那么会使用默认的 {@link com.egzosn.pay.common.api.DefaultPayMessageHandler}
* @throws IOException IOException
*/
@RequestMapping(value = "payBackOld.json")
public String payBackOld(HttpServletRequest request) throws IOException {
//业务处理在对应的PayMessageHandler里面处理在哪里设置PayMessageHandler详情查看com.egzosn.pay.common.api.PayService.setPayMessageHandler()
return unionPayService.payBack(request.getParameterMap(), request.getInputStream()).toMessage();
}
/**
* 支付回调地址
*
* @param request 请求
* @return 是否成功
* <p>
* 业务处理在对应的PayMessageHandler里面处理在哪里设置PayMessageHandler详情查看{@link com.egzosn.pay.common.api.PayService#setPayMessageHandler(com.egzosn.pay.common.api.PayMessageHandler)}
* <p>
* 如果未设置 {@link com.egzosn.pay.common.api.PayMessageHandler} 那么会使用默认的 {@link com.egzosn.pay.common.api.DefaultPayMessageHandler}
* @throws IOException IOException
*/
@RequestMapping(value = "payBack.json")
public String payBack(HttpServletRequest request) {
//业务处理在对应的PayMessageHandler里面处理在哪里设置PayMessageHandler详情查看com.egzosn.pay.common.api.PayService.setPayMessageHandler()
return unionPayService.payBack(new HttpRequestNoticeParams(request)).toMessage();
}
/**
* 查询
*
* @param order 订单的请求体
* @return 返回查询回来的结果集,支付方原值返回
*/
@RequestMapping("query")
public Map<String, Object> query(QueryOrder order) {
return unionPayService.query(new AssistOrder(order.getTradeNo(), order.getOutTradeNo()));
}
/**
* 申请退款接口
*
* @param order 订单的请求体
* @return 返回支付方申请退款后的结果
*/
@RequestMapping("refund")
public UnionRefundResult refund(RefundOrder order) {
return unionPayService.refund(order);
}
/**
* 下载对账单
*
* @param order 订单的请求体
* @return 返回支付方下载对账单的结果
*/
@RequestMapping("downloadBill")
public Object downloadBill(QueryOrder order) {
return unionPayService.downloadBill(order.getBillDate(), order.getBillType());
}
}

View File

@@ -0,0 +1,188 @@
package org.wfc.payment.unionpay.model;
/**
* 支付账户
*
*/
//@Table(name = "apy_account")
//@Entity
public class ApyAccount {
// 支付账号id
// @Id
// @GeneratedValue
// @Column(name = "pay_id")
private Integer payId;
// 支付合作id,商户id差不多是支付平台的账号或id
// @Column(name = "partner")
private String partner;
// 应用id
// @Column(name = "appid")
private String appId;
// 支付平台公钥(签名校验使用)sign_type只有单一key时public_key与private_key相等比如sign_type=MD5的情况
private String publicKey;
// 应用私钥(生成签名)
// @Column(name = "private_key")
private String privateKey;
// 异步回调地址
// @Column(name = "notify_url")
private String notifyUrl;
// 同步回调地址
// @Column(name = "return_url")
private String returnUrl;
// 收款账号
// @Column(name = "seller")
private String seller;
//请求证书地址,请使用绝对路径
// @Column(name = "keystore_path")
private String keystorePath;
//证书对应的密码
// @Column(name = "store_password")
private String storePassword;
// 签名类型
// @Column(name = "sign_type")
private String signType;
// 编码类型 枚举值,字符编码 utf-8,gbk等等
// @Column(name = "input_charset")
private String inputCharset;
//支付类型,aliPay支付宝wxPay微信, youdianPay: 友店微信,此处开发者自定义对应com.egzosn.pay.demo.entity.PayType枚举值
// @Enumerated(EnumType.STRING)
// @Column(name = "pay_type")
private PayType payType;
//是否为测试环境
private boolean isTest = false;
public Integer getPayId() {
return payId;
}
public void setPayId(Integer payId) {
this.payId = payId;
}
public String getPartner() {
return partner;
}
public void setPartner(String partner) {
this.partner = partner;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getPublicKey() {
return publicKey;
}
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}
public String getPrivateKey() {
return privateKey;
}
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
public String getReturnUrl() {
return returnUrl;
}
public void setReturnUrl(String returnUrl) {
this.returnUrl = returnUrl;
}
public String getSeller() {
return seller;
}
public void setSeller(String seller) {
this.seller = seller;
}
public String getSignType() {
return signType;
}
public void setSignType(String signType) {
this.signType = signType;
}
public PayType getPayType() {
return payType;
}
public void setPayType(PayType payType) {
this.payType = payType;
}
public String getInputCharset() {
return inputCharset;
}
public void setInputCharset(String inputCharset) {
this.inputCharset = inputCharset;
}
public boolean isTest() {
return isTest;
}
public String getKeystorePath() {
return keystorePath;
}
public void setKeystorePath(String keystorePath) {
this.keystorePath = keystorePath;
}
public String getStorePassword() {
return storePassword;
}
public void setStorePassword(String storePassword) {
this.storePassword = storePassword;
}
public void setTest(boolean test) {
isTest = test;
}
@Override
public String toString() {
return "ApyAccount{" +
"payId=" + payId +
", partner='" + partner + '\'' +
", appId='" + appId + '\'' +
", publicKey='" + publicKey + '\'' +
", privateKey='" + privateKey + '\'' +
", notifyUrl='" + notifyUrl + '\'' +
", returnUrl='" + returnUrl + '\'' +
", seller='" + seller + '\'' +
", signType='" + signType + '\'' +
", inputCharset='" + inputCharset + '\'' +
", payType=" + payType +
'}';
}
}

View File

@@ -0,0 +1,56 @@
package org.wfc.payment.unionpay.model;
import org.wfc.payment.unionpay.service.impl.UnionPayMessageImpl;
import com.egzosn.pay.common.api.PayService;
import com.egzosn.pay.common.bean.BasePayType;
import com.egzosn.pay.common.bean.CertStoreType;
import com.egzosn.pay.common.bean.TransactionType;
import com.egzosn.pay.union.api.UnionPayConfigStorage;
import com.egzosn.pay.union.api.UnionPayService;
import com.egzosn.pay.union.bean.UnionTransactionType;
/**
* 支付类型
*
*/
public enum PayType implements BasePayType {
UNION_PAY {
@Override
public PayService<UnionPayConfigStorage> getPayService(ApyAccount apyAccount) {
UnionPayConfigStorage unionPayConfigStorage = new UnionPayConfigStorage();
unionPayConfigStorage.setMerId(apyAccount.getPartner());
unionPayConfigStorage.setCertSign(true);
//中级证书路径
unionPayConfigStorage.setAcpMiddleCert("D:/certs/acp_test_middle.cer");
//根证书路径
unionPayConfigStorage.setAcpRootCert("D:/certs/acp_test_root.cer");
// 私钥证书路径
unionPayConfigStorage.setKeyPrivateCert("D:/certs/acp_test_sign.pfx");
//私钥证书对应的密码
unionPayConfigStorage.setKeyPrivateCertPwd("000000");
//设置证书对应的存储方式,这里默认为文件地址
unionPayConfigStorage.setCertStoreType(CertStoreType.PATH);
unionPayConfigStorage.setNotifyUrl(apyAccount.getNotifyUrl());
unionPayConfigStorage.setReturnUrl(apyAccount.getReturnUrl());
unionPayConfigStorage.setSignType(apyAccount.getSignType());
unionPayConfigStorage.setPayType(apyAccount.getPayType().toString());
unionPayConfigStorage.setInputCharset(apyAccount.getInputCharset());
unionPayConfigStorage.setTest(apyAccount.isTest());
final UnionPayService unionPayService = new UnionPayService(unionPayConfigStorage);
unionPayService.setPayMessageHandler(new UnionPayMessageImpl(apyAccount.getPayId()));
return unionPayService;
}
@Override
public TransactionType getTransactionType(String transactionType) {
return UnionTransactionType.valueOf(transactionType);
}
};
public abstract PayService<UnionPayConfigStorage> getPayService(ApyAccount apyAccount);
}

View File

@@ -0,0 +1,130 @@
package org.wfc.payment.unionpay.model;
import java.math.BigDecimal;
import java.util.Date;
/**
* 订单辅助接口
* @author egan
* email egzosn@gmail.com
* date 2017/3/12 14:50
*/
public class QueryOrder {
private Integer payId;
// 支付平台订单号
private String tradeNo;
// 商户单号
private String outTradeNo;
// 退款金额
private BigDecimal refundAmount;
// 总金额
private BigDecimal totalAmount;
// 账单时间:具体请查看对应支付平台
private Date billDate;
// 账单时间:具体请查看对应支付平台
private String billType;
// 支付平台订单号或者账单日期
private Object tradeNoOrBillDate;
// 商户单号或者 账单类型
private String outTradeNoBillType;
// 交易类型
private String transactionType;
public Integer getPayId() {
return payId;
}
public void setPayId(Integer payId) {
this.payId = payId;
}
public String getTradeNo() {
return tradeNo;
}
public void setTradeNo(String tradeNo) {
this.tradeNo = tradeNo;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public BigDecimal getRefundAmount() {
return refundAmount;
}
public void setRefundAmount(BigDecimal refundAmount) {
this.refundAmount = refundAmount;
}
public BigDecimal getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(BigDecimal totalAmount) {
this.totalAmount = totalAmount;
}
public Date getBillDate() {
return billDate;
}
public void setBillDate(Date billDate) {
this.billDate = billDate;
}
public String getBillType() {
return billType;
}
public void setBillType(String billType) {
this.billType = billType;
}
public Object getTradeNoOrBillDate() {
return tradeNoOrBillDate;
}
public void setTradeNoOrBillDate(Object tradeNoOrBillDate) {
this.tradeNoOrBillDate = tradeNoOrBillDate;
}
public String getOutTradeNoBillType() {
return outTradeNoBillType;
}
public void setOutTradeNoBillType(String outTradeNoBillType) {
this.outTradeNoBillType = outTradeNoBillType;
}
public String getTransactionType() {
return transactionType;
}
public void setTransactionType(String transactionType) {
this.transactionType = transactionType;
}
@Override
public String toString() {
return "QueryOrder{" +
"payId=" + payId +
", tradeNo='" + tradeNo + '\'' +
", outTradeNo='" + outTradeNo + '\'' +
", refundAmount=" + refundAmount +
", totalAmount=" + totalAmount +
", billDate=" + billDate +
", billType='" + billType + '\'' +
", tradeNoOrBillDate=" + tradeNoOrBillDate +
", outTradeNoBillType='" + outTradeNoBillType + '\'' +
", transactionType='" + transactionType + '\'' +
'}';
}
}

View File

@@ -0,0 +1,69 @@
package org.wfc.payment.unionpay.repository;
import java.util.HashMap;
import java.util.Map;
import org.wfc.payment.unionpay.model.ApyAccount;
import org.wfc.payment.unionpay.model.PayType;
import com.egzosn.pay.common.util.sign.SignUtils;
/**
* 账户
*
* @author egan
* email egzosn@gmail.com
* date 2016/11/18 1:21
*/
//@Repository
public class ApyAccountRepository {
// 这里简单模拟引入orm等框架之后可自行删除
protected static final Map<Integer, ApyAccount> apyAccounts = new HashMap<>();
/**
* 这里简单初始化引入orm等框架之后可自行删除
*/
static {
ApyAccount apyAccount4 = new ApyAccount();
apyAccount4.setPayId(4);
apyAccount4.setPartner("700000000000001");
//公钥,验签证书链格式: 中级证书路径;根证书路径
apyAccount4.setPublicKey("D:/certs/acp_test_middle.cer;D:/certs/acp_test_root.cer");
//私钥, 私钥证书格式: 私钥证书路径;私钥证书对应的密码
apyAccount4.setPrivateKey("D:/certs/acp_test_sign.pfx;000000");
apyAccount4.setNotifyUrl("http://127.0.0.1/payBack4.json");
// 无需同步回调可不填 app填这个就可以
apyAccount4.setReturnUrl("http://127.0.0.1/payBack4.json");
apyAccount4.setSeller("");
apyAccount4.setInputCharset("UTF-8");
apyAccount4.setSignType(SignUtils.RSA2.name());
apyAccount4.setPayType(PayType.UNION_PAY);
apyAccount4.setTest(true);
apyAccounts.put(apyAccount4.getPayId(), apyAccount4);
}
//_____________________________________________________________
/**
* Provides access to the apyAccounts map.
*
* @return the apyAccounts map
*/
public static Map<Integer, ApyAccount> getApyAccounts() {
return apyAccounts;
}
/**
* 根据id获取对应的账户信息
*
* @param payId 账户id
* @return 账户信息
*/
public ApyAccount findByPayId(Integer payId) {
// Retrieve the ApyAccount from the map using the payId
return apyAccounts.get(payId);
}
}

View File

@@ -0,0 +1,55 @@
package org.wfc.payment.unionpay.service;
import org.wfc.payment.unionpay.model.ApyAccount;
import org.wfc.payment.unionpay.repository.ApyAccountRepository;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@Service
public class ApyAccountService {
// @Resource
private ApyAccountRepository dao;
@Resource
private AutowireCapableBeanFactory spring;
/**
* 缓存
*/
private static final Map<Integer, PayResponse> payResponses = new HashMap<>();
/**
* 这里简单初始化引入orm等框架之后可自行删除
*/
public ApyAccountService() {
dao = new ApyAccountRepository();
}
/**
* 获取支付响应
* @param id 账户id
* @return 支付响应
*/
public PayResponse getPayResponse(Integer id) {
PayResponse payResponse = payResponses.get(id);
if (payResponse == null) {
ApyAccount apyAccount = dao.findByPayId(id);
if (apyAccount == null) {
throw new IllegalArgumentException ("无法查询");
}
payResponse = new PayResponse();
spring.autowireBean(payResponse);
payResponse.init(apyAccount);
payResponses.put(id, payResponse);
// 查询
}
return payResponse;
}
}

View File

@@ -0,0 +1,79 @@
package org.wfc.payment.unionpay.service;
import javax.annotation.Resource;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.wfc.payment.unionpay.model.ApyAccount;
import com.egzosn.pay.common.api.PayConfigStorage;
import com.egzosn.pay.common.api.PayService;
import com.egzosn.pay.common.http.HttpConfigStorage;
/**
* 支付响应对象
*
*/
public class PayResponse {
@Resource
private AutowireCapableBeanFactory spring;
private PayConfigStorage storage;
private PayService<? extends PayConfigStorage> service;
public PayResponse() {
// This constructor is intentionally empty. Nothing special is needed here.
}
/**
* 初始化支付配置
*
* @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();
//这里设置http请求配置
// buildRouter(apyAccount.getPayId()); // Deprecated method call removed
}
/**
* 获取http配置如果配置为null则为默认配置无代理,无证书的请求方式。
* 此处非必需
*
* @param apyAccount 账户信息
* @return 请求配置
*/
public HttpConfigStorage getHttpConfigStorage(ApyAccount apyAccount) {
HttpConfigStorage httpConfigStorage = new HttpConfigStorage();
/* 网路代理配置 根据需求进行设置*/
// //http代理地址
// httpConfigStorage.setHttpProxyHost("192.168.1.69");
// //代理端口
// httpConfigStorage.setHttpProxyPort(3308);
// //代理用户名
// httpConfigStorage.setHttpProxyUsername("user");
// //代理密码
// httpConfigStorage.setHttpProxyPassword("password");
// 设置ssl证书路径 https证书设置 方式二
httpConfigStorage.setKeystore(apyAccount.getKeystorePath());
//设置ssl证书对应的密码
httpConfigStorage.setStorePassword(apyAccount.getStorePassword());
return httpConfigStorage;
}
public PayConfigStorage getStorage() {
return storage;
}
public PayService<? extends PayConfigStorage> getService() {
return service;
}
}

View File

@@ -0,0 +1,18 @@
package org.wfc.payment.unionpay.service.impl;
import com.egzosn.pay.common.api.PayMessageHandler;
import com.egzosn.pay.common.api.PayService;
import com.egzosn.pay.common.bean.PayMessage;
public abstract class BasePayMessageImpl<M extends PayMessage, S extends PayService<?>> implements PayMessageHandler<M, S> {
//支付账户id
private Integer payId;
protected BasePayMessageImpl(Integer payId) {
this.payId = payId;
}
public Integer getPayId() {
return payId;
}
}

View File

@@ -0,0 +1,28 @@
package org.wfc.payment.unionpay.service.impl;
import com.egzosn.pay.common.bean.PayOutMessage;
import com.egzosn.pay.common.exception.PayErrorException;
import com.egzosn.pay.union.api.UnionPayService;
import com.egzosn.pay.union.bean.SDKConstants;
import com.egzosn.pay.union.bean.UnionPayMessage;
import java.util.Map;
public class UnionPayMessageImpl extends BasePayMessageImpl<UnionPayMessage, UnionPayService> {
public UnionPayMessageImpl(Integer payId) {
super(payId);
}
@Override
public PayOutMessage handle(UnionPayMessage payMessage, Map<String, Object> context, UnionPayService payService) throws PayErrorException {
//交易状态
if (SDKConstants.OK_RESP_CODE.equals(payMessage.getPayMessage().get(SDKConstants.param_respCode))) {
/////这里进行成功的处理
return payService.successPayOutMessage(payMessage);
}
return payService.getPayOutMessage("fail", "失败");
}
}

View File

@@ -29,7 +29,7 @@ public class SwaggerConfig extends WebMvcConfigurationSupport {
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("public")
.pathsToMatch("/api/payment/**")
.pathsToMatch("/payment/**")
.packagesToScan("org.wfc.payment.wxpay.controller")
.build();
}

View File

@@ -19,368 +19,381 @@ import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.util.Date;
@Tag(name = "WeChat Pay")
@RestController
@RequestMapping("/wxpay")
@AllArgsConstructor
// @AllArgsConstructor
public class WxPayController {
@Autowired
private WxPayService wxService;
/**
* <pre>
* 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
* 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。
* 需要调用查询接口的情况:
* ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
* ◆ 调用支付接口后,返回系统错误或未知交易状态情况;
* ◆ 调用被扫支付API返回USERPAYING的状态
* ◆ 调用关单或撤销接口API之前需确认支付状态
* 接口地址https://api.mch.weixin.qq.com/pay/orderquery
* </pre>
*
* @param transactionId 微信订单号
* @param outTradeNo 商户系统内部的订单号当没提供transactionId时需要传这个。
*/
@Operation(summary = "Query order")
@GetMapping("/queryOrder")
public WxPayOrderQueryResult queryOrder(@RequestParam(required = false) String transactionId,
@RequestParam(required = false) String outTradeNo)
throws WxPayException {
return this.wxService.queryOrder(transactionId, outTradeNo);
}
private final WxPayService wxService;
@Operation(summary = "Query order")
@PostMapping("/queryOrder")
public WxPayOrderQueryResult queryOrder(@RequestBody WxPayOrderQueryRequest wxPayOrderQueryRequest) throws WxPayException {
return this.wxService.queryOrder(wxPayOrderQueryRequest);
}
@Autowired
public WxPayController(WxPayService wxService) {
this.wxService = wxService;
}
/**
* <pre>
* 关闭订单
* 应用场景
* 以下情况需要调用关单接口
* 1. 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付
* 2. 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
* 注意订单生成后不能马上调用关单接口最短调用时间间隔为5分钟。
* 接口地址https://api.mch.weixin.qq.com/pay/closeorder
* 是否需要证书: 不需要。
* </pre>
*
* @param outTradeNo 商户系统内部的订单号
*/
@Operation(summary = "Close order")
@GetMapping("/closeOrder/{outTradeNo}")
public WxPayOrderCloseResult closeOrder(@PathVariable String outTradeNo) throws WxPayException {
return this.wxService.closeOrder(outTradeNo);
}
/**
* <pre>
* 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
* 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。
* 需要调用查询接口的情况
* ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知
* ◆ 调用支付接口后,返回系统错误或未知交易状态情况;
* ◆ 调用被扫支付API返回USERPAYING的状态
* ◆ 调用关单或撤销接口API之前需确认支付状态
* 接口地址https://api.mch.weixin.qq.com/pay/orderquery
* </pre>
*
* @param transactionId 微信订单号
* @param outTradeNo 商户系统内部的订单号当没提供transactionId时需要传这个。
*/
@Operation(summary = "Query order")
@GetMapping("/queryOrder")
public WxPayOrderQueryResult queryOrder(@RequestParam(required = false) String transactionId,
@RequestParam(required = false) String outTradeNo)
throws WxPayException {
return this.wxService.queryOrder(transactionId, outTradeNo);
}
@Operation(summary = "Close order")
@PostMapping("/closeOrder")
public WxPayOrderCloseResult closeOrder(@RequestBody WxPayOrderCloseRequest wxPayOrderCloseRequest) throws WxPayException {
return this.wxService.closeOrder(wxPayOrderCloseRequest);
}
@Operation(summary = "Query order")
@PostMapping("/queryOrder")
public WxPayOrderQueryResult queryOrder(@RequestBody WxPayOrderQueryRequest wxPayOrderQueryRequest)
throws WxPayException {
return this.wxService.queryOrder(wxPayOrderQueryRequest);
}
/**
* 调用统一下单接口,并组装生成支付所需参数对象.
*
* @param request 统一下单请求参数
* @param <T> 请使用{@link com.github.binarywang.wxpay.bean.order}包下的类
* @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
*/
@Operation(summary = "统一下单,并组装所需支付参数")
@PostMapping("/createOrder")
public <T> T createOrder(@RequestBody WxPayUnifiedOrderRequest request) throws WxPayException {
return this.wxService.createOrder(request);
}
/**
* <pre>
* 关闭订单
* 应用场景
* 以下情况需要调用关单接口:
* 1. 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
* 2. 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
* 注意订单生成后不能马上调用关单接口最短调用时间间隔为5分钟。
* 接口地址https://api.mch.weixin.qq.com/pay/closeorder
* 是否需要证书: 不需要。
* </pre>
*
* @param outTradeNo 商户系统内部的订单号
*/
@Operation(summary = "Close order")
@GetMapping("/closeOrder/{outTradeNo}")
public WxPayOrderCloseResult closeOrder(@PathVariable String outTradeNo) throws WxPayException {
return this.wxService.closeOrder(outTradeNo);
}
/**
* 统一下单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
* 接口地址https://api.mch.weixin.qq.com/pay/unifiedorder
*
* @param request 请求对象注意一些参数如appid、mchid等不用设置方法内会自动从配置对象中获取到前提是对应配置中已经设置
*/
@Operation(summary = "原生的统一下单接口")
@PostMapping("/unifiedOrder")
public WxPayUnifiedOrderResult unifiedOrder(@RequestBody WxPayUnifiedOrderRequest request) throws WxPayException {
return this.wxService.unifiedOrder(request);
}
@Operation(summary = "Close order")
@PostMapping("/closeOrder")
public WxPayOrderCloseResult closeOrder(@RequestBody WxPayOrderCloseRequest wxPayOrderCloseRequest)
throws WxPayException {
return this.wxService.closeOrder(wxPayOrderCloseRequest);
}
/**
* <pre>
* 微信支付-申请退款
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
* 接口链接https://api.mch.weixin.qq.com/secapi/pay/refund
* </pre>
*
* @param request 请求对象
* @return 退款操作结果
*/
@Operation(summary = "Refund")
@PostMapping("/refund")
public WxPayRefundResult refund(@RequestBody WxPayRefundRequest request) throws WxPayException {
return this.wxService.refund(request);
}
/**
* 调用统一下单接口,并组装生成支付所需参数对象.
*
* @param request 统一下单请求参数
* @param <T> 请使用{@link com.github.binarywang.wxpay.bean.order}包下的类
* @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
*/
@Operation(summary = "统一下单,并组装所需支付参数")
@PostMapping("/createOrder")
public <T> T createOrder(@RequestBody WxPayUnifiedOrderRequest request) throws WxPayException {
return this.wxService.createOrder(request);
}
/**
* <pre>
* 微信支付-查询退款
* 应用场景:
* 提交退款申请后通过调用该接口查询退款状态。退款有一定延时用零钱支付的退款20分钟内到账
* 银行卡支付的退款3个工作日后重新查询退款状态。
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
* 接口链接https://api.mch.weixin.qq.com/pay/refundquery
* </pre>
* 以下四个参数四选一
*
* @param transactionId 微信订单号
* @param outTradeNo 商户订单号
* @param outRefundNo 商户退款单号
* @param refundId 微信退款单号
* @return 退款信息
*/
@Operation(summary = "退款查询")
@GetMapping("/refundQuery")
public WxPayRefundQueryResult refundQuery(@RequestParam(required = false) String transactionId,
@RequestParam(required = false) String outTradeNo,
@RequestParam(required = false) String outRefundNo,
@RequestParam(required = false) String refundId)
throws WxPayException {
return this.wxService.refundQuery(transactionId, outTradeNo, outRefundNo, refundId);
}
/**
* 统一下单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
* 接口地址https://api.mch.weixin.qq.com/pay/unifiedorder
*
* @param request 请求对象注意一些参数如appid、mchid等不用设置方法内会自动从配置对象中获取到前提是对应配置中已经设置
*/
@Operation(summary = "原生的统一下单接口")
@PostMapping("/unifiedOrder")
public WxPayUnifiedOrderResult unifiedOrder(@RequestBody WxPayUnifiedOrderRequest request) throws WxPayException {
return this.wxService.unifiedOrder(request);
}
@Operation(summary = "退款查询")
@PostMapping("/refundQuery")
public WxPayRefundQueryResult refundQuery(@RequestBody WxPayRefundQueryRequest wxPayRefundQueryRequest) throws WxPayException {
return this.wxService.refundQuery(wxPayRefundQueryRequest);
}
/**
* <pre>
* 微信支付-申请退款
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
* 接口链接https://api.mch.weixin.qq.com/secapi/pay/refund
* </pre>
*
* @param request 请求对象
* @return 退款操作结果
*/
@Operation(summary = "Refund")
@PostMapping("/refund")
public WxPayRefundResult refund(@RequestBody WxPayRefundRequest request) throws WxPayException {
return this.wxService.refund(request);
}
@Operation(summary = "支付回调通知处理")
@PostMapping("/notify/order")
public String parseOrderNotifyResult(@RequestBody String xmlData) throws WxPayException {
final WxPayOrderNotifyResult notifyResult = this.wxService.parseOrderNotifyResult(xmlData);
// TODO 根据自己业务场景需要构造返回对象
return WxPayNotifyResponse.success("成功");
}
/**
* <pre>
* 微信支付-查询退款
* 应用场景:
* 提交退款申请后通过调用该接口查询退款状态。退款有一定延时用零钱支付的退款20分钟内到账
* 银行卡支付的退款3个工作日后重新查询退款状态。
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
* 接口链接https://api.mch.weixin.qq.com/pay/refundquery
* </pre>
*
* 以下四个参数四选一
*
* @param transactionId 微信订单号
* @param outTradeNo 商户订单号
* @param outRefundNo 商户退款单号
* @param refundId 微信退款单号
* @return 退款信息
*/
@Operation(summary = "退款查询")
@GetMapping("/refundQuery")
public WxPayRefundQueryResult refundQuery(@RequestParam(required = false) String transactionId,
@RequestParam(required = false) String outTradeNo,
@RequestParam(required = false) String outRefundNo,
@RequestParam(required = false) String refundId)
throws WxPayException {
return this.wxService.refundQuery(transactionId, outTradeNo, outRefundNo, refundId);
}
@Operation(summary = "退款回调通知处理")
@PostMapping("/notify/refund")
public String parseRefundNotifyResult(@RequestBody String xmlData) throws WxPayException {
final WxPayRefundNotifyResult result = this.wxService.parseRefundNotifyResult(xmlData);
// TODO 根据自己业务场景需要构造返回对象
return WxPayNotifyResponse.success("成功");
}
@Operation(summary = "退款查询")
@PostMapping("/refundQuery")
public WxPayRefundQueryResult refundQuery(@RequestBody WxPayRefundQueryRequest wxPayRefundQueryRequest)
throws WxPayException {
return this.wxService.refundQuery(wxPayRefundQueryRequest);
}
@Operation(summary = "扫码支付回调通知处理")
@PostMapping("/notify/scanpay")
public String parseScanPayNotifyResult(String xmlData) throws WxPayException {
final WxScanPayNotifyResult result = this.wxService.parseScanPayNotifyResult(xmlData);
// TODO 根据自己业务场景需要构造返回对象
return WxPayNotifyResponse.success("成功");
}
@Operation(summary = "支付回调通知处理")
@PostMapping("/notify/order")
public String parseOrderNotifyResult(@RequestBody String xmlData) throws WxPayException {
final WxPayOrderNotifyResult notifyResult = this.wxService.parseOrderNotifyResult(xmlData);
// TODO 根据自己业务场景需要构造返回对象
return WxPayNotifyResponse.success("成功");
}
/**
* 发送微信红包给个人用户
* <pre>
* 文档详见:
* 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
* 接口地址https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack
* 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4
* 接口地址https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack
* </pre>
*
* @param request 请求对象
*/
@Operation(summary = "发送红包")
@PostMapping("/sendRedpack")
public WxPaySendRedpackResult sendRedpack(@RequestBody WxPaySendRedpackRequest request) throws WxPayException {
return this.wxService.getRedpackService().sendRedpack(request);
}
@Operation(summary = "退款回调通知处理")
@PostMapping("/notify/refund")
public String parseRefundNotifyResult(@RequestBody String xmlData) throws WxPayException {
final WxPayRefundNotifyResult result = this.wxService.parseRefundNotifyResult(xmlData);
// TODO 根据自己业务场景需要构造返回对象
return WxPayNotifyResponse.success("成功");
}
/**
* <pre>
* 查询红包记录
* 用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。
* 请求Url https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo
* 是否需要证书 是(证书及使用说明详见商户证书)
* 请求方式 POST
* </pre>
*
* @param mchBillNo 商户发放红包的商户订单号比如10000098201411111234567890
*/
@Operation(summary = "查询红包")
@GetMapping("/queryRedpack/{mchBillNo}")
public WxPayRedpackQueryResult queryRedpack(@PathVariable String mchBillNo) throws WxPayException {
return this.wxService.getRedpackService().queryRedpack(mchBillNo);
}
@Operation(summary = "扫码支付回调通知处理")
@PostMapping("/notify/scanpay")
public String parseScanPayNotifyResult(String xmlData) throws WxPayException {
final WxScanPayNotifyResult result = this.wxService.parseScanPayNotifyResult(xmlData);
// TODO 根据自己业务场景需要构造返回对象
return WxPayNotifyResponse.success("成功");
}
/**
* <pre>
* 扫码支付模式一生成二维码的方法
* 二维码中的内容为链接,形式为:
* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
* 其中XXXXX为商户需要填写的内容商户将该链接生成二维码如需要打印发布二维码需要采用此格式。商户可调用第三方库生成二维码图片。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
* </pre>
*
* @param productId 产品Id
* @param logoFile 商户logo图片的文件对象可以为空
* @param sideLength 要生成的二维码的边长如果为空则取默认值400
* @return 生成的二维码的字节数组
*/
public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) throws Exception {
return this.wxService.createScanPayQrcodeMode1(productId, logoFile, sideLength);
}
/**
* 发送微信红包给个人用户
*
* <pre>
* 文档详见:
* 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
* 接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack
* 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4
* 接口地址https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack
* </pre>
*
* @param request 请求对象
*/
@Operation(summary = "发送红包")
@PostMapping("/sendRedpack")
public WxPaySendRedpackResult sendRedpack(@RequestBody WxPaySendRedpackRequest request) throws WxPayException {
return this.wxService.getRedpackService().sendRedpack(request);
}
/**
* <pre>
* 扫码支付模式一生成二维码的方法
* 二维码中的内容为链接,形式为:
* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
* 其中XXXXX为商户需要填写的内容商户将该链接生成二维码如需要打印发布二维码需要采用此格式。商户可调用第三方库生成二维码图片。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
* </pre>
*
* @param productId 产品Id
* @return 生成的二维码URL连接
*/
public String createScanPayQrcodeMode1(String productId) {
return this.wxService.createScanPayQrcodeMode1(productId);
}
/**
* <pre>
* 查询红包记录
* 用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。
* 请求Url https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo
* 是否需要证书 是(证书及使用说明详见商户证书)
* 请求方式 POST
* </pre>
*
* @param mchBillNo 商户发放红包的商户订单号比如10000098201411111234567890
*/
@Operation(summary = "查询红包")
@GetMapping("/queryRedpack/{mchBillNo}")
public WxPayRedpackQueryResult queryRedpack(@PathVariable String mchBillNo) throws WxPayException {
return this.wxService.getRedpackService().queryRedpack(mchBillNo);
}
/**
* <pre>
* 扫码支付模式生成二维码的方法
* 对应链接格式weixin//wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。
* 该模式链接较短,生成的二维码打印到结账小票上的识别率较高。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
* </pre>
*
* @param codeUrl 微信返回的交易会话的二维码链接
* @param logoFile 商户logo图片的文件对象可以为空
* @param sideLength 要生成的二维码的边长如果为空则取默认值400
* @return 生成的二维码的字节数组
*/
public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) throws Exception {
return this.wxService.createScanPayQrcodeMode2(codeUrl, logoFile, sideLength);
}
/**
* <pre>
* 扫码支付模式生成二维码的方法
* 二维码中的内容为链接,形式为:
* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
* 其中XXXXX为商户需要填写的内容商户将该链接生成二维码如需要打印发布二维码需要采用此格式。商户可调用第三方库生成二维码图片。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
* </pre>
*
* @param productId 产品Id
* @param logoFile 商户logo图片的文件对象可以为空
* @param sideLength 要生成的二维码的边长如果为空则取默认值400
* @return 生成的二维码的字节数组
*/
public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) throws Exception {
return this.wxService.createScanPayQrcodeMode1(productId, logoFile, sideLength);
}
/**
* <pre>
* 交易保障
* 应用场景
* 商户在调用微信支付提供的相关接口时,会得到微信支付返回的相关信息以及获得整个接口的响应时间。
* 为提高整体的服务水平,协助商户一起提高服务质量,微信支付提供了相关接口调用耗时和返回信息的主动上报接口,
* 微信支付可以根据商户侧上报的数据进一步优化网络部署,完善服务监控,和商户更好的协作为用户提供更好的业务体验。
* 接口地址: https://api.mch.weixin.qq.com/payitil/report
* 是否需要证书:不需要
* </pre>
*/
@Operation(summary = "提交交易保障数据")
@PostMapping("/report")
public void report(@RequestBody WxPayReportRequest request) throws WxPayException {
this.wxService.report(request);
}
/**
* <pre>
* 扫码支付模式一生成二维码的方法
* 二维码中的内容为链接,形式为
* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
* 其中XXXXX为商户需要填写的内容商户将该链接生成二维码如需要打印发布二维码需要采用此格式。商户可调用第三方库生成二维码图片。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
* </pre>
*
* @param productId 产品Id
* @return 生成的二维码URL连接
*/
public String createScanPayQrcodeMode1(String productId) {
return this.wxService.createScanPayQrcodeMode1(productId);
}
/**
* <pre>
* 下载对账单
* 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态
* 注意:
* 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中跟原支付单订单号一致bill_type为REVOKED
* 2、微信在次日9点启动生成前一天的对账单建议商户10点后再获取
* 3、对账单中涉及金额的字段单位为“元”。
* 4、对账单接口只能下载三个月以内的账单。
* 接口链接https://api.mch.weixin.qq.com/pay/downloadbill
* 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单</a>
* </pre>
*
* @param billDate 对账单日期 bill_date 下载对账单的日期格式20140603
* @param billType 账单类型 bill_type ALL返回当日所有订单信息默认值SUCCESS返回当日成功支付的订单REFUND返回当日退款订单
* @param tarType 压缩账单 tar_type 非必传参数固定值GZIP返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
* @param deviceInfo 设备号 device_info 非必传参数,终端设备号
* @return 保存到本地的临时文件
*/
@Operation(summary = "下载对账单")
@GetMapping("/downloadBill/{billDate}/{billType}/{tarType}/{deviceInfo}")
public WxPayBillResult downloadBill(@PathVariable String billDate, @PathVariable String billType,
@PathVariable String tarType, @PathVariable String deviceInfo) throws WxPayException {
return this.wxService.downloadBill(billDate, billType, tarType, deviceInfo);
}
/**
* <pre>
* 扫码支付模式二生成二维码的方法
* 对应链接格式weixin//wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片
* 该模式链接较短,生成的二维码打印到结账小票上的识别率较高。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
* </pre>
*
* @param codeUrl 微信返回的交易会话的二维码链接
* @param logoFile 商户logo图片的文件对象可以为空
* @param sideLength 要生成的二维码的边长如果为空则取默认值400
* @return 生成的二维码的字节数组
*/
public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) throws Exception {
return this.wxService.createScanPayQrcodeMode2(codeUrl, logoFile, sideLength);
}
@Operation(summary = "下载对账单")
@PostMapping("/downloadBill")
public WxPayBillResult downloadBill(WxPayDownloadBillRequest wxPayDownloadBillRequest) throws WxPayException {
return this.wxService.downloadBill(wxPayDownloadBillRequest);
}
/**
* <pre>
* 交易保障
* 应用场景:
* 商户在调用微信支付提供的相关接口时,会得到微信支付返回的相关信息以及获得整个接口的响应时间。
* 为提高整体的服务水平,协助商户一起提高服务质量,微信支付提供了相关接口调用耗时和返回信息的主动上报接口,
* 微信支付可以根据商户侧上报的数据进一步优化网络部署,完善服务监控,和商户更好的协作为用户提供更好的业务体验。
* 接口地址: https://api.mch.weixin.qq.com/payitil/report
* 是否需要证书:不需要
* </pre>
*/
@Operation(summary = "提交交易保障数据")
@PostMapping("/report")
public void report(@RequestBody WxPayReportRequest request) throws WxPayException {
this.wxService.report(request);
}
/**
* <pre>
* 提交刷卡支付
* 文档地址https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
* 应用场景
* 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付。
* 提醒1提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时商户系统等待5秒后调用【查询订单API】查询支付实际交易结果当返回结果为“USERPAYING”时商户系统可设置间隔时间(建议10秒)重新查询支付结果,直到支付成功或超时(建议30秒)
* 提醒2在调用查询接口返回后如果交易状况不明晰请调用【撤销订单API】此时如果交易失败则关闭订单该单不能再支付成功如果交易成功则将扣款退回到用户账户。当撤销无返回或错误时请再次调用。注意请勿扣款后立即调用【撤销订单API】,建议至少15秒后再调用。撤销订单API需要双向证书
* 接口地址: https://api.mch.weixin.qq.com/pay/micropay
* 是否需要证书:不需要。
* </pre>
*/
@Operation(summary = "提交刷卡支付")
@PostMapping("/micropay")
public WxPayMicropayResult micropay(@RequestBody WxPayMicropayRequest request) throws WxPayException {
return this.wxService.micropay(request);
}
/**
* <pre>
* 下载对账单
* 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
* 注意
* 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中跟原支付单订单号一致bill_type为REVOKED
* 2、微信在次日9点启动生成前一天的对账单建议商户10点后再获取
* 3、对账单中涉及金额的字段单位为“元”
* 4、对账单接口只能下载三个月以内的账单。
* 接口链接https://api.mch.weixin.qq.com/pay/downloadbill
* 详情请见: <a href=
"https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单</a>
* </pre>
*
* @param billDate 对账单日期 bill_date 下载对账单的日期格式20140603
* @param billType 账单类型 bill_type
* ALL返回当日所有订单信息默认值SUCCESS返回当日成功支付的订单REFUND返回当日退款订单
* @param tarType 压缩账单 tar_type 非必传参数固定值GZIP返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
* @param deviceInfo 设备号 device_info 非必传参数,终端设备号
* @return 保存到本地的临时文件
*/
@Operation(summary = "下载对账单")
@GetMapping("/downloadBill/{billDate}/{billType}/{tarType}/{deviceInfo}")
public WxPayBillResult downloadBill(@PathVariable String billDate, @PathVariable String billType,
@PathVariable String tarType, @PathVariable String deviceInfo) throws WxPayException {
return this.wxService.downloadBill(billDate, billType, tarType, deviceInfo);
}
/**
* <pre>
* 撤销订单API
* 文档地址https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
* 应用场景:
* 支付交易返回失败或支付系统超时,调用该接口撤销交易。如果此订单用户支付失败,微信支付系统会将此订单关闭;如果用户支付成功,微信支付系统会将此订单资金退还给用户。
* 注意7天以内的交易单可调用撤销其他正常支付的单如需实现相同功能请调用申请退款API。提交支付交易后调用【查询订单API】没有明确的支付结果再调用【撤销订单API】。
* 调用支付接口后请勿立即调用撤销订单API建议支付后至少15s后再调用撤销订单接口。
* 接口链接 https://api.mch.weixin.qq.com/secapi/pay/reverse
* 是否需要证书:请求需要双向证书。
* </pre>
*/
@Operation(summary = "撤销订单")
@PostMapping("/reverseOrder")
public WxPayOrderReverseResult reverseOrder(@RequestBody WxPayOrderReverseRequest request) throws WxPayException {
return this.wxService.reverseOrder(request);
}
@Operation(summary = "下载对账单")
@PostMapping("/downloadBill")
public WxPayBillResult downloadBill(WxPayDownloadBillRequest wxPayDownloadBillRequest) throws WxPayException {
return this.wxService.downloadBill(wxPayDownloadBillRequest);
}
@Operation(summary = "获取沙箱环境签名key")
@GetMapping("/getSandboxSignKey")
public String getSandboxSignKey() throws WxPayException {
return this.wxService.getSandboxSignKey();
}
/**
* <pre>
* 提交刷卡支付
* 文档地址https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
* 应用场景:
* 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付。
* 提醒1提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时商户系统等待5秒后调用【查询订单API】查询支付实际交易结果当返回结果为“USERPAYING”时商户系统可设置间隔时间(建议10秒)重新查询支付结果,直到支付成功或超时(建议30秒)
* 提醒2在调用查询接口返回后如果交易状况不明晰请调用【撤销订单API】此时如果交易失败则关闭订单该单不能再支付成功如果交易成功则将扣款退回到用户账户。当撤销无返回或错误时请再次调用。注意请勿扣款后立即调用【撤销订单API】,建议至少15秒后再调用。撤销订单API需要双向证书。
* 接口地址: https://api.mch.weixin.qq.com/pay/micropay
* 是否需要证书:不需要。
* </pre>
*/
@Operation(summary = "提交刷卡支付")
@PostMapping("/micropay")
public WxPayMicropayResult micropay(@RequestBody WxPayMicropayRequest request) throws WxPayException {
return this.wxService.micropay(request);
}
@Operation(summary = "发放代金券")
@PostMapping("/sendCoupon")
public WxPayCouponSendResult sendCoupon(@RequestBody WxPayCouponSendRequest request) throws WxPayException {
return this.wxService.sendCoupon(request);
}
/**
* <pre>
* 撤销订单API
* 文档地址https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
* 应用场景:
* 支付交易返回失败或支付系统超时,调用该接口撤销交易。如果此订单用户支付失败,微信支付系统会将此订单关闭;如果用户支付成功,微信支付系统会将此订单资金退还给用户。
* 注意7天以内的交易单可调用撤销其他正常支付的单如需实现相同功能请调用申请退款API。提交支付交易后调用【查询订单API】没有明确的支付结果再调用【撤销订单API】。
* 调用支付接口后请勿立即调用撤销订单API建议支付后至少15s后再调用撤销订单接口。
* 接口链接 https://api.mch.weixin.qq.com/secapi/pay/reverse
* 是否需要证书:请求需要双向证书。
* </pre>
*/
@Operation(summary = "撤销订单")
@PostMapping("/reverseOrder")
public WxPayOrderReverseResult reverseOrder(@RequestBody WxPayOrderReverseRequest request) throws WxPayException {
return this.wxService.reverseOrder(request);
}
@Operation(summary = "查询代金券批次")
@PostMapping("/queryCouponStock")
public WxPayCouponStockQueryResult queryCouponStock(@RequestBody WxPayCouponStockQueryRequest request) throws WxPayException {
return this.wxService.queryCouponStock(request);
}
@Operation(summary = "获取沙箱环境签名key")
@GetMapping("/getSandboxSignKey")
public String getSandboxSignKey() throws WxPayException {
return this.wxService.getSandboxSignKey();
}
@Operation(summary = "查询代金券信息")
@PostMapping("/queryCouponInfo")
public WxPayCouponInfoQueryResult queryCouponInfo(@RequestBody WxPayCouponInfoQueryRequest request) throws WxPayException {
return this.wxService.queryCouponInfo(request);
}
@Operation(summary = "发放代金券")
@PostMapping("/sendCoupon")
public WxPayCouponSendResult sendCoupon(@RequestBody WxPayCouponSendRequest request) throws WxPayException {
return this.wxService.sendCoupon(request);
}
@Operation(summary = "拉取订单评价数据")
@PostMapping("/queryComment")
public String queryComment(Date beginDate, Date endDate, Integer offset, Integer limit) throws WxPayException {
return this.wxService.queryComment(beginDate, endDate, offset, limit);
}
@Operation(summary = "查询代金券批次")
@PostMapping("/queryCouponStock")
public WxPayCouponStockQueryResult queryCouponStock(@RequestBody WxPayCouponStockQueryRequest request)
throws WxPayException {
return this.wxService.queryCouponStock(request);
}
@Operation(summary = "查询代金券信息")
@PostMapping("/queryCouponInfo")
public WxPayCouponInfoQueryResult queryCouponInfo(@RequestBody WxPayCouponInfoQueryRequest request)
throws WxPayException {
return this.wxService.queryCouponInfo(request);
}
@Operation(summary = "拉取订单评价数据")
@PostMapping("/queryComment")
public String queryComment(Date beginDate, Date endDate, Integer offset, Integer limit) throws WxPayException {
return this.wxService.queryComment(beginDate, endDate, offset, limit);
}
}

View File

@@ -55,7 +55,7 @@ spring:
# mybatis-plus配置
mybatis-plus:
# 搜索指定包别名
type-aliases-package: org.wfc.system
type-aliases-package: org.wfc.payment.*.model
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapper-locations: classpath:mapper/**/*.xml
global-config:
@@ -72,19 +72,13 @@ swagger:
logging:
level:
root: debug
org:
springframework:
web: debug
mybatis:
mapper: debug
wfc:
system: debug
com:
github:
binarywang: debug
file:
name: /opt/wfc/logs/wfc-payment.log
root: info
org.springframework.web: info
org.mybatis.mapper: debug
com.github.binarywang: debug
org.wfc.payment.wxpay: debug
org.wfc.payment.alipay: debug
org.wfc.payment.ccpay: debug
wxpay:
appId: 121412414112
@@ -104,7 +98,7 @@ alipay:
signType: RSA2
charset: utf-8
gatewayUrl: https://openapi.alipaydev.com/gateway.do
logPath: /opt/wfc/logs/alipay/alipay_log.txt
logPath: /opt/wfc/logs/alipay/alipay.log
maxQueryRetry: 5
queryDuration: 5
maxCancelRetry: 3
@@ -117,9 +111,45 @@ alipay:
supportPhone:
ccpay:
url: https://api.paymentgateway.com/v1/payments
paymentUrl: https://api.paymentgateway.com/v1/payment
tokenUrl: https://api.paymentgateway.com/v1/token
queryUrl: https://api.paymentgateway.com/v1/query
refundUrl: https://api.paymentgateway.com/v1/refund
apiKey: api-key
merchantId: merchant-id
currency: USD
timeout: 30
callbackUrl: https://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/payment/callback
callbackUrl: https://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/payment/callback
unionpay:
merId: 700000000000001
keyPrivateCert: /opt/wfc/conf/cert/unionpay/wfc-union.pfx
keyPrivateCertPwd: 123456
signCertType: PKCS12
encryptCertPath: /opt/wfc/conf/cert/unionpay/wfc-union.cer
acpMiddleCert: /opt/wfc/conf/cert/unionpay/wfc-middle.cer
acpRootCert: /opt/wfc/conf/cert/unionpay/wfc-root.cer
frontUrl: https://gateway.test.95516.com/gateway/api/frontTransReq.do
backUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/notify
signMethod: 01
version: 5.1.0
channelType: 07
accessType: 0
currencyCode: 156
bizType: 000201
txnType: 01
txnSubType: 01
payTimeout: 30
queryTimeout: 30
refundTimeout: 30
frontFailUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/fail
frontSuccessUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/success
frontBackUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/front
backBackUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/back
frontNotifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/front/notify
backNotifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/back/notify
refundNotifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/refund/notify
queryNotifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/query/notify
refundSuccessUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/refund/success
refundFailUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/refund/fail
querySuccessUrl:

View File

@@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wfc.payment.mapper.AliPayMapper">
<resultMap type="AliPay" id="AliPayResult">
<id property="deptId" column="dept_id" />
<result property="parentId" column="parent_id" />
<result property="ancestors" column="ancestors" />
<result property="deptName" column="dept_name" />
<result property="orderNum" column="order_num" />
<result property="leader" column="leader" />
<result property="phone" column="phone" />
<result property="email" column="email" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="parentName" column="parent_name" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectAliPayInfoVo">
select d.dept_id, d.parent_id, d.ancestors, d.remark, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time
from sys_dept d
</sql>
<select id="selectAliPayInfoByUserId" parameterType="AliPay" resultMap="AliPayResult">
<include refid="selectAliPayInfoVo"/>
where d.del_flag = '0'
<if test="deptId != null and deptId != 0">
AND dept_id = #{deptId}
</if>
<if test="parentId != null and parentId != 0">
AND parent_id = #{parentId}
</if>
<if test="deptName != null and deptName != ''">
AND dept_name like concat('%', #{deptName}, '%')
</if>
<if test="status != null and status != ''">
AND status = #{status}
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
order by d.parent_id, d.order_num
</select>
<insert id="insertAliPayInfo" parameterType="AliPay">
insert into sys_dept(
<if test="deptId != null and deptId != 0">dept_id,</if>
<if test="parentId != null and parentId != 0">parent_id,</if>
<if test="deptName != null and deptName != ''">dept_name,</if>
<if test="ancestors != null and ancestors != ''">ancestors,</if>
<if test="orderNum != null">order_num,</if>
<if test="leader != null and leader != ''">leader,</if>
<if test="phone != null and phone != ''">phone,</if>
<if test="email != null and email != ''">email,</if>
<if test="status != null">status,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
)values(
<if test="deptId != null and deptId != 0">#{deptId},</if>
<if test="parentId != null and parentId != 0">#{parentId},</if>
<if test="deptName != null and deptName != ''">#{deptName},</if>
<if test="ancestors != null and ancestors != ''">#{ancestors},</if>
<if test="orderNum != null">#{orderNum},</if>
<if test="leader != null and leader != ''">#{leader},</if>
<if test="phone != null and phone != ''">#{phone},</if>
<if test="email != null and email != ''">#{email},</if>
<if test="status != null">#{status},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
)
</insert>
<update id="updateAliPayInfoById" parameterType="AliPay">
update sys_dept
<set>
<if test="parentId != null and parentId != 0">parent_id = #{parentId},</if>
<if test="deptName != null and deptName != ''">dept_name = #{deptName},</if>
<if test="ancestors != null and ancestors != ''">ancestors = #{ancestors},</if>
<if test="orderNum != null">order_num = #{orderNum},</if>
<if test="leader != null">leader = #{leader},</if>
<if test="phone != null">phone = #{phone},</if>
<if test="email != null">email = #{email},</if>
<if test="status != null and status != ''">status = #{status},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="remark != null and remark != ''">remark = #{remark},</if>
update_time = sysdate()
</set>
where dept_id = #{id}
</update>
<delete id="deleteAliPayInfoById" parameterType="Long">
update sys_dept set del_flag = '2' where dept_id = #{id}
</delete>
</mapper>

View File

@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wfc.payment.mapper.CreditCardMapper">
<resultMap type="CreditCard" id="CreditCardResult">
<id property="configId" column="config_id" />
<result property="configName" column="config_name" />
<result property="configKey" column="config_key" />
<result property="configValue" column="config_value" />
<result property="configType" column="config_type" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectConfigVo">
select config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark
from sys_config
</sql>
<!-- 查询条件 -->
<sql id="sqlwhereSearch">
<where>
<if test="configId !=null">
and config_id = #{configId}
</if>
<if test="configKey !=null and configKey != ''">
and config_key = #{configKey}
</if>
</where>
</sql>
<select id="selectConfig" parameterType="CreditCard" resultMap="CreditCardResult">
<include refid="selectConfigVo"/>
<include refid="sqlwhereSearch"/>
</select>
<select id="selectCreditCardInfoByUserId" parameterType="CreditCard" resultMap="CreditCardResult">
<include refid="selectConfigVo"/>
<where>
<if test="configName != null and configName != ''">
AND config_name like concat('%', #{configName}, '%')
</if>
<if test="configType != null and configType != ''">
AND config_type = #{configType}
</if>
<if test="configKey != null and configKey != ''">
AND config_key like concat('%', #{configKey}, '%')
</if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
</where>
</select>
<select id="selectCCInfoByUserId" parameterType="Long" resultMap="CreditCardResult">
<include refid="selectConfigVo"/>
where config_id = #{configId}
</select>
<select id="checkConfigKeyUnique" parameterType="String" resultMap="CreditCardResult">
<include refid="selectConfigVo"/>
where config_key = #{configKey} limit 1
</select>
<insert id="insertCreditCardInfo" parameterType="CreditCard">
insert into sys_config (
<if test="configName != null and configName != '' ">config_name,</if>
<if test="configKey != null and configKey != '' ">config_key,</if>
<if test="configValue != null and configValue != '' ">config_value,</if>
<if test="configType != null and configType != '' ">config_type,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
)values(
<if test="configName != null and configName != ''">#{configName},</if>
<if test="configKey != null and configKey != ''">#{configKey},</if>
<if test="configValue != null and configValue != ''">#{configValue},</if>
<if test="configType != null and configType != ''">#{configType},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
)
</insert>
<update id="updateCreditCardInfo" parameterType="CreditCard">
update sys_config
<set>
<if test="configName != null and configName != ''">config_name = #{configName},</if>
<if test="configKey != null and configKey != ''">config_key = #{configKey},</if>
<if test="configValue != null and configValue != ''">config_value = #{configValue},</if>
<if test="configType != null and configType != ''">config_type = #{configType},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="remark != null">remark = #{remark},</if>
update_time = sysdate()
</set>
where config_id = #{configId}
</update>
<delete id="deleteCreditCardInfoById" parameterType="Long">
delete from credit_card where user_id = #{userId}
</delete>
<delete id="deleteConfigByIds" parameterType="Long">
delete from sys_config where config_id in
<foreach item="configId" collection="array" open="(" separator="," close=")">
#{configId}
</foreach>
</delete>
</mapper>

View File

@@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wfc.payment.mapper.PayPalMapper">
<resultMap type="PayPal" id="PayPalResult">
<id property="deptId" column="dept_id" />
<result property="parentId" column="parent_id" />
<result property="ancestors" column="ancestors" />
<result property="deptName" column="dept_name" />
<result property="orderNum" column="order_num" />
<result property="leader" column="leader" />
<result property="phone" column="phone" />
<result property="email" column="email" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="parentName" column="parent_name" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectPayPalInfoVo">
select d.dept_id, d.parent_id, d.ancestors, d.remark, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time
from sys_dept d
</sql>
<select id="selectPayPalInfoByUserId" parameterType="PayPal" resultMap="PayPalResult">
<include refid="selectPayPalInfoVo"/>
where d.del_flag = '0'
<if test="deptId != null and deptId != 0">
AND dept_id = #{deptId}
</if>
<if test="parentId != null and parentId != 0">
AND parent_id = #{parentId}
</if>
<if test="deptName != null and deptName != ''">
AND dept_name like concat('%', #{deptName}, '%')
</if>
<if test="status != null and status != ''">
AND status = #{status}
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
order by d.parent_id, d.order_num
</select>
<insert id="insertPayPalInfo" parameterType="PayPal">
insert into sys_dept(
<if test="deptId != null and deptId != 0">dept_id,</if>
<if test="parentId != null and parentId != 0">parent_id,</if>
<if test="deptName != null and deptName != ''">dept_name,</if>
<if test="ancestors != null and ancestors != ''">ancestors,</if>
<if test="orderNum != null">order_num,</if>
<if test="leader != null and leader != ''">leader,</if>
<if test="phone != null and phone != ''">phone,</if>
<if test="email != null and email != ''">email,</if>
<if test="status != null">status,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
)values(
<if test="deptId != null and deptId != 0">#{deptId},</if>
<if test="parentId != null and parentId != 0">#{parentId},</if>
<if test="deptName != null and deptName != ''">#{deptName},</if>
<if test="ancestors != null and ancestors != ''">#{ancestors},</if>
<if test="orderNum != null">#{orderNum},</if>
<if test="leader != null and leader != ''">#{leader},</if>
<if test="phone != null and phone != ''">#{phone},</if>
<if test="email != null and email != ''">#{email},</if>
<if test="status != null">#{status},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
)
</insert>
<update id="updatePayPalInfoById" parameterType="PayPal">
update sys_dept
<set>
<if test="parentId != null and parentId != 0">parent_id = #{parentId},</if>
<if test="deptName != null and deptName != ''">dept_name = #{deptName},</if>
<if test="ancestors != null and ancestors != ''">ancestors = #{ancestors},</if>
<if test="orderNum != null">order_num = #{orderNum},</if>
<if test="leader != null">leader = #{leader},</if>
<if test="phone != null">phone = #{phone},</if>
<if test="email != null">email = #{email},</if>
<if test="status != null and status != ''">status = #{status},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="remark != null and remark != ''">remark = #{remark},</if>
update_time = sysdate()
</set>
where dept_id = #{id}
</update>
<delete id="deletePayPalInfoById" parameterType="Long">
update sys_dept set del_flag = '2' where dept_id = #{id}
</delete>
</mapper>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wfc.payment.ccpay.mapper.UCreditCardPaymentMapper">
<insert id="insertPayment" parameterType="org.wfc.payment.ccpay.model.UCreditCardPayment">
INSERT INTO u_credit_card_payment (transaction_id, user_id, order_id, amount, currency, status, payment_time, card_type, card_holder_name, billing_address, card_last_four, gateway_response)
VALUES (#{transactionId}, #{userId}, #{orderId}, #{amount}, #{currency}, #{status}, #{paymentTime}, #{cardType}, #{cardHolderName}, #{billingAddress}, #{cardLastFour}, #{gatewayResponse})
</insert>
<select id="selectPaymentById" parameterType="long" resultType="org.wfc.payment.ccpay.model.UCreditCardPayment">
SELECT * FROM u_credit_card_payment WHERE id = #{id}
</select>
<!-- 其他需要的 SQL 映射 -->
</mapper>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wfc.payment.ccpay.mapper.UCreditCardTokenMapper">
<insert id="insertToken" parameterType="org.wfc.payment.ccpay.model.UCreditCardToken">
INSERT INTO u_credit_card_token (user_id, token, card_last_four, card_type, created_at)
VALUES (#{userId}, #{token}, #{cardLastFour}, #{cardType}, #{createdAt})
</insert>
<select id="selectTokenByUserId" parameterType="long" resultType="org.wfc.payment.ccpay.model.UCreditCardToken">
SELECT * FROM u_credit_card_token WHERE user_id = #{userId}
</select>
</mapper>

View File

@@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wfc.payment.mapper.WxPayMapper">
<resultMap type="WxPay" id="WxPayResult">
<id property="deptId" column="dept_id" />
<result property="parentId" column="parent_id" />
<result property="ancestors" column="ancestors" />
<result property="deptName" column="dept_name" />
<result property="orderNum" column="order_num" />
<result property="leader" column="leader" />
<result property="phone" column="phone" />
<result property="email" column="email" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="parentName" column="parent_name" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectWxPayInfoVo">
select d.dept_id, d.parent_id, d.ancestors, d.remark, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time
from sys_dept d
</sql>
<select id="selectWxPayInfoByUserId" parameterType="WxPay" resultMap="WxPayResult">
<include refid="selectWxPayInfoVo"/>
where d.del_flag = '0'
<if test="deptId != null and deptId != 0">
AND dept_id = #{deptId}
</if>
<if test="parentId != null and parentId != 0">
AND parent_id = #{parentId}
</if>
<if test="deptName != null and deptName != ''">
AND dept_name like concat('%', #{deptName}, '%')
</if>
<if test="status != null and status != ''">
AND status = #{status}
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
order by d.parent_id, d.order_num
</select>
<insert id="insertWxPayInfo" parameterType="WxPay">
insert into sys_dept(
<if test="deptId != null and deptId != 0">dept_id,</if>
<if test="parentId != null and parentId != 0">parent_id,</if>
<if test="deptName != null and deptName != ''">dept_name,</if>
<if test="ancestors != null and ancestors != ''">ancestors,</if>
<if test="orderNum != null">order_num,</if>
<if test="leader != null and leader != ''">leader,</if>
<if test="phone != null and phone != ''">phone,</if>
<if test="email != null and email != ''">email,</if>
<if test="status != null">status,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
)values(
<if test="deptId != null and deptId != 0">#{deptId},</if>
<if test="parentId != null and parentId != 0">#{parentId},</if>
<if test="deptName != null and deptName != ''">#{deptName},</if>
<if test="ancestors != null and ancestors != ''">#{ancestors},</if>
<if test="orderNum != null">#{orderNum},</if>
<if test="leader != null and leader != ''">#{leader},</if>
<if test="phone != null and phone != ''">#{phone},</if>
<if test="email != null and email != ''">#{email},</if>
<if test="status != null">#{status},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
)
</insert>
<update id="updateWxPayInfoById" parameterType="WxPay">
update sys_dept
<set>
<if test="parentId != null and parentId != 0">parent_id = #{parentId},</if>
<if test="deptName != null and deptName != ''">dept_name = #{deptName},</if>
<if test="ancestors != null and ancestors != ''">ancestors = #{ancestors},</if>
<if test="orderNum != null">order_num = #{orderNum},</if>
<if test="leader != null">leader = #{leader},</if>
<if test="phone != null">phone = #{phone},</if>
<if test="email != null">email = #{email},</if>
<if test="status != null and status != ''">status = #{status},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="remark != null and remark != ''">remark = #{remark},</if>
update_time = sysdate()
</set>
where dept_id = #{id}
</update>
<delete id="deleteWxPayInfoById" parameterType="Long">
update sys_dept set del_flag = '2' where dept_id = #{id}
</delete>
</mapper>