feat: payment update
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
// 其他需要的方法
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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", "失败");
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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>
|
||||
@@ -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') >= date_format(#{params.beginTime},'%y%m%d')
|
||||
</if>
|
||||
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
|
||||
and date_format(create_time,'%y%m%d') <= 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user