7.13 支付宝支付沙箱申请、对接alipay
This commit is contained in:
parent
cf575464ea
commit
267e250820
1
.gitignore
vendored
1
.gitignore
vendored
@ -38,3 +38,4 @@ build/
|
||||
.DS_Store
|
||||
/data/
|
||||
/.idea/
|
||||
/pay-mall-app/src/main/resources/application-local.yml
|
||||
|
48
docs/dev-ops/mysql/sql/0713paymall.sql
Normal file
48
docs/dev-ops/mysql/sql/0713paymall.sql
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : group_buy_local
|
||||
Source Server Type : MySQL
|
||||
Source Server Version : 80042
|
||||
Source Host : localhost:13306
|
||||
Source Schema : pay-mall
|
||||
|
||||
Target Server Type : MySQL
|
||||
Target Server Version : 80042
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 13/07/2025 14:21:55
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for pay_order
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `pay_order`;
|
||||
CREATE TABLE `pay_order` (
|
||||
`id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID',
|
||||
`user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户ID',
|
||||
`product_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID',
|
||||
`product_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品名称',
|
||||
`order_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单ID',
|
||||
`order_time` datetime NOT NULL COMMENT '下单时间',
|
||||
`total_amount` decimal(8, 2) UNSIGNED NULL DEFAULT NULL COMMENT '订单金额',
|
||||
`status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单状态;create-创建完成、pay_wait-等待支付、pay_success-支付成功、deal_done-交易完成、close-订单关单',
|
||||
`pay_url` varchar(2014) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '支付信息',
|
||||
`pay_time` datetime NULL DEFAULT NULL COMMENT '支付时间',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uq_order_id`(`order_id` ASC) USING BTREE,
|
||||
INDEX `idx_user_id_product_id`(`user_id` ASC, `product_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of pay_order
|
||||
-- ----------------------------
|
||||
INSERT INTO `pay_order` VALUES (5, 'smile01', '10001', '测试商品', '51403944017404', '2025-07-12 05:49:16', 1.68, 'PAY_WAIT', '<form name=\"punchout_form\" method=\"post\" action=\"https://openapi-sandbox.dl.alipaydev.com/gateway.do?charset=utf-8&method=alipay.trade.page.pay&sign=Af8UHbR23xcDThup0mv3NVZLlkMAcQ3tjmqGNBpwYqJ1Xn1ytqt42NWBsbDxKHT3rEo3h3dmd60wJ9N0LTmjElq%2B9HGFukp7KtxOiZRlbxip9x9yl4mCjQTUunf6l7iMsUAAtBUh%2FiVJOsI7Uy4Jy8Fg7fqjRAjc06fKcsynU5wb3xtOhr9f8uQIpe7ykxLg3Uc6YyR9GYdTcceVRu15BoSur6xz4S%2FMhRTOqc8XbWrqBGhvWMk%2BV6FHbx04AHYg7HHc0%2FTndoIHFSX9c1h7Jysxbyxp3q40GMfrnpX53VkqcPpQBbLA8f%2BWO8MnzbnxobeKcXAR11gxSbl4FcEWng%3D%3D&return_url=https%3A%2F%2Fblog.bitday.top¬ify_url=https%3A%2F%2Fpay.bitday.top%2Fapi%2Fv1%2Falipay%2Falipay_notify_url&version=1.0&app_id=9021000150645052&sign_type=RSA2×tamp=2025-07-13+14%3A21%3A33&alipay_sdk=alipay-sdk-java-4.38.157.ALL&format=json\">\n<input type=\"hidden\" name=\"biz_content\" value=\"{"out_trade_no":"51403944017404","total_amount":"1.68","subject":"测试商品","product_code":"FAST_INSTANT_TRADE_PAY"}\">\n<input type=\"submit\" value=\"立即支付\" style=\"display:none\" >\n</form>\n<script>document.forms[0].submit();</script>', NULL, '2025-07-12 13:49:15', '2025-07-13 14:21:33');
|
||||
INSERT INTO `pay_order` VALUES (6, '10001', '10001', '测试商品', '66665553128265', '2025-07-13 06:19:11', 1.68, 'PAY_WAIT', '<form name=\"punchout_form\" method=\"post\" action=\"https://openapi-sandbox.dl.alipaydev.com/gateway.do?charset=utf-8&method=alipay.trade.page.pay&sign=lQ1WTro6vDXTQet%2Bd%2BJ7TWIIWXF%2B5SWg0r53joEBUesQL12UtgHrWa%2BafAwjkJWxH9zPqwAvFuXr1ZFfmMnqz1PTsRXo4ACTAJC0Se2uFSYAU1HK8Cyk4jHh9OwEjW1MQXdWT1l52KjLuZOBeJAlUvVPyAfxQnBx0HF2XKHEfFLFBgeRufAp%2BEzCM%2BoX8l0G%2FkQdskCRhICLMh2tFj2T4i4sgsSwuJQDV%2Fs0EOwpDpDKV3Z9xPEzkI2zZM6ZB8jCfTa734H8%2BC9IWZmKX2njnNj89g4h9RVuLd92l0veNn%2FJmrxTz296eCWJl6yU5PLSB0pX0IiSnUoHiySFnrswaA%3D%3D&return_url=https%3A%2F%2Fblog.bitday.top¬ify_url=https%3A%2F%2Fpay.bitday.top%2Fapi%2Fv1%2Falipay%2Falipay_notify_url&version=1.0&app_id=9021000150645052&sign_type=RSA2×tamp=2025-07-13+14%3A19%3A11&alipay_sdk=alipay-sdk-java-4.38.157.ALL&format=json\">\n<input type=\"hidden\" name=\"biz_content\" value=\"{"out_trade_no":"66665553128265","total_amount":"1.68","subject":"测试商品","product_code":"FAST_INSTANT_TRADE_PAY"}\">\n<input type=\"submit\" value=\"立即支付\" style=\"display:none\" >\n</form>\n<script>document.forms[0].submit();</script>', NULL, '2025-07-13 14:19:11', '2025-07-13 14:21:21');
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : 127.0.0.1
|
||||
Source Server Type : MySQL
|
||||
Source Server Version : 50639
|
||||
Source Host : localhost:3306
|
||||
Source Schema : road-map
|
||||
|
||||
Target Server Type : MySQL
|
||||
Target Server Version : 50639
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 15/07/2023 09:26:39
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
CREATE database if NOT EXISTS `xfg_frame_archetype` default character set utf8mb4 collate utf8mb4_0900_ai_ci;
|
||||
use `xfg_frame_archetype`;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for employee
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `employee`;
|
||||
CREATE TABLE `employee` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`employee_number` varchar(16) NOT NULL DEFAULT '' COMMENT '雇员ID',
|
||||
`employee_name` varchar(32) NOT NULL DEFAULT '' COMMENT '雇员姓名',
|
||||
`employee_level` varchar(8) NOT NULL DEFAULT '' COMMENT '雇员级别',
|
||||
`employee_title` varchar(16) NOT NULL DEFAULT '' COMMENT '雇员岗位Title',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_employee_number` (`employee_number`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of employee
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `employee` VALUES (1, '10000001', 'sXvfDpsWnJdLsCVk64tJgw==', 'T-3', '中级工程师', '2023-07-14 15:26:26', '2023-07-14 15:26:26');
|
||||
INSERT INTO `employee` VALUES (2, '10000010', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40');
|
||||
INSERT INTO `employee` VALUES (3, '10000011', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40');
|
||||
INSERT INTO `employee` VALUES (4, '10000012', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40');
|
||||
INSERT INTO `employee` VALUES (5, '10000013', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40');
|
||||
INSERT INTO `employee` VALUES (6, '10000014', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40');
|
||||
INSERT INTO `employee` VALUES (9, '10000002', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-15 07:42:52', '2023-07-15 07:42:52');
|
||||
INSERT INTO `employee` VALUES (22, '10000015', 'hMCgLG6WV3CsNBQ1UD6PEQ==', 'T2', '见习工程师', '2023-07-15 08:02:31', '2023-07-15 08:02:31');
|
||||
INSERT INTO `employee` VALUES (23, '10000016', 'hMCgLG6WV3CsNBQ1UD6PEQ==', 'T2', '见习工程师', '2023-07-15 08:02:31', '2023-07-15 08:02:31');
|
||||
INSERT INTO `employee` VALUES (24, '10000017', 'hMCgLG6WV3CsNBQ1UD6PEQ==', 'T2', '见习工程师', '2023-07-15 08:02:31', '2023-07-15 08:02:31');
|
||||
INSERT INTO `employee` VALUES (39, '10000022', 'GyG+V0r6mBCNsdusuKl03g==', 'T1', '实习工程师', '2023-07-15 09:17:49', '2023-07-15 09:17:49');
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for employee_salary
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `employee_salary`;
|
||||
CREATE TABLE `employee_salary` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`employee_number` varchar(16) NOT NULL DEFAULT '' COMMENT '雇员编号',
|
||||
`salary_total_amount` decimal(8,2) NOT NULL COMMENT '薪资总额',
|
||||
`salary_merit_amount` decimal(8,2) NOT NULL COMMENT '绩效工资',
|
||||
`salary_base_amount` decimal(8,2) NOT NULL COMMENT '基础工资',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_employee_number` (`employee_number`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of employee_salary
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `employee_salary` VALUES (1, '10000001', 5100.00, 1020.00, 4080.00, '2023-07-14 16:09:06', '2023-07-14 16:09:06');
|
||||
INSERT INTO `employee_salary` VALUES (2, '10000010', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10');
|
||||
INSERT INTO `employee_salary` VALUES (3, '10000011', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10');
|
||||
INSERT INTO `employee_salary` VALUES (4, '10000012', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10');
|
||||
INSERT INTO `employee_salary` VALUES (5, '10000013', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10');
|
||||
INSERT INTO `employee_salary` VALUES (6, '10000014', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10');
|
||||
INSERT INTO `employee_salary` VALUES (8, '10000022', 100.00, 10.00, 90.00, '2023-07-15 09:17:49', '2023-07-15 09:17:49');
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for employee_salary_adjust
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `employee_salary_adjust`;
|
||||
CREATE TABLE `employee_salary_adjust` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`employee_number` varchar(16) NOT NULL DEFAULT '' COMMENT '雇员编号',
|
||||
`adjust_order_id` varchar(32) NOT NULL DEFAULT '' COMMENT '调薪单号',
|
||||
`adjust_total_amount` decimal(8,2) NOT NULL COMMENT '总额调薪',
|
||||
`adjust_base_amount` decimal(8,2) NOT NULL COMMENT '基础调薪',
|
||||
`adjust_merit_amount` decimal(8,2) NOT NULL COMMENT '绩效调薪',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_order_id` (`adjust_order_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of employee_salary_adjust
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `employee_salary_adjust` VALUES (1, '10000001', '109089990198888811', 1000.00, 800.00, 200.00, '2023-07-14 16:55:53', '2023-07-14 16:55:53');
|
||||
INSERT INTO `employee_salary_adjust` VALUES (2, '10000001', '100908977676001', 100.00, 20.00, 80.00, '2023-07-14 21:57:39', '2023-07-14 21:57:39');
|
||||
COMMIT;
|
@ -20,6 +20,10 @@
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
10
pay-mall-api/src/main/java/edu/whut/api/IPayService.java
Normal file
10
pay-mall-api/src/main/java/edu/whut/api/IPayService.java
Normal file
@ -0,0 +1,10 @@
|
||||
package edu.whut.api;
|
||||
|
||||
import edu.whut.api.dto.CreatePayRequestDTO;
|
||||
import edu.whut.api.response.Response;
|
||||
|
||||
public interface IPayService {
|
||||
|
||||
Response<String> createPayOrder(CreatePayRequestDTO createPayRequestDTO);
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package edu.whut.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CreatePayRequestDTO {
|
||||
|
||||
// 用户ID 【实际产生中会通过登录模块获取,不需要透彻】
|
||||
private String userId;
|
||||
// 产品编号
|
||||
private String productId;
|
||||
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
/**
|
||||
* 数据传输对象 xxxRequestDTO xxxResponseDTO
|
||||
*/
|
||||
package edu.whut.api.dto;
|
23
pay-mall-app/src/main/java/edu/whut/config/AliPayConfig.java
Normal file
23
pay-mall-app/src/main/java/edu/whut/config/AliPayConfig.java
Normal file
@ -0,0 +1,23 @@
|
||||
package edu.whut.config;
|
||||
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class AliPayConfig {
|
||||
|
||||
@Bean("alipayClient")
|
||||
public AlipayClient alipayClient(AliPayConfigProperties properties) {
|
||||
return new DefaultAlipayClient(properties.getGatewayUrl(),
|
||||
properties.getApp_id(),
|
||||
properties.getMerchant_private_key(),
|
||||
properties.getFormat(),
|
||||
properties.getCharset(),
|
||||
properties.getAlipay_public_key(),
|
||||
properties.getSign_type());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package edu.whut.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "alipay", ignoreInvalidFields = true)
|
||||
public class AliPayConfigProperties {
|
||||
|
||||
// 「沙箱环境」应用ID - 您的APPID,收款账号既是你的APPID对应支付宝账号。获取地址;https://open.alipay.com/develop/sandbox/app
|
||||
private String app_id;
|
||||
// 「沙箱环境」商户私钥,你的PKCS8格式RSA2私钥
|
||||
private String merchant_private_key;
|
||||
// 「沙箱环境」支付宝公钥
|
||||
private String alipay_public_key;
|
||||
// 「沙箱环境」服务器异步通知页面路径
|
||||
private String notify_url;
|
||||
// 「沙箱环境」页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
|
||||
private String return_url;
|
||||
// 「沙箱环境」
|
||||
private String gatewayUrl;
|
||||
// 签名方式
|
||||
private String sign_type = "RSA2";
|
||||
// 字符编码格式
|
||||
private String charset = "utf-8";
|
||||
// 传输格式
|
||||
private String format = "json";
|
||||
|
||||
}
|
@ -38,11 +38,21 @@ mybatis:
|
||||
# 微信公众号对接
|
||||
weixin:
|
||||
config:
|
||||
originalid: gh_b748269e1f4c
|
||||
token: asdf
|
||||
app-id: wx7cc74be9b340b26e
|
||||
app-secret: d4e73551512c6dc7a2e8f746c26b7f2c
|
||||
template_id: ARDqdKXuGvASjsDqXzeunq0P8chMQ7tXk_4-BPULJ6U
|
||||
original-id: ${paymall.wechat.original-id}
|
||||
token: ${paymall.wechat.token}
|
||||
app-id: ${paymall.wechat.app-id}
|
||||
app-secret: ${paymall.wechat.app-secret}
|
||||
template_id: ${paymall.wechat.template-id}
|
||||
|
||||
# 支付宝支付 - 沙箱 https://opendocs.alipay.com/common/02kkv7
|
||||
alipay:
|
||||
enabled: true
|
||||
app_id: ${paymall.alipay.app-id}
|
||||
merchant_private_key: ${paymall.alipay.merchant-private-key}
|
||||
alipay_public_key: ${paymall.alipay.alipay-public-key}
|
||||
notify_url: ${paymall.alipay.notify-url}
|
||||
return_url: ${paymall.alipay.return-url}
|
||||
gateway-url: ${paymall.alipay.gateway-url}
|
||||
|
||||
# 日志
|
||||
logging:
|
||||
|
@ -1,5 +1,3 @@
|
||||
spring:
|
||||
config:
|
||||
name: pay-mall-app
|
||||
profiles:
|
||||
active: dev
|
||||
active: dev,local
|
||||
|
@ -32,4 +32,9 @@
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<update id="updateOrderPayInfo" parameterType="edu.whut.infrastructure.dao.po.PayOrder">
|
||||
update pay_order set pay_url = #{payUrl}, status = #{status}, update_time = now()
|
||||
where order_id = #{orderId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
111
pay-mall-app/src/test/java/edu/whut/test/AliPayTest.java
Normal file
111
pay-mall-app/src/test/java/edu/whut/test/AliPayTest.java
Normal file
@ -0,0 +1,111 @@
|
||||
package edu.whut.test;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
import com.alipay.api.domain.AlipayTradeQueryModel;
|
||||
import com.alipay.api.domain.AlipayTradeRefundModel;
|
||||
import com.alipay.api.request.AlipayTradePagePayRequest;
|
||||
import com.alipay.api.request.AlipayTradeQueryRequest;
|
||||
import com.alipay.api.request.AlipayTradeRefundRequest;
|
||||
import com.alipay.api.response.AlipayTradeRefundResponse;
|
||||
import edu.whut.config.AliPayConfigProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Slf4j
|
||||
@SpringBootTest
|
||||
@RunWith(SpringRunner.class)
|
||||
public class AliPayTest {
|
||||
@Autowired
|
||||
private AliPayConfigProperties config; // 字段注入
|
||||
|
||||
private AlipayClient alipayClient;
|
||||
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
log.info(config.getNotify_url());
|
||||
// ④ 用属性里的值来构造 AlipayClient
|
||||
this.alipayClient = new DefaultAlipayClient(
|
||||
config.getGatewayUrl(),
|
||||
config.getApp_id(),
|
||||
config.getMerchant_private_key(),
|
||||
config.getFormat(),
|
||||
config.getCharset(),
|
||||
config.getAlipay_public_key(),
|
||||
config.getSign_type()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_aliPay_pageExecute() throws AlipayApiException {
|
||||
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); // 发送请求的 Request类
|
||||
request.setNotifyUrl(config.getNotify_url());
|
||||
request.setReturnUrl(config.getReturn_url());
|
||||
|
||||
JSONObject bizContent = new JSONObject();
|
||||
bizContent.put("out_trade_no", "smile000091004001"); // 我们自己生成的订单编号
|
||||
bizContent.put("total_amount", "0.01"); // 订单的总金额
|
||||
bizContent.put("subject", "测试商品"); // 支付的名称
|
||||
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); // 固定配置
|
||||
request.setBizContent(bizContent.toString());
|
||||
|
||||
String form = alipayClient.pageExecute(request).getBody();
|
||||
log.info("测试结果:{}", form);
|
||||
|
||||
/**
|
||||
* 会生成一个form表单;
|
||||
<form name="punchout_form" method="post" action="https://openapi-sandbox.dl.alipaydev.com/gateway.do?charset=utf-8&method=alipay.trade.page.pay&sign=vl9G%2FJHoVvn5cW87mYYK2PhiISCw4pFdB9kYLEqx645S6Q%2BzN9OBw1QbfkmvNB5EOApbNOsz2UyvKeWQtUVswyHJhadIIEvbbP925VIvWveqYvPY6rnoFfA3OXXZR%2FxFrDLxij%2BhCtz7N6T9Iyxraf4UGuiTmez8LJZu60Exr2ej%2FSeZIwRXOflB6u7xFXfcJqVHE0sz1%2B2vkDaMjYBJ77dZoLLUs2smavzN%2BZIRs7%2FT8w39w7ymab23uMSM%2FXLMi%2B%2BrL9rSzvdWgk9NwxLIKslc2IWg2%2Bk5%2BVOc1KyY2K%2F35XzRzaeYGWuMCCLYCwDVE2Lvp8ul99A5%2FebYQaaV9g%3D%3D&return_url=https%3A%2F%2Fblog.bitday.top¬ify_url=https%3A%2F%2Fpay.bitday.top%2Fapi%2Fv1%2Falipay%2Falipay_notify_url&version=1.0&app_id=9021000150645052&sign_type=RSA2×tamp=2025-07-12+16%3A29%3A37&alipay_sdk=alipay-sdk-java-4.38.157.ALL&format=json">
|
||||
<input type="hidden" name="biz_content" value="{"out_trade_no":"smile000091004001","total_amount":"0.01","subject":"测试商品","product_code":"FAST_INSTANT_TRADE_PAY"}">
|
||||
<input type="submit" value="立即支付" style="display:none" >
|
||||
</form>
|
||||
<script>document.forms[0].submit();</script>
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单
|
||||
*/
|
||||
@Test
|
||||
public void test_alipay_certificateExecute() throws AlipayApiException {
|
||||
|
||||
AlipayTradeQueryModel bizModel = new AlipayTradeQueryModel();
|
||||
bizModel.setOutTradeNo("daniel82AAAA000032333361Y001");
|
||||
|
||||
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
|
||||
request.setBizModel(bizModel);
|
||||
|
||||
String body = alipayClient.execute(request).getBody();
|
||||
log.info("测试结果:{}", body);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款接口
|
||||
*/
|
||||
@Test
|
||||
public void test_alipay_refund() throws AlipayApiException {
|
||||
AlipayTradeRefundRequest request =new AlipayTradeRefundRequest();
|
||||
AlipayTradeRefundModel refundModel =new AlipayTradeRefundModel();
|
||||
refundModel.setOutTradeNo("daniel82AAAA000032333361X03");
|
||||
refundModel.setRefundAmount("1.00");
|
||||
refundModel.setRefundReason("退款说明");
|
||||
request.setBizModel(refundModel);
|
||||
|
||||
AlipayTradeRefundResponse execute = alipayClient.execute(request);
|
||||
log.info("测试结果:{}", execute.isSuccess());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(new BigDecimal("9.99").doubleValue());
|
||||
}
|
||||
|
||||
}
|
@ -38,6 +38,11 @@
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
<!-- 支付宝支付 -->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
</dependency>
|
||||
<!-- 系统模块 -->
|
||||
<dependency>
|
||||
<groupId>edu.whut</groupId>
|
||||
|
@ -2,6 +2,7 @@ package edu.whut.domain.order.adapter.repository;
|
||||
|
||||
import edu.whut.domain.order.model.aggregate.CreateOrderAggregate;
|
||||
import edu.whut.domain.order.model.entity.OrderEntity;
|
||||
import edu.whut.domain.order.model.entity.PayOrderEntity;
|
||||
import edu.whut.domain.order.model.entity.ShopCartEntity;
|
||||
|
||||
public interface IOrderRepository {
|
||||
@ -9,4 +10,5 @@ public interface IOrderRepository {
|
||||
|
||||
OrderEntity queryUnPayOrder(ShopCartEntity shopCartEntity);
|
||||
|
||||
void updateOrderPayInfo(PayOrderEntity payOrderEntity);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package edu.whut.domain.order.service;
|
||||
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import edu.whut.domain.order.adapter.port.IProductPort;
|
||||
import edu.whut.domain.order.adapter.repository.IOrderRepository;
|
||||
import edu.whut.domain.order.model.aggregate.CreateOrderAggregate;
|
||||
@ -10,6 +11,8 @@ import edu.whut.domain.order.model.entity.ShopCartEntity;
|
||||
import edu.whut.domain.order.model.valobj.OrderStatusVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractOrderService implements IOrderService {
|
||||
|
||||
@ -36,9 +39,14 @@ public abstract class AbstractOrderService implements IOrderService {
|
||||
.orderId(unpaidOrderEntity.getOrderId())
|
||||
.payUrl(unpaidOrderEntity.getPayUrl())
|
||||
.build();
|
||||
// TODO: 如果存在“已创建未支付”状态
|
||||
} else if (null != unpaidOrderEntity && OrderStatusVO.CREATE.equals(unpaidOrderEntity.getOrderStatusVO())) {
|
||||
|
||||
} else if (null != unpaidOrderEntity && OrderStatusVO.CREATE.equals(unpaidOrderEntity.getOrderStatusVO())) {
|
||||
log.info("创建订单-存在,存在未创建'支付单'订单,创建支付单开始 userId:{} productId:{} orderId:{}", shopCartEntity.getUserId(), shopCartEntity.getProductId(), unpaidOrderEntity.getOrderId());
|
||||
PayOrderEntity payOrderEntity = doPrepayOrder(shopCartEntity.getUserId(), shopCartEntity.getProductId(), unpaidOrderEntity.getProductName(), unpaidOrderEntity.getOrderId(), unpaidOrderEntity.getTotalAmount());
|
||||
return PayOrderEntity.builder()
|
||||
.orderId(payOrderEntity.getOrderId())
|
||||
.payUrl(payOrderEntity.getPayUrl())
|
||||
.build();
|
||||
}
|
||||
|
||||
// 2. 调用产品服务,查询商品详细信息
|
||||
@ -57,10 +65,14 @@ public abstract class AbstractOrderService implements IOrderService {
|
||||
// 5. 交由子类实现,保存订单聚合
|
||||
this.doSaveOrder(orderAggregate);
|
||||
|
||||
PayOrderEntity payOrderEntity = doPrepayOrder(shopCartEntity.getUserId(), productEntity.getProductId(), productEntity.getProductName(), orderEntity.getOrderId(), productEntity.getPrice());
|
||||
log.info("创建订单-完成,生成支付单。userId: {} orderId: {} payUrl: {}", shopCartEntity.getUserId(), orderEntity.getOrderId(), payOrderEntity.getPayUrl());
|
||||
|
||||
|
||||
// 6. 返回支付实体
|
||||
return PayOrderEntity.builder()
|
||||
.orderId(orderEntity.getOrderId())
|
||||
.payUrl("暂无")
|
||||
.payUrl(payOrderEntity.getPayUrl())
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -69,4 +81,5 @@ public abstract class AbstractOrderService implements IOrderService {
|
||||
*/
|
||||
protected abstract void doSaveOrder(CreateOrderAggregate orderAggregate);
|
||||
|
||||
protected abstract PayOrderEntity doPrepayOrder(String userId, String productId, String productName, String orderId, BigDecimal totalAmount) throws AlipayApiException;
|
||||
}
|
||||
|
@ -1,14 +1,32 @@
|
||||
package edu.whut.domain.order.service;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.request.AlipayTradePagePayRequest;
|
||||
import edu.whut.domain.order.adapter.port.IProductPort;
|
||||
import edu.whut.domain.order.adapter.repository.IOrderRepository;
|
||||
import edu.whut.domain.order.model.aggregate.CreateOrderAggregate;
|
||||
import edu.whut.domain.order.model.entity.PayOrderEntity;
|
||||
import edu.whut.domain.order.model.valobj.OrderStatusVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OrderService extends AbstractOrderService{
|
||||
|
||||
@Value("${alipay.notify_url}")
|
||||
private String notifyUrl;
|
||||
@Value("${alipay.return_url}")
|
||||
private String returnUrl;
|
||||
|
||||
@Resource
|
||||
private AlipayClient alipayClient;
|
||||
|
||||
public OrderService(IOrderRepository repository, IProductPort port) {
|
||||
super(repository, port);
|
||||
}
|
||||
@ -18,4 +36,33 @@ public class OrderService extends AbstractOrderService{
|
||||
repository.doSaveOrder(orderAggregate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预支付订单
|
||||
*/
|
||||
@Override
|
||||
protected PayOrderEntity doPrepayOrder(String userId, String productId, String productName, String orderId, BigDecimal totalAmount) throws AlipayApiException {
|
||||
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
|
||||
request.setNotifyUrl(notifyUrl);
|
||||
request.setReturnUrl(returnUrl);
|
||||
|
||||
JSONObject bizContent = new JSONObject();
|
||||
bizContent.put("out_trade_no", orderId);
|
||||
bizContent.put("total_amount", totalAmount.toString());
|
||||
bizContent.put("subject", productName);
|
||||
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
|
||||
request.setBizContent(bizContent.toString());
|
||||
|
||||
String form = alipayClient.pageExecute(request).getBody();
|
||||
|
||||
PayOrderEntity payOrderEntity = new PayOrderEntity();
|
||||
payOrderEntity.setOrderId(orderId);
|
||||
payOrderEntity.setPayUrl(form);
|
||||
//等待支付
|
||||
payOrderEntity.setOrderStatus(OrderStatusVO.PAY_WAIT);
|
||||
|
||||
repository.updateOrderPayInfo(payOrderEntity);
|
||||
|
||||
return payOrderEntity;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package edu.whut.infrastructure.adapter.repository;
|
||||
import edu.whut.domain.order.adapter.repository.IOrderRepository;
|
||||
import edu.whut.domain.order.model.aggregate.CreateOrderAggregate;
|
||||
import edu.whut.domain.order.model.entity.OrderEntity;
|
||||
import edu.whut.domain.order.model.entity.PayOrderEntity;
|
||||
import edu.whut.domain.order.model.entity.ProductEntity;
|
||||
import edu.whut.domain.order.model.entity.ShopCartEntity;
|
||||
import edu.whut.domain.order.model.valobj.OrderStatusVO;
|
||||
@ -11,8 +12,6 @@ import edu.whut.infrastructure.dao.po.PayOrder;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class OrderRepository implements IOrderRepository {
|
||||
@ -59,4 +58,15 @@ public class OrderRepository implements IOrderRepository {
|
||||
.payUrl(order.getPayUrl())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOrderPayInfo(PayOrderEntity payOrderEntity) {
|
||||
PayOrder payOrderReq = PayOrder.builder()
|
||||
.userId(payOrderEntity.getUserId())
|
||||
.orderId(payOrderEntity.getOrderId())
|
||||
.status(payOrderEntity.getOrderStatus().getCode())
|
||||
.payUrl(payOrderEntity.getPayUrl())
|
||||
.build();
|
||||
orderDao.updateOrderPayInfo(payOrderReq);
|
||||
}
|
||||
}
|
||||
|
@ -9,4 +9,6 @@ public interface IOrderDao {
|
||||
|
||||
PayOrder queryUnPayOrder(PayOrder payOrder);
|
||||
|
||||
void updateOrderPayInfo(PayOrder payOrder);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package edu.whut.trigger.http;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.internal.util.AlipaySignature;
|
||||
import edu.whut.api.IPayService;
|
||||
import edu.whut.api.dto.CreatePayRequestDTO;
|
||||
import edu.whut.api.response.Response;
|
||||
import edu.whut.domain.order.model.entity.PayOrderEntity;
|
||||
import edu.whut.domain.order.model.entity.ShopCartEntity;
|
||||
import edu.whut.domain.order.service.IOrderService;
|
||||
import edu.whut.types.common.Constants;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@RestController()
|
||||
@CrossOrigin("*")
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/alipay")
|
||||
public class AliPayController implements IPayService {
|
||||
|
||||
@Value("${alipay.alipay_public_key}")
|
||||
private String alipayPublicKey;
|
||||
|
||||
private final IOrderService orderService;
|
||||
|
||||
/**
|
||||
* {
|
||||
* "userId": "10001",
|
||||
* "productId": "10001"
|
||||
* }
|
||||
*/
|
||||
@PostMapping("/create_pay_order")
|
||||
@Override
|
||||
public Response<String> createPayOrder(@RequestBody CreatePayRequestDTO createPayRequestDTO) {
|
||||
try {
|
||||
log.info("商品下单,根据商品ID创建支付单开始 userId:{} productId:{}", createPayRequestDTO.getUserId(), createPayRequestDTO.getUserId());
|
||||
String userId = createPayRequestDTO.getUserId();
|
||||
String productId = createPayRequestDTO.getProductId();
|
||||
// 下单
|
||||
PayOrderEntity payOrderEntity = orderService.createOrder(ShopCartEntity.builder()
|
||||
.userId(userId)
|
||||
.productId(productId)
|
||||
.build());
|
||||
|
||||
log.info("商品下单,根据商品ID创建支付单完成 userId:{} productId:{} orderId:{}", userId, productId, payOrderEntity.getOrderId());
|
||||
return Response.<String>builder()
|
||||
.code(Constants.ResponseCode.SUCCESS.getCode())
|
||||
.info(Constants.ResponseCode.SUCCESS.getInfo())
|
||||
.data(payOrderEntity.getPayUrl())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
log.error("商品下单,根据商品ID创建支付单失败 userId:{} productId:{}", createPayRequestDTO.getUserId(), createPayRequestDTO.getUserId(), e);
|
||||
return Response.<String>builder()
|
||||
.code(Constants.ResponseCode.UN_ERROR.getCode())
|
||||
.info(Constants.ResponseCode.UN_ERROR.getInfo())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/alipay_notify_url")
|
||||
public String payNotify(HttpServletRequest request) throws AlipayApiException {
|
||||
log.info("支付回调,消息接收 {}", request.getParameter("trade_status"));
|
||||
|
||||
if (!request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
|
||||
return "false";
|
||||
}
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
Map<String, String[]> requestParams = request.getParameterMap();
|
||||
for (String name : requestParams.keySet()) {
|
||||
params.put(name, request.getParameter(name));
|
||||
}
|
||||
|
||||
String tradeNo = params.get("out_trade_no");
|
||||
String gmtPayment = params.get("gmt_payment");
|
||||
String alipayTradeNo = params.get("trade_no");
|
||||
|
||||
String sign = params.get("sign");
|
||||
String content = AlipaySignature.getSignCheckContentV1(params);
|
||||
boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, alipayPublicKey, "UTF-8"); // 验证签名
|
||||
// 支付宝验签
|
||||
if (!checkSignature) {
|
||||
return "false";
|
||||
}
|
||||
|
||||
// 验签通过
|
||||
log.info("支付回调,交易名称: {}", params.get("subject"));
|
||||
log.info("支付回调,交易状态: {}", params.get("trade_status"));
|
||||
log.info("支付回调,支付宝交易凭证号: {}", params.get("trade_no"));
|
||||
log.info("支付回调,商户订单号: {}", params.get("out_trade_no"));
|
||||
log.info("支付回调,交易金额: {}", params.get("total_amount"));
|
||||
log.info("支付回调,买家在支付宝唯一id: {}", params.get("buyer_id"));
|
||||
log.info("支付回调,买家付款时间: {}", params.get("gmt_payment"));
|
||||
log.info("支付回调,买家付款金额: {}", params.get("buyer_pay_amount"));
|
||||
log.info("支付回调,支付回调,更新订单 {}", tradeNo);
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
}
|
@ -10,6 +10,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 微信会回调该接口
|
||||
* https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index 平台地址
|
||||
* https://pay.bitday.top/api/v1/weixin/portal/receive 内网穿透
|
||||
*/
|
||||
@ -73,6 +74,7 @@ public class WeixinPortalController {
|
||||
MessageTextEntity message = XmlUtil.xmlToBean(requestBody, MessageTextEntity.class);
|
||||
|
||||
if ("event".equals(message.getMsgType()) && "SCAN".equals(message.getEvent())) {
|
||||
//存储用户登录状态
|
||||
loginService.saveLoginState(message.getTicket(), openid);
|
||||
return buildMessageTextEntity(openid, "登录成功");
|
||||
}
|
||||
|
@ -21,4 +21,5 @@ public class Constants {
|
||||
private String info;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
7
pom.xml
7
pom.xml
@ -130,7 +130,12 @@
|
||||
<artifactId>adapter-rxjava2</artifactId>
|
||||
<version>2.9.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 支付宝沙箱支付对接文档:https://opendocs.alipay.com/common/02kkv7 -->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>4.38.157.ALL</version>
|
||||
</dependency>
|
||||
<!-- 工程模块 -->
|
||||
<dependency>
|
||||
<groupId>edu.whut</groupId>
|
||||
|
Loading…
x
Reference in New Issue
Block a user