支付宝沙箱功能的使用
支付结构图
- 大体结构图:
- 详细结构图
模拟支付代码
-
真正支付是商家app下单->商家后台产生订单信息->为订单信息创建支付接口->返回支付结果给商家app异步调动商家后台
-
模拟: 自定义数据->为其创建支付->返回支付结果给商家app异步创建订单信息->将信息存入数据库
-
两者区别,先创建订单再支付,还是先支付再创建订单。(这里采用第二种)
1、资源配置类
server:
port: 8090
spring:
datasource:
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
url: jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false
#没用到
redis:
host: 127.0.0.1
port: 6379
#用于实现订单超时
rabbitmq:
host: 127.0.0.1
port: 5672
username: test
password: 123456
virtual-host: /test
listener:
type: simple
simple:
acknowledge-mode: manual
default-requeue-rejected: false
2、配置类
public class AlipayConfigInfo {
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
public static String app_id="2021000118******";
// 商户私钥,您的PKCS8格式RSA2私钥
public static String merchant_private_key = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCxJ3d8MYUrrJ+Bte5q8v9JOxw3YGbrkxNNufiBwb0cKjxRDg5QADl149+nn/REgWmR6dLCatVZYy2avFcuUuYd0/xdPYZskUb6YtGrghwPVzmuNAPORBnt6hBGWJRduNIBnyoONRzXugJRRFDa3Mr3l9Ca0J4+AzNdXzEYXWU5Xci3c7uruZ9XRoLBrjvmMPL71e9hnJQ5Z9qGSq92qdgh83jUE189HcmmFVqwpAaMQhEkTukuKwjy6UF6FzoYO7dH/wzQJBeFJv1ePm90dJmQLh7gvZ8TdyVrDlx0RT9vP2l1EkCTww7jaUteOPXzCdgi9PqOTbgtQNLdVeSB0R9HAgMBAAECggEBAKVc+MzGENAGz9GteIL+lsvN0HXkl824OSGpwc2lghgjWLA0lamZvAlOj3wR9FpqDph0khaG0OYijPROcHa+TS10rrJ+dtcq+P1KdvtIdVbgjegNh6vnp+iMP2razot5tRZscz5V17mLWRRw16SkyxU48jFBISUzqaOz8skSjSVw1wg1Cr0ScHU8tP9BJ+ELXs/3JDM/w8erCjaVVbpmCDmegq6Zu3WmqiLj+EEmxa3oe0pAilgKwAKs1ot0UlYLuYvuTXf3S5R42AVnmkS/bOFwgNiN+5AvwZYZZ/s/1ld9W6HvjEGQ6A2vdPwWiG4XE4jC7clFCbT7YYIyiQwWHgECgYEA2BYJ6kJyz1OnR7BeguSWl5I6gZ+H51hJsgMf28/pDYQSLly+kmdKklM8yznXI21emhDeN3xM9KGmKOqpI0CsFtbKhiNp2DKO/Fg/t2nooPNVkUget2hpxuZKZZWAVmCqRY0tZrVblQxJUd/2QCxeDJLJV84ztRdd5QCBfGIGQwECgYEA0eB494eCrDYI2hugSDb7bjeczxsEyBlgvNH+FArvqoJEJjwByaUX8U146fdmlpzirohstkMW3I75iCpZSbKFmQDTRHV2AlPCcGtle/5FJGbw4+W3ahJTU3i4zrtZup0WAhEmeqlszf8mSmtNOV20J1OIL9MgRcGdQGdaHI/2ikcCgYEAy423OV3vGS8MXZPe9B6xXYb6ZjEJrPyWL4KR+Fcaiwjmt5XWT8PNk5mloyuRZmYYv7k0G8CUHb5I8DJdsj+x3LHphgLGKks2NrBLFVRHN5cB/CGcDdnmCt/VJWx3wOa+f1ZGdoJRC07Porj/F+Szk9SSpowwWV7xrE+Vqr4MeAECgYASDVG6UMCPmXI3eGrX60rDFyt4sOU/ZNdqRlGpXatxqhS8iSrKMlYV3kkJLst3JvVkd72KC8k6nV2fNa1KZn2RRH3nhIbq+lNeIg6vlJZT5DrSD18wU3UxV8/lkD3OjFZpRRpfMJV4PnsHqaURyxqEy22KV4mOFnI1KO6aSFO3XwKBgQC7GdDHszlMyD1rSUP1RiMXoUZq/S+IY20gZbdAXdlLYtUInRLSEpyTJhIhHF0scqpQSPMbUzWEoyjV7vU7swv40oBC9oyyXOO8P6j72wmrraw8/SAtX1YZBtG6tJeMIUIenGqA68FvEiul7fCwOPO85GKtSpypoidjnxFX+Fqj0g==";
// 支付宝公钥
// 对应APPID下的支付宝公钥。你的公钥
public static String alipay_public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlXQ2puhU475iJGI1WEM2ArLu1i5uhdrLa8WpHUB4pc9ZrGWAdJZd3UVr9NuBb6+4x4LZILTWHrIr/7AjaIaOb7ub4JnFNnpy61U7bXHUANV8kkjwMxPYLXdg05Yoo5MsnGyUYUmlb8Zyik6t5BktyUpcEoGAmxpAPZoLMCkKme5jbFLzv1VzWxCfGXQKsJoOHfTMG2xQXEk7MR3+8/MLVpuffqgNfdrvxpzH1vlvbVs0L3//t/eOH+lOUHhF/fM6Lcc68KBNN330TIXS8+wl+FDfQkcLL1kL7YfK6W5fSFaMzJkhuq8voyz+bW8ngaTYuh3MkK7x04+GqUsaj8TQKQIDAQAB";
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
/**
* 返回的时候此页面不会返回到用户页面,只会执行你写到控制器里的地址,用户端回调方式是get
这里地址是采用内网映射 可以采用natapp或者ngork https://natapp.cn/
*/
public static String return_url = "http://5t4x9a.natappfree.cc/success";
// 页面跳转同步通知页面路径 需http://格式的完整路径,返回的路径方式时post
public static String notify_url="http://5t4x9a.natappfree.cc/nodify";
// 签名方式
public static String sign_type = "RSA2";
// 返回格式
public static String format = "json";
// 字符编码格式
public static String charset = "utf-8";
// 支付宝网关
public static String gatewayUrl="https://openapi.alipaydev.com/gateway.do";
//实例化客户端
private static AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,app_id,merchant_private_key,format,charset,alipay_public_key,sign_type);
}
3、实体类
//这里只记录订单信息
@Entity
@Table(name = "F_orders")
@Data
@AllArgsConstructor
public class Orders {
public Orders(){
Date now = new Date();
this.createTime = now;
this.updateTime = now;
}
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "id")
private int id;
@Column(name = "order_id")
private String orderId;
@Column(name = "user_id")
private String userId;
@Column(name = "order_number")
private int orderNumber;
@Column(name = "total_money")
private float totalPrice;
@Column(name = "create_time")
private Date createTime;
@Column(name = "update_time")
private Date updateTime;
}
4、dto(展示层)
@ApiModel(value = "订单信息")
@Data
public class OrdersDo {
@ApiModelProperty(value = "id",example = "12123214")
private int id;
@ApiModelProperty(value = "订单id",example = "924021")
private String orderId;
@ApiModelProperty(value = "用户id",example = "12312124")
private String userId;
@ApiModelProperty(value = "商品总数",example = "23")
private int orderNumber;
@ApiModelProperty(value = "商品总金额",example = "24231")
private float totalPrice;
private Date createTime;
private Date updateTime;
}
5、类型转换
@Mapper
public interface OrdersHelper {
OrdersHelper INSTANCE = Mappers.getMapper(OrdersHelper.class);
Orders transformInit(@MappingTarget Orders orders , OrdersDo orderDo);
OrdersDo transform4Update(@MappingTarget OrdersDo orderDo , Orders orders);
}
6、dao层
public interface OrdersDao extends JpaSpecificationExecutor<Orders>, JpaRepository<Orders,Integer> {
}
7、业务层
@Service
public class OrdersService {
@Autowired
private OrdersDao ordersDao;
public OrdersDo save(String id,String userId,int count,float total){
Orders orders = new Orders();
orders.setOrderId(id);
orders.setUserId(userId);
orders.setOrderNumber(count);
orders.setTotalPrice(total);
ordersDao.save(orders);
return OrdersHelper.INSTANCE.transform4Update(new OrdersDo(),orders);
}
}
8、控制层
- 路径控制
@Controller
public class UrlController {
@Autowired
private OrdersService ordersService;
//用户付款成功后回调路径
@GetMapping("/success")
@ResponseBody
public String success(){
return "成功付款";
}
//模拟调用商户服务器接口
@PostMapping("/nodify")
public void nodify(HttpServletRequest request){
String out_trade_no = request.getParameter("out_trade_no");
float total_amount = Float.valueOf(request.getParameter("total_amount"));
// List<String> list = JSON.parseArray(goods_detail, String.class);
int count = 1;
OrdersDo ordersDo = ordersService.save(out_trade_no, "213142142121", count, total_amount);
System.out.println(ordersDo);
}
}
- 调用支付宝接口
@Controller
public class AlipayController {
@Autowired
private RabbitTemplate rabbitTemplate;
public static void returnResponse (HttpServletResponse response,String form){
try {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(form);
response.getWriter().flush();
response.getWriter().close();
} catch (IOException e) {
e.printStackTrace();
}
}
//创建订单整合Rabbitmq实现订单超时关闭交易
@GetMapping("/createGrade")
public void createGrade(HttpServletResponse response) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format(new Date());
Message message = new Message(("关闭交易当前时间:"+format).getBytes(StandardCharsets.UTF_8));
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
String outTradeNo = "33"; // 商户订单号,商户网站订单系统中唯一订单号,必填
String totalAmount = "99.9"; // 付款金额,必填
String subject = "羽绒服"; // 订单名称,必填
String body = "冬日神器"; // 商品描述,可空
String buyer_id = "ggbwwk8873@sandbox.com";
request.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","
+ "\"total_amount\":\"" + totalAmount + "\","
+ "\"subject\":\"" + subject + "\","
+ "\"body\":\"" + body + "\","
+ "\"buyer_id\":\"" + buyer_id + "\","
+" \"goods_detail\":[{" +
" \"goods_id\":\"123214421311\"," +
"\"goods_name\":\"ipad\"," +
"\"quantity\":1," +
"\"price\":2000," +
"\"goods_category\":\"34543238\"," +
"\"categories_tree\":\"124868003|126232002|126252004\"," +
"\"body\":\"特价手机\"," +
"\"show_url\":\"http://www.alipay.com/xxx.jpg\"" +
" }],"
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
// 在公共参数中设置回跳和通知地址
//用户支付成功返回地址
request.setReturnUrl(return_url);
//商家接收地址
request.setNotifyUrl(notify_url);
AlipayTradePagePayResponse payResponse = alipayClient.pageExecute(request);
rabbitTemplate.convertAndSend("direct.delay.exchange","DelayKey",message);
String form = payResponse.getBody();
returnResponse(response,form);
} catch (AlipayApiException e) {
e.printStackTrace();
}
}
//查询订单信息
@GetMapping("/query")
public void queryTrace(HttpServletResponse response) throws Exception {
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"33\"," +
" \"query_options\":[" +
" \"trade_settle_info\"" +
" ]" +
" }");
AlipayTradeQueryResponse tradeQueryResponse = alipayClient.execute(request);
String body = tradeQueryResponse.getBody();
returnResponse(response,body);
}
//撤销订单
@GetMapping("/cancelTrade")
public void cancelTrade(HttpServletResponse response) throws Exception{
AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"33\"," +
"\"trade_no\":\"\"" +
"}");
AlipayTradeCancelResponse tradeCancelResponse = alipayClient.execute(request);
String body = tradeCancelResponse.getBody();
returnResponse(response,body);
if (tradeCancelResponse.isSuccess()){
System.out.println("删除订单或者修改订单状态");
}
}
//交易退款
@GetMapping("/refundTrade")
public void refundTrade(HttpServletResponse response) throws Exception{
while (true){
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
String refund_amount = "50";
request.setBizContent("{" +
"\"out_trade_no\":\"33\"," +
"\"trade_no\":\"\"," +
"\"refund_amount\":50," +
"\"refund_reason\":\"正常退款\"," +
"\"out_request_no\":\"HZ01RF001\"," +
" \"refund_royalty_parameters\":[{" +
" \"royalty_type\":\"transfer\"," +
"\"trans_out\":\"mswwrs2745@sandbox.com\"," +
"\"trans_out_type\":\"loginName\"," +
"\"trans_in_type\":\"loginName\"," +
"\"trans_in\":\"ggbwwk8873@sandbox.com\"," +
"\"amount\":0.1," +
"\"desc\":\"分账给ggbwwk8873@sandbox.com\"" +
" }]" +
" }");
AlipayTradeRefundResponse alipayTradeRefundResponse = alipayClient.execute(request);
String form = alipayTradeRefundResponse.getBody();
returnResponse(response,form);
if (alipayTradeRefundResponse.isSuccess()){
System.out.println("退款金额:"+refund_amount);
break;
}
Thread.sleep(5000);
}
}
//查询订单下载地址
@GetMapping("/orderQuery")
public void orderQuery(HttpServletResponse response) throws AlipayApiException {
AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
request.setBizContent("{" +
"\"bill_type\":\"trade\"," +
"\"bill_date\":\"2021-08-25\"" +
" }");
AlipayDataDataserviceBillDownloadurlQueryResponse queryResponse = alipayClient.execute(request);
String form = queryResponse.getBody();
System.out.println(form);
returnResponse(response,form);
if (queryResponse.isSuccess()){
System.out.println("查询成功");
}
}
}
9、RabbitMq
- 配置
@Configuration
public class RabbitMQConfig {
private static String direct_queue = "direct.pay.queue";
private static String exchange = "direct.pay.exchange";
private static String dead_exchange = "dead_exchange";
private static String routing_key = "routing_key";
@Bean
public Queue directQueue(){
Map<String,Object> args = new HashMap<>(3);
args.put("x-dead-letter-exchange",dead_exchange);
args.put("x-dead-letter-routing-key","DelayKey");
//10秒过期
args.put("x-message-ttl",10000);
//队列名 是否持久化 是否独占队列 是否自动删除 其他规则
return new Queue(direct_queue,true,false,false,args);
}
@Bean
public DirectExchange directExchange(){
return new DirectExchange(exchange);
}
@Bean
public Binding binding(){
return BindingBuilder.bind(directQueue()).to(directExchange()).with(routing_key);
}
}
- 消费
@Component
public class DelayConsumer {
//延时队列实现订单超时关闭支付
@RabbitListener(bindings = {@QueueBinding(value = @Queue(value = "direct.delay.queue"),exchange = @Exchange(value = "direct.delay.exchange"),key = {"DelayKey"})})
public void counsumer(Channel channel, Message message) throws Exception {
System.out.println(message.getBody());
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"33\"" +
" }");
AlipayTradeCloseResponse response = alipayClient.execute(request);
System.out.println("成功");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format(new Date());
System.out.println("关闭订单当前时间:"+format);
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
}
- 延时队列结构图
- 码云地址:https://gitee.com/linyefu/springboot-apply
- 帮忙点点赞谢谢,一起研究学习