2
0

fix: 支付模块调整和对接

This commit is contained in:
caiyuchao
2025-01-14 15:47:51 +08:00
parent 3a289f9f2e
commit 79a420f07c
90 changed files with 5075 additions and 2604 deletions

View File

@@ -39,6 +39,7 @@
<swagger.core.version>1.6.2</swagger.core.version> <swagger.core.version>1.6.2</swagger.core.version>
<org.mapstruct.version>1.6.3</org.mapstruct.version> <org.mapstruct.version>1.6.3</org.mapstruct.version>
<mail.version>1.6.2</mail.version> <mail.version>1.6.2</mail.version>
<ijapy.version>2.9.11</ijapy.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<wfc.nacos.server>${env.NACOS_SERVER_NAME}</wfc.nacos.server> <wfc.nacos.server>${env.NACOS_SERVER_NAME}</wfc.nacos.server>
<wfc.nacos.port>${env.NACOS_SERVER_PORT}</wfc.nacos.port> <wfc.nacos.port>${env.NACOS_SERVER_PORT}</wfc.nacos.port>
@@ -335,6 +336,13 @@
<artifactId>javax.mail</artifactId> <artifactId>javax.mail</artifactId>
<version>${mail.version}</version> <version>${mail.version}</version>
</dependency> </dependency>
<!-- 支付 -->
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-All</artifactId>
<version>${ijapy.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

View File

@@ -15,6 +15,7 @@ import org.wfc.common.core.domain.R;
import org.wfc.common.core.web.page.TableDataInfo; import org.wfc.common.core.web.page.TableDataInfo;
import org.wfc.user.api.domain.UUser; import org.wfc.user.api.domain.UUser;
import org.wfc.user.api.domain.bo.UClientBo; import org.wfc.user.api.domain.bo.UClientBo;
import org.wfc.user.api.domain.vo.UOrderVo;
import org.wfc.user.api.factory.RemoteUUserFallbackFactory; import org.wfc.user.api.factory.RemoteUUserFallbackFactory;
/** /**
@@ -84,4 +85,10 @@ public interface RemoteUUserService
*/ */
@PostMapping("/client/recordClientUser") @PostMapping("/client/recordClientUser")
public R<Boolean> recordClientUser(@RequestBody UClientBo clientBo); public R<Boolean> recordClientUser(@RequestBody UClientBo clientBo);
@PostMapping("/order/paySuccess/{id}")
public R<Boolean> paySuccess(@PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
@GetMapping(value = "/order/{id}")
public R<UOrderVo> getOrderById(@PathVariable("id") Long id);
} }

View File

@@ -0,0 +1,40 @@
package org.wfc.user.api.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author: cyc
* @since: 2025-01-13
*/
@Data
public class UOrderVo {
private Long userId;
private Long packageId;
private Long paymentId;
private String orderNo;
private Integer type;
private BigDecimal orderAmount;
private Integer status;
private Long id;
private Boolean delFlag;
private Long createBy;
private Date createTime;
private Long updateBy;
private Date updateTime;
}

View File

@@ -11,6 +11,7 @@ import org.wfc.common.core.web.page.TableDataInfo;
import org.wfc.user.api.RemoteUUserService; import org.wfc.user.api.RemoteUUserService;
import org.wfc.user.api.domain.UUser; import org.wfc.user.api.domain.UUser;
import org.wfc.user.api.domain.bo.UClientBo; import org.wfc.user.api.domain.bo.UClientBo;
import org.wfc.user.api.domain.vo.UOrderVo;
import java.util.Collections; import java.util.Collections;
@@ -71,6 +72,16 @@ public class RemoteUUserFallbackFactory implements FallbackFactory<RemoteUUserSe
public R<Boolean> recordClientUser(UClientBo clientBo) { public R<Boolean> recordClientUser(UClientBo clientBo) {
return R.fail("根据设备mac保存或更新设备信息失败:" + throwable.getMessage()); return R.fail("根据设备mac保存或更新设备信息失败:" + throwable.getMessage());
} }
@Override
public R<Boolean> paySuccess(Long id, String source) {
return R.fail("pay callback error:" + throwable.getMessage());
}
@Override
public R<UOrderVo> getOrderById(Long id) {
return R.fail("get order error:" + throwable.getMessage());
}
}; };
} }
} }

View File

@@ -73,52 +73,50 @@
<artifactId>wfc-common-swagger</artifactId> <artifactId>wfc-common-swagger</artifactId>
</dependency> </dependency>
<!-- stripe for credit card pay -->
<dependency> <dependency>
<groupId>com.stripe</groupId> <groupId>com.github.javen205</groupId>
<artifactId>stripe-java</artifactId> <artifactId>IJPay-WxPay</artifactId>
<version>20.0.0</version> <version>${ijapy.version}</version>
</dependency> </dependency>
<!-- for WeChat Pay -->
<dependency> <dependency>
<groupId>com.github.binarywang</groupId> <groupId>com.github.javen205</groupId>
<artifactId>weixin-java-pay</artifactId> <artifactId>IJPay-AliPay</artifactId>
<version>4.6.0</version> <version>${ijapy.version}</version>
</dependency> </dependency>
<!-- for Ali Pay -->
<dependency> <dependency>
<groupId>com.alipay.sdk</groupId> <groupId>com.github.javen205</groupId>
<artifactId>alipay-sdk-java</artifactId> <artifactId>IJPay-QQ</artifactId>
<version>4.11.0.ALL</version> <version>${ijapy.version}</version>
</dependency> </dependency>
<!-- for Union Pay -->
<dependency> <dependency>
<groupId>com.egzosn</groupId> <groupId>com.github.javen205</groupId>
<artifactId>pay-java-union</artifactId> <artifactId>IJPay-UnionPay</artifactId>
<version>2.14.7</version> <version>${ijapy.version}</version>
</dependency> </dependency>
<!-- Missing dependency for pay-java-web -->
<dependency> <dependency>
<groupId>com.egzosn</groupId> <groupId>com.github.javen205</groupId>
<artifactId>pay-java-web-support</artifactId> <artifactId>IJPay-JDPay</artifactId>
<version>2.14.7</version> <version>${ijapy.version}</version>
</dependency> </dependency>
<!-- Swagger 依赖项 -->
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>com.github.javen205</groupId>
<artifactId>springdoc-openapi-ui</artifactId> <artifactId>IJPay-PayPal</artifactId>
<version>1.6.14</version> <version>${ijapy.version}</version>
</dependency>
<dependency>
<groupId>org.wfc</groupId>
<artifactId>wfc-api-user</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.persistence</groupId> <groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId> <artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -136,13 +134,6 @@
</goals> </goals>
</execution> </execution>
</executions> </executions>
<configuration>
<archive>
<manifestEntries>
<Implementation-Version>${wfc-modules-payment.version}</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>

View File

@@ -1,18 +1,11 @@
package org.wfc.payment; package org.wfc.payment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.ComponentScan;
import org.wfc.common.security.annotation.EnableCustomConfig;
import org.wfc.common.security.annotation.EnableRyFeignClients;
import javax.annotation.PostConstruct;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.wfc.payment.ccpay.config.CcpayConfig; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.wfc.common.security.annotation.EnableCustomConfig;
import org.wfc.common.security.annotation.EnableRyFeignClients;
/** /**
* Payment module * Payment module
@@ -26,26 +19,9 @@ public class WfcPaymentApplication
{ {
private static final Logger logger = LoggerFactory.getLogger(WfcPaymentApplication.class); private static final Logger logger = LoggerFactory.getLogger(WfcPaymentApplication.class);
private final CcpayConfig ccpayConfig;
@Autowired
public WfcPaymentApplication(CcpayConfig ccpayConfig) {
this.ccpayConfig = ccpayConfig;
}
public static void main(String[] args) public static void main(String[] args)
{ {
SpringApplication.run(WfcPaymentApplication.class, args); SpringApplication.run(WfcPaymentApplication.class, args);
logger.info("(♥◠‿◠)ノ゙ Payment module startup successfully ლ(´ڡ`ლ)゙ \n"); logger.info("(♥◠‿◠)ノ゙ Payment module startup successfully ლ(´ڡ`ლ)゙ \n");
} }
@PostConstruct
public void printConfig() {
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());
System.out.println("CCPay Timeout: " + ccpayConfig.getTimeout());
System.out.println("CCPay Callback URL: " + ccpayConfig.getCallbackUrl());
}
} }

View File

@@ -1,25 +0,0 @@
package org.wfc.payment.alipay.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "alipay")
public class AlipayConfig {
private String appId;
private String privateKey;
private String publicKey;
private String notifyUrl;
private String returnUrl;
private String signType;
private String charset;
private String gatewayUrl;
private String logPath;
private int maxQueryRetry;
private int queryDuration;
private int maxCancelRetry;
private int cancelDuration;
private int heartbeatDelay;
}

View File

@@ -1,93 +0,0 @@
package org.wfc.payment.alipay.controller;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.wfc.payment.alipay.service.IAlipayPaymentService;
import org.wfc.payment.alipay.service.IAlipayQueryOrderService;
import org.wfc.payment.alipay.service.IAlipayTradeCloseService;
import org.wfc.payment.alipay.service.IAlipayRefundService;
import org.wfc.payment.alipay.service.IAlipayNotifyService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
@Tag(name = "Ali Pay")
@RestController
@RequestMapping("/alipay")
@AllArgsConstructor
public class AlipayController {
private final IAlipayPaymentService alipayPaymentService;
private final IAlipayQueryOrderService alipayQueryService;
private final IAlipayTradeCloseService alipayCloseService;
private final IAlipayRefundService alipayRefundService;
@Operation(summary = "Create Alipay order")
@GetMapping("/pay")
public String pay(@RequestParam String outTradeNo, @RequestParam String totalAmount, @RequestParam String subject,
@RequestParam String body) {
try {
return alipayPaymentService.createPayment(outTradeNo, totalAmount, subject, body);
} catch (AlipayApiException e) {
e.printStackTrace();
return "Error occurred while processing payment";
}
}
@Operation(summary = "Query Alipay order")
@GetMapping("/query")
public AlipayTradeQueryResponse query(@RequestParam String outTradeNo) {
try {
return alipayQueryService.queryOrder(outTradeNo);
} catch (AlipayApiException e) {
e.printStackTrace();
return null;
}
}
@Operation(summary = "Close Alipay order")
@GetMapping("/close")
public AlipayTradeCloseResponse close(@RequestParam String outTradeNo) {
try {
return alipayCloseService.closeOrder(outTradeNo);
} catch (AlipayApiException e) {
e.printStackTrace();
return null;
}
}
@Operation(summary = "Refund Alipay order")
@GetMapping("/refund")
public AlipayTradeRefundResponse refund(@RequestParam String outTradeNo, @RequestParam String refundAmount,
@RequestParam String refundReason) {
try {
return alipayRefundService.refundOrder(outTradeNo, refundAmount, refundReason);
} catch (AlipayApiException e) {
e.printStackTrace();
return null;
}
}
private final IAlipayNotifyService alipayNotifyService;
@PostMapping("/notify")
public String handleAlipayNotify(@RequestParam Map<String, String> params) {
try {
boolean result = alipayNotifyService.handleAlipayNotify(params);
return result ? "success" : "failure";
} catch (AlipayApiException e) {
e.printStackTrace();
return "failure";
}
}
}

View File

@@ -1,17 +0,0 @@
package org.wfc.payment.alipay.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.wfc.payment.alipay.model.UAlipayOrderModel;
@Mapper
public interface UAlipayOrderMapper {
void insertOrder(UAlipayOrderModel uAlipayOrder);
void updateOrder(UAlipayOrderModel uAlipayOrder);
UAlipayOrderModel selectOrderByOutTradeNo(@Param("outTradeNo") String outTradeNo);
UAlipayOrderModel selectOrderById(@Param("id") Long id);
}

View File

@@ -1,26 +0,0 @@
package org.wfc.payment.alipay.model;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
@Data
@Entity
public class UAlipayOrderModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private String outTradeNo;
private String tradeStatus;
private BigDecimal totalAmount;
private String subject;
private String body;
private String createBy;
private Date createTime;
private String updateBy;
private Date updateTime;
// Getters and Setters
}

View File

@@ -1,9 +0,0 @@
package org.wfc.payment.alipay.service;
import java.util.Map;
import com.alipay.api.AlipayApiException;
public interface IAlipayNotifyService {
boolean handleAlipayNotify(Map<String, String> params) throws AlipayApiException;
}

View File

@@ -1,7 +0,0 @@
package org.wfc.payment.alipay.service;
import com.alipay.api.AlipayApiException;
public interface IAlipayPaymentService {
String createPayment(String outTradeNo, String totalAmount, String subject, String body) throws AlipayApiException;
}

View File

@@ -1,8 +0,0 @@
package org.wfc.payment.alipay.service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeQueryResponse;
public interface IAlipayQueryOrderService {
AlipayTradeQueryResponse queryOrder(String outTradeNo) throws AlipayApiException;
}

View File

@@ -1,9 +0,0 @@
package org.wfc.payment.alipay.service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeRefundResponse;
public interface IAlipayRefundService {
AlipayTradeRefundResponse refundOrder(String outTradeNo, String refundAmount, String refundReason)
throws AlipayApiException;
}

View File

@@ -1,8 +0,0 @@
package org.wfc.payment.alipay.service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeCloseResponse;
public interface IAlipayTradeCloseService {
AlipayTradeCloseResponse closeOrder(String outTradeNo) throws AlipayApiException;
}

View File

@@ -1,60 +0,0 @@
package org.wfc.payment.alipay.service.impl;
import java.math.BigDecimal;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.wfc.payment.alipay.config.AlipayConfig;
import org.wfc.payment.alipay.mapper.UAlipayOrderMapper;
import org.wfc.payment.alipay.model.UAlipayOrderModel;
import org.wfc.payment.alipay.service.IAlipayNotifyService;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import java.util.Date;
@Service
public class AlipayNotifyServiceImpl implements IAlipayNotifyService {
private final AlipayConfig alipayConfig;
private final UAlipayOrderMapper alipayOrderMapper;
@Autowired
public AlipayNotifyServiceImpl(UAlipayOrderMapper alipayOrderMapper, AlipayConfig alipayConfig) {
this.alipayOrderMapper = alipayOrderMapper;
this.alipayConfig = alipayConfig;
}
public boolean handleAlipayNotify(Map<String, String> params) throws AlipayApiException {
boolean signVerified = AlipaySignature.rsaCheckV1(params,
alipayConfig.getPublicKey(),
alipayConfig.getCharset(),
alipayConfig.getSignType());
if (signVerified) {
// 处理业务逻辑,例如更新订单状态
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
BigDecimal totalAmount = new BigDecimal(params.get("total_amount"));
String subject = params.get("subject");
String body = params.get("body");
UAlipayOrderModel order = alipayOrderMapper.selectOrderByOutTradeNo(outTradeNo);
if (order == null) {
order = new UAlipayOrderModel();
order.setOutTradeNo(outTradeNo);
order.setCreateTime(new Date());
alipayOrderMapper.insertOrder(order);
}
order.setTradeStatus(tradeStatus);
order.setTotalAmount(totalAmount);
order.setSubject(subject);
order.setBody(body);
order.setUpdateTime(new Date());
alipayOrderMapper.updateOrder(order);
return "TRADE_SUCCESS".equals(tradeStatus);
}
return false;
}
}

View File

@@ -1,44 +0,0 @@
package org.wfc.payment.alipay.service.impl;
import org.springframework.stereotype.Service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import org.wfc.payment.alipay.config.AlipayConfig;
import org.wfc.payment.alipay.service.IAlipayPaymentService;
import lombok.AllArgsConstructor;
@Service
@AllArgsConstructor
public class AlipayPaymentServiceImpl implements IAlipayPaymentService {
private final AlipayConfig alipayConfig;
@Override
public String createPayment(String outTradeNo, String totalAmount, String subject, String body)
throws AlipayApiException {
AlipayClient alipayClient = new DefaultAlipayClient(
alipayConfig.getGatewayUrl(),
alipayConfig.getAppId(),
alipayConfig.getPrivateKey(),
"json",
alipayConfig.getCharset(),
alipayConfig.getPublicKey(),
alipayConfig.getSignType());
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl(alipayConfig.getReturnUrl());
request.setNotifyUrl(alipayConfig.getNotifyUrl());
request.setBizContent("{" +
"\"out_trade_no\":\"" + outTradeNo + "\"," +
"\"total_amount\":\"" + totalAmount + "\"," +
"\"subject\":\"" + subject + "\"," +
"\"body\":\"" + body + "\"," +
"\"product_code\":\"FAST_INSTANT_TRADE_PAY\"" +
"}");
return alipayClient.pageExecute(request).getBody();
}
}

View File

@@ -1,39 +0,0 @@
package org.wfc.payment.alipay.service.impl;
import org.springframework.stereotype.Service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import lombok.AllArgsConstructor;
import org.wfc.payment.alipay.config.AlipayConfig;
import org.wfc.payment.alipay.service.IAlipayQueryOrderService;
@Service
@AllArgsConstructor
public class AlipayQueryOrderServiceImpl implements IAlipayQueryOrderService {
private final AlipayConfig alipayConfig;
@Override
public AlipayTradeQueryResponse queryOrder(String outTradeNo) throws AlipayApiException {
AlipayClient alipayClient = new DefaultAlipayClient(
alipayConfig.getGatewayUrl(),
alipayConfig.getAppId(),
alipayConfig.getPrivateKey(),
"json",
alipayConfig.getCharset(),
alipayConfig.getPublicKey(),
alipayConfig.getSignType());
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"" + outTradeNo + "\"" +
"}");
return alipayClient.execute(request);
}
}

View File

@@ -1,43 +0,0 @@
package org.wfc.payment.alipay.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import lombok.AllArgsConstructor;
import org.wfc.payment.alipay.config.AlipayConfig;
import org.wfc.payment.alipay.service.IAlipayRefundService;
@Service
@AllArgsConstructor
public class AlipayRefundServiceImpl implements IAlipayRefundService {
private final AlipayConfig alipayConfig;
@Override
public AlipayTradeRefundResponse refundOrder(String outTradeNo, String refundAmount, String refundReason)
throws AlipayApiException {
AlipayClient alipayClient = new DefaultAlipayClient(
alipayConfig.getGatewayUrl(),
alipayConfig.getAppId(),
alipayConfig.getPrivateKey(),
"json",
alipayConfig.getCharset(),
alipayConfig.getPublicKey(),
alipayConfig.getSignType());
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"" + outTradeNo + "\"," +
"\"refund_amount\":\"" + refundAmount + "\"," +
"\"refund_reason\":\"" + refundReason + "\"" +
"}");
return alipayClient.execute(request);
}
}

View File

@@ -1,37 +0,0 @@
package org.wfc.payment.alipay.service.impl;
import org.springframework.stereotype.Service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import org.wfc.payment.alipay.config.AlipayConfig;
import org.wfc.payment.alipay.service.IAlipayTradeCloseService;
import lombok.AllArgsConstructor;
@Service
@AllArgsConstructor
public class AlipayTradeCloseServiceImpl implements IAlipayTradeCloseService {
private final AlipayConfig alipayConfig;
@Override
public AlipayTradeCloseResponse closeOrder(String outTradeNo) throws AlipayApiException {
AlipayClient alipayClient = new DefaultAlipayClient(
alipayConfig.getGatewayUrl(),
alipayConfig.getAppId(),
alipayConfig.getPrivateKey(),
"json",
alipayConfig.getCharset(),
alipayConfig.getPublicKey(),
alipayConfig.getSignType());
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"" + outTradeNo + "\"" +
"}");
return alipayClient.execute(request);
}
}

View File

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

View File

@@ -0,0 +1,16 @@
package org.wfc.payment.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.wfc.payment.interceptor.AliPayInterceptor;
import org.wfc.payment.interceptor.WxPayInterceptor;
@Configuration
public class PayConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AliPayInterceptor()).addPathPatterns("/aliPay/**");
registry.addInterceptor(new WxPayInterceptor()).addPathPatterns("/wxPay/**");
}
}

View File

@@ -0,0 +1,27 @@
package org.wfc.payment.domain;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
*
* <p>支付宝配置 Bean</p>
*
* @author cyc
*/
@Component
@Data
@ConfigurationProperties(prefix = "alipay")
public class AliPayBean {
private String appId;
private String privateKey;
private String publicKey;
private String appCertPath;
private String aliPayCertPath;
private String aliPayRootCertPath;
private String serverUrl;
private String domain;
private String testDomain;
}

View File

@@ -0,0 +1,82 @@
package org.wfc.payment.domain;
import com.alibaba.fastjson.JSON;
/**
* @author cyc
*/
public class H5SceneInfo {
private H5 h5_info;
public H5 getH5Info() {
return h5_info;
}
public void setH5Info(H5 h5_info) {
this.h5_info = h5_info;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
public static class H5 {
private String type;
private String app_name;
private String bundle_id;
private String package_name;
private String wap_url;
private String wap_name;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getApp_name() {
return app_name;
}
public void setApp_name(String app_name) {
this.app_name = app_name;
}
public String getBundle_id() {
return bundle_id;
}
public void setBundle_id(String bundle_id) {
this.bundle_id = bundle_id;
}
public String getPackage_name() {
return package_name;
}
public void setPackage_name(String package_name) {
this.package_name = package_name;
}
public String getWap_url() {
return wap_url;
}
public void setWap_url(String wap_url) {
this.wap_url = wap_url;
}
public String getWap_name() {
return wap_name;
}
public void setWap_name(String wap_name) {
this.wap_name = wap_name;
}
}
}

View File

@@ -0,0 +1,71 @@
package org.wfc.payment.domain;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
*
* <p>JD配置 Bean</p>
*
* @author cyc
*/
@Component
@ConfigurationProperties(prefix = "jdpay")
public class JdPayBean {
private String mchId;
private String rsaPrivateKey;
private String desKey;
private String rsaPublicKey;
private String certPath;
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getRsaPrivateKey() {
return rsaPrivateKey;
}
public void setRsaPrivateKey(String rsaPrivateKey) {
this.rsaPrivateKey = rsaPrivateKey;
}
public String getDesKey() {
return desKey;
}
public void setDesKey(String desKey) {
this.desKey = desKey;
}
public String getRsaPublicKey() {
return rsaPublicKey;
}
public void setRsaPublicKey(String rsaPublicKey) {
this.rsaPublicKey = rsaPublicKey;
}
public String getCertPath() {
return certPath;
}
public void setCertPath(String certPath) {
this.certPath = certPath;
}
@Override
public String toString() {
return "JdPayBean{" +
"mchId='" + mchId + '\'' +
", rsaPrivateKey='" + rsaPrivateKey + '\'' +
", desKey='" + desKey + '\'' +
", rsaPublicKey='" + rsaPublicKey + '\'' +
", certPath='" + certPath + '\'' +
'}';
}
}

View File

@@ -0,0 +1,61 @@
package org.wfc.payment.domain;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
*
* <p>PayPal配置 Bean</p>
*
* @author cyc
*/
@Component
@ConfigurationProperties(prefix = "paypal")
public class PayPalBean {
private String clientId;
private String secret;
private Boolean sandBox;
private String domain;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public Boolean getSandBox() {
return sandBox;
}
public void setSandBox(Boolean sandBox) {
this.sandBox = sandBox;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
@Override
public String toString() {
return "PayPalBean{" +
"clientId='" + clientId + '\'' +
", secret='" + secret + '\'' +
", sandBox=" + sandBox +
", domain='" + domain + '\'' +
'}';
}
}

View File

@@ -0,0 +1,61 @@
package org.wfc.payment.domain;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
*
* <p>云闪付配置 Bean</p>
*
* @author cyc
*/
@Component
@ConfigurationProperties(prefix = "union")
public class UnionPayBean {
private String machId;
private String key;
private String serverUrl;
private String domain;
public String getMachId() {
return machId;
}
public void setMachId(String machId) {
this.machId = machId;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getServerUrl() {
return serverUrl;
}
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
@Override
public String toString() {
return "UnionPayBean{" +
"machId='" + machId + '\'' +
", key='" + key + '\'' +
", serverUrl='" + serverUrl + '\'' +
", domain='" + domain + '\'' +
'}';
}
}

View File

@@ -0,0 +1,75 @@
package org.wfc.payment.domain;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
*
* <p>微信配置 Bean</p>
*
* @author cyc
*/
@Component
@ConfigurationProperties(prefix = "wxpay")
public class WxPayBean {
private String appId;
private String appSecret;
private String mchId;
private String partnerKey;
private String certPath;
private String domain;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getPartnerKey() {
return partnerKey;
}
public void setPartnerKey(String partnerKey) {
this.partnerKey = partnerKey;
}
public String getCertPath() {
return certPath;
}
public void setCertPath(String certPath) {
this.certPath = certPath;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
@Override
public String toString() {
return "WxPayBean [appId=" + appId + ", appSecret=" + appSecret + ", mchId=" + mchId + ", partnerKey="
+ partnerKey + ", certPath=" + certPath + ", domain=" + domain + "]";
}
}

View File

@@ -0,0 +1,119 @@
package org.wfc.payment.domain;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
*
* <p>微信配置 Bean</p>
*
* @author cyc
*/
@Component
@ConfigurationProperties(prefix = "v3")
public class WxPayV3Bean {
private String appId;
private String keyPath;
private String publicKeyPath;
private String certPath;
private String certP12Path;
private String platformCertPath;
private String mchId;
private String apiKey;
private String apiKey3;
private String domain;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getKeyPath() {
return keyPath;
}
public void setKeyPath(String keyPath) {
this.keyPath = keyPath;
}
public String getPublicKeyPath() {
return publicKeyPath;
}
public void setPublicKeyPath(String publicKeyPath) {
this.publicKeyPath = publicKeyPath;
}
public String getCertPath() {
return certPath;
}
public void setCertPath(String certPath) {
this.certPath = certPath;
}
public String getCertP12Path() {
return certP12Path;
}
public void setCertP12Path(String certP12Path) {
this.certP12Path = certP12Path;
}
public String getPlatformCertPath() {
return platformCertPath;
}
public void setPlatformCertPath(String platformCertPath) {
this.platformCertPath = platformCertPath;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getApiKey3() {
return apiKey3;
}
public void setApiKey3(String apiKey3) {
this.apiKey3 = apiKey3;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
@Override
public String toString() {
return "WxPayV3Bean{" +
"keyPath='" + keyPath + '\'' +
", certPath='" + certPath + '\'' +
", certP12Path='" + certP12Path + '\'' +
", platformCertPath='" + platformCertPath + '\'' +
", mchId='" + mchId + '\'' +
", apiKey='" + apiKey + '\'' +
", apiKey3='" + apiKey3 + '\'' +
", domain='" + domain + '\'' +
'}';
}
}

View File

@@ -0,0 +1,85 @@
package org.wfc.payment.domain.vo;
import java.io.Serializable;
/**
* @author cyc
*/
public class AjaxResult implements Serializable {
private static final long serialVersionUID = 6439646269084700779L;
private int code = 0;
/**
* 返回的中文消息
*/
private String message;
/**
* 成功时携带的数据
*/
private Object data;
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
/**
* 校验错误
*
* @return
*/
public boolean hasError() {
return this.code != 0;
}
/**
* 添加错误用于alertError
*
* @param message
* @return
*/
public AjaxResult addError(String message) {
this.message = message;
this.code = 1;
return this;
}
/**
* 用于Confirm的错误信息
*
* @param message 描述消息
* @return {AjaxResult}
*/
public AjaxResult addConfirmError(String message) {
this.message = message;
this.code = 2;
return this;
}
/**
* 封装成功时的数据
*
* @param data Object
* @return {AjaxResult}
*/
public AjaxResult success(Object data) {
this.data = data;
this.code = 0;
return this;
}
}

View File

@@ -0,0 +1,33 @@
package org.wfc.payment.interceptor;
import com.alipay.api.AlipayApiException;
import com.ijpay.alipay.AliPayApiConfigKit;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.wfc.payment.pay.alipay.controller.AbstractAliPayApiController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* <p>支付宝支付拦截器</p>
*
* @author cyc
*/
public class AliPayInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws AlipayApiException {
if (HandlerMethod.class.equals(handler.getClass())) {
HandlerMethod method = (HandlerMethod) handler;
Object controller = method.getBean();
if (!(controller instanceof AbstractAliPayApiController)) {
throw new RuntimeException("Controller need to inherit AbstractAliPayApiController");
}
AliPayApiConfigKit.setThreadLocalAliPayApiConfig(((AbstractAliPayApiController) controller).getApiConfig());
return true;
}
return false;
}
}

View File

@@ -0,0 +1,32 @@
package org.wfc.payment.interceptor;
import com.ijpay.wxpay.WxPayApiConfigKit;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.wfc.payment.pay.wxpay.controller.AbstractWxPayApiController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* <p>微信支付拦截器</p>
*
* @author cyc
*/
public class WxPayInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) {
if (HandlerMethod.class.equals(handler.getClass())) {
HandlerMethod method = (HandlerMethod) handler;
Object controller = method.getBean();
if (!(controller instanceof AbstractWxPayApiController)) {
throw new RuntimeException("Controller need to inherit AbstractWxPayApiController");
}
WxPayApiConfigKit.setThreadLocalWxPayApiConfig(((AbstractWxPayApiController) controller).getApiConfig());
return true;
}
return false;
}
}

View File

@@ -0,0 +1,17 @@
package org.wfc.payment.pay.alipay.controller;
import com.alipay.api.AlipayApiException;
import com.ijpay.alipay.AliPayApiConfig;
/**
* @author cyc
*/
public abstract class AbstractAliPayApiController {
/**
* 获取支付宝配置
*
* @return {@link AliPayApiConfig} 支付宝配置
* @throws AlipayApiException 支付宝 Api 异常
*/
public abstract AliPayApiConfig getApiConfig() throws AlipayApiException;
}

View File

@@ -0,0 +1,823 @@
package org.wfc.payment.pay.alipay.controller;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayCommerceCityfacilitatorVoucherGenerateModel;
import com.alipay.api.domain.AlipayDataDataserviceBillDownloadurlQueryModel;
import com.alipay.api.domain.AlipayFundAccountQueryModel;
import com.alipay.api.domain.AlipayFundAuthOrderFreezeModel;
import com.alipay.api.domain.AlipayFundCouponOrderAgreementPayModel;
import com.alipay.api.domain.AlipayFundTransCommonQueryModel;
import com.alipay.api.domain.AlipayFundTransOrderQueryModel;
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.AlipayOpenAuthTokenAppModel;
import com.alipay.api.domain.AlipayOpenAuthTokenAppQueryModel;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeCancelModel;
import com.alipay.api.domain.AlipayTradeCloseModel;
import com.alipay.api.domain.AlipayTradeCreateModel;
import com.alipay.api.domain.AlipayTradeOrderSettleModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.response.AlipayFundAuthOrderFreezeResponse;
import com.alipay.api.response.AlipayFundCouponOrderAgreementPayResponse;
import com.alipay.api.response.AlipayTradeCreateResponse;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.wfc.common.core.domain.R;
import org.wfc.payment.domain.AliPayBean;
import org.wfc.payment.utils.StringUtils;
import org.wfc.payment.domain.vo.AjaxResult;
import org.wfc.user.api.RemoteUUserService;
import org.wfc.user.api.domain.vo.UOrderVo;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
/**
*
* <p>支付宝支付 Demo</p>
*
* @author cyc
*/
@Controller
@RequestMapping("/aliPay")
public class AliPayController extends AbstractAliPayApiController {
private static final Logger log = LoggerFactory.getLogger(AliPayController.class);
@Resource
private AliPayBean aliPayBean;
@Resource
private RemoteUUserService remoteUUserService;
private final AjaxResult result = new AjaxResult();
// 普通公钥模式
private final static String NOTIFY_URL = "/payment/aliPay/callback";
private final static String PRE_NOTIFY_URL = "/sys-api";
private final static String TEST_PRE_NOTIFY_URL = "/proxy-default";
/**
* 证书模式
*/
// private final static String NOTIFY_URL = "/aliPay/cert_notify_url";
private final static String RETURN_URL = "/u";
/**
* 证书模式
*/
// private final static String RETURN_URL = "/aliPay/cert_return_url";
@Override
public AliPayApiConfig getApiConfig() throws AlipayApiException {
AliPayApiConfig aliPayApiConfig;
try {
aliPayApiConfig = AliPayApiConfigKit.getApiConfig(aliPayBean.getAppId());
} catch (Exception e) {
aliPayApiConfig = AliPayApiConfig.builder()
.setAppId(aliPayBean.getAppId())
.setAliPayPublicKey(aliPayBean.getPublicKey())
.setAppCertPath(aliPayBean.getAppCertPath())
.setAliPayCertPath(aliPayBean.getAliPayCertPath())
.setAliPayRootCertPath(aliPayBean.getAliPayRootCertPath())
.setCharset("UTF-8")
.setPrivateKey(aliPayBean.getPrivateKey())
.setServiceUrl(aliPayBean.getServerUrl())
.setSignType("RSA2")
// 普通公钥方式
.build();
// 证书模式
// .buildByCert();
}
return aliPayApiConfig;
}
@RequestMapping("/test")
@ResponseBody
public AliPayApiConfig test() {
AliPayApiConfig aliPayApiConfig = AliPayApiConfigKit.getAliPayApiConfig();
String charset = aliPayApiConfig.getCharset();
log.info("charset>" + charset);
return aliPayApiConfig;
}
/**
* app支付
*/
@RequestMapping(value = "/appPay")
@ResponseBody
public AjaxResult appPay() {
try {
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("我是测试数据-By Javen");
model.setSubject("App支付测试-By Javen");
model.setOutTradeNo(StringUtils.getOutTradeNo());
model.setTimeoutExpress("30m");
model.setTotalAmount("0.01");
model.setPassbackParams("callback params");
model.setProductCode("QUICK_MSECURITY_PAY");
String orderInfo = AliPayApi.appPayToResponse(model, aliPayBean.getDomain() + NOTIFY_URL).getBody();
result.success(orderInfo);
} catch (AlipayApiException e) {
e.printStackTrace();
result.addError("system error:" + e.getMessage());
}
return result;
}
@RequestMapping(value = "/wapPay")
@ResponseBody
public void wapPay(HttpServletResponse response) {
String body = "我是测试数据-By Javen";
String subject = "Javen Wap支付测试";
String totalAmount = "1";
String passBackParams = "1";
String returnUrl = aliPayBean.getDomain() + RETURN_URL;
String notifyUrl = aliPayBean.getDomain() + NOTIFY_URL;
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setBody(body);
model.setSubject(subject);
model.setTotalAmount(totalAmount);
model.setPassbackParams(passBackParams);
String outTradeNo = StringUtils.getOutTradeNo();
System.out.println("wap outTradeNo>" + outTradeNo);
model.setOutTradeNo(outTradeNo);
model.setProductCode("QUICK_WAP_PAY");
try {
AliPayApi.wapPay(response, model, returnUrl, notifyUrl);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* PC支付
*/
@RequestMapping(value = "/pcPay")
@ResponseBody
public void pcPay(HttpServletResponse response, @RequestParam Long orderId) {
try {
R<UOrderVo> orderRes = remoteUUserService.getOrderById(orderId);
UOrderVo orderVo = orderRes.getData();
if (orderVo == null) {
return;
}
String totalAmount = orderVo.getOrderAmount().setScale(2, RoundingMode.HALF_UP).toString();
// String outTradeNo = StringUtils.getOutTradeNo();
log.info("pc outTradeNo>" + orderId);
String returnUrl = aliPayBean.getDomain() + RETURN_URL;
String notifyUrl = aliPayBean.getDomain() + PRE_NOTIFY_URL + NOTIFY_URL;
if (StrUtil.isNotBlank(aliPayBean.getTestDomain())) {
notifyUrl = aliPayBean.getTestDomain() + TEST_PRE_NOTIFY_URL + NOTIFY_URL;
}
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo(orderId.toString());
model.setProductCode("FAST_INSTANT_TRADE_PAY");
model.setTotalAmount(totalAmount);
model.setSubject("WANFI PAY");
// model.setBody("Javen IJPay PC支付测试");
model.setPassbackParams("passback_params");
/**
* 花呗分期相关的设置,测试环境不支持花呗分期的测试
* hb_fq_num代表花呗分期数仅支持传入3、6、12其他期数暂不支持传入会报错
* hb_fq_seller_percent代表卖家承担收费比例商家承担手续费传入100用户承担手续费传入0仅支持传入100、0两种其他比例暂不支持传入会报错。
*/
// ExtendParams extendParams = new ExtendParams();
// extendParams.setHbFqNum("3");
// extendParams.setHbFqSellerPercent("0");
// model.setExtendParams(extendParams);
AliPayApi.tradePage(response, model, notifyUrl, returnUrl);
// https://opensupport.alipay.com/support/helpcenter/192/201602488772?ant_source=antsupport
// Alipay Easy SDK新版目前只支持输出form表单不支持打印出url链接。
// AliPayApi.tradePage(response, "GET", model, notifyUrl, returnUrl);
} catch (Exception e) {
e.printStackTrace();
}
}
@RequestMapping(value = "/tradePay")
@ResponseBody
public String tradePay(@RequestParam("authCode") String authCode, @RequestParam("scene") String scene) {
String subject = null;
String waveCode = "wave_code";
String barCode = "bar_code";
if (scene.equals(waveCode)) {
subject = "Javen 支付宝声波支付测试";
} else if (scene.equals(barCode)) {
subject = "Javen 支付宝条形码支付测试";
}
String totalAmount = "100";
String notifyUrl = aliPayBean.getDomain() + NOTIFY_URL;
AlipayTradePayModel model = new AlipayTradePayModel();
model.setAuthCode(authCode);
model.setSubject(subject);
model.setTotalAmount(totalAmount);
model.setOutTradeNo(StringUtils.getOutTradeNo());
model.setScene(scene);
try {
return AliPayApi.tradePayToResponse(model, notifyUrl).getBody();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 扫码支付
*/
@RequestMapping(value = "/tradePreCreatePay")
@ResponseBody
public String tradePreCreatePay() {
String subject = "Javen 支付宝扫码支付测试";
String totalAmount = "86";
String storeId = "123";
// String notifyUrl = aliPayBean.getDomain() + NOTIFY_URL;
String notifyUrl = aliPayBean.getDomain() + "/aliPay/cert_notify_url";
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
model.setSubject(subject);
model.setTotalAmount(totalAmount);
model.setStoreId(storeId);
model.setTimeoutExpress("5m");
model.setOutTradeNo(StringUtils.getOutTradeNo());
try {
String resultStr = AliPayApi.tradePrecreatePayToResponse(model, notifyUrl).getBody();
JSONObject jsonObject = JSONObject.parseObject(resultStr);
return jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 单笔转账到支付宝账户
* https://docs.open.alipay.com/309/106235/
*/
@RequestMapping(value = "/transfer")
@ResponseBody
public String transfer() {
String totalAmount = "66";
AlipayFundTransToaccountTransferModel model = new AlipayFundTransToaccountTransferModel();
model.setOutBizNo(StringUtils.getOutTradeNo());
model.setPayeeType("ALIPAY_LOGONID");
model.setPayeeAccount("gxthqd7606@sandbox.com");
model.setAmount(totalAmount);
model.setPayerShowName("测试退款");
model.setPayerRealName("沙箱环境");
model.setRemark("javen测试单笔转账到支付宝");
try {
return AliPayApi.transferToResponse(model).getBody();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/transferQuery")
@ResponseBody
public String transferQuery(@RequestParam(required = false, name = "outBizNo") String outBizNo,
@RequestParam(required = false, name = "orderId") String orderId) {
AlipayFundTransOrderQueryModel model = new AlipayFundTransOrderQueryModel();
if (StringUtils.isNotEmpty(outBizNo)) {
model.setOutBizNo(outBizNo);
}
if (StringUtils.isNotEmpty(orderId)) {
model.setOrderId(orderId);
}
try {
return AliPayApi.transferQueryToResponse(model).getBody();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/uniTransfer")
@ResponseBody
public String uniTransfer() {
String totalAmount = "1";
AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
model.setOutBizNo(StringUtils.getOutTradeNo());
model.setTransAmount(totalAmount);
model.setProductCode("TRANS_ACCOUNT_NO_PWD");
model.setBizScene("DIRECT_TRANSFER");
model.setOrderTitle("统一转账-转账至支付宝账户");
model.setRemark("IJPay 测试统一转账");
Participant payeeInfo = new Participant();
payeeInfo.setIdentity("gxthqd7606@sandbox.com");
payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
payeeInfo.setName("沙箱环境");
model.setPayeeInfo(payeeInfo);
try {
return AliPayApi.uniTransferToResponse(model, null).getBody();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/uniTransferQuery")
@ResponseBody
public String uniTransferQuery(@RequestParam(required = false, name = "outBizNo") String outBizNo,
@RequestParam(required = false, name = "orderId") String orderId) {
AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel();
if (StringUtils.isNotEmpty(outBizNo)) {
model.setOutBizNo(outBizNo);
}
if (StringUtils.isNotEmpty(orderId)) {
model.setOrderId(orderId);
}
try {
return AliPayApi.transCommonQueryToResponse(model, null).getBody();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/accountQuery")
@ResponseBody
public String accountQuery(@RequestParam(required = true, name = "aliPayUserId") String aliPayUserId) {
AlipayFundAccountQueryModel model = new AlipayFundAccountQueryModel();
model.setAlipayUserId(aliPayUserId);
model.setAccountType("ACCTRANS_ACCOUNT");
try {
return AliPayApi.accountQueryToResponse(model, null).getBody();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 资金授权冻结接口
*/
@RequestMapping(value = "/authOrderFreeze")
@ResponseBody
public AlipayFundAuthOrderFreezeResponse authOrderFreeze(@RequestParam("auth_code") String authCode) {
try {
AlipayFundAuthOrderFreezeModel model = new AlipayFundAuthOrderFreezeModel();
model.setOutOrderNo(StringUtils.getOutTradeNo());
model.setOutRequestNo(StringUtils.getOutTradeNo());
model.setAuthCode(authCode);
model.setAuthCodeType("bar_code");
model.setOrderTitle("资金授权冻结-By IJPay");
model.setAmount("36");
model.setProductCode("PRE_AUTH");
return AliPayApi.authOrderFreezeToResponse(model);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 红包协议支付接口
* https://docs.open.alipay.com/301/106168/
*/
@RequestMapping(value = "/agreementPay")
@ResponseBody
public AlipayFundCouponOrderAgreementPayResponse agreementPay() {
try {
AlipayFundCouponOrderAgreementPayModel model = new AlipayFundCouponOrderAgreementPayModel();
model.setOutOrderNo(StringUtils.getOutTradeNo());
model.setOutRequestNo(StringUtils.getOutTradeNo());
model.setOrderTitle("红包协议支付接口-By IJPay");
model.setAmount("36");
model.setPayerUserId("2088102180432465");
return AliPayApi.fundCouponOrderAgreementPayToResponse(model);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 下载对账单
*/
@RequestMapping(value = "/dataDataServiceBill")
@ResponseBody
public String dataDataServiceBill(@RequestParam("billDate") String billDate) {
try {
AlipayDataDataserviceBillDownloadurlQueryModel model = new AlipayDataDataserviceBillDownloadurlQueryModel();
model.setBillType("trade");
model.setBillDate(billDate);
return AliPayApi.billDownloadUrlQuery(model);
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 退款
*/
@RequestMapping(value = "/tradeRefund")
@ResponseBody
public String tradeRefund(@RequestParam(required = false, name = "outTradeNo") String outTradeNo, @RequestParam(required = false, name = "tradeNo") String tradeNo) {
try {
AlipayTradeRefundModel model = new AlipayTradeRefundModel();
if (StringUtils.isNotEmpty(outTradeNo)) {
model.setOutTradeNo(outTradeNo);
}
if (StringUtils.isNotEmpty(tradeNo)) {
model.setTradeNo(tradeNo);
}
model.setRefundAmount("86.00");
model.setRefundReason("正常退款");
return AliPayApi.tradeRefundToResponse(model).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 交易查询
*/
@RequestMapping(value = "/tradeQuery")
@ResponseBody
public String tradeQuery(@RequestParam(required = false, name = "outTradeNo") String outTradeNo, @RequestParam(required = false, name = "tradeNo") String tradeNo) {
try {
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
if (StringUtils.isNotEmpty(outTradeNo)) {
model.setOutTradeNo(outTradeNo);
}
if (StringUtils.isNotEmpty(tradeNo)) {
model.setTradeNo(tradeNo);
}
return AliPayApi.tradeQueryToResponse(model).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/tradeQueryByStr")
@ResponseBody
public String tradeQueryByStr(@RequestParam(required = false, name = "outTradeNo") String outTradeNo, @RequestParam(required = false, name = "tradeNo") String tradeNo) {
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
if (StringUtils.isNotEmpty(outTradeNo)) {
model.setOutTradeNo(outTradeNo);
}
if (StringUtils.isNotEmpty(tradeNo)) {
model.setTradeNo(tradeNo);
}
try {
return AliPayApi.tradeQueryToResponse(model).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 创建订单
* {"alipay_trade_create_response":{"code":"10000","msg":"Success","out_trade_no":"081014283315033","trade_no":"2017081021001004200200274066"},"sign":"ZagfFZntf0loojZzdrBNnHhenhyRrsXwHLBNt1Z/dBbx7cF1o7SZQrzNjRHHmVypHKuCmYifikZIqbNNrFJauSuhT4MQkBJE+YGPDtHqDf4Ajdsv3JEyAM3TR/Xm5gUOpzCY7w+RZzkHevsTd4cjKeGM54GBh0hQH/gSyhs4pEN3lRWopqcKkrkOGZPcmunkbrUAF7+AhKGUpK+AqDw4xmKFuVChDKaRdnhM6/yVsezJFXzlQeVgFjbfiWqULxBXq1gqicntyUxvRygKA+5zDTqE5Jj3XRDjVFIDBeOBAnM+u03fUP489wV5V5apyI449RWeybLg08Wo+jUmeOuXOA=="}
*/
@RequestMapping(value = "/tradeCreate")
@ResponseBody
public String tradeCreate(@RequestParam("outTradeNo") String outTradeNo) {
String notifyUrl = aliPayBean.getDomain() + NOTIFY_URL;
AlipayTradeCreateModel model = new AlipayTradeCreateModel();
model.setOutTradeNo(outTradeNo);
model.setTotalAmount("88.88");
model.setBody("Body");
model.setSubject("Javen 测试统一收单交易创建接口");
//买家支付宝账号和buyer_id不能同时为空
model.setBuyerLogonId("abpkvd0206@sandbox.com");
try {
AlipayTradeCreateResponse response = AliPayApi.tradeCreateToResponse(model, notifyUrl);
return response.getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 撤销订单
*/
@RequestMapping(value = "/tradeCancel")
@ResponseBody
public String tradeCancel(@RequestParam(required = false, name = "outTradeNo") String outTradeNo, @RequestParam(required = false, name = "tradeNo") String tradeNo) {
try {
AlipayTradeCancelModel model = new AlipayTradeCancelModel();
if (StringUtils.isNotEmpty(outTradeNo)) {
model.setOutTradeNo(outTradeNo);
}
if (StringUtils.isNotEmpty(tradeNo)) {
model.setTradeNo(tradeNo);
}
return AliPayApi.tradeCancelToResponse(model).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 关闭订单
*/
@RequestMapping(value = "/tradeClose")
@ResponseBody
public String tradeClose(@RequestParam("outTradeNo") String outTradeNo, @RequestParam("tradeNo") String tradeNo) {
try {
AlipayTradeCloseModel model = new AlipayTradeCloseModel();
if (StringUtils.isNotEmpty(outTradeNo)) {
model.setOutTradeNo(outTradeNo);
}
if (StringUtils.isNotEmpty(tradeNo)) {
model.setTradeNo(tradeNo);
}
return AliPayApi.tradeCloseToResponse(model).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 结算
*/
@RequestMapping(value = "/tradeOrderSettle")
@ResponseBody
public String tradeOrderSettle(@RequestParam("tradeNo") String tradeNo) {
try {
AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
model.setOutRequestNo(StringUtils.getOutTradeNo());
model.setTradeNo(tradeNo);
return AliPayApi.tradeOrderSettleToResponse(model).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 获取应用授权URL并授权
*/
@RequestMapping(value = "/toOauth")
@ResponseBody
public void toOauth(HttpServletResponse response) {
try {
String redirectUri = aliPayBean.getDomain() + "/aliPay/redirect_uri";
String oauth2Url = AliPayApi.getOauth2Url(aliPayBean.getAppId(), redirectUri);
response.sendRedirect(oauth2Url);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 应用授权回调
*/
@RequestMapping(value = "/redirect_uri")
@ResponseBody
public String redirectUri(@RequestParam("app_id") String appId, @RequestParam("app_auth_code") String appAuthCode) {
try {
System.out.println("app_id:" + appId);
System.out.println("app_auth_code:" + appAuthCode);
//使用app_auth_code换取app_auth_token
AlipayOpenAuthTokenAppModel model = new AlipayOpenAuthTokenAppModel();
model.setGrantType("authorization_code");
model.setCode(appAuthCode);
return AliPayApi.openAuthTokenAppToResponse(model).getBody();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 查询授权信息
*/
@RequestMapping(value = "/openAuthTokenAppQuery")
@ResponseBody
public String openAuthTokenAppQuery(@RequestParam("appAuthToken") String appAuthToken) {
try {
AlipayOpenAuthTokenAppQueryModel model = new AlipayOpenAuthTokenAppQueryModel();
model.setAppAuthToken(appAuthToken);
return AliPayApi.openAuthTokenAppQueryToResponse(model).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 批量付款到支付宝账户有密接口
*/
@RequestMapping(value = "/batchTrans")
@ResponseBody
public void batchTrans(HttpServletResponse response) {
try {
String signType = "MD5";
String notifyUrl = aliPayBean.getDomain() + NOTIFY_URL;
Map<String, String> params = new HashMap<>(15);
params.put("partner", "PID");
params.put("sign_type", signType);
params.put("notify_url", notifyUrl);
params.put("account_name", "xxx");
params.put("detail_data", "流水号1^收款方账号1^收款账号姓名1^付款金额1^备注说明1|流水号2^收款方账号2^收款账号姓名2^付款金额2^备注说明2");
params.put("batch_no", String.valueOf(System.currentTimeMillis()));
params.put("batch_num", 1 + "");
params.put("batch_fee", 10.00 + "");
params.put("email", "xx@xxx.com");
AliPayApi.batchTrans(params, aliPayBean.getPrivateKey(), signType, response);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 地铁购票核销码发码
*/
@RequestMapping(value = "/voucherGenerate")
@ResponseBody
public String voucherGenerate(@RequestParam("tradeNo") String tradeNo) {
try {
//需要支付成功的订单号
// String tradeNo = getPara("tradeNo");
AlipayCommerceCityfacilitatorVoucherGenerateModel model = new AlipayCommerceCityfacilitatorVoucherGenerateModel();
model.setCityCode("440300");
model.setTradeNo(tradeNo);
model.setTotalFee("8");
model.setTicketNum("2");
model.setTicketType("oneway");
model.setSiteBegin("001");
model.setSiteEnd("002");
model.setTicketPrice("4");
return AliPayApi.voucherGenerateToResponse(model).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/return_url")
@ResponseBody
public String returnUrl(HttpServletRequest request) {
try {
// 获取支付宝GET过来反馈信息
Map<String, String> map = AliPayApi.toMap(request);
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
boolean verifyResult = AlipaySignature.rsaCheckV1(map, aliPayBean.getPublicKey(), "UTF-8",
"RSA2");
if (verifyResult) {
// TODO 请在这里加上商户的业务逻辑程序代码
System.out.println("return_url 验证成功");
return "success";
} else {
System.out.println("return_url 验证失败");
// TODO
return "failure";
}
} catch (AlipayApiException e) {
e.printStackTrace();
return "failure";
}
}
@RequestMapping(value = "/cert_return_url")
@ResponseBody
public String certReturnUrl(HttpServletRequest request) {
try {
// 获取支付宝GET过来反馈信息
Map<String, String> map = AliPayApi.toMap(request);
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
boolean verifyResult = AlipaySignature.rsaCertCheckV1(map, aliPayBean.getAliPayCertPath(), "UTF-8",
"RSA2");
if (verifyResult) {
// TODO 请在这里加上商户的业务逻辑程序代码
System.out.println("certReturnUrl 验证成功");
return "success";
} else {
System.out.println("certReturnUrl 验证失败");
// TODO
return "failure";
}
} catch (AlipayApiException e) {
e.printStackTrace();
return "failure";
}
}
@RequestMapping(value = "/callback")
@ResponseBody
public String notifyUrl(HttpServletRequest request) {
try {
// 获取支付宝POST过来反馈信息
Map<String, String> params = AliPayApi.toMap(request);
for (Map.Entry<String, String> entry : params.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
boolean verifyResult = AlipaySignature.rsaCheckV1(params, aliPayBean.getPublicKey(), "UTF-8", "RSA2");
if (verifyResult) {
// TODO 请在这里加上商户的业务逻辑程序代码 异步通知可能出现订单重复通知 需要做去重处理
System.out.println("notify_url 验证成功succcess");
String outTradeNo = params.get("out_trade_no");
remoteUUserService.paySuccess(Long.valueOf(outTradeNo), "inner");
return "success";
} else {
System.out.println("notify_url 验证失败");
// TODO
return "failure";
}
} catch (AlipayApiException e) {
e.printStackTrace();
return "failure";
}
}
@RequestMapping(value = "/cert_notify_url")
@ResponseBody
public String certNotifyUrl(HttpServletRequest request) {
try {
// 获取支付宝POST过来反馈信息
Map<String, String> params = AliPayApi.toMap(request);
for (Map.Entry<String, String> entry : params.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
boolean verifyResult = AlipaySignature.rsaCertCheckV1(params, aliPayBean.getAliPayCertPath(), "UTF-8", "RSA2");
if (verifyResult) {
// TODO 请在这里加上商户的业务逻辑程序代码 异步通知可能出现订单重复通知 需要做去重处理
System.out.println("certNotifyUrl 验证成功succcess");
return "success";
} else {
System.out.println("certNotifyUrl 验证失败");
// TODO
return "failure";
}
} catch (AlipayApiException e) {
e.printStackTrace();
return "failure";
}
}
}

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.config; package org.wfc.payment.pay.ccpay.config;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,15 +1,15 @@
package org.wfc.payment.ccpay.controller; package org.wfc.payment.pay.ccpay.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.wfc.payment.ccpay.model.PaymentRequest; import org.wfc.payment.pay.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.PaymentResponse; import org.wfc.payment.pay.ccpay.model.PaymentResponse;
import org.wfc.payment.ccpay.model.UCreditCardToken; import org.wfc.payment.pay.ccpay.model.UCreditCardToken;
import org.wfc.payment.ccpay.model.RefundResponse; import org.wfc.payment.pay.ccpay.model.RefundResponse;
import org.wfc.payment.ccpay.model.RefundRequest; import org.wfc.payment.pay.ccpay.model.RefundRequest;
import org.wfc.payment.ccpay.service.IUCreditCardOrderService; import org.wfc.payment.pay.ccpay.service.IUCreditCardOrderService;
import org.wfc.payment.ccpay.service.IUCreditCardTokenService; import org.wfc.payment.pay.ccpay.service.IUCreditCardTokenService;
/** /**
* Credit card payment controller * Credit card payment controller

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.exception; package org.wfc.payment.pay.ccpay.exception;
public class RuntimeException extends Exception { public class RuntimeException extends Exception {

View File

@@ -1,8 +1,8 @@
package org.wfc.payment.ccpay.mapper; package org.wfc.payment.pay.ccpay.mapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.wfc.payment.ccpay.model.UCreditCardOrder; import org.wfc.payment.pay.ccpay.model.UCreditCardOrder;
@Mapper @Mapper
public interface UCreditCardOrderMapper { public interface UCreditCardOrderMapper {

View File

@@ -1,8 +1,8 @@
package org.wfc.payment.ccpay.mapper; package org.wfc.payment.pay.ccpay.mapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.wfc.payment.ccpay.model.UCreditCardToken; import org.wfc.payment.pay.ccpay.model.UCreditCardToken;
@Mapper @Mapper
public interface UCreditCardTokenMapper { public interface UCreditCardTokenMapper {

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.model; package org.wfc.payment.pay.ccpay.model;
import lombok.Data; import lombok.Data;

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.model; package org.wfc.payment.pay.ccpay.model;
import lombok.Data; import lombok.Data;

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.model; package org.wfc.payment.pay.ccpay.model;
public class RefundRequest { public class RefundRequest {
private String transactionId; private String transactionId;

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.model; package org.wfc.payment.pay.ccpay.model;
public class RefundResponse { public class RefundResponse {
private String status; private String status;

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.model; package org.wfc.payment.pay.ccpay.model;
import javax.persistence.*; import javax.persistence.*;
import java.math.BigDecimal; import java.math.BigDecimal;

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.model; package org.wfc.payment.pay.ccpay.model;
import javax.persistence.*; import javax.persistence.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;

View File

@@ -1,10 +1,10 @@
package org.wfc.payment.ccpay.service; package org.wfc.payment.pay.ccpay.service;
import org.wfc.payment.ccpay.model.PaymentRequest; import org.wfc.payment.pay.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.PaymentResponse; import org.wfc.payment.pay.ccpay.model.PaymentResponse;
import org.wfc.payment.ccpay.model.RefundRequest; import org.wfc.payment.pay.ccpay.model.RefundRequest;
import org.wfc.payment.ccpay.model.RefundResponse; import org.wfc.payment.pay.ccpay.model.RefundResponse;
import org.wfc.payment.ccpay.model.UCreditCardOrder; import org.wfc.payment.pay.ccpay.model.UCreditCardOrder;
public interface IUCreditCardOrderService { public interface IUCreditCardOrderService {

View File

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

View File

@@ -1,4 +1,4 @@
package org.wfc.payment.ccpay.service.impl; package org.wfc.payment.pay.ccpay.service.impl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
@@ -8,14 +8,14 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.wfc.payment.ccpay.config.CcpayConfig; import org.wfc.payment.pay.ccpay.config.CcpayConfig;
import org.wfc.payment.ccpay.mapper.UCreditCardOrderMapper; import org.wfc.payment.pay.ccpay.mapper.UCreditCardOrderMapper;
import org.wfc.payment.ccpay.model.PaymentRequest; import org.wfc.payment.pay.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.PaymentResponse; import org.wfc.payment.pay.ccpay.model.PaymentResponse;
import org.wfc.payment.ccpay.model.RefundRequest; import org.wfc.payment.pay.ccpay.model.RefundRequest;
import org.wfc.payment.ccpay.model.RefundResponse; import org.wfc.payment.pay.ccpay.model.RefundResponse;
import org.wfc.payment.ccpay.model.UCreditCardOrder; import org.wfc.payment.pay.ccpay.model.UCreditCardOrder;
import org.wfc.payment.ccpay.service.IUCreditCardOrderService; import org.wfc.payment.pay.ccpay.service.IUCreditCardOrderService;
import java.util.HashMap; import java.util.HashMap;

View File

@@ -1,11 +1,11 @@
package org.wfc.payment.ccpay.service.impl; package org.wfc.payment.pay.ccpay.service.impl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.wfc.payment.ccpay.mapper.UCreditCardTokenMapper; import org.wfc.payment.pay.ccpay.mapper.UCreditCardTokenMapper;
import org.wfc.payment.ccpay.model.PaymentRequest; import org.wfc.payment.pay.ccpay.model.PaymentRequest;
import org.wfc.payment.ccpay.model.UCreditCardToken; import org.wfc.payment.pay.ccpay.model.UCreditCardToken;
import org.wfc.payment.ccpay.service.IUCreditCardTokenService; import org.wfc.payment.pay.ccpay.service.IUCreditCardTokenService;
@Service @Service
public class UCreditCardTokenServiceImpl implements IUCreditCardTokenService { public class UCreditCardTokenServiceImpl implements IUCreditCardTokenService {

View File

@@ -0,0 +1,66 @@
/**
*
* <p> 京东APP支付 </p>
*
* @author cyc
*/
package org.wfc.payment.pay.jdpay.controller;
public class AppParams {
private String orderId;
private String merchant;
private String appId;
private String signData;
private String extraInfo;
public AppParams() {
}
public AppParams(String orderId, String merchant, String appId, String signData, String extraInfo) {
this.orderId = orderId;
this.merchant = merchant;
this.appId = appId;
this.signData = signData;
this.extraInfo = extraInfo;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getMerchant() {
return merchant;
}
public void setMerchant(String merchant) {
this.merchant = merchant;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getSignData() {
return signData;
}
public void setSignData(String signData) {
this.signData = signData;
}
public String getExtraInfo() {
return extraInfo;
}
public void setExtraInfo(String extraInfo) {
this.extraInfo = extraInfo;
}
}

View File

@@ -0,0 +1,359 @@
package org.wfc.payment.pay.jdpay.controller;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.XmlUtil;
import com.ijpay.jdpay.JdPayApi;
import com.ijpay.jdpay.kit.JdPayKit;
import com.ijpay.jdpay.model.CustomerPayModel;
import com.ijpay.jdpay.model.FkmModel;
import com.ijpay.jdpay.model.QueryBaiTiaoFqModel;
import com.ijpay.jdpay.model.QueryOrderModel;
import com.ijpay.jdpay.model.RefundModel;
import com.ijpay.jdpay.model.SaveOrderModel;
import com.ijpay.jdpay.model.UniOrderModel;
import com.ijpay.jdpay.model.UserRelationModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.wfc.payment.domain.JdPayBean;
import org.wfc.payment.domain.vo.AjaxResult;
import java.util.Date;
import java.util.Map;
/**
*
* <p>微信支付 Demo</p>
*
* @author cyc
*/
@Controller
@RequestMapping("/JDPay")
public class JdPayController {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
JdPayBean jdPayBean;
@GetMapping("/test")
@ResponseBody
public JdPayBean test() {
return jdPayBean;
}
/**
* App 支付
*
* @return
*/
@RequestMapping(value = "/appPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult appPay() {
String reqXml = UniOrderModel.builder()
.version("V2.0")
.merchant(jdPayBean.getMchId())
.tradeNum(System.currentTimeMillis() + "")
.tradeName("IJPay 让支付触手可及")
.tradeDesc("https://gitee.com/javen205/IJPay")
.tradeTime(DateUtil.format(new Date(), "yyyyMMddHHmmss"))
.amount("1")
.orderType("1")
.currency("CNY")
.note("备注")
.notifyUrl("http://jdpaydemo.jd.com/asynNotify.htm")
.tradeType("GEN")
.build()
.genReqXml(jdPayBean.getRsaPrivateKey(), jdPayBean.getDesKey(), "V2.0", jdPayBean.getMchId());
// 执行请求
String resultData = JdPayApi.uniOrder(reqXml);
log.info("resultData:" + resultData);
// 解析响应的 xml 数据
Map<String, String> map = JdPayKit.parseResp(resultData);
String code = map.get("code");
String encrypt = map.get("encrypt");
if (!"000000".equals(code)) {
String desc = map.get("desc");
return new AjaxResult().addError(desc);
}
// 解密并验证签名
String decrypt = JdPayKit.decrypt(jdPayBean.getRsaPublicKey(), jdPayBean.getDesKey(), encrypt);
log.info("decrypt>" + decrypt);
// 将 xml 转化为 map
Map<String, Object> toMap = XmlUtil.xmlToMap(decrypt);
log.info("result toMap>" + toMap);
String orderId = (String) toMap.get("orderId");
StringBuilder sb = new StringBuilder();
sb.append("merchant=").append(jdPayBean.getMchId());
sb.append("&orderId=").append(orderId);
sb.append("&key=").append("test");
String sign = JdPayKit.md5LowerCase(sb.toString());
return new AjaxResult().success(new AppParams(orderId, jdPayBean.getMchId(), "123456789",
sign, "123456789"));
}
/**
* PC H5 支付
*
* @param payType
* @return
*/
@RequestMapping(value = "/saveOrder", method = {RequestMethod.POST, RequestMethod.GET})
public ModelAndView saveOrder(@RequestParam("payType") String payType) {
ModelAndView mv = new ModelAndView();
Map<String, String> map = SaveOrderModel.builder()
.version("V2.0")
.merchant(jdPayBean.getMchId())
.tradeNum(System.currentTimeMillis() + "")
.tradeName("IJPay")
.tradeDesc("IJPay 让支付触手可及")
.tradeTime(DateUtil.format(new Date(), "yyyyMMddHHmmss"))
.amount("10000")
.orderType("0")
.currency("CNY")
.note("IJPay 了解一下")
.callbackUrl("https://jdpay.com")
.notifyUrl("https://jdpay.com")
.userId("IJPay001")
.build()
.createSign(jdPayBean.getRsaPrivateKey(), jdPayBean.getDesKey());
mv.addObject("map", map);
mv.addObject("payUrl", payType.equals("pc") ? JdPayApi.PC_SAVE_ORDER_URL : JdPayApi.H5_SAVE_ORDER_URL);
mv.setViewName("jd_pc_h5.html");
return mv;
}
/**
* 商户二维码支付
*/
@RequestMapping(value = "/customerPay", method = {RequestMethod.POST, RequestMethod.GET})
public ModelAndView customerPay() {
ModelAndView mv = new ModelAndView();
Map<String, String> map = CustomerPayModel.builder()
.version("V2.0")
.merchant(jdPayBean.getMchId())
.tradeNum(System.currentTimeMillis() + "")
.tradeName("IJPay")
.tradeDesc("IJPay 让支付触手可及")
.tradeTime(DateUtil.format(new Date(), "yyyyMMddHHmmss"))
// .amount("1000")
.orderType("0")
.currency("CNY")
.note("IJPay 了解一下")
.notifyUrl("https://jdpay.com")
.build()
.createSign(jdPayBean.getRsaPrivateKey(), jdPayBean.getDesKey());
mv.addObject("map", map);
mv.addObject("payUrl", JdPayApi.CUSTOMER_PAY_URL);
mv.setViewName("jd_customer_pay.html");
return mv;
}
@RequestMapping(value = "/queryOrder", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult queryOrder(@RequestParam("tradeType") String tradeType,
@RequestParam("oTradeNum") String oTradeNum,
@RequestParam("tradeNum") String tradeNum) {
String reqXml = QueryOrderModel.builder()
.version("V2.0")
.merchant(jdPayBean.getMchId())
.tradeNum(tradeNum)
.tradeType(tradeType)
.oTradeNum(oTradeNum)
.build()
.genReqXml(jdPayBean.getRsaPrivateKey(), jdPayBean.getDesKey(), "V2.0", jdPayBean.getMchId());
String queryResult = JdPayApi.queryOrder(reqXml);
log.info("queryResult:" + queryResult);
// 解析响应的 xml 数据
Map<String, String> map = JdPayKit.parseResp(queryResult);
String code = map.get("code");
String encrypt = map.get("encrypt");
if (!"000000".equals(code)) {
String desc = map.get("desc");
return new AjaxResult().addError(desc);
}
// 解密并验证签名
String decrypt = JdPayKit.decrypt(jdPayBean.getRsaPublicKey(), jdPayBean.getDesKey(), encrypt);
log.info("decrypt>" + decrypt);
return new AjaxResult().success(decrypt);
}
@RequestMapping(value = "/fkmPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult fkmPay(@RequestParam("token") String token,
@RequestParam("amount") String amount) {
String reqXml = FkmModel.builder()
.token(token)
.version("V2.0")
.merchant(jdPayBean.getMchId())
.device("IJPay Dev")
.tradeNum(System.currentTimeMillis() + "")
.tradeName("IJPay 刷卡支付")
.tradeDesc("IJPay 了解一下")
.tradeTime(DateUtil.format(new Date(), "yyyyMMddHHmmss"))
.amount(amount)
.currency("CNY")
.note("备注")
.notifyUrl("https://gitee.com/javen205/IJPay")
.build()
.genReqXml(jdPayBean.getRsaPrivateKey(), jdPayBean.getDesKey(), "V2.0", jdPayBean.getMchId());
String queryResult = JdPayApi.fkmPay(reqXml);
log.info("queryResult:" + queryResult);
// 解析响应的 xml 数据
Map<String, String> map = JdPayKit.parseResp(queryResult);
String code = map.get("code");
String encrypt = map.get("encrypt");
if (!"000000".equals(code)) {
String desc = map.get("desc");
return new AjaxResult().addError(desc);
}
// 解密并验证签名
String decrypt = JdPayKit.decrypt(jdPayBean.getRsaPublicKey(), jdPayBean.getDesKey(), encrypt);
log.info("decrypt>" + decrypt);
return new AjaxResult().success(decrypt);
}
@RequestMapping(value = "/userRelation", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult userRelation(@RequestParam("userId") String userId,
@RequestParam("type") String type) {
String reqXml = UserRelationModel.builder()
.version("V2.0")
.merchant(jdPayBean.getMchId())
.userId(userId)
.build()
.genReqXml(jdPayBean.getRsaPrivateKey(), jdPayBean.getDesKey(), "V2.0", jdPayBean.getMchId());
String result = null;
if ("get".equals(type)) {
result = JdPayApi.getUserRelation(reqXml);
} else {
result = JdPayApi.cancelUserRelation(reqXml);
}
log.info(result);
// 解析响应的 xml 数据
Map<String, String> map = JdPayKit.parseResp(result);
String code = map.get("code");
String encrypt = map.get("encrypt");
if (!"000000".equals(code)) {
String desc = map.get("desc");
return new AjaxResult().addError(desc);
}
// 解密并验证签名
String decrypt = JdPayKit.decrypt(jdPayBean.getRsaPublicKey(), jdPayBean.getDesKey(), encrypt);
log.info("decrypt>" + decrypt);
Map<String, Object> toMap = XmlUtil.xmlToMap(decrypt);
System.out.println(toMap);
return new AjaxResult().success(decrypt);
}
@RequestMapping(value = "/refund", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult refund(@RequestParam("amount") String amount,
@RequestParam("oTradeNum") String oTradeNum,
@RequestParam("tradeNum") String tradeNum) {
System.out.println(Base64.encode(FileUtil.readBytes(jdPayBean.getCertPath())));
String reqXml = RefundModel.builder()
.version("V2.0")
.merchant(jdPayBean.getMchId())
.tradeNum(tradeNum)
.oTradeNum(oTradeNum)
.amount(amount)
.currency("CNY")
.build()
.genReqXml(jdPayBean.getRsaPrivateKey(), jdPayBean.getDesKey(), "V2.0", jdPayBean.getMchId());
String queryResult = JdPayApi.refund(reqXml);
log.info("queryResult:" + queryResult);
// 解析响应的 xml 数据
Map<String, String> map = JdPayKit.parseResp(queryResult);
String code = map.get("code");
String encrypt = map.get("encrypt");
if (!"000000".equals(code)) {
String desc = map.get("desc");
return new AjaxResult().addError(desc);
}
// 解密并验证签名
String decrypt = JdPayKit.decrypt(jdPayBean.getRsaPublicKey(), jdPayBean.getDesKey(), encrypt);
log.info("decrypt>" + decrypt);
return new AjaxResult().success(decrypt);
}
@RequestMapping(value = "/queryBaiTiaoFq", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult queryBaiTiaoFq(@RequestParam("amount") String amount) {
String reqXml = QueryBaiTiaoFqModel.builder()
.version("V2.0")
.merchant(jdPayBean.getMchId())
.tradeNum(System.currentTimeMillis() + "")
.amount(amount)
.build()
.genReqXml(jdPayBean.getRsaPrivateKey(), jdPayBean.getDesKey(), "V2.0", jdPayBean.getMchId());
String baiTiaoResult = JdPayApi.queryBaiTiaoFq(reqXml);
log.info(baiTiaoResult);
// 解析响应的 xml 数据
Map<String, String> map = JdPayKit.parseResp(baiTiaoResult);
String code = map.get("code");
String encrypt = map.get("encrypt");
if (!"000000".equals(code)) {
String desc = map.get("desc");
return new AjaxResult().addError(desc);
}
// 解密并验证签名
String decrypt = JdPayKit.decrypt(jdPayBean.getRsaPublicKey(), jdPayBean.getDesKey(), encrypt);
log.info("decrypt>" + decrypt);
Map<String, Object> toMap = XmlUtil.xmlToMap(decrypt);
System.out.println(toMap);
return new AjaxResult().success(decrypt);
}
}

View File

@@ -0,0 +1,297 @@
/**
*
* <p>PayPal 支付示例</p>
*
* @author cyc
*/
package org.wfc.payment.pay.paypal.controller;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.PayKit;
import com.ijpay.paypal.PayPalApi;
import com.ijpay.paypal.PayPalApiConfig;
import com.ijpay.paypal.PayPalApiConfigKit;
import com.ijpay.paypal.accesstoken.AccessToken;
import com.ijpay.paypal.accesstoken.AccessTokenKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.wfc.payment.domain.PayPalBean;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/payPal")
public class PayPalController {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
PayPalBean payPalBean;
private final static String RETURN_URL = "/payPal/return";
private final static String CANCEL_URL = "/payPal/cancel";
@RequestMapping("test")
@ResponseBody
public PayPalBean test() {
return payPalBean;
}
public PayPalApiConfig getConfig() {
PayPalApiConfig config = new PayPalApiConfig();
config.setClientId(payPalBean.getClientId());
config.setSecret(payPalBean.getSecret());
config.setSandBox(payPalBean.getSandBox());
config.setDomain(payPalBean.getDomain());
PayPalApiConfigKit.setThreadLocalApiConfig(config);
return config;
}
@RequestMapping(value = "/getAccessToken")
@ResponseBody
public AccessToken getAccessToken() {
try {
getConfig();
return AccessTokenKit.get();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/createOrder")
@ResponseBody
public void createOrder(HttpServletResponse response) {
try {
PayPalApiConfig config = getConfig();
//参数请求参数文档 https://developer.paypal.com/docs/api/orders/v2/#orders_create
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("intent", "CAPTURE");
ArrayList<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> amount = new HashMap<>();
amount.put("currency_code", "USD");
amount.put("value", "0.01");
Map<String, Object> itemMap = new HashMap<>();
itemMap.put("amount", amount);
list.add(itemMap);
dataMap.put("purchase_units", list);
Map<String, String> card = new HashMap<>();
card.put("name", "test buyer");
card.put("number", "4231220385792723");
card.put("security_code", "123");
card.put("expiry", "2029-07");
Map<String, String> experienceContext = new HashMap<>();
experienceContext.put("cancel_url", config.getDomain().concat(CANCEL_URL));
experienceContext.put("return_url", config.getDomain().concat(RETURN_URL));
Map<String, Map<String,String>> paymentSource = new HashMap<>();
paymentSource.put("experience_context",experienceContext);
paymentSource.put("card",card);
// dataMap.put("payment_source", paymentSource);
String data = JSONUtil.toJsonStr(dataMap);
log.info(data);
IJPayHttpResponse resData = PayPalApi.createOrder(config, data);
log.info(resData.toString());
if (resData.getStatus() == 201) {
String resultStr = resData.getBody();
JSONObject jsonObject = JSONUtil.parseObj(resultStr);
JSONArray links = jsonObject.getJSONArray("links");
for (int i = 0; i < links.size(); i++) {
JSONObject item = links.getJSONObject(i);
String rel = item.getStr("rel");
String href = item.getStr("href");
if ("approve".equalsIgnoreCase(rel)) {
response.sendRedirect(href);
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@RequestMapping(value = "/updateOrder")
@ResponseBody
public String updateOrder(@RequestParam("id") String id) {
try {
PayPalApiConfig config = getConfig();
// https://developer.paypal.com/docs/api/orders/v2/#orders_patch
ArrayList<Map<String, Object>> updateData = new ArrayList<>();
Map<String, Object> itemMap = new HashMap<>();
itemMap.put("op", "replace");
itemMap.put("path", "/purchase_units/@reference_id=='default'/amount");
Map<String, Object> amount = new HashMap<>();
amount.put("currency_code", "USD");
amount.put("value", "199.00");
itemMap.put("value", amount);
updateData.add(itemMap);
String data = JSONUtil.toJsonStr(updateData);
log.info(data);
IJPayHttpResponse resData = PayPalApi.updateOrder(config, id, data);
log.info(resData.toString());
if (resData.getStatus() == 204) {
return "success";
}
return "接口请求错误码为:" + resData.getStatus();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/queryOrder")
@ResponseBody
public String queryOrder(@RequestParam("id") String id) {
try {
PayPalApiConfig config = getConfig();
IJPayHttpResponse response = PayPalApi.queryOrder(config, id);
log.info(response.toString());
if (response.getStatus() == 200) {
return response.getBody();
} else {
return "接口请求错误码为:" + response.getStatus();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/captureOrder")
@ResponseBody
public String captureOrder(@RequestParam("id") String id) {
try {
PayPalApiConfig config = getConfig();
IJPayHttpResponse response = PayPalApi.captureOrder(config, id, "");
log.info(response.toString());
if (response.getStatus() == 200 || response.getStatus() == 201) {
return response.getBody();
} else {
return "接口请求错误码为:" + response.getStatus();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/captureQuery")
@ResponseBody
public String captureQuery(@RequestParam("captureId") String captureId) {
try {
PayPalApiConfig config = getConfig();
IJPayHttpResponse response = PayPalApi.captureQuery(config, captureId);
log.info(response.toString());
if (response.getStatus() == 200) {
return response.getBody();
} else {
return "接口请求错误码为:" + response.getStatus();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/refund")
@ResponseBody
public String refund(@RequestParam("id") String id) {
try {
PayPalApiConfig config = getConfig();
System.out.println("id>" + id);
Map<String, Object> map = new HashMap<>();
map.put("invoice_id", PayKit.generateStr());
map.put("note_to_payer", "test product");
Map<String, String> amount = new HashMap<>();
amount.put("value", "1.00");
amount.put("currency_code", "USD");
map.put("amount", amount);
String data = JSONUtil.toJsonStr(map);
log.info("refund data" + data);
IJPayHttpResponse response = PayPalApi.refund(config, id, data);
log.info(response.toString());
if (response.getStatus() == 201) {
return response.getBody();
} else {
return "接口请求错误码为:" + response.getStatus();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/refundQuery")
@ResponseBody
public String refundQuery(@RequestParam("id") String id) {
try {
PayPalApiConfig config = getConfig();
IJPayHttpResponse response = PayPalApi.refundQuery(config, id);
log.info(response.toString());
if (response.getStatus() == 200) {
return response.getBody();
} else {
return "接口请求错误码为:" + response.getStatus();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/return")
@ResponseBody
public String returnUrl(HttpServletRequest request) {
try {
String token = request.getParameter("token");
String payerId = request.getParameter("PayerID");
log.info("token:" + token);
log.info("payerId:" + payerId);
return token;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping(value = "/cancel")
@ResponseBody
public String cancelUrl(HttpServletRequest request, HttpServletResponse response) {
String readData = HttpKit.readData(request);
System.out.println(readData);
return readData;
}
}

View File

@@ -0,0 +1,551 @@
package org.wfc.payment.pay.unionpay.controller;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.IpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.unionpay.UnionPayApi;
import com.ijpay.unionpay.enums.ServiceEnum;
import com.ijpay.unionpay.model.AuthCodeToOpenIdModel;
import com.ijpay.unionpay.model.BillDownloadModel;
import com.ijpay.unionpay.model.MicroPayModel;
import com.ijpay.unionpay.model.OrderQueryModel;
import com.ijpay.unionpay.model.RefundModel;
import com.ijpay.unionpay.model.RefundQueryModel;
import com.ijpay.unionpay.model.UnifiedOrderModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.wfc.payment.domain.UnionPayBean;
import org.wfc.payment.domain.vo.AjaxResult;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/unionPay")
public class UnionPayController {
private static final Logger logger = LoggerFactory.getLogger(UnionPayController.class);
@Autowired
UnionPayBean unionPayBean;
@RequestMapping("test")
@ResponseBody
public UnionPayBean test() {
return unionPayBean;
}
/**
* 刷卡支付
*/
@RequestMapping(value = "/microPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult microPay(HttpServletRequest request, HttpServletResponse response) {
try {
String authCode = request.getParameter("authCode");
String totalFee = request.getParameter("totalFee");
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
Map<String, String> params = MicroPayModel.builder()
.service(ServiceEnum.MICRO_PAY.toString())
.mch_id(unionPayBean.getMachId())
.out_trade_no(WxPayKit.generateStr())
.body("IJPay 云闪付测试")
.attach("聚合支付 SDK")
.total_fee(totalFee)
.mch_create_ip(ip)
.auth_code(authCode)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
logger.info("请求参数:" + JSONUtil.toJsonStr(params));
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
String returnCode = result.get("status");
String resultCode = result.get("result_code");
String errMsg = result.get("err_msg");
String errCode = result.get("err_code");
if (!"0".equals(returnCode) || !"0".equals(resultCode)) {
return new AjaxResult().addError("errCode:" + errCode + " errMsg:" + errMsg);
}
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/queryOrder", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult query(@RequestParam(value = "transactionId", required = false) String transactionId,
@RequestParam(value = "outTradeNo", required = false) String outTradeNo) {
try {
if (StrUtil.isEmpty(transactionId) && StrUtil.isEmpty(outTradeNo)) {
return new AjaxResult().addError("out_trade_no transaction_id 不能同时为空");
}
Map<String, String> params = OrderQueryModel.builder()
.service(ServiceEnum.QUERY.toString())
.mch_id(unionPayBean.getMachId())
.out_trade_no(outTradeNo)
.transaction_id(transactionId)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
if (!WxPayKit.verifyNotify(result, unionPayBean.getKey(), SignType.MD5)) {
return new AjaxResult().addError("签名异常");
}
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/microPayReverse", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult microPayReverse(@RequestParam("outTradeNo") String outTradeNo) {
try {
Map<String, String> params = OrderQueryModel.builder()
.service(ServiceEnum.MICRO_PAY_REVERSE.toString())
.mch_id(unionPayBean.getMachId())
.out_trade_no(outTradeNo)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/refund", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult refund(@RequestParam(value = "transactionId", required = false) String transactionId,
@RequestParam(value = "outTradeNo", required = false) String outTradeNo,
@RequestParam(value = "totalFee") String totalFee,
@RequestParam(value = "refundFee") String refundFee) {
try {
if (StrUtil.isEmpty(transactionId) && StrUtil.isEmpty(outTradeNo)) {
return new AjaxResult().addError("out_trade_no transaction_id 不能同时为空");
}
Map<String, String> params = RefundModel.builder()
.service(ServiceEnum.REFUND.toString())
.mch_id(unionPayBean.getMachId())
.out_trade_no(outTradeNo)
.transaction_id(transactionId)
.out_refund_no(transactionId)
.total_fee(totalFee)
.refund_fee(refundFee)
.op_user_id(unionPayBean.getMachId())
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/queryRefund", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult queryRefund(@RequestParam(value = "transactionId", required = false) String transactionId,
@RequestParam(value = "outTradeNo", required = false) String outTradeNo,
@RequestParam(value = "outRefundNo", required = false) String outRefundNo,
@RequestParam(value = "refundId", required = false) String refundId) {
try {
if (StrUtil.isEmpty(transactionId) && StrUtil.isEmpty(outTradeNo)) {
return new AjaxResult().addError("out_trade_no transaction_id 不能同时为空");
}
if (StrUtil.isEmpty(outRefundNo) && StrUtil.isEmpty(refundId)) {
return new AjaxResult().addError("out_refund_no refund_id 不能同时为空");
}
Map<String, String> params = RefundQueryModel.builder()
.service(ServiceEnum.REFUND_QUERY.toString())
.mch_id(unionPayBean.getMachId())
.out_trade_no(outTradeNo)
.transaction_id(transactionId)
.out_refund_no(outRefundNo)
.refund_id(refundId)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/authCodeToOpenId", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult authCodeToOpenId(@RequestParam(value = "code") String code) {
try {
Map<String, String> params = AuthCodeToOpenIdModel.builder()
.service(ServiceEnum.AUTH_CODE_TO_OPENID.toString())
.mch_id(unionPayBean.getMachId())
.auth_code(code)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/native", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult nativePay(HttpServletRequest request,
@RequestParam(value = "totalFee", defaultValue = "1") String totalFee) {
try {
String notifyUrl = unionPayBean.getDomain().concat("/unionPay/payNotify");
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
Map<String, String> params = UnifiedOrderModel.builder()
.service(ServiceEnum.NATIVE.toString())
.mch_id(unionPayBean.getMachId())
.out_trade_no(WxPayKit.generateStr())
.body("IJPay 云闪付-扫码支付")
.attach("聚合支付 SDK")
.total_fee(totalFee)
.mch_create_ip(ip)
.notify_url(notifyUrl)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/wxJsPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult wxJsPay(HttpServletRequest request,
@RequestParam(value = "totalFee", defaultValue = "1") String totalFee,
@RequestParam(value = "openId") String openId) {
try {
String notifyUrl = unionPayBean.getDomain().concat("/unionPay/payNotify");
String ip = IpKit.getRealIp(request);
if (ip.contains(",")) {
ip = ip.split(",")[0];
}
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
Map<String, String> params = UnifiedOrderModel.builder()
.service(ServiceEnum.WEI_XIN_JS_PAY.toString())
.mch_id(unionPayBean.getMachId())
.is_raw("1")
.out_trade_no(WxPayKit.generateStr())
.body("IJPay 云闪付-微信公众号/小程序支付")
.sub_openid(openId)
// .sub_appid("appId")
.attach("聚合支付 SDK")
.total_fee(totalFee)
.mch_create_ip(ip)
.notify_url(notifyUrl)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
System.out.println(params);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/wxApp", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult wxApp(HttpServletRequest request,
@RequestParam(value = "totalFee", defaultValue = "1") String totalFee,
@RequestParam(value = "appId") String appId) {
try {
String notifyUrl = unionPayBean.getDomain().concat("/unionPay/payNotify");
String ip = IpKit.getRealIp(request);
if (ip.contains(",")) {
ip = ip.split(",")[0];
}
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
Map<String, String> params = UnifiedOrderModel.builder()
.service(ServiceEnum.WEI_XIN_APP_PAY.toString())
.mch_id(unionPayBean.getMachId())
.appid(appId)
.out_trade_no(WxPayKit.generateStr())
.body("IJPay 云闪付-微信 App 支付")
.attach("聚合支付 SDK")
.total_fee(totalFee)
.mch_create_ip(ip)
.notify_url(notifyUrl)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
System.out.println(params);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
if (!WxPayKit.verifyNotify(result, unionPayBean.getKey(), SignType.MD5)) {
return new AjaxResult().addError("签名异常");
}
String status = result.get("status");
String resultCode = result.get("result_code");
if (!"0".equals(status) && !"0".equals(resultCode)) {
return new AjaxResult().addError(result.get("err_msg"));
}
return new AjaxResult().success(result.get("pay_info"));
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/aliJsPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult aliJsPay(HttpServletRequest request,
@RequestParam(value = "totalFee", defaultValue = "1") String totalFee,
@RequestParam(value = "buyerLogonId", required = false) String buyerLogonId,
@RequestParam(value = "buyerId", required = false) String buyerId) {
try {
if (StrUtil.isEmpty(buyerLogonId) && StrUtil.isEmpty(buyerId)) {
return new AjaxResult().addError("buyer_logon_id buyer_id 不能同时为空");
}
String notifyUrl = unionPayBean.getDomain().concat("/unionPay/payNotify");
String ip = IpKit.getRealIp(request);
if (ip.contains(",")) {
ip = ip.split(",")[0];
}
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
Map<String, String> params = UnifiedOrderModel.builder()
.service(ServiceEnum.ALI_PAY_JS_PAY.toString())
.mch_id(unionPayBean.getMachId())
.out_trade_no(WxPayKit.generateStr())
.body("IJPay 云闪付-支付宝服务窗口")
.attach("聚合支付 SDK")
.total_fee(totalFee)
.mch_create_ip(ip)
.notify_url(notifyUrl)
.nonce_str(WxPayKit.generateStr())
.buyer_id(buyerId)
.buyer_logon_id(buyerLogonId)
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
System.out.println(params);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/unionPayUserAuth", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public void unionPayUserAuth(HttpServletResponse response) throws IOException {
String notifyUrl = unionPayBean.getDomain().concat("/unionPay/callBack");
String authUrl = UnionPayApi.buildAuthUrl(notifyUrl);
logger.info("authUrl:" + authUrl);
response.sendRedirect(authUrl);
}
@RequestMapping(value = "/callBack", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public Map<String, String> unionPayCall(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
params.put(name, valueStr);
}
return params;
}
@RequestMapping(value = "/unionJsPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult unionJsPay(HttpServletRequest request,
@RequestParam(value = "totalFee", defaultValue = "1") String totalFee,
@RequestParam(value = "userId", required = false) String userId) {
try {
String notifyUrl = unionPayBean.getDomain().concat("/unionPay/payNotify");
String ip = IpKit.getRealIp(request);
if (ip.contains(",")) {
ip = ip.split(",")[0];
}
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
Map<String, String> params = UnifiedOrderModel.builder()
.service(ServiceEnum.UNION_JS_PAY.toString())
.mch_id(unionPayBean.getMachId())
.out_trade_no(WxPayKit.generateStr())
.body("IJPay 云闪付-银联JS支付")
.user_id(userId)
.customer_ip(ip)
.attach("聚合支付 SDK")
.total_fee(totalFee)
.mch_create_ip(ip)
.notify_url(notifyUrl)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
System.out.println(params);
String xmlResult = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
@RequestMapping(value = "/billDownload", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult billDownload(@RequestParam(value = "billDate", defaultValue = "20200325") String billDate,
@RequestParam(value = "billType", defaultValue = "ALL") String billType) {
try {
Map<String, String> params = BillDownloadModel.builder()
.service(ServiceEnum.BILL_MERCHANT.toString())
.bill_date(billDate)
.bill_type(billType)
.mch_id(unionPayBean.getMachId())
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(unionPayBean.getKey(), SignType.MD5);
System.out.println(params);
String result = UnionPayApi.execution(unionPayBean.getServerUrl(), params);
logger.info("result:" + result);
return new AjaxResult().success(result);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError(e.getMessage());
}
}
/**
* 异步通知
*/
@RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String payNotify(HttpServletRequest request) {
String xmlMsg = HttpKit.readData(request);
logger.info("支付通知=" + xmlMsg);
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
String status = params.get("status");
String returnCode = params.get("result_code");
logger.info(status + " " + returnCode);
if ("0".equals(status) && "0".equals(returnCode)) {
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
// 注意此处签名方式需与统一下单的签名类型一致
if (WxPayKit.verifyNotify(params, unionPayBean.getKey(), SignType.MD5)) {
logger.info("支付成功....");
// 更新订单信息
// 发送通知等
return "success";
}
}
return "fail";
}
}

View File

@@ -0,0 +1,16 @@
package org.wfc.payment.pay.wxpay.controller;
import com.ijpay.wxpay.WxPayApiConfig;
/**
* @author cyc
*/
public abstract class AbstractWxPayApiController {
/**
* 获取微信支付配置
*
* @return {@link WxPayApiConfig} 微信支付配置
*/
public abstract WxPayApiConfig getApiConfig();
}

View File

@@ -0,0 +1,964 @@
package org.wfc.payment.pay.wxpay.controller;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.IpKit;
import com.ijpay.core.kit.QrCodeKit;
import com.ijpay.core.kit.RsaKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.ijpay.wxpay.model.GetTransferInfoModel;
import com.ijpay.wxpay.model.MicroPayModel;
import com.ijpay.wxpay.model.OrderQueryModel;
import com.ijpay.wxpay.model.ProfitSharingModel;
import com.ijpay.wxpay.model.ReceiverModel;
import com.ijpay.wxpay.model.RefundModel;
import com.ijpay.wxpay.model.RefundQueryModel;
import com.ijpay.wxpay.model.SendRedPackModel;
import com.ijpay.wxpay.model.TransferModel;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.wfc.payment.domain.H5SceneInfo;
import org.wfc.payment.domain.WxPayBean;
import org.wfc.payment.domain.vo.AjaxResult;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* <p>微信支付 Demo</p>
*
* @author cyc
*/
@Controller
@RequestMapping("/wxPay")
public class WxPayController extends AbstractWxPayApiController {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
WxPayBean wxPayBean;
private String notifyUrl;
private String refundNotifyUrl;
private static final String USER_PAYING = "USERPAYING";
@Override
public WxPayApiConfig getApiConfig() {
WxPayApiConfig apiConfig;
try {
apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBean.getAppId());
} catch (Exception e) {
apiConfig = WxPayApiConfig.builder()
.appId(wxPayBean.getAppId())
.mchId(wxPayBean.getMchId())
.partnerKey(wxPayBean.getPartnerKey())
.certPath(wxPayBean.getCertPath())
.domain(wxPayBean.getDomain())
.build();
}
notifyUrl = apiConfig.getDomain().concat("/wxPay/payNotify");
refundNotifyUrl = apiConfig.getDomain().concat("/wxPay/refundNotify");
return apiConfig;
}
@GetMapping("/test")
@ResponseBody
public WxPayBean test() {
return wxPayBean;
}
@GetMapping("/getKey")
@ResponseBody
public String getKey() {
return WxPayApi.getSignKey(wxPayBean.getMchId(), wxPayBean.getPartnerKey(), SignType.MD5);
}
/**
* 微信H5 支付
* 注意必须再web页面中发起支付且域名已添加到开发配置中
*/
@RequestMapping(value = "/wapPay", method = {RequestMethod.POST, RequestMethod.GET})
public void wapPay(HttpServletRequest request, HttpServletResponse response) throws IOException {
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
H5SceneInfo sceneInfo = new H5SceneInfo();
H5SceneInfo.H5 h5_info = new H5SceneInfo.H5();
h5_info.setType("Wap");
//此域名必须在商户平台--"产品中心"--"开发配置"中添加
h5_info.setWap_url("https://gitee.com/javen205/IJPay");
h5_info.setWap_name("IJPay VIP 充值");
sceneInfo.setH5Info(h5_info);
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = UnifiedOrderModel
.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.body("IJPay 让支付触手可及-H5支付")
.attach("Node.js 版:https://gitee.com/javen205/TNWX")
.out_trade_no(WxPayKit.generateStr())
.total_fee("1000")
.spbill_create_ip(ip)
.notify_url(notifyUrl)
.trade_type(TradeType.MWEB.getTradeType())
.scene_info(JSON.toJSONString(sceneInfo))
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.pushOrder(false, params);
log.info(xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
String return_code = result.get("return_code");
String return_msg = result.get("return_msg");
if (!WxPayKit.codeIsOk(return_code)) {
throw new RuntimeException(return_msg);
}
String result_code = result.get("result_code");
if (!WxPayKit.codeIsOk(result_code)) {
throw new RuntimeException(return_msg);
}
// 以下字段在return_code 和result_code都为SUCCESS的时候有返回
String prepayId = result.get("prepay_id");
String webUrl = result.get("mweb_url");
log.info("prepay_id:" + prepayId + " mweb_url:" + webUrl);
response.sendRedirect(webUrl);
}
/**
* 公众号支付
*/
@RequestMapping(value = "/webPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult webPay(HttpServletRequest request, @RequestParam("total_fee") String totalFee) {
// openId采用 网页授权获取 access_token APISnsAccessTokenApi获取
String openId = (String) request.getSession().getAttribute("openId");
if (openId == null) {
openId = "11111111";
}
if (StrUtil.isEmpty(openId)) {
return new AjaxResult().addError("openId is null");
}
if (StrUtil.isEmpty(totalFee)) {
return new AjaxResult().addError("请输入数字金额");
}
String ip = IpKit.getRealIp(request);
if (StrUtil.isEmpty(ip)) {
ip = "127.0.0.1";
}
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = UnifiedOrderModel
.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.body("IJPay 让支付触手可及-公众号支付")
.attach("Node.js 版:https://gitee.com/javen205/TNWX")
.out_trade_no(WxPayKit.generateStr())
.total_fee("1000")
.spbill_create_ip(ip)
.notify_url(notifyUrl)
.trade_type(TradeType.JSAPI.getTradeType())
.openid(openId)
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.pushOrder(false, params);
log.info(xmlResult);
Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);
String returnCode = resultMap.get("return_code");
String returnMsg = resultMap.get("return_msg");
if (!WxPayKit.codeIsOk(returnCode)) {
return new AjaxResult().addError(returnMsg);
}
String resultCode = resultMap.get("result_code");
if (!WxPayKit.codeIsOk(resultCode)) {
return new AjaxResult().addError(returnMsg);
}
// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
String prepayId = resultMap.get("prepay_id");
Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxPayApiConfig.getAppId(),
wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String jsonStr = JSON.toJSONString(packageParams);
return new AjaxResult().success(jsonStr);
}
/**
* 扫码模式一
*/
@RequestMapping(value = "/scanCode1", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult scanCode1(HttpServletRequest request, HttpServletResponse response,
@RequestParam("productId") String productId) {
try {
if (StrUtil.isBlank(productId)) {
return new AjaxResult().addError("productId is null");
}
WxPayApiConfig config = WxPayApiConfigKit.getWxPayApiConfig();
//获取扫码支付模式一url
String qrCodeUrl = WxPayKit.bizPayUrl(config.getPartnerKey(), config.getAppId(), config.getMchId(), productId);
log.info(qrCodeUrl);
//生成二维码保存的路径
String name = "payQRCode1.png";
log.info(ResourceUtils.getURL("classpath:").getPath());
boolean encode = QrCodeKit.encode(qrCodeUrl, BarcodeFormat.QR_CODE, 3, ErrorCorrectionLevel.H,
"png", 200, 200,
ResourceUtils.getURL("classpath:").getPath().concat("static").concat(File.separator).concat(name));
if (encode) {
//在页面上显示
return new AjaxResult().success(name);
}
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult().addError("系统异常:" + e.getMessage());
}
return null;
}
/**
* 扫码支付模式一回调
*/
@RequestMapping(value = "/scanCodeNotify", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String scanCodeNotify(HttpServletRequest request, HttpServletResponse response) {
try {
String result = HttpKit.readData(request);
log.info("scanCodeNotify>>>" + result);
/**
* 获取返回的信息内容中各个参数的值
*/
Map<String, String> map = WxPayKit.xmlToMap(result);
for (String key : map.keySet()) {
log.info("key= " + key + " and value= " + map.get(key));
}
String appId = map.get("appid");
String openId = map.get("openid");
String mchId = map.get("mch_id");
String isSubscribe = map.get("is_subscribe");
String nonceStr = map.get("nonce_str");
String productId = map.get("product_id");
String sign = map.get("sign");
Map<String, String> packageParams = new HashMap<String, String>(6);
packageParams.put("appid", appId);
packageParams.put("openid", openId);
packageParams.put("mch_id", mchId);
packageParams.put("is_subscribe", isSubscribe);
packageParams.put("nonce_str", nonceStr);
packageParams.put("product_id", productId);
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
String packageSign = WxPayKit.createSign(packageParams, wxPayApiConfig.getPartnerKey(), SignType.MD5);
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
Map<String, String> params = UnifiedOrderModel
.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.body("IJPay 让支付触手可及-扫码支付模式一")
.attach("Node.js 版:https://gitee.com/javen205/TNWX")
.out_trade_no(WxPayKit.generateStr())
.total_fee("1")
.spbill_create_ip(ip)
.notify_url(notifyUrl)
.trade_type(TradeType.NATIVE.getTradeType())
.openid(openId)
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.pushOrder(false, params);
log.info("统一下单:" + xmlResult);
/**
* 发送信息给微信服务器
*/
Map<String, String> payResult = WxPayKit.xmlToMap(xmlResult);
String returnCode = payResult.get("return_code");
String resultCode = payResult.get("result_code");
if (WxPayKit.codeIsOk(returnCode) && WxPayKit.codeIsOk(resultCode)) {
// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
String prepayId = payResult.get("prepay_id");
Map<String, String> prepayParams = new HashMap<String, String>(10);
prepayParams.put("return_code", "SUCCESS");
prepayParams.put("appid", appId);
prepayParams.put("mch_id", mchId);
prepayParams.put("nonce_str", System.currentTimeMillis() + "");
prepayParams.put("prepay_id", prepayId);
String prepaySign;
if (sign.equals(packageSign)) {
prepayParams.put("result_code", "SUCCESS");
} else {
prepayParams.put("result_code", "FAIL");
//result_code为FAIL时添加该键值对value值是微信告诉客户的信息
prepayParams.put("err_code_des", "订单失效");
}
prepaySign = WxPayKit.createSign(prepayParams, wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
prepayParams.put("sign", prepaySign);
String xml = WxPayKit.toXml(prepayParams);
log.error(xml);
return xml;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 扫码支付模式二
*/
@RequestMapping(value = "/scanCode2", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult scanCode2(HttpServletRequest request, HttpServletResponse response,
@RequestParam("total_fee") String totalFee) {
if (StrUtil.isBlank(totalFee)) {
return new AjaxResult().addError("支付金额不能为空");
}
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = UnifiedOrderModel
.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.body("IJPay 让支付触手可及-扫码支付模式二")
.attach("Node.js 版:https://gitee.com/javen205/TNWXX")
.out_trade_no(WxPayKit.generateStr())
.total_fee("1")
.spbill_create_ip(ip)
.notify_url(notifyUrl)
.trade_type(TradeType.NATIVE.getTradeType())
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.pushOrder(false, params);
log.info("统一下单:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
String returnCode = result.get("return_code");
String returnMsg = result.get("return_msg");
System.out.println(returnMsg);
if (!WxPayKit.codeIsOk(returnCode)) {
return new AjaxResult().addError("error:" + returnMsg);
}
String resultCode = result.get("result_code");
if (!WxPayKit.codeIsOk(resultCode)) {
return new AjaxResult().addError("error:" + returnMsg);
}
//生成预付订单success
String qrCodeUrl = result.get("code_url");
String name = "payQRCode2.png";
boolean encode = QrCodeKit.encode(qrCodeUrl, BarcodeFormat.QR_CODE, 3, ErrorCorrectionLevel.H, "png", 200, 200,
request.getSession().getServletContext().getRealPath("/") + File.separator + name);
if (encode) {
//在页面上显示
return new AjaxResult().success(name);
}
return null;
}
/**
* 刷卡支付
*/
@RequestMapping(value = "/microPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult microPay(HttpServletRequest request, HttpServletResponse response) {
String authCode = request.getParameter("auth_code");
String totalFee = request.getParameter("total_fee");
if (StrUtil.isBlank(totalFee)) {
return new AjaxResult().addError("支付金额不能为空");
}
if (StrUtil.isBlank(authCode)) {
return new AjaxResult().addError("auth_code参数错误");
}
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = MicroPayModel.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.body("IJPay 让支付触手可及-刷卡支付")
.attach("Node.js 版:https://gitee.com/javen205/TNWXX")
.out_trade_no(WxPayKit.generateStr())
.total_fee("1")
.spbill_create_ip(ip)
.auth_code(authCode)
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.microPay(false, params);
//同步返回结果
log.info("xmlResult:" + xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
String returnCode = result.get("return_code");
String returnMsg = result.get("return_msg");
if (!WxPayKit.codeIsOk(returnCode)) {
//通讯失败
String errCode = result.get("err_code");
if (StrUtil.isNotBlank(errCode)) {
//用户支付中,需要输入密码
if (USER_PAYING.equals(errCode)) {
//等待5秒后调用【查询订单API】
}
}
log.info("提交刷卡支付失败>>" + xmlResult);
return new AjaxResult().addError(returnMsg);
}
String resultCode = result.get("result_code");
if (!WxPayKit.codeIsOk(resultCode)) {
log.info("支付失败>>" + xmlResult);
String errCodeDes = result.get("err_code_des");
return new AjaxResult().addError(errCodeDes);
}
//支付成功
return new AjaxResult().success(xmlResult);
}
/**
* 微信APP支付
*/
@RequestMapping(value = "/appPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult appPay(HttpServletRequest request) {
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = UnifiedOrderModel
.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.body("IJPay 让支付触手可及-App支付")
.attach("Node.js 版:https://gitee.com/javen205/TNWXX")
.out_trade_no(WxPayKit.generateStr())
.total_fee("1000")
.spbill_create_ip(ip)
.notify_url(notifyUrl)
.trade_type(TradeType.APP.getTradeType())
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.pushOrder(false, params);
log.info(xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
String returnCode = result.get("return_code");
String returnMsg = result.get("return_msg");
if (!WxPayKit.codeIsOk(returnCode)) {
return new AjaxResult().addError(returnMsg);
}
String resultCode = result.get("result_code");
if (!WxPayKit.codeIsOk(resultCode)) {
return new AjaxResult().addError(returnMsg);
}
// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
String prepayId = result.get("prepay_id");
Map<String, String> packageParams = WxPayKit.appPrepayIdCreateSign(wxPayApiConfig.getAppId(), wxPayApiConfig.getMchId(), prepayId,
wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String jsonStr = JSON.toJSONString(packageParams);
log.info("返回apk的参数:" + jsonStr);
return new AjaxResult().success(jsonStr);
}
/**
* 微信小程序支付
*/
@RequestMapping(value = "/miniAppPay", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult miniAppPay(HttpServletRequest request) {
//需要通过授权来获取openId
String openId = (String) request.getSession().getAttribute("openId");
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = UnifiedOrderModel
.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.body("IJPay 让支付触手可及-小程序支付")
.attach("Node.js 版:https://gitee.com/javen205/TNWXX")
.out_trade_no(WxPayKit.generateStr())
.total_fee("1000")
.spbill_create_ip(ip)
.notify_url(notifyUrl)
.trade_type(TradeType.JSAPI.getTradeType())
.openid(openId)
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.pushOrder(false, params);
log.info(xmlResult);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
String returnCode = result.get("return_code");
String returnMsg = result.get("return_msg");
if (!WxPayKit.codeIsOk(returnCode)) {
return new AjaxResult().addError(returnMsg);
}
String resultCode = result.get("result_code");
if (!WxPayKit.codeIsOk(resultCode)) {
return new AjaxResult().addError(returnMsg);
}
// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
String prepayId = result.get("prepay_id");
Map<String, String> packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayApiConfig.getAppId(), prepayId,
wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String jsonStr = JSON.toJSONString(packageParams);
log.info("小程序支付的参数:" + jsonStr);
return new AjaxResult().success(jsonStr);
}
@RequestMapping(value = "/queryOrder", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String queryOrder(@RequestParam(value = "transactionId", required = false) String transactionId, @RequestParam(value = "outTradeNo", required = false) String outTradeNo) {
try {
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = OrderQueryModel.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.transaction_id(transactionId)
.out_trade_no(outTradeNo)
.nonce_str(WxPayKit.generateStr())
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);
log.info("请求参数:{}", WxPayKit.toXml(params));
String query = WxPayApi.orderQuery(params);
log.info("查询结果: {}", query);
return query;
} catch (Exception e) {
e.printStackTrace();
return "系统错误";
}
}
/**
* 企业付款到零钱
*/
@RequestMapping(value = "/transfer", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String transfer(HttpServletRequest request, @RequestParam("openId") String openId) {
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = TransferModel.builder()
.mch_appid(wxPayApiConfig.getAppId())
.mchid(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.partner_trade_no(WxPayKit.generateStr())
.openid(openId)
.check_name("NO_CHECK")
.amount("100")
.desc("IJPay 让支付触手可及-企业付款")
.spbill_create_ip(ip)
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5, false);
// 提现
String transfers = WxPayApi.transfers(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
log.info("提现结果:" + transfers);
Map<String, String> map = WxPayKit.xmlToMap(transfers);
String returnCode = map.get("return_code");
String resultCode = map.get("result_code");
if (WxPayKit.codeIsOk(returnCode) && WxPayKit.codeIsOk(resultCode)) {
// 提现成功
} else {
// 提现失败
}
return transfers;
}
/**
* 查询企业付款到零钱
*/
@RequestMapping(value = "/transferInfo", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String transferInfo(@RequestParam("partner_trade_no") String partnerTradeNo) {
try {
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = GetTransferInfoModel.builder()
.nonce_str(WxPayKit.generateStr())
.partner_trade_no(partnerTradeNo)
.mch_id(wxPayApiConfig.getMchId())
.appid(wxPayApiConfig.getAppId())
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5, false);
return WxPayApi.getTransferInfo(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取RSA加密公钥
*/
@RequestMapping(value = "/getPublicKey", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String getPublicKey() {
try {
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = new HashMap<String, String>(4);
params.put("mch_id", wxPayApiConfig.getMchId());
params.put("nonce_str", String.valueOf(System.currentTimeMillis()));
params.put("sign_type", "MD5");
String createSign = WxPayKit.createSign(params, wxPayApiConfig.getPartnerKey(), SignType.MD5);
params.put("sign", createSign);
return WxPayApi.getPublicKey(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 企业付款到银行卡
*/
@RequestMapping(value = "/payBank", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String payBank() {
try {
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
//通过WxPayApi.getPublicKey接口获取RSA加密公钥
//假设获取到的RSA加密公钥为PUBLIC_KEY(PKCS#8格式)
final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Bl76IwSvBTiibZ+CNRUA6BfahMshZ0WJpHD1GpmvcQjeN6Yrv6c9eIl6gB4nU3isN7bn+LmoVTpH1gHViaV2YyG/zXj4z4h7r+V+ezesMqqorEg38BCNUHNmhnw4/C0I4gBAQ4x0SJOGnfKGZKR9yzvbkJtvEn732JcEZCbdTZmaxkwlenXvM+mStcJaxBCB/h5xJ5VOF5nDbTPzLphIpzddr3zx/Jxjna9QB1v/YSKYXn+iuwruNUXGCvvxBWaBGKrjOdRTRy9adWOgNmtuYDQJ2YOfG8PtPe06ELKjmr2CfaAGrKKUroyaGvy3qxAV0PlT+UQ4ADSXWt/zl0o5wIDAQAB";
Map<String, String> params = new HashMap<String, String>(10);
params.put("mch_id", wxPayApiConfig.getMchId());
params.put("partner_trade_no", System.currentTimeMillis() + "");
params.put("nonce_str", System.currentTimeMillis() + "");
//收款方银行卡号
params.put("enc_bank_no", RsaKit.encryptByPublicKeyByWx("银行卡号", PUBLIC_KEY));
//收款方用户名
params.put("enc_true_name", RsaKit.encryptByPublicKeyByWx("银行卡持有人姓名", PUBLIC_KEY));
//收款方开户行
params.put("bank_code", "1001");
params.put("amount", "1");
params.put("desc", "IJPay 让支付触手可及-付款到银行卡");
params.put("sign", WxPayKit.createSign(params, wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256));
return WxPayApi.payBank(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 查询企业付款到银行
*/
@RequestMapping(value = "/queryBank", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String queryBank(@RequestParam("partner_trade_no") String partnerTradeNo) {
try {
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = new HashMap<String, String>(4);
params.put("mch_id", wxPayApiConfig.getMchId());
params.put("partner_trade_no", partnerTradeNo);
params.put("nonce_str", System.currentTimeMillis() + "");
params.put("sign", WxPayKit.createSign(params, wxPayApiConfig.getPartnerKey(), SignType.MD5));
return WxPayApi.queryBank(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 添加分账接收方
*/
@RequestMapping(value = "/profitSharingAddReceiver", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String profitSharingAddReceiver() {
try {
ReceiverModel receiver = ReceiverModel.builder()
.type("PERSONAL_OPENID")
.account("openid")
.relation_type("PARTNER")
.build();
Map<String, String> params = ProfitSharingModel.builder()
.mch_id(wxPayBean.getMchId())
.appid(wxPayBean.getAppId())
.nonce_str(WxPayKit.generateStr())
.receiver(JSON.toJSONString(receiver))
.build()
.createSign(wxPayBean.getPartnerKey(), SignType.HMACSHA256);
log.info("请求参数:{}", WxPayKit.toXml(params));
String result = WxPayApi.profitSharingAddReceiver(params);
log.info("请求结果:{}", result);
return JSON.toJSONString(WxPayKit.xmlToMap(result));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 请求单次分账
*/
@RequestMapping(value = "/profitSharing", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String profitSharing(@RequestParam(value = "transactionId") String transactionId) {
List<ReceiverModel> list = new ArrayList<>();
list.add(ReceiverModel.builder()
.type("PERSONAL_OPENID")
.account("openid")
.amount(66)
.description("IJPay 分账")
.build());
Map<String, String> params = ProfitSharingModel.builder()
.mch_id(wxPayBean.getMchId())
.appid(wxPayBean.getAppId())
.nonce_str(WxPayKit.generateStr())
.transaction_id(transactionId)
.out_order_no(WxPayKit.generateStr())
.receivers(JSON.toJSONString(list))
.build()
.createSign(wxPayBean.getPartnerKey(), SignType.HMACSHA256);
log.info("请求参数:{}", WxPayKit.toXml(params));
String result = WxPayApi.profitSharing(params, wxPayBean.getCertPath(), wxPayBean.getMchId());
log.info("请求结果:{}", result);
return JSON.toJSONString(WxPayKit.xmlToMap(result));
}
/**
* 微信退款
*/
@RequestMapping(value = "/refund", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String refund(@RequestParam(value = "transactionId", required = false) String transactionId,
@RequestParam(value = "outTradeNo", required = false) String outTradeNo) {
try {
log.info("transactionId: {} outTradeNo:{}", transactionId, outTradeNo);
if (StrUtil.isBlank(outTradeNo) && StrUtil.isBlank(transactionId)) {
return "transactionId、out_trade_no二选一";
}
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = RefundModel.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.transaction_id(transactionId)
.out_trade_no(outTradeNo)
.out_refund_no(WxPayKit.generateStr())
.total_fee("1")
.refund_fee("1")
.notify_url(refundNotifyUrl)
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);
String refundStr = WxPayApi.orderRefund(false, params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
log.info("refundStr: {}", refundStr);
return refundStr;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 微信退款查询
*/
@RequestMapping(value = "/refundQuery", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String refundQuery(@RequestParam("transactionId") String transactionId,
@RequestParam("out_trade_no") String outTradeNo,
@RequestParam("out_refund_no") String outRefundNo,
@RequestParam("refund_id") String refundId) {
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = RefundQueryModel.builder()
.appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId())
.nonce_str(WxPayKit.generateStr())
.transaction_id(transactionId)
.out_trade_no(outTradeNo)
.out_refund_no(outRefundNo)
.refund_id(refundId)
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);
return WxPayApi.orderRefundQuery(false, params);
}
/**
* 退款通知
*/
@RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String refundNotify(HttpServletRequest request) {
String xmlMsg = HttpKit.readData(request);
log.info("退款通知=" + xmlMsg);
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
String returnCode = params.get("return_code");
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
if (WxPayKit.codeIsOk(returnCode)) {
String reqInfo = params.get("req_info");
String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());
log.info("退款通知解密后的数据=" + decryptData);
// 更新订单信息
// 发送通知等
Map<String, String> xml = new HashMap<String, String>(2);
xml.put("return_code", "SUCCESS");
xml.put("return_msg", "OK");
return WxPayKit.toXml(xml);
}
return null;
}
@RequestMapping(value = "/sendRedPack", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String sendRedPack(HttpServletRequest request, @RequestParam("openId") String openId) {
try {
String ip = IpKit.getRealIp(request);
if (StrUtil.isBlank(ip)) {
ip = "127.0.0.1";
}
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
Map<String, String> params = SendRedPackModel.builder()
.nonce_str(WxPayKit.generateStr())
.mch_billno(WxPayKit.generateStr())
.mch_id(wxPayApiConfig.getMchId())
.wxappid(wxPayApiConfig.getAppId())
.send_name("IJPay 红包测试")
.re_openid(openId)
.total_amount("1000")
.total_num("1")
.wishing("感谢您使用 IJPay")
.client_ip(ip)
.act_name("感恩回馈活动")
.remark("点 start 送红包,快来抢!")
.build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);
String result = WxPayApi.sendRedPack(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
System.out.println("发送红包结果:" + result);
Map<String, String> map = WxPayKit.xmlToMap(result);
return JSON.toJSONString(map);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 异步通知
*/
@RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String payNotify(HttpServletRequest request) {
String xmlMsg = HttpKit.readData(request);
log.info("支付通知=" + xmlMsg);
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
String returnCode = params.get("return_code");
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
// 注意此处签名方式需与统一下单的签名类型一致
if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) {
if (WxPayKit.codeIsOk(returnCode)) {
// 更新订单信息
// 发送通知等
Map<String, String> xml = new HashMap<String, String>(2);
xml.put("return_code", "SUCCESS");
xml.put("return_msg", "OK");
return WxPayKit.toXml(xml);
}
}
return null;
}
}

View File

@@ -0,0 +1,982 @@
package org.wfc.payment.pay.wxpay.controller;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.AuthTypeEnum;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.AesUtil;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.core.utils.DateTimeZoneUtil;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.Apply4SubApiEnum;
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
import com.ijpay.wxpay.enums.v3.CertAlgorithmTypeEnum;
import com.ijpay.wxpay.enums.v3.ComplaintsApiEnum;
import com.ijpay.wxpay.enums.v3.OtherApiEnum;
import com.ijpay.wxpay.enums.v3.PayGiftActivityApiEnum;
import com.ijpay.wxpay.enums.v3.PayScoreApiEnum;
import com.ijpay.wxpay.enums.v3.TransferApiEnum;
import com.ijpay.wxpay.model.v3.Amount;
import com.ijpay.wxpay.model.v3.BatchTransferModel;
import com.ijpay.wxpay.model.v3.H5Info;
import com.ijpay.wxpay.model.v3.Payer;
import com.ijpay.wxpay.model.v3.RefundAmount;
import com.ijpay.wxpay.model.v3.RefundGoodsDetail;
import com.ijpay.wxpay.model.v3.RefundModel;
import com.ijpay.wxpay.model.v3.SceneInfo;
import com.ijpay.wxpay.model.v3.TransferDetailInput;
import com.ijpay.wxpay.model.v3.UnifiedOrderModel;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.signers.PlainDSAEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.wfc.payment.domain.WxPayV3Bean;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* <p>微信支付 v3 接口示例</p>
*
* @author cyc
*/
@Controller
@RequestMapping("/v3")
public class WxPayV3Controller {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final static int OK = 200;
@Resource
WxPayV3Bean wxPayV3Bean;
String serialNo;
String platSerialNo;
@RequestMapping("")
@ResponseBody
public String index() {
log.info(wxPayV3Bean.toString());
try {
String classPath = "classpath:/dev/apiclient_key.pem";
String v3 = "classpath:/dev/wxpay_v3.properties";
String absolutePath = PayKit.getAbsolutePath(classPath);
log.info("absolutePath:{}", absolutePath);
String certFileContent = PayKit.getCertFileContent(classPath);
log.info("classPath content:{}", certFileContent);
InputStream inputStream = PayKit.getCertFileInputStream(v3);
if (null != inputStream) {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
String str = result.toString();
log.info("file content:{}", str);
}
} catch (Exception e) {
log.error("文件不存在", e);
}
return ("欢迎使用 的微信支付 Api-v3");
}
@RequestMapping("/getSerialNumber")
@ResponseBody
public String serialNumber() {
return getSerialNumber();
}
@RequestMapping("/getPlatSerialNumber")
@ResponseBody
public String platSerialNumber() {
return getPlatSerialNumber();
}
private String getSerialNumber() {
if (StrUtil.isEmpty(serialNo)) {
// 获取证书序列号
X509Certificate certificate = PayKit.getCertificate(wxPayV3Bean.getCertPath());
if (null != certificate) {
serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
// 提前两天检查证书是否有效
boolean isValid = PayKit.checkCertificateIsValid(certificate, wxPayV3Bean.getMchId(), -2);
log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
}
// System.out.println("输出证书信息:\n" + certificate.toString());
// // 输出关键信息,截取部分并进行标记
// System.out.println("证书序列号:" + certificate.getSerialNumber().toString(16));
// System.out.println("版本号:" + certificate.getVersion());
// System.out.println("签发者:" + certificate.getIssuerDN());
// System.out.println("有效起始日期:" + certificate.getNotBefore());
// System.out.println("有效终止日期:" + certificate.getNotAfter());
// System.out.println("主体名:" + certificate.getSubjectDN());
// System.out.println("签名算法:" + certificate.getSigAlgName());
// System.out.println("签名:" + certificate.getSignature().toString());
}
System.out.println("serialNo:" + serialNo);
return serialNo;
}
private String getPlatSerialNumber() {
if (StrUtil.isEmpty(platSerialNo)) {
// 获取平台证书序列号
X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getPlatformCertPath()));
platSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
}
System.out.println("platSerialNo:" + platSerialNo);
return platSerialNo;
}
private String savePlatformCert(String associatedData, String nonce, String cipherText, String algorithm, String certPath) {
try {
String key3 = wxPayV3Bean.getApiKey3();
String publicKey;
if (StrUtil.equals(algorithm, AuthTypeEnum.SM2.getPlatformCertAlgorithm())) {
publicKey = PayKit.sm4DecryptToString(key3, cipherText, nonce, associatedData);
} else {
AesUtil aesUtil = new AesUtil(wxPayV3Bean.getApiKey3().getBytes(StandardCharsets.UTF_8));
// 平台证书密文解密
// encrypt_certificate 中的 associated_data nonce ciphertext
publicKey = aesUtil.decryptToString(
associatedData.getBytes(StandardCharsets.UTF_8),
nonce.getBytes(StandardCharsets.UTF_8),
cipherText
);
}
if (StrUtil.isNotEmpty(publicKey)) {
// 保存证书
FileWriter writer = new FileWriter(certPath);
writer.write(publicKey);
// 获取平台证书序列号
X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
return certificate.getSerialNumber().toString(16).toUpperCase();
}
return "";
} catch (Exception e) {
log.error("保存平台证书异常", e);
return e.getMessage();
}
}
@RequestMapping("/platformCert")
@ResponseBody
public String platformCert() {
try {
String associatedData = "certificate";
String nonce = "80d28946a64a";
String cipherText = "DwAqW4+4TeUaOEylfKEXhw+XqGh/YTRhUmLw/tBfQ5nM9DZ9d+9aGEghycwV1jwo52vXb/t6ueBvBRHRIW5JgDRcXmTHw9IMTrIK6HxTt2qiaGTWJU9whsF+GGeQdA7gBCHZm3AJUwrzerAGW1mclXBTvXqaCl6haE7AOHJ2g4RtQThi3nxOI63/yc3WaiAlSR22GuCpy6wJBfljBq5Bx2xXDZXlF2TNbDIeodiEnJEG2m9eBWKuvKPyUPyClRXG1fdOkKnCZZ6u+ipb4IJx28n3MmhEtuc2heqqlFUbeONaRpXv6KOZmH/IdEL6nqNDP2D7cXutNVCi0TtSfC7ojnO/+PKRu3MGO2Z9q3zyZXmkWHCSms/C3ACatPUKHIK+92MxjSQDc1E/8faghTc9bDgn8cqWpVKcL3GHK+RfuYKiMcdSkUDJyMJOwEXMYNUdseQMJ3gL4pfxuQu6QrVvJ17q3ZjzkexkPNU4PNSlIBJg+KX61cyBTBumaHy/EbHiP9V2GeM729a0h5UYYJVedSo1guIGjMZ4tA3WgwQrlpp3VAMKEBLRJMcnHd4pH5YQ/4hiUlHGEHttWtnxKFwnJ6jHr3OmFLV1FiUUOZEDAqR0U1KhtGjOffnmB9tymWF8FwRNiH2Tee/cCDBaHhNtfPI5129SrlSR7bZc+h7uzz9z+1OOkNrWHzAoWEe3XVGKAywpn5HGbcL+9nsEVZRJLvV7aOxAZBkxhg8H5Fjt1ioTJL+qXgRzse1BX1iiwfCR0fzEWT9ldDTDW0Y1b3tb419MhdmTQB5FsMXYOzqp5h+Tz1FwEGsa6TJsmdjJQSNz+7qPSg5D6C2gc9/6PkysSu/6XfsWXD7cQkuZ+TJ/Xb6Q1Uu7ZB90SauA8uPQUIchW5zQ6UfK5dwMkOuEcE/141/Aw2rlDqjtsE17u1dQ6TCax/ZQTDQ2MDUaBPEaDIMPcgL7fCeijoRgovkBY92m86leZvQ+HVbxlFx5CoPhz4a81kt9XJuEYOztSIKlm7QNfW0BvSUhLmxDNCjcxqwyydtKbLzA+EBb2gG4ORiH8IOTbV0+G4S6BqetU7RrO+/nKt21nXVqXUmdkhkBakLN8FUcHygyWnVxbA7OI2RGnJJUnxqHd3kTbzD5Wxco4JIQsTOV6KtO5c960oVYUARZIP1SdQhqwELm27AktEN7kzg/ew/blnTys/eauGyw78XCROb9F1wbZBToUZ7L+8/m/2tyyyqNid+sC9fYqJoIOGfFOe6COWzTI/XPytCHwgHeUxmgk7NYfU0ukR223RPUOym6kLzSMMBKCivnNg68tbLRJHEOpQTXFBaFFHt2qpceJpJgw5sKFqx3eQnIFuyvA1i8s2zKLhULZio9hpsDJQREOcNeHVjEZazdCGnbe3Vjg7uqOoVHdE/YbNzJNQEsB3/erYJB+eGzyFwFmdAHenG5RE6FhCutjszwRiSvW9F7wvRK36gm7NnVJZkvlbGwh0UHr0pbcrOmxT81xtNSvMzT0VZNLTUX2ur3AGLwi2ej8BIC0H41nw4ToxTnwtFR1Xy55+pUiwpB7JzraA08dCXdFdtZ72Tw/dNBy5h1P7EtQYiKzXp6rndfOEWgNOsan7e1XRpCnX7xoAkdPvy40OuQ5gNbDKry5gVDEZhmEk/WRuGGaX06CG9m7NfErUsnQYrDJVjXWKYuARd9R7W0aa5nUXqz/Pjul/LAatJgWhZgFBGXhNr9iAoade/0FPpBj0QWa8SWqKYKiOqXqhfhppUq35FIa0a1Vvxcn3E38XYpVZVTDEXcEcD0RLCu/ezdOa6vRcB7hjgXFIRZQAka0aXnQxwOZwE2Rt3yWXqc+Q1ah2oOrg8Lg3ETc644X9QP4FxOtDwz/A==";
String algorithm = "AEAD_AES_256_GCM";
return savePlatformCert(associatedData, nonce, cipherText, algorithm, wxPayV3Bean.getPlatformCertPath());
} catch (Exception e) {
log.error("保存平台证书异常", e);
return e.getMessage();
}
}
@RequestMapping("/smPlatformCert")
@ResponseBody
public String smPlatformCert() {
try {
String associatedData = "certificate";
String nonce = "";
String cipherText = "";
String algorithm = "AEAD_SM4_GCM";
return savePlatformCert(associatedData, nonce, cipherText, algorithm, wxPayV3Bean.getPlatformCertPath());
} catch (Exception e) {
log.error("保存国密平台证书异常", e);
return e.getMessage();
}
}
@RequestMapping("/get")
@ResponseBody
public String v3Get() {
// 获取平台证书列表
try {
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.GET,
WxDomainEnum.CHINA.toString(),
CertAlgorithmTypeEnum.getCertSuffixUrl(CertAlgorithmTypeEnum.SM2.getCode()),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
"",
AuthTypeEnum.RSA.getCode()
);
Map<String, List<String>> headers = response.getHeaders();
log.info("请求头: {}", headers);
String timestamp = response.getHeader("Wechatpay-Timestamp");
String nonceStr = response.getHeader("Wechatpay-Nonce");
String serialNumber = response.getHeader("Wechatpay-Serial");
String signature = response.getHeader("Wechatpay-Signature");
String body = response.getBody();
int status = response.getStatus();
log.info("serialNumber: {}", serialNumber);
log.info("status: {}", status);
log.info("body: {}", body);
int isOk = 200;
if (status == isOk) {
JSONObject jsonObject = JSONUtil.parseObj(body);
JSONArray dataArray = jsonObject.getJSONArray("data");
// 默认认为只有一个平台证书
JSONObject encryptObject = dataArray.getJSONObject(0);
JSONObject encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
String associatedData = encryptCertificate.getStr("associated_data");
String cipherText = encryptCertificate.getStr("ciphertext");
String nonce = encryptCertificate.getStr("nonce");
String algorithm = encryptCertificate.getStr("algorithm");
String serialNo = encryptObject.getStr("serial_no");
final String platSerialNo = savePlatformCert(associatedData, nonce, cipherText, algorithm, wxPayV3Bean.getPlatformCertPath());
log.info("平台证书序列号: {} serialNo: {}", platSerialNo, serialNo);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature:{}", verifySignature);
}
return body;
} catch (Exception e) {
log.error("获取平台证书列表异常", e);
return null;
}
}
@RequestMapping("/nativePay")
@ResponseBody
public String nativePay() {
try {
String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
.setAppid(wxPayV3Bean.getAppId())
.setMchid(wxPayV3Bean.getMchId())
.setDescription("IJPay 让支付触手可及")
.setOut_trade_no(PayKit.generateStr())
.setTime_expire(timeExpire)
.setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
.setAmount(new Amount().setTotal(1));
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.NATIVE_PAY.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
JSONUtil.toJsonStr(unifiedOrderModel),
AuthTypeEnum.RSA.getCode()
);
log.info("统一下单响应 {}", response);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
return response.getBody();
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/appPay")
@ResponseBody
public String appPay() {
try {
String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
.setAppid(wxPayV3Bean.getAppId())
.setMchid(wxPayV3Bean.getMchId())
.setDescription("IJPay 让支付触手可及")
.setOut_trade_no(PayKit.generateStr())
.setTime_expire(timeExpire)
.setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
.setAmount(new Amount().setTotal(1));
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.APP_PAY.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
JSONUtil.toJsonStr(unifiedOrderModel),
AuthTypeEnum.RSA.getCode()
);
log.info("统一下单响应 {}", response);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
if (response.getStatus() == OK && verifySignature) {
String body = response.getBody();
JSONObject jsonObject = JSONUtil.parseObj(body);
String prepayId = jsonObject.getStr("prepay_id");
Map<String, String> map = WxPayKit.appCreateSign(wxPayV3Bean.getAppId(), wxPayV3Bean.getMchId(), prepayId, wxPayV3Bean.getKeyPath());
log.info("唤起支付参数:{}", map);
return JSONUtil.toJsonStr(map);
}
return JSONUtil.toJsonStr(response);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/query")
@ResponseBody
public String query(@RequestParam String outTradeNo) {
try {
Map<String, String> params = new HashMap<>(16);
params.put("mchid", wxPayV3Bean.getMchId());
log.info("统一下单参数 {}", JSONUtil.toJsonStr(params));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.GET,
WxDomainEnum.CHINA.toString(),
String.format(BasePayApiEnum.ORDER_QUERY_BY_OUT_TRADE_NO.toString(), outTradeNo),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
params,
AuthTypeEnum.RSA.getCode()
);
log.info("查询响应 {}", response);
if (response.getStatus() == OK) {
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
return response.getBody();
}
return JSONUtil.toJsonStr(response);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/jsApiPay")
@ResponseBody
public String jsApiPay(@RequestParam(value = "openId", required = false, defaultValue = "o-_-itxuXeGW3O1cxJ7FXNmq8Wf8") String openId) {
try {
String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
.setAppid(wxPayV3Bean.getAppId())
.setMchid(wxPayV3Bean.getMchId())
.setDescription("IJPay 让支付触手可及")
.setOut_trade_no(PayKit.generateStr())
.setTime_expire(timeExpire)
.setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
.setAmount(new Amount().setTotal(1))
.setPayer(new Payer().setOpenid(openId));
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.JS_API_PAY.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
JSONUtil.toJsonStr(unifiedOrderModel)
);
log.info("统一下单响应 {}", response);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
if (response.getStatus() == OK && verifySignature) {
String body = response.getBody();
JSONObject jsonObject = JSONUtil.parseObj(body);
String prepayId = jsonObject.getStr("prepay_id");
Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), prepayId, wxPayV3Bean.getKeyPath());
log.info("唤起支付参数:{}", map);
return JSONUtil.toJsonStr(map);
}
return JSONUtil.toJsonStr(response);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/wapPay")
@ResponseBody
public String wapPay() {
try {
String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
.setAppid(wxPayV3Bean.getAppId())
.setMchid(wxPayV3Bean.getMchId())
.setDescription("IJPay 让支付触手可及")
.setOut_trade_no(PayKit.generateStr())
.setTime_expire(timeExpire)
.setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
.setAmount(new Amount().setTotal(1))
.setScene_info(
new SceneInfo()
.setPayer_client_ip("").
setH5_info(new H5Info()
.setType("Wap")));
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.H5_PAY.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
JSONUtil.toJsonStr(unifiedOrderModel)
);
log.info("统一下单响应 {}", response);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
if (response.getStatus() == OK && verifySignature) {
String body = response.getBody();
return JSONUtil.toJsonStr(body);
}
return JSONUtil.toJsonStr(response);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/batchTransfer")
@ResponseBody
public String batchTransfer(@RequestParam(value = "openId", required = false, defaultValue = "o-_-itxuXeGW3O1cxJ7FXNmq8Wf8") String openId) {
try {
BatchTransferModel batchTransferModel = new BatchTransferModel()
.setAppid(wxPayV3Bean.getAppId())
.setOut_batch_no(PayKit.generateStr())
.setBatch_name("IJPay 测试微信转账到零钱")
.setBatch_remark("IJPay 测试微信转账到零钱")
.setTotal_amount(1)
.setTotal_num(1)
.setTransfer_detail_list(Collections.singletonList(
new TransferDetailInput()
.setOut_detail_no(PayKit.generateStr())
.setTransfer_amount(1)
.setTransfer_remark("IJPay 测试微信转账到零钱")
.setOpenid(openId)));
log.info("发起商家转账请求参数 {}", JSONUtil.toJsonStr(batchTransferModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
TransferApiEnum.TRANSFER_BATCHES.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
JSONUtil.toJsonStr(batchTransferModel)
);
log.info("发起商家转账响应 {}", response);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
if (response.getStatus() == OK && verifySignature) {
return response.getBody();
}
return JSONUtil.toJsonStr(response);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/put")
@ResponseBody
public String put() {
try {
Map<String, String> params = new HashMap<>();
params.put("url", "https://gitee.com/javen205/IJPay");
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.PUT,
WxDomainEnum.CHINA.toString(),
ComplaintsApiEnum.COMPLAINTS_NOTIFICATION.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
JSONUtil.toJsonStr(params)
);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
log.info("响应 {}", response);
return response.getBody();
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/getParams")
@ResponseBody
public String payScoreServiceOrder() {
try {
Map<String, String> params = new HashMap<>();
params.put("service_id", "500001");
params.put("appid", "wxd678efh567hg6787");
params.put("out_order_no", "1234323JKHDFE1243252");
IJPayHttpResponse result = WxPayApi.v3(
RequestMethodEnum.GET,
WxDomainEnum.CHINA.toString(),
PayScoreApiEnum.PAY_SCORE_SERVICE_ORDER.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
params
);
System.out.println(result);
return JSONUtil.toJsonStr(result);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/delete")
@ResponseBody
public String v3Delete() {
// 创建/查询/更新/删除投诉通知回调
try {
HashMap<String, String> hashMap = new HashMap<>(12);
hashMap.put("url", "https://qq.com");
IJPayHttpResponse result = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
ComplaintsApiEnum.COMPLAINTS_NOTIFICATION.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
JSONUtil.toJsonStr(hashMap)
);
System.out.println(result);
result = WxPayApi.v3(
RequestMethodEnum.DELETE,
WxDomainEnum.CHINA.toString(),
ComplaintsApiEnum.COMPLAINTS_NOTIFICATION.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
""
);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(result, wxPayV3Bean.getPlatformCertPath());
System.out.println("verifySignature:" + verifySignature);
// 如果返回的为 204 表示删除成功
System.out.println(result);
return JSONUtil.toJsonStr(result);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/upload")
@ResponseBody
public String v3Upload() {
// v3 接口上传文件
try {
String filePath = "/Users/Javen/Documents/pic/cat.png";
File file = FileUtil.newFile(filePath);
String sha256 = SecureUtil.sha256(file);
HashMap<Object, Object> map = new HashMap<>();
map.put("filename", file.getName());
map.put("sha256", sha256);
String body = JSONUtil.toJsonStr(map);
System.out.println(body);
IJPayHttpResponse result = WxPayApi.v3(
WxDomainEnum.CHINA.toString(),
OtherApiEnum.MERCHANT_UPLOAD_MEDIA.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
body,
file
);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(result, wxPayV3Bean.getPlatformCertPath());
System.out.println("verifySignature:" + verifySignature);
System.out.println(result);
return JSONUtil.toJsonStr(result);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/post")
@ResponseBody
public String payGiftActivity() {
// 支付有礼-终止活动
try {
String urlSuffix = String.format(PayGiftActivityApiEnum.PAY_GIFT_ACTIVITY_TERMINATE.toString(), "10028001");
System.out.println(urlSuffix);
IJPayHttpResponse result = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
urlSuffix,
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
""
);
System.out.println(result);
return JSONUtil.toJsonStr(result);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/sensitive")
@ResponseBody
public String sensitive() {
// 带有敏感信息接口
try {
String body = "处理请求参数";
IJPayHttpResponse result = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
Apply4SubApiEnum.APPLY_4_SUB.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
getPlatSerialNumber(),
wxPayV3Bean.getKeyPath(),
body
);
System.out.println(result);
return JSONUtil.toJsonStr(result);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
public static String sm2Encrypt(String plainText, SM2 sm2) {
byte[] dateBytes = plainText.getBytes();
// 这里需要手动设置sm2 对象的默认值与我们期望的不一致
sm2.setMode(SM2Engine.Mode.C1C2C3);
sm2.setEncoding(new PlainDSAEncoding());
// 加密
byte[] encrypt = sm2.encrypt(dateBytes);
return HexUtil.encodeHexStr(encrypt);
}
public static String sm2Decrypt(String cipherText, SM2 sm2) {
// 解密
byte[] decrypt = sm2.decrypt(HexUtil.decodeHex(cipherText));
return new String(decrypt);
}
@RequestMapping("/cipher")
@ResponseBody
public String cipher(@RequestParam(required = false) String authType) {
try {
String plainText = "IJPay";
String privateKeyPath = wxPayV3Bean.getKeyPath();
String publicKeyPath = wxPayV3Bean.getPublicKeyPath();
if (StrUtil.equals(authType, AuthTypeEnum.SM2.getCode())) {
String privateKeyByContent = PayKit.getPrivateKeyByContent(PayKit.getCertFileContent(privateKeyPath));
String publicKeyByContent = PayKit.getPublicKeyByContent(PayKit.getCertFileContent(publicKeyPath));
PrivateKey privateKey = PayKit.getPrivateKey(privateKeyPath, AuthTypeEnum.SM2.getCode());
PublicKey publicKey = PayKit.getSmPublicKey(publicKeyByContent);
// 创建sm2 对象
SM2 sm2 = SmUtil.sm2(privateKey, publicKey);
// SM2 sm2 = SmUtil.sm2(privateKeyByContent, publicKeyByContent);
String encrypt = sm2Encrypt(plainText, sm2);
log.info("加密: {}", encrypt);
log.info("解密: {}", sm2Decrypt(encrypt, sm2));
} else {
// 敏感信息加密
X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getPlatformCertPath()));
String encrypt = PayKit.rsaEncryptOAEP(plainText, certificate);
log.info("明文:{} 加密后密文:{}", plainText, encrypt);
// 敏感信息解密
String encryptStr = "";
PrivateKey privateKey = PayKit.getPrivateKey(wxPayV3Bean.getKeyPath(), AuthTypeEnum.RSA.getCode());
String decrypt = PayKit.rsaDecryptOAEP(encryptStr, privateKey);
log.info("解密后明文:{}", decrypt);
}
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
return null;
}
/**
* 申请交易账单
*
* @param billDate 2020-06-14 当天账单后一天出,不然会出现「账单日期格式不正确」错误
* @return 交易账单下载地址
*/
@RequestMapping("/tradeBill")
@ResponseBody
public String tradeBill(@RequestParam(value = "billDate", required = false) String billDate) {
try {
if (StrUtil.isEmpty(billDate)) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.DATE, -1);
billDate = DateUtil.format(calendar.getTime(), "YYYY-MM-dd");
}
Map<String, String> params = new HashMap<>(12);
params.put("bill_date", billDate);
params.put("bill_type", "ALL");
params.put("tar_type", "GZIP");
IJPayHttpResponse result = WxPayApi.v3(
RequestMethodEnum.GET,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.TRADE_BILL.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
params
);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(result, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
log.info("result:{}", result);
return JSONUtil.toJsonStr(result);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
/**
* 申请资金账单
*
* @param billDate 2020-06-14 当天账单后一天出,不然会出现「账单日期格式不正确」错误
* @return 资金账单下载地址
*/
@RequestMapping("/fundFlowBill")
@ResponseBody
public String fundFlowBill(@RequestParam(value = "billDate", required = false) String billDate) {
try {
if (StrUtil.isEmpty(billDate)) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.DATE, -1);
billDate = DateUtil.format(calendar.getTime(), "YYYY-MM-dd");
}
Map<String, String> params = new HashMap<>(12);
params.put("bill_date", billDate);
params.put("account_type", "BASIC");
IJPayHttpResponse result = WxPayApi.v3(
RequestMethodEnum.GET,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.FUND_FLOW_BILL.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
params
);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(result, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
log.info("result:{}", result);
return JSONUtil.toJsonStr(result);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/billDownload")
@ResponseBody
public String billDownload(@RequestParam(value = "token") String token,
@RequestParam(value = "tarType", required = false) String tarType) {
try {
Map<String, String> params = new HashMap<>(12);
params.put("token", token);
if (StrUtil.isNotEmpty(tarType)) {
params.put("tartype", tarType);
}
IJPayHttpResponse result = WxPayApi.v3(
RequestMethodEnum.GET,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.BILL_DOWNLOAD.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
params
);
log.info("result:{}", result);
return JSONUtil.toJsonStr(result);
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
}
@RequestMapping("/refund")
@ResponseBody
public String refund(@RequestParam(required = false) String transactionId,
@RequestParam(required = false) String outTradeNo) {
try {
String outRefundNo = PayKit.generateStr();
log.info("商户退款单号: {}", outRefundNo);
List<RefundGoodsDetail> list = new ArrayList<>();
RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
.setMerchant_goods_id("123")
.setGoods_name("IJPay 测试")
.setUnit_price(1)
.setRefund_amount(1)
.setRefund_quantity(1);
list.add(refundGoodsDetail);
RefundModel refundModel = new RefundModel()
.setOut_refund_no(outRefundNo)
.setReason("IJPay 测试退款")
.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/refundNotify"))
.setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
.setGoods_detail(list);
if (StrUtil.isNotEmpty(transactionId)) {
refundModel.setTransaction_id(transactionId);
}
if (StrUtil.isNotEmpty(outTradeNo)) {
refundModel.setOut_trade_no(outTradeNo);
}
log.info("退款参数 {}", JSONUtil.toJsonStr(refundModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.REFUND.toString(),
wxPayV3Bean.getMchId(),
getSerialNumber(),
null,
wxPayV3Bean.getKeyPath(),
JSONUtil.toJsonStr(refundModel)
);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
log.info("退款响应 {}", response);
if (verifySignature) {
return response.getBody();
}
} catch (Exception e) {
log.error("系统异常", e);
return e.getMessage();
}
return null;
}
@RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
@ResponseBody
public void payNotify(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> map = new HashMap<>(12);
try {
String timestamp = request.getHeader("Wechatpay-Timestamp");
String nonce = request.getHeader("Wechatpay-Nonce");
String serialNo = request.getHeader("Wechatpay-Serial");
String signature = request.getHeader("Wechatpay-Signature");
log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
String result = HttpKit.readData(request);
log.info("支付通知密文 {}", result);
// 需要通过证书序列号查找对应的证书verifyNotify 中有验证证书的序列号
String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
log.info("支付通知明文 {}", plainText);
if (StrUtil.isNotEmpty(plainText)) {
response.setStatus(200);
map.put("code", "SUCCESS");
map.put("message", "SUCCESS");
} else {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "签名错误");
}
response.setHeader("Content-type", ContentType.JSON.toString());
response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
} catch (Exception e) {
log.error("系统异常", e);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,150 @@
package org.wfc.payment.utils;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
import java.util.UUID;
/**
* 字符串工具类继承lang3字符串工具类
*
* @author L.com
*/
public final class StringUtils extends org.apache.commons.lang3.StringUtils {
public static String encode(String str) {
String encode = null;
try {
encode = URLEncoder.encode(str, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encode;
}
/**
* 获取UUID去掉`-`的
*
* @return {String}
*/
public static String generateStr() {
return UUID.randomUUID().toString().replace("-", "");
}
/**
* 要求外部订单号必须唯一。
*
* @return {String}
*/
public static String getOutTradeNo() {
SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
Date date = new Date();
String key = format.format(date);
key = key + System.currentTimeMillis();
key = key.substring(0, 15);
return key;
}
/**
* 字符串格式化
* <p>
* use: format("my name is {0}, and i like {1}!", "L.cm", "java")
* <p>
* int long use {0,number,#}
*
* @param s
* @param args
* @return {String}转换后的字符串
*/
public static String format(String s, Object... args) {
return MessageFormat.format(s, args);
}
/**
* 替换某个字符
*
* @param str
* @param regex
* @param args
* @return {String}
*/
public static String replace(String str, String regex, String... args) {
int length = args.length;
for (int i = 0; i < length; i++) {
str = str.replaceFirst(regex, args[i]);
}
return str;
}
/**
* 清理字符串,清理出某些不可见字符
*
* @param txt
* @return {String}
*/
public static String cleanChars(String txt) {
return txt.replaceAll("[   `·•<C2B7>\\f\\t\\v]", "");
}
/**
* 随机字符串
*/
private static final String INT_TEMP = "0123456789";
private static final String STR_TEMP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final String ALL_TEMP = INT_TEMP + STR_TEMP;
private static final Random RANDOM = new Random();
/**
* 生成的随机数类型
*/
public enum RandomType {
/**
* 整数
*/
INT,
/**
* 字符串
*/
STRING,
/**
* 所有类型
*/
ALL
}
/**
* 随机数生成
*
* @param count
* @return {String}
*/
public static String random(int count, RandomType randomType) {
if (count == 0) {
return "";
}
if (count < 0) {
throw new IllegalArgumentException("Requested random string length " + count + " is less than 0.");
}
char[] buffer = new char[count];
for (int i = 0; i < count; i++) {
if (randomType.equals(RandomType.INT)) {
buffer[i] = INT_TEMP.charAt(RANDOM.nextInt(INT_TEMP.length()));
} else if (randomType.equals(RandomType.STRING)) {
buffer[i] = STR_TEMP.charAt(RANDOM.nextInt(STR_TEMP.length()));
} else {
buffer[i] = ALL_TEMP.charAt(RANDOM.nextInt(ALL_TEMP.length()));
}
}
return new String(buffer);
}
public static void main(String[] args) {
System.out.println(random(32, RandomType.ALL));
}
}

View File

@@ -1,39 +0,0 @@
package org.wfc.payment.wxpay.config;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnClass(WxPayService.class)
@EnableConfigurationProperties(WxPayProperties.class)
@AllArgsConstructor
public class WWxPayConfig {
private WxPayProperties properties;
@Bean
@ConditionalOnMissingBean
public WxPayService wxService() {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));
payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(this.properties.getUseSandboxEnv());
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}

View File

@@ -1,48 +0,0 @@
package org.wfc.payment.wxpay.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* wxpay pay properties.
*
*/
@Data
@ConfigurationProperties(prefix = "wxpay")
public class WxPayProperties {
/**
* 设置微信公众号或者小程序等的appid
*/
private String appId;
/**
* 微信支付商户号
*/
private String mchId;
/**
* 微信支付商户密钥
*/
private String mchKey;
/**
* 服务商模式下的子商户公众账号ID普通模式请不要配置请在配置文件中将对应项删除
*/
private String subAppId;
/**
* 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除
*/
private String subMchId;
/**
* apiclient_cert.p12文件的绝对路径或者如果放在项目中请以classpath:开头指定
*/
private String keyPath;
/**
* 可以指定是否使用沙箱环境
*/
private Boolean useSandboxEnv;
}

View File

@@ -1,431 +0,0 @@
package org.wfc.payment.wxpay.controller;
import com.alipay.api.AlipayApiException;
import com.github.binarywang.wxpay.bean.coupon.*;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.wfc.payment.wxpay.service.IWxPayNotifyOrderService;
import org.wfc.payment.wxpay.service.IWxPayNotifyRefundService;
import org.wfc.payment.wxpay.service.IWxPayNotifyScanpayService;
import java.io.File;
import java.util.Date;
import java.util.Map;
@Tag(name = "WeChat Pay")
@RestController
@RequestMapping("/wxpay")
@AllArgsConstructor
public class WxPayController {
private final WxPayService wxService;
// @Autowired
// public WxPayController(WxPayService wxService) {
// this.wxService = 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);
}
@Operation(summary = "Query order")
@PostMapping("/queryOrder")
public WxPayOrderQueryResult queryOrder(@RequestBody WxPayOrderQueryRequest wxPayOrderQueryRequest)
throws WxPayException {
return this.wxService.queryOrder(wxPayOrderQueryRequest);
}
/**
* <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);
}
@Operation(summary = "Close order")
@PostMapping("/closeOrder")
public WxPayOrderCloseResult closeOrder(@RequestBody WxPayOrderCloseRequest wxPayOrderCloseRequest)
throws WxPayException {
return this.wxService.closeOrder(wxPayOrderCloseRequest);
}
/**
* 调用统一下单接口,并组装生成支付所需参数对象.
*
* @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);
}
/**
* 统一下单(详见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);
}
/**
* <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);
}
/**
* <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("/refundQuery")
public WxPayRefundQueryResult refundQuery(@RequestBody WxPayRefundQueryRequest wxPayRefundQueryRequest)
throws WxPayException {
return this.wxService.refundQuery(wxPayRefundQueryRequest);
}
private final IWxPayNotifyOrderService wxPayNotifyOrderService;
private static final String MSG_SUCCESS = "success";
private static final String MSG_FAILURE = "failure";
@Operation(summary = "支付回调通知处理")
@PostMapping("/notify/order")
public String parseOrderNotifyResult(@RequestBody String xmlData) throws WxPayException {
final WxPayOrderNotifyResult notifyResult = this.wxService.parseOrderNotifyResult(xmlData);
// 根据自己业务场景需要构造返回对象
try {
Map<String, String> notifyResultMap = notifyResult.toMap();
boolean result = wxPayNotifyOrderService.handleWxPayNotifyOrder(notifyResultMap);
return result ? MSG_SUCCESS : MSG_FAILURE;
} catch (Exception e) {
e.printStackTrace();
return MSG_FAILURE;
}
}
private final IWxPayNotifyRefundService wxPayNotifyRefundService;
@Operation(summary = "退款回调通知处理")
@PostMapping("/notify/refund")
public String parseRefundNotifyResult(@RequestBody String xmlData) throws WxPayException {
final WxPayRefundNotifyResult notifyResult = this.wxService.parseRefundNotifyResult(xmlData);
// 根据自己业务场景需要构造返回对象
try {
Map<String, String> notifyResultMap = notifyResult.toMap();
boolean result = wxPayNotifyRefundService.handleWxPayNotifyRefund(notifyResultMap);
return result ? MSG_SUCCESS : MSG_FAILURE;
} catch (Exception e) {
e.printStackTrace();
return MSG_FAILURE;
}
}
private final IWxPayNotifyScanpayService wxPayNotifyScanpayService;
@Operation(summary = "扫码支付回调通知处理")
@PostMapping("/notify/scanpay")
public String parseScanPayNotifyResult(String xmlData) throws WxPayException {
final WxScanPayNotifyResult notifyResult = this.wxService.parseScanPayNotifyResult(xmlData);
// 根据自己业务场景需要构造返回对象
try {
Map<String, String> notifyResultMap = notifyResult.toMap();
boolean result = wxPayNotifyScanpayService.handleWxPayNotifyScanpay(notifyResultMap);
return result ? MSG_SUCCESS : MSG_FAILURE;
} catch (Exception e) {
e.printStackTrace();
return MSG_FAILURE;
}
}
/**
* 发送微信红包给个人用户
*
* <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>
* 查询红包记录
* 用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。
* 请求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?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>
* 扫码支付模式一生成二维码的方法
* 二维码中的内容为链接,形式为:
* 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>
* 扫码支付模式二生成二维码的方法
* 对应链接格式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>
* 交易保障
* 应用场景:
* 商户在调用微信支付提供的相关接口时,会得到微信支付返回的相关信息以及获得整个接口的响应时间。
* 为提高整体的服务水平,协助商户一起提高服务质量,微信支付提供了相关接口调用耗时和返回信息的主动上报接口,
* 微信支付可以根据商户侧上报的数据进一步优化网络部署,完善服务监控,和商户更好的协作为用户提供更好的业务体验。
* 接口地址: 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>
* 下载对账单
* 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
* 注意:
* 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);
}
@Operation(summary = "下载对账单")
@PostMapping("/downloadBill")
public WxPayBillResult downloadBill(WxPayDownloadBillRequest wxPayDownloadBillRequest) throws WxPayException {
return this.wxService.downloadBill(wxPayDownloadBillRequest);
}
/**
* <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>
* 撤销订单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 = "获取沙箱环境签名key")
@GetMapping("/getSandboxSignKey")
public String getSandboxSignKey() throws WxPayException {
return this.wxService.getSandboxSignKey();
}
@Operation(summary = "发放代金券")
@PostMapping("/sendCoupon")
public WxPayCouponSendResult sendCoupon(@RequestBody WxPayCouponSendRequest request) throws WxPayException {
return this.wxService.sendCoupon(request);
}
@Operation(summary = "查询代金券批次")
@PostMapping("/queryCouponStock")
public WxPayCouponStockQueryResult queryCouponStock(@RequestBody WxPayCouponStockQueryRequest request)
throws WxPayException {
return this.wxService.queryCouponStock(request);
}
@Operation(summary = "查询代金券信息")
@PostMapping("/queryCouponInfo")
public WxPayCouponInfoQueryResult queryCouponInfo(@RequestBody WxPayCouponInfoQueryRequest request)
throws WxPayException {
return this.wxService.queryCouponInfo(request);
}
@Operation(summary = "拉取订单评价数据")
@PostMapping("/queryComment")
public String queryComment(Date beginDate, Date endDate, Integer offset, Integer limit) throws WxPayException {
return this.wxService.queryComment(beginDate, endDate, offset, limit);
}
}

View File

@@ -1,21 +0,0 @@
package org.wfc.payment.wxpay.error;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/error")
public class ErrorController {
@GetMapping(value = "/404")
public String error404() {
return "error";
}
@GetMapping(value = "/500")
public String error500() {
return "error";
}
}

View File

@@ -1,19 +0,0 @@
package org.wfc.payment.wxpay.error;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
@Component
public class ErrorPageConfiguration implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
errorPageRegistry.addErrorPages(
new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500")
);
}
}

View File

@@ -1,17 +0,0 @@
package org.wfc.payment.wxpay.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.wfc.payment.wxpay.model.UWxPayOrderModel;
@Mapper
public interface UWxPayOrderMapper {
void insertOrder(UWxPayOrderModel uWxPayOrder);
void updateOrder(UWxPayOrderModel uWxPayOrder);
UWxPayOrderModel selectOrderByOutTradeNo(@Param("outTradeNo") String outTradeNo);
UWxPayOrderModel selectOrderById(@Param("id") Long id);
}

View File

@@ -1,26 +0,0 @@
package org.wfc.payment.wxpay.model;
import javax.persistence.*;
import java.util.Date;
import lombok.Data;
@Data
@Entity
public class UWxPayOrderModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private String outTradeNo;
private String trancationId;
private String tradeStatus;
private Long totalAmount;
private String subject;
private String body;
private String createBy;
private Date createTime;
private String updateBy;
private Date updateTime;
// Getters and Setters
}

View File

@@ -1,7 +0,0 @@
package org.wfc.payment.wxpay.service;
import java.util.Map;
public interface IWxPayNotifyOrderService {
boolean handleWxPayNotifyOrder(Map<String, String> params);
}

View File

@@ -1,7 +0,0 @@
package org.wfc.payment.wxpay.service;
import java.util.Map;
public interface IWxPayNotifyRefundService {
boolean handleWxPayNotifyRefund(Map<String, String> params);
}

View File

@@ -1,7 +0,0 @@
package org.wfc.payment.wxpay.service;
import java.util.Map;
public interface IWxPayNotifyScanpayService {
boolean handleWxPayNotifyScanpay(Map<String, String> params);
}

View File

@@ -1,49 +0,0 @@
package org.wfc.payment.wxpay.service.impl;
import java.util.Map;
import org.springframework.stereotype.Service;
import org.wfc.payment.wxpay.mapper.UWxPayOrderMapper;
import org.wfc.payment.wxpay.model.UWxPayOrderModel;
import lombok.AllArgsConstructor;
import java.util.Date;
import org.wfc.payment.wxpay.utils.VerifySignUtils;
import org.wfc.payment.wxpay.service.IWxPayNotifyOrderService;
@AllArgsConstructor
@Service
public class WxPayNotifyOrderServiceImpl implements IWxPayNotifyOrderService {
private final UWxPayOrderMapper wxpayOrderMapper;
private final VerifySignUtils verifySignUtils;
public boolean handleWxPayNotifyOrder(Map<String, String> params) {
// 验证签名
boolean signVerified = verifySignUtils.verifySignature(params);
if (signVerified) {
// 处理业务逻辑,例如更新订单状态
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_state");
Long totalAmount = new Long(params.get("total_fee")); // 微信支付金额单位为分
String subject = params.get("subject");
String body = params.get("body");
UWxPayOrderModel order = wxpayOrderMapper.selectOrderByOutTradeNo(outTradeNo);
if (order == null) {
order = new UWxPayOrderModel();
order.setOutTradeNo(outTradeNo);
order.setCreateTime(new Date());
wxpayOrderMapper.insertOrder(order);
}
order.setTradeStatus(tradeStatus);
order.setTotalAmount(totalAmount);
order.setSubject(subject);
order.setBody(body);
order.setUpdateTime(new Date());
wxpayOrderMapper.updateOrder(order);
return "SUCCESS".equals(tradeStatus);
}
return false;
}
}

View File

@@ -1,49 +0,0 @@
package org.wfc.payment.wxpay.service.impl;
import java.util.Map;
import org.springframework.stereotype.Service;
import org.wfc.payment.wxpay.mapper.UWxPayOrderMapper;
import org.wfc.payment.wxpay.model.UWxPayOrderModel;
import lombok.AllArgsConstructor;
import java.util.Date;
import org.wfc.payment.wxpay.utils.VerifySignUtils;
import org.wfc.payment.wxpay.service.IWxPayNotifyRefundService;
@AllArgsConstructor
@Service
public class WxPayNotifyRefundServiceImpl implements IWxPayNotifyRefundService {
private final UWxPayOrderMapper wxpayOrderMapper;
private final VerifySignUtils verifySignUtils;
public boolean handleWxPayNotifyRefund(Map<String, String> params) {
// 验证签名
boolean signVerified = verifySignUtils.verifySignature(params);
if (signVerified) {
// 处理业务逻辑,例如更新订单状态
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
Long totalAmount = new Long(params.get("total_fee")); // 微信支付金额单位为分
String subject = params.get("subject");
String body = params.get("body");
UWxPayOrderModel order = wxpayOrderMapper.selectOrderByOutTradeNo(outTradeNo);
if (order == null) {
order = new UWxPayOrderModel();
order.setOutTradeNo(outTradeNo);
order.setCreateTime(new Date());
wxpayOrderMapper.insertOrder(order);
}
order.setTradeStatus(tradeStatus);
order.setTotalAmount(totalAmount);
order.setSubject(subject);
order.setBody(body);
order.setUpdateTime(new Date());
wxpayOrderMapper.updateOrder(order);
return "SUCCESS".equals(tradeStatus);
}
return false;
}
}

View File

@@ -1,50 +0,0 @@
package org.wfc.payment.wxpay.service.impl;
import java.util.Map;
import org.springframework.stereotype.Service;
import org.wfc.payment.wxpay.mapper.UWxPayOrderMapper;
import org.wfc.payment.wxpay.model.UWxPayOrderModel;
import org.wfc.payment.wxpay.service.IWxPayNotifyScanpayService;
import lombok.AllArgsConstructor;
import java.util.Date;
import org.wfc.payment.wxpay.utils.VerifySignUtils;
@AllArgsConstructor
@Service
public class WxPayNotifyScanpayServiceImpl implements IWxPayNotifyScanpayService {
private final UWxPayOrderMapper wxpayOrderMapper;
private final VerifySignUtils verifySignUtils;
public boolean handleWxPayNotifyScanpay(Map<String, String> params) {
// 验证签名
boolean signVerified = verifySignUtils.verifySignature(params);
if (signVerified) {
// 处理业务逻辑,例如更新订单状态
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
Long totalAmount = new Long(params.get("total_fee")); // 微信支付金额单位为分
String subject = params.get("subject");
String body = params.get("body");
UWxPayOrderModel order = wxpayOrderMapper.selectOrderByOutTradeNo(outTradeNo);
if (order == null) {
order = new UWxPayOrderModel();
order.setOutTradeNo(outTradeNo);
order.setCreateTime(new Date());
wxpayOrderMapper.insertOrder(order);
}
order.setTradeStatus(tradeStatus);
order.setTotalAmount(totalAmount);
order.setSubject(subject);
order.setBody(body);
order.setUpdateTime(new Date());
wxpayOrderMapper.updateOrder(order);
return "SUCCESS".equals(tradeStatus);
}
return false;
}
}

View File

@@ -1,102 +0,0 @@
package org.wfc.payment.wxpay.utils;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.Collections;
import java.util.List;
import java.security.PublicKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.wfc.payment.wxpay.config.WxPayProperties;
@Component
public class VerifySignUtils {
private final WxPayProperties wxpayProperties;
@Autowired
public VerifySignUtils(WxPayProperties wxpayProperties) {
this.wxpayProperties = wxpayProperties;
}
public static String sign(String data, PrivateKey privateKey) throws SignatureException {
if (data == null || privateKey == null) {
throw new IllegalArgumentException("Data and private key cannot be null");
}
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data.getBytes(StandardCharsets.UTF_8));
byte[] signBytes = signature.sign();
return Base64.getEncoder().encodeToString(signBytes);
} catch (Exception e) {
throw new SignatureException("Failed to sign data", e);
}
}
public static boolean verify(String data, String sign, PublicKey publicKey) throws SignatureException {
if (data == null || sign == null || publicKey == null) {
throw new IllegalArgumentException("Data, sign and public key cannot be null");
}
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(data.getBytes(StandardCharsets.UTF_8));
byte[] signBytes = Base64.getDecoder().decode(sign);
return signature.verify(signBytes);
} catch (Exception e) {
throw new SignatureException("Failed to verify signature", e);
}
}
public boolean verifySignature(Map<String, String> params) {
if (params == null || params.isEmpty()) {
return false;
}
// Extract signature parameter
String sign = params.remove("sign");
if (sign == null) {
return false;
}
// Sort parameters
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
// Build parameter string
StringBuilder data = new StringBuilder();
for (String key : keys) {
String value = params.get(key);
if (value != null) {
data.append(key)
.append("=")
.append(value)
.append("&");
}
}
// Remove last '&'
if (data.length() > 0) {
data.setLength(data.length() - 1);
}
try {
byte[] keyBytes = Base64.getDecoder().decode(wxpayProperties.getMchKey());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return verify(data.toString(), sign, publicKey);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}

View File

@@ -1,6 +1,5 @@
# spring配置 # spring配置
spring: spring:
redis: redis:
host: wfc-redis host: wfc-redis
port: 6379 port: 6379
@@ -55,76 +54,13 @@ mybatis-plus:
logic-delete-value: 1 logic-delete-value: 1
logic-not-delete-value: 0 logic-not-delete-value: 0
wxpay:
appId: 121412414112
mchId: 1131412414
mchKey: 1525342aa
subAppId: #服务商模式下的子商户公众账号ID
subMchId: #服务商模式下的子商户号
keyPath: /opt/wfc/conf/wxpay/wxpay_key.pem
useSandboxEnv: false
alipay: alipay:
appId: 121412414112 appId: 9021000122699258
privateKey: 1131412414 privateKey: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7YAcIXV5GJlTWBOoBcrVG1zKxHunznSjYXwTS2DM3YgloxzKye4apfcmBDVnoL93m4QrJTtbiHYvu4yJjJfJsQEY+Wo44IczhDypyu+Il6JpQOwylTs94/+3aaQ1wThsDaGs8edaFGteuw+1pUVl4nxF00fS1VoIR30riqAGFAXrPhcSA6Y9c8HK1htxCelICnPzjpqC4s8ZjrjS7FoyHP2ZAay5fx1VEtah30E4RvycFfV/i2+k3JGFOSeevdCx6Ufu+9Y/RaG4Sh84QuYRQUhAHUswlFDHpRrAnxHzt0zDkOkg3BrCT7vMtBbSOP9BdIhpVTaZm4diQdNbLSl4hAgMBAAECggEAKb1Xc7aQ1KGfTlmj4xSxawlvImOXjAwbWC+6fFlq91BgdjXBhl7b/Y+mvpfBymY3UUIaTAPC/HXGgT2ZoGqImTKsMyGrArgM0qm1M//EfdtV3L96rqxirTqduoSiWL0daWHuWXduoRH8r9K3ZTmY67TLh7FpiKevq9mI7fqs8/qgq5QAN4UPFb3Cq9hDNTU4l6+Bywdg1KkwJ2Jc98SlrIdVl+1eCMAgueLR0aNHTobyPBZ/KfwGRV0OQ3QqjLVgL3zlbzuylYhaZqPgxxd46vgWwkyMiiv7u2OyCetq4LFd+tcNDz0Yqk6rK9/S0oxbN8NM5DLkpwFh/433BoPS3QKBgQD/dsxNr2PYdPLp6pOvw7H2AFMH8CkwTlRg+2f/0fgQF14rJwZgEU6fL5A2JvQeRRC5mCff2m5tDqrS321JNyH/JIKJ+4J8I34GEo/kSCHL3RmyvJGQOQ/EpEyxvP8BV3ob6UO3LR58DOGlJr8eTsr3Y8o9cAMuknCNxvsd2LvybwKBgQC7xKkx4KIPBny6sCOtChOkgIrY3hOCi+ZsHQVESXKzeku0NkH/qrAG+S9pb1XCzXdM2HrzkMeuz6tqi+2TY8nORyY2DZHNW7FqzkAiZ/NO2AgGIlALq1ZfJZke2MxgtBnxSsQ03gfXP9opu/FsLH9a+s6edfHPvKD4kHxlLBfAbwKBgQDYvr6QmuKn4HHJLZGoau0uvw+ziHwp1AubTTLrxgYmAO2Qx0eNcqG2RfChQWOV2xtZnFMYhodyWCNvTsm2eOSLSTrIP3ByStq95DnZganLAgivsXX/W6qZOJ0poCTryoB79enSHKHktjksmjdFS6zBQRVyEvtgJDcC03Rz2lN8WQKBgQCCoJE4otb7bv7s/ccEBeOeaNKvhue5xUwbYKEeXZ6PYAA0sh5+GCf34flq90qJiFl7u4rl0Y4pfk35hLlV9XEasYLSzePmIuktrakOhpTNABus8MgRJjSjYsvAmwCsMf9uTx5qzSBVThWfPSH6qIY9LAj8Un9UjxzJb/Mqi19GvwKBgQC0/KB+3robTqy9KOV4iEKJ4kmnXDRu7ecpMyc8k5HzpolIHcXLZHkBK9pMCXBQ9Kwy6BjRGNnUZOahS+tvnMcjHpwdhu90r7D51GXW/+PeFtphYTscFhHv1yuWbbojzhKf69pZnsVmyllIBqRgtbkS2WNHxWo/peCg47TcLaQNMA==
publicKey: 1525342aa publicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhBZoE6p1TKpd/WsAJRTA2D6yUTzqLmZ73scxbPxxKwPIg2ys2Ap21u/lVmqBWO9Wf2Z7wUwr/6BP1PQqVpg0GAqU3yjjZ0LGfBitzMBMbGrlOLqJQ3PKgnUNmnOdLR4FlHCAjKtuyxjHkxBTHg/L4punk4lkFJQD8YvzFrYalS6WYw5j1/oq080NbcjPirPCRlsU7MRraQuUqSTdPwm2iHkroKwCEbGv+RtNJCfOkKNQVtRFFgPGMhU4nQ620gdfzsGJsNFKVJnD5SjeDWniBAbaGaVF4rEfKJPe6+XrcMg3h+9Fz+A2IU1KCCoth2neEZEaU1t0KBGxXIuo4efi/QIDAQAB
notifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/alipay/notify appCertPath: \u5E94\u7528\u516C\u94A5\u8BC1\u4E66
returnUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/alipay/return aliPayCertPath: \u652F\u4ED8\u5B9D\u516C\u94A5\u8BC1\u4E66
signType: RSA2 aliPayRootCertPath: \u652F\u4ED8\u5B9D\u6839\u8BC1\u4E66
charset: utf-8 serverUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
gatewayUrl: https://openapi.alipaydev.com/gateway.do domain: http://localhost:8085
logPath: /opt/wfc/logs/alipay/alipay.log testDomain: http://129.204.171.210:8085
maxQueryRetry: 5
queryDuration: 5
maxCancelRetry: 3
cancelDuration: 2
heartbeatDelay: 5
heartbeatDuration: 5
storeId:
storeName:
supportEmail:
supportPhone:
ccpay:
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
unionpay:
merId: 700000000000001
keyPrivateCert: /opt/wfc/conf/cert/unionpay/wfc-union.pfx
keyPrivateCertPwd: 123456
signCertType: PKCS12
encryptCertPath: /opt/wfc/conf/cert/unionpay/wfc-union.cer
acpMiddleCert: /opt/wfc/conf/cert/unionpay/wfc-middle.cer
acpRootCert: /opt/wfc/conf/cert/unionpay/wfc-root.cer
frontUrl: https://gateway.test.95516.com/gateway/api/frontTransReq.do
backUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/notify
signMethod: 01
version: 5.1.0
channelType: 07
accessType: 0
currencyCode: 156
bizType: 000201
txnType: 01
txnSubType: 01
payTimeout: 30
queryTimeout: 30
refundTimeout: 30
frontFailUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/fail
frontSuccessUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/success
frontBackUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/front
backBackUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/back
frontNotifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/front/notify
backNotifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/back/notify
refundNotifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/refund/notify
queryNotifyUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/query/notify
refundSuccessUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/refund/success
refundFailUrl: http://wfc-gateway:${GATEWAY_SERVER_PORT:8080}/unionpay/refund/fail
querySuccessUrl:

View File

@@ -1,33 +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.alipay.mapper.UAlipayOrderMapper">
<resultMap id="UAlipayOrderResultMap" type="org.wfc.payment.alipay.model.UAlipayOrderModel">
<id property="id" column="id"/>
<result property="userId" column="user_id"/>
<result property="outTradeNo" column="out_trade_no"/>
<result property="tradeStatus" column="trade_status"/>
<result property="totalAmount" column="total_amount"/>
<result property="subject" column="subject"/>
<result property="body" column="body"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<select id="selectOrderByOutTradeNo" resultMap="UAlipayOrderResultMap">
SELECT * FROM u_alipay_order WHERE out_trade_no = #{outTradeNo}
</select>
<insert id="insertOrder">
INSERT INTO u_alipay_order (out_trade_no, trade_status, total_amount, subject, body, create_time, update_time)
VALUES (#{outTradeNo}, #{tradeStatus}, #{totalAmount}, #{subject}, #{body}, #{createTime}, #{updateTime})
</insert>
<update id="updateOrder">
UPDATE u_alipay_order
SET trade_status = #{tradeStatus}, total_amount = #{totalAmount}, subject = #{subject}, body = #{body}, update_time = #{updateTime}
WHERE out_trade_no = #{outTradeNo}
</update>
<select id="selectOrderById" parameterType="long" resultType="org.wfc.payment.alipay.model.UAlipayOrderModel" resultMap="UAlipayOrderResultMap">
SELECT * FROM u_alipay_order WHERE id = #{id}
</select>
</mapper>

View File

@@ -1,15 +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.ccpay.mapper.UCreditCardOrderMapper">
<insert id="insertOrder" parameterType="org.wfc.payment.ccpay.model.UCreditCardOrder">
INSERT INTO u_credit_card_order (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="selectOrderById" parameterType="long" resultType="org.wfc.payment.ccpay.model.UCreditCardOrder">
SELECT * FROM u_credit_card_order WHERE id = #{id}
</select>
<!-- 其他需要的 SQL 映射 -->
</mapper>

View File

@@ -1,14 +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.ccpay.mapper.UCreditCardTokenMapper">
<insert id="insertToken" parameterType="org.wfc.payment.ccpay.model.UCreditCardToken">
INSERT INTO u_credit_card_token (user_id, token, card_last_four, card_type, created_at)
VALUES (#{userId}, #{token}, #{cardLastFour}, #{cardType}, #{createdAt})
</insert>
<select id="selectTokenByUserId" parameterType="long" resultType="org.wfc.payment.ccpay.model.UCreditCardToken">
SELECT * FROM u_credit_card_token WHERE user_id = #{userId}
</select>
</mapper>

View File

@@ -1,34 +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.wxpay.mapper.UWxPayOrderMapper">
<resultMap id="UWxPayOrderResultMap" type="org.wfc.payment.wxpay.model.UWxPayOrderModel">
<id property="id" column="id"/>
<result property="userId" column="user_id"/>
<result property="outTradeNo" column="out_trade_no"/>
<result property="trancationId" column="trancation_id"/>
<result property="tradeStatus" column="trade_status"/>
<result property="totalAmount" column="total_amount"/>
<result property="subject" column="subject"/>
<result property="body" column="body"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<select id="selectOrderByOutTradeNo" resultMap="UWxPayOrderResultMap">
SELECT * FROM u_wxpay_order WHERE out_trade_no = #{outTradeNo}
</select>
<insert id="insertOrder">out_trade_no,
INSERT INTO u_wxpay_order (out_trade_no, trancation_id, trade_status, total_amount, subject, body, create_time, update_time)
VALUES (#{outTradeNo}, #{trancationId}, #{tradeStatus}, #{totalAmount}, #{subject}, #{body}, #{createTime}, #{updateTime})
</insert>
<update id="updateOrder">
UPDATE u_wxpay_order
SET trade_status = #{tradeStatus}, total_amount = #{totalAmount}, subject = #{subject}, body = #{body}, update_time = #{updateTime}
WHERE out_trade_no = #{outTradeNo}
</update>
<select id="selectOrderById" parameterType="long" resultType="org.wfc.payment.wxpay.model.UWxPayOrderModel" resultMap="UWxPayOrderResultMap">
SELECT * FROM u_wxpay_order WHERE id = #{id}
</select>
</mapper>

View File

@@ -13,9 +13,11 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.wfc.common.core.domain.LoginUser; import org.wfc.common.core.domain.LoginUser;
import org.wfc.common.core.domain.R;
import org.wfc.common.core.web.controller.BaseController; import org.wfc.common.core.web.controller.BaseController;
import org.wfc.common.core.web.domain.AjaxResult; import org.wfc.common.core.web.domain.AjaxResult;
import org.wfc.common.core.web.page.TableDataInfo; import org.wfc.common.core.web.page.TableDataInfo;
import org.wfc.common.security.annotation.InnerAuth;
import org.wfc.common.security.utils.SecurityUtils; import org.wfc.common.security.utils.SecurityUtils;
import org.wfc.user.domain.UOrder; import org.wfc.user.domain.UOrder;
import org.wfc.user.domain.UPackage; import org.wfc.user.domain.UPackage;
@@ -96,8 +98,8 @@ public class UOrderController extends BaseController {
} }
@PostMapping @PostMapping
public AjaxResult add(@RequestBody UOrder uOrder) { public R<Long> add(@RequestBody UOrder uOrder) {
return toAjax(uOrderService.saveOrder(uOrder)); return R.ok(uOrderService.saveOrder(uOrder));
} }
@PutMapping @PutMapping
@@ -110,4 +112,9 @@ public class UOrderController extends BaseController {
return toAjax(uOrderService.removeByIds(CollUtil.newArrayList(ids))); return toAjax(uOrderService.removeByIds(CollUtil.newArrayList(ids)));
} }
@InnerAuth
@PostMapping("paySuccess/{id}")
public AjaxResult paySuccess(@PathVariable("id") Long id) {
return toAjax(uOrderService.paySuccess(id));
}
} }

View File

@@ -13,6 +13,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/ */
public interface IUOrderService extends IService<UOrder> { public interface IUOrderService extends IService<UOrder> {
boolean saveOrder(UOrder order); Long saveOrder(UOrder order);
boolean paySuccess(Long orderId);
} }

View File

@@ -15,6 +15,7 @@ import org.wfc.user.api.IWifiApi;
import org.wfc.user.api.omada.domain.convert.OmadaConvert; import org.wfc.user.api.omada.domain.convert.OmadaConvert;
import org.wfc.user.api.omada.domain.dto.ClientRateLimitSettingDto; import org.wfc.user.api.omada.domain.dto.ClientRateLimitSettingDto;
import org.wfc.user.domain.UAccount; import org.wfc.user.domain.UAccount;
import org.wfc.user.domain.UBillRule;
import org.wfc.user.domain.UClient; import org.wfc.user.domain.UClient;
import org.wfc.user.domain.UOrder; import org.wfc.user.domain.UOrder;
import org.wfc.user.domain.UPackage; import org.wfc.user.domain.UPackage;
@@ -22,6 +23,7 @@ import org.wfc.user.domain.URateLimit;
import org.wfc.user.domain.constant.OrderStatusEnum; import org.wfc.user.domain.constant.OrderStatusEnum;
import org.wfc.user.domain.constant.OrderTypeEnum; import org.wfc.user.domain.constant.OrderTypeEnum;
import org.wfc.user.domain.constant.PeriodTypeEnum; import org.wfc.user.domain.constant.PeriodTypeEnum;
import org.wfc.user.mapper.UBillRuleMapper;
import org.wfc.user.mapper.UOrderMapper; import org.wfc.user.mapper.UOrderMapper;
import org.wfc.user.service.IUAccountService; import org.wfc.user.service.IUAccountService;
import org.wfc.user.service.IUClientService; import org.wfc.user.service.IUClientService;
@@ -58,14 +60,21 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
@Autowired @Autowired
private IUClientService clientService; private IUClientService clientService;
@Autowired
private UBillRuleMapper billRuleMapper;
@Autowired @Autowired
private IWifiApi wifiApi; private IWifiApi wifiApi;
public void paySuccess(Long orderId) { @Override
public boolean paySuccess(Long orderId) {
// 支付成功回调(预留) // 支付成功回调(预留)
// 更新当前订单状态为已支付 // 更新当前订单状态为已支付
UOrder order = this.getById(orderId); UOrder order = this.getById(orderId);
if (OrderStatusEnum.PAID.getCode().equals(order.getStatus())) {
return false;
}
order.setStatus(OrderStatusEnum.PAID.getCode()); order.setStatus(OrderStatusEnum.PAID.getCode());
this.updateById(order); this.updateById(order);
@@ -109,7 +118,7 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
wifiApi.updateClientRateLimitSetting(client.getSiteId(), client.getClientMac(), clientRateLimitSetting); wifiApi.updateClientRateLimitSetting(client.getSiteId(), client.getClientMac(), clientRateLimitSetting);
} }
} }
return true;
} }
private void callbackPackage(UOrder order, UAccount account) { private void callbackPackage(UOrder order, UAccount account) {
@@ -156,14 +165,20 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
} }
@Override @Override
public boolean saveOrder(UOrder order) { public Long saveOrder(UOrder order) {
order.setUserId(SecurityUtils.getUserId()); order.setUserId(SecurityUtils.getUserId());
order.setStatus(OrderStatusEnum.UNPAID.getCode()); order.setStatus(OrderStatusEnum.UNPAID.getCode());
order.setOrderNo(System.currentTimeMillis() + StrUtil.EMPTY); order.setOrderNo(System.currentTimeMillis() + StrUtil.EMPTY);
this.save(order); this.save(order);
// 支付成功回调 List<UBillRule> billRules = billRuleMapper.selectList(Wrappers.lambdaQuery());
paySuccess(order.getId()); billRules.stream().findFirst().ifPresent(billRule -> {
// 测试
if (billRule.getTraffic() == 1) {
// 支付成功回调
paySuccess(order.getId());
}
});
return true; return order.getId();
} }
} }