JAVA對接支付寶


我們在做開發時很多時候會涉及到支付功能,常見會對接支付寶和微信支付,本文將對JAVA對接支付寶進行詳細的講解。

在進行開發編碼之前我們首選需要去申請開發所需要的支付寶一些配置,即支付寶沙盒環境的申請、

 

  1. 支付寶沙盒環境申請

     1.1 注冊

       登錄支付寶開發者網站 https://developers.alipay.com/ ,使用個人的支付寶掃碼登錄后,填寫個人信息並提交

     1.2 沙盒環境設置 

       按如下圖所示進入沙盒環境設置頁面

      

 

    

 

   

    打開頁面 https://opendocs.alipay.com/open/291/105971 下載公私鑰生成工具,安裝后生成應用的公鑰和私鑰

    

 

  生成公私鑰如下圖

 

  

 

   將公私鑰保存好,后面程序中要用到,同時將公鑰復制到沙盒環境的設置中,如下圖

 

   

 

  

   保存會生成一個支付寶的公鑰,這個公鑰用於后續的支付寶支付后的回調驗簽使用

    

 

 

   至此。沙盒環境設置完畢。

 

2. 開發部分

  我們模擬一個簡單的訂單支付功能,只有一個簡單的金額字段

  2.1 數據庫表結構

    

 1 CREATE TABLE `user_order_t` (
 2   `order_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '訂單Id',
 3   `user_id` varchar(64) DEFAULT NULL COMMENT '用戶Id',
 4   `order_no` varchar(64) NOT NULL COMMENT '訂單號',
 5   `order_amount` decimal(16,4) NOT NULL COMMENT '訂單金額',
 6   `order_status` int(11) NOT NULL COMMENT '0 待付款 1 已付款 -1 已取消',
 7   `create_time` varchar(32) NOT NULL COMMENT '創建時間',
 8   `last_update_time` varchar(32) NOT NULL COMMENT '最后修改時間',
 9   PRIMARY KEY (`order_id`)
10 ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4;

 

 

 2.2 項目結構

   新建一個springboot項目,結構如圖

   

 

 

 

  2.3 pom依賴

    

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4     <modelVersion>4.0.0</modelVersion>
  5     <parent>
  6         <groupId>org.springframework.boot</groupId>
  7         <artifactId>spring-boot-starter-parent</artifactId>
  8         <version>2.2.5.RELEASE</version>
  9         <relativePath/> <!-- lookup parent from repository -->
 10     </parent>
 11     <groupId>com.devin</groupId>
 12     <artifactId>alipay_demo</artifactId>
 13     <version>0.0.1-SNAPSHOT</version>
 14     <name>alipay_demo</name>
 15     <description>Demo project for Spring Boot</description>
 16 
 17     <properties>
 18         <java.version>1.8</java.version>
 19     </properties>
 20 
 21     <dependencies>
 22 
 23         <dependency>
 24             <groupId>org.springframework.boot</groupId>
 25             <artifactId>spring-boot-starter-web</artifactId>
 26         </dependency>
 27 
 28 
 29         <dependency>
 30             <groupId>tk.mybatis</groupId>
 31             <artifactId>mapper-spring-boot-starter</artifactId>
 32             <version>2.0.4</version>
 33         </dependency>
 34 
 35         <dependency>
 36             <groupId>org.springframework.boot</groupId>
 37             <artifactId>spring-boot-starter-jdbc</artifactId>
 38             <version>2.0.0.RELEASE</version>
 39         </dependency>
 40 
 41         <dependency>
 42             <groupId>org.mybatis.spring.boot</groupId>
 43             <artifactId>mybatis-spring-boot-starter</artifactId>
 44             <version>2.0.1</version>
 45         </dependency>
 46 
 47         <dependency>
 48             <groupId>mysql</groupId>
 49             <artifactId>mysql-connector-java</artifactId>
 50             <version>5.1.17</version>
 51         </dependency>
 52 
 53         <dependency>
 54             <groupId>com.alibaba</groupId>
 55             <artifactId>druid</artifactId>
 56             <version>1.1.1</version>
 57         </dependency>
 58 
 59         <dependency>
 60             <groupId>org.projectlombok</groupId>
 61             <artifactId>lombok</artifactId>
 62             <version>1.16.22</version>
 63         </dependency>
 64 
 65 
 66         <dependency>
 67             <groupId>org.springframework.boot</groupId>
 68             <artifactId>spring-boot-starter-amqp</artifactId>
 69             <version>2.1.8.RELEASE</version>
 70         </dependency>
 71 
 72         <dependency>
 73             <groupId>org.springframework.boot</groupId>
 74             <artifactId>spring-boot-test</artifactId>
 75             <version>2.2.6.RELEASE</version>
 76         </dependency>
 77         <dependency>
 78             <groupId>junit</groupId>
 79             <artifactId>junit</artifactId>
 80             <version>4.12</version>
 81         </dependency>
 82         <dependency>
 83             <groupId>org.springframework</groupId>
 84             <artifactId>spring-test</artifactId>
 85             <version>5.2.5.RELEASE</version>
 86         </dependency>
 87 
 88 
 89         <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
 90         <dependency>
 91             <groupId>com.alibaba</groupId>
 92             <artifactId>fastjson</artifactId>
 93             <version>1.2.57</version>
 94         </dependency>
 95 
 96 
 97         <dependency>
 98             <groupId>org.apache.commons</groupId>
 99             <artifactId>commons-lang3</artifactId>
100             <version>3.5</version>
101         </dependency>
102 
103         <dependency>
104             <groupId>commons-codec</groupId>
105             <artifactId>commons-codec</artifactId>
106             <version>1.10</version>
107         </dependency>
108         <dependency>
109             <groupId>com.alipay.sdk</groupId>
110             <artifactId>alipay-sdk-java</artifactId>
111             <version>3.4.27.ALL</version>
112         </dependency>
113 
114     </dependencies>
115 
116     <build>
117         <plugins>
118             <plugin>
119                 <groupId>org.springframework.boot</groupId>
120                 <artifactId>spring-boot-maven-plugin</artifactId>
121             </plugin>
122         </plugins>
123     </build>
124 
125     <repositories>
126         <repository>
127             <id>maven-ali</id>
128             <url>http://maven.aliyun.com/nexus/content/groups/public//</url>
129             <releases>
130                 <enabled>true</enabled>
131             </releases>
132             <snapshots>
133                 <enabled>true</enabled>
134                 <updatePolicy>always</updatePolicy>
135                 <checksumPolicy>fail</checksumPolicy>
136             </snapshots>
137         </repository>
138     </repositories>
139 
140 </project>

 

  2.4  模型的定義

     2.4.1 訂單model  

       

 1 package com.devin.alipay_demo.entity;
 2 
 3 import javax.persistence.GeneratedValue;
 4 import javax.persistence.GenerationType;
 5 import javax.persistence.Id;
 6 import javax.persistence.Table;
 7 import java.math.BigDecimal;
 8 
 9 /**
10  * @author Devin Zhang
11  * @className UserOrder
12  * @description TODO
13  * @date 2020/5/12 10:49
14  */
15 @Table(name = "user_order_t")
16 public class UserOrder {
17 
18     @Id
19     @GeneratedValue(strategy= GenerationType.IDENTITY)
20     private Integer orderId;
21     private String orderNo;
22     private String userId;
23     private BigDecimal orderAmount;
24     private Integer orderStatus;
25     private String createTime;
26     private String lastUpdateTime;
27 
28     public Integer getOrderId() {
29         return orderId;
30     }
31 
32     public void setOrderId(Integer orderId) {
33         this.orderId = orderId;
34     }
35 
36     public String getOrderNo() {
37         return orderNo;
38     }
39 
40     public void setOrderNo(String orderNo) {
41         this.orderNo = orderNo;
42     }
43 
44     public String getUserId() {
45         return userId;
46     }
47 
48     public void setUserId(String userId) {
49         this.userId = userId;
50     }
51 
52     public BigDecimal getOrderAmount() {
53         return orderAmount;
54     }
55 
56     public void setOrderAmount(BigDecimal orderAmount) {
57         this.orderAmount = orderAmount;
58     }
59 
60     public Integer getOrderStatus() {
61         return orderStatus;
62     }
63 
64     public void setOrderStatus(Integer orderStatus) {
65         this.orderStatus = orderStatus;
66     }
67 
68     public String getCreateTime() {
69         return createTime;
70     }
71 
72     public void setCreateTime(String createTime) {
73         this.createTime = createTime;
74     }
75 
76     public String getLastUpdateTime() {
77         return lastUpdateTime;
78     }
79 
80     public void setLastUpdateTime(String lastUpdateTime) {
81         this.lastUpdateTime = lastUpdateTime;
82     }
83 }

  2.4.2 支付寶調用參數封裝model

    

 1 package com.devin.alipay_demo.dto;
 2 
 3 /**
 4  * @author Devin Zhang
 5  * @className AlipayBean
 6  * @description TODO
 7  * @date 2020/5/12 11:33
 8  */
 9 
10 public class AlipayBean {
11     /**
12      * 商戶訂單號,必填
13      */
14     private String out_trade_no;
15     /**
16      * 訂單名稱,必填
17      */
18     private String subject;
19     /**
20      * 付款金額,必填
21      * 根據支付寶接口協議,必須使用下划線
22      */
23     private String total_amount;
24     /**
25      * 商品描述,可空
26      */
27     private String body;
28     /**
29      * 超時時間參數
30      */
31     private String timeout_express = "10m";
32     /**
33      * 產品編號
34      */
35     private String product_code = "FAST_INSTANT_TRADE_PAY";
36 
37     public String getOut_trade_no() {
38         return out_trade_no;
39     }
40 
41     public void setOut_trade_no(String out_trade_no) {
42         this.out_trade_no = out_trade_no;
43     }
44 
45     public String getSubject() {
46         return subject;
47     }
48 
49     public void setSubject(String subject) {
50         this.subject = subject;
51     }
52 
53     public String getTotal_amount() {
54         return total_amount;
55     }
56 
57     public void setTotal_amount(String total_amount) {
58         this.total_amount = total_amount;
59     }
60 
61     public String getBody() {
62         return body;
63     }
64 
65     public void setBody(String body) {
66         this.body = body;
67     }
68 
69     public String getTimeout_express() {
70         return timeout_express;
71     }
72 
73     public void setTimeout_express(String timeout_express) {
74         this.timeout_express = timeout_express;
75     }
76 
77     public String getProduct_code() {
78         return product_code;
79     }
80 
81     public void setProduct_code(String product_code) {
82         this.product_code = product_code;
83     }
84 }

 

  2.5 工具類 

    2.5.1 支付寶參數讀取

     

package com.devin.alipay_demo.util;

import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author Devin Zhang
 * @className AlipayProperties
 * @description 讀取支付寶配置
 * @date 2020/5/12 11:16
 */
@Component
public class AlipayProperties {

    private static final String APP_ID = "appId";
    private static final String PRIVATE_KEY = "privateKey";
    private static final String PUBLIC_KEY = "publicKey";
    private static final String NOTIFY_URL = "notifyUrl";
    private static final String RETURN_URL = "returnUrl";
    private static final String SIGN_TYPE = "signType";
    private static final String CHARSET = "charset";
    private static final String GATEWAY_URL = "gatewayUrl";
    private static final String LOG_PATH = "logPath";

    /**
     * 保存加載配置參數
     */
    private static Map<String, String> propertiesMap = new HashMap<>();

    /**
     * 加載屬性
     */
    @PostConstruct
    public void loadProperties() throws Exception {
        // 獲得PathMatchingResourcePatternResolver對象
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            // 加載resource文件(也可以加載resources)
            Resource resources = resolver.getResource("classpath:config/alipay.properties");
            PropertiesFactoryBean config = new PropertiesFactoryBean();
            config.setLocation(resources);
            config.afterPropertiesSet();
            Properties prop = config.getObject();
            // 循環遍歷所有得鍵值對並且存入集合
            for (String key : prop.stringPropertyNames()) {
                propertiesMap.put(key, (String) prop.get(key));
            }
        } catch (Exception e) {
            throw new Exception("配置文件加載失敗");
        }
    }


    public String getAppId() {
        return propertiesMap.get(APP_ID);
    }

    public String getPrivateKey() {
        return propertiesMap.get(PRIVATE_KEY);
    }

    public String getPublicKey() {
        return propertiesMap.get(PUBLIC_KEY);
    }

    public String getNotifyUrl() {
        return propertiesMap.get(NOTIFY_URL);
    }

    public String getReturnUrl() {
        return propertiesMap.get(RETURN_URL);
    }

    public String getSignType() {
        return propertiesMap.get(SIGN_TYPE);
    }

    public String getCharset() {
        return propertiesMap.get(CHARSET);
    }

    public String getGatewayUrl() {
        return propertiesMap.get(GATEWAY_URL);
    }

    public String getLogPath() {
        return propertiesMap.get(LOG_PATH);
    }


}

 

    2.5.2 支付寶工具類

      

 1 package com.devin.alipay_demo.util;
 2 
 3 import com.alibaba.fastjson.JSON;
 4 import com.alipay.api.AlipayApiException;
 5 import com.alipay.api.AlipayClient;
 6 import com.alipay.api.DefaultAlipayClient;
 7 import com.alipay.api.request.AlipayTradePagePayRequest;
 8 import com.devin.alipay_demo.dto.AlipayBean;
 9 import org.springframework.stereotype.Component;
10 
11 import javax.annotation.Resource;
12 
13 /**
14  * @author Devin Zhang
15  * @className AliPayUtil
16  * @description TODO
17  * @date 2020/5/12 10:47
18  */
19 
20 @Component
21 public class AliPayUtil {
22 
23     @Resource
24     private AlipayProperties alipayProperties;
25     /**
26      * 支付接口
27      *
28      * @param alipayBean 封裝的支付寶入參
29      * @return 返回支付結果
30      * @throws AlipayApiException 拋出異常
31      */
32     public String pay(AlipayBean alipayBean) throws AlipayApiException {
33         // 1、獲得初始化的AlipayClient
34         String serverUrl = alipayProperties.getGatewayUrl();
35         String appId = alipayProperties.getAppId();
36         String privateKey = alipayProperties.getPrivateKey();
37         String format = "json";
38         String charset = alipayProperties.getCharset();
39         String alipayPublicKey = alipayProperties.getPublicKey();
40         String signType = alipayProperties.getSignType();
41         String returnUrl = alipayProperties.getReturnUrl();
42         String notifyUrl = alipayProperties.getNotifyUrl();
43         AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, alipayPublicKey, signType);
44         // 2、設置請求參數
45         AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
46         // 頁面跳轉同步通知頁面路徑
47         alipayRequest.setReturnUrl(returnUrl);
48         // 服務器異步通知頁面路徑
49         alipayRequest.setNotifyUrl(notifyUrl);
50         // 封裝參數
51         alipayRequest.setBizContent(JSON.toJSONString(alipayBean));
52         // 3、請求支付寶進行付款,並獲取支付結果
53         return alipayClient.pageExecute(alipayRequest).getBody();
54     }
55 
56 }

   

   2.5.3 訂單狀態枚舉

     

 1 package com.devin.alipay_demo.util;
 2 
 3 /**
 4  * @author Devin Zhang
 5  * @className OrderEnum
 6  * @description TODO
 7  * @date 2020/5/12 11:43
 8  */
 9 
10 public enum OrderEnum {
11     ORDER_STATUS_PAID(1, "已支付"),
12     ORDER_STATUS_NOT_PAY(0, "待支付"),
13 
14     ORDER_STATUS_CANCEL(2, "已取消");
15 
16 
17     private int status;
18     private String statusName;
19 
20     OrderEnum(int status, String statusName) {
21         this.status = status;
22         this.statusName = statusName;
23     }
24 
25     public int getStatus(){
26         return this.status;
27     }
28 
29 
30 }

 

 2.6 dao 

     2.6.1 訂單操作dao

  因為使用了通用mapper tkmybatis,所以dao只是實現了相應的父類

   

 1 package com.devin.alipay_demo.dao;
 2 
 3 import com.devin.alipay_demo.entity.UserOrder;
 4 import tk.mybatis.mapper.common.Mapper;
 5 import tk.mybatis.mapper.common.MySqlMapper;
 6 
 7 /**
 8  * @author Devin Zhang
 9  * @className UserOrderMapper
10  * @description TODO
11  * @date 2020/5/12 10:54
12  */
13 
14 public interface UserOrderMapper extends Mapper<UserOrder>, MySqlMapper<UserOrder> {
15 }

 

    2.6.2 對應的mapper xml文件

   同樣,xml文件中內容也為空

   

1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
3 <mapper namespace="com.devin.alipay_demo.dao.UserOrderMapper" >
4 
5 </mapper>

 

   2.7 service

     service中定義的下單等方法,其中下單時回去調用支付寶

     

 1 package com.devin.alipay_demo.service;
 2 
 3 import com.alipay.api.AlipayApiException;
 4 import com.devin.alipay_demo.dao.UserOrderMapper;
 5 import com.devin.alipay_demo.dto.AlipayBean;
 6 import com.devin.alipay_demo.entity.UserOrder;
 7 import com.devin.alipay_demo.util.AliPayUtil;
 8 import com.devin.alipay_demo.util.OrderEnum;
 9 import org.apache.commons.lang3.time.DateFormatUtils;
10 import org.springframework.stereotype.Service;
11 import tk.mybatis.mapper.entity.Example;
12 
13 import javax.annotation.Resource;
14 import java.math.BigDecimal;
15 import java.util.Date;
16 import java.util.UUID;
17 
18 /**
19  * @author Devin Zhang
20  * @className OrderService
21  * @description TODO
22  * @date 2020/5/12 10:53
23  */
24 
25 @Service
26 public class OrderService {
27 
28 
29     @Resource
30     private UserOrderMapper userOrderMapper;
31 
32     @Resource
33     private AliPayUtil aliPayUtil;
34 
35     /**
36      * 下單
37      *
38      * @param orderAmount 訂單金額
39      * @return 返回支付結果頁面內容
40      * @throws AlipayApiException
41      */
42     public String orderPay(BigDecimal orderAmount) throws AlipayApiException {
43 
44         //1. 產生訂單
45         UserOrder order = new UserOrder();
46         order.setOrderNo(System.currentTimeMillis() + "");
47         order.setUserId(UUID.randomUUID().toString());
48         order.setOrderAmount(orderAmount);
49         order.setOrderStatus(OrderEnum.ORDER_STATUS_NOT_PAY.getStatus());
50         String format = "yyyy-MM-dd HH:mm:ss";
51         order.setCreateTime(DateFormatUtils.format(new Date(), format));
52         order.setLastUpdateTime(DateFormatUtils.format(new Date(), format));
53 
54         userOrderMapper.insert(order);
55 
56         //2. 調用支付寶
57         AlipayBean alipayBean = new AlipayBean();
58         alipayBean.setOut_trade_no(order.getOrderNo());
59         alipayBean.setSubject("充值:" + order.getOrderAmount());
60         alipayBean.setTotal_amount(orderAmount.toString());
61         String pay = aliPayUtil.pay(alipayBean);
62         System.out.println("pay:" + pay);
63         return pay;
64     }
65 
66     /**
67      * 根據訂單號查詢訂單
68      *
69      * @param orderNo
70      * @return 返回訂單信息
71      */
72     public UserOrder getOrderByOrderNo(String orderNo) {
73         Example example = new Example(UserOrder.class);
74         Example.Criteria criteria = example.createCriteria();
75         criteria.andEqualTo("orderNo", orderNo);
76         return userOrderMapper.selectOneByExample(example);
77     }
78 
79     /**
80      * 更新訂單
81      *
82      * @param userOrder 訂單對象
83      * @return 返回更新結果
84      */
85     public int updateOrder(UserOrder userOrder) {
86         return userOrderMapper.updateByPrimaryKeySelective(userOrder);
87     }
88 }

 

  2.8 Controller

   

  1 package com.devin.alipay_demo.controller;
  2 
  3 import com.alipay.api.AlipayApiException;
  4 import com.alipay.api.internal.util.AlipaySignature;
  5 import com.devin.alipay_demo.entity.UserOrder;
  6 import com.devin.alipay_demo.service.OrderService;
  7 import com.devin.alipay_demo.util.AlipayProperties;
  8 import com.devin.alipay_demo.util.OrderEnum;
  9 import org.apache.commons.lang3.time.DateFormatUtils;
 10 import org.springframework.stereotype.Controller;
 11 import org.springframework.web.bind.annotation.PostMapping;
 12 import org.springframework.web.bind.annotation.RequestMapping;
 13 import org.springframework.web.bind.annotation.ResponseBody;
 14 
 15 import javax.annotation.Resource;
 16 import javax.servlet.http.HttpServletRequest;
 17 import javax.servlet.http.HttpServletResponse;
 18 import java.math.BigDecimal;
 19 import java.util.Date;
 20 import java.util.HashMap;
 21 import java.util.Map;
 22 
 23 /**
 24  * @author Devin Zhang
 25  * @className OrderController
 26  * @description TODO
 27  * @date 2020/5/12 10:53
 28  */
 29 
 30 @Controller
 31 @RequestMapping("/order")
 32 public class OrderController {
 33 
 34     @Resource
 35     private OrderService orderService;
 36     @Resource
 37     private AlipayProperties alipayProperties;
 38 
 39     /**
 40      * 跳轉到下單頁面
 41      *
 42      * @return
 43      */
 44     @RequestMapping("/goPay")
 45     public String goPay() {
 46         return "pay";
 47     }
 48 
 49     /**
 50      * 下單,並調用支付寶
 51      *
 52      * @param orderAmount
 53      * @return
 54      * @throws AlipayApiException
 55      */
 56     @PostMapping("/pay")
 57     public void pay(BigDecimal orderAmount, HttpServletResponse httpResponse) throws Exception {
 58         String payResult = orderService.orderPay(orderAmount);
 59         httpResponse.setContentType("text/html;charset=" + alipayProperties.getCharset());
 60         httpResponse.getWriter().write(payResult);
 61         httpResponse.getWriter().flush();
 62         httpResponse.getWriter().close();
 63     }
 64 
 65 
 66     /**
 67      * 支付成功的跳轉頁面
 68      *
 69      * @return
 70      */
 71     @RequestMapping("/goPaySuccPage")
 72     public String goPaySuccPage() {
 73         return "pay_succ";
 74     }
 75 
 76     /**
 77      * 支付成功的回調接口
 78      *
 79      * @return
 80      */
 81     @ResponseBody
 82     @RequestMapping("/notifyPayResult")
 83     public String notifyPayResult(HttpServletRequest request) {
 84         System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<進入支付寶回調->>>>>>>>>>>>>>>>>>>>>>>>>");
 85         // 1.從支付寶回調的request域中取值放到map中
 86         Map<String, String[]> requestParams = request.getParameterMap();
 87 
 88         Map<String, String> params = new HashMap();
 89         for (String name : requestParams.keySet()) {
 90             String[] values = requestParams.get(name);
 91             String valueStr = "";
 92             for (int i = 0; i < values.length; i++) {
 93                 valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
 94             }
 95             params.put(name, valueStr);
 96         }
 97         //2.封裝必須參數
 98         // 商戶訂單號
 99         String outTradeNo = params.get("out_trade_no");
100         //交易狀態
101         String tradeStatus = params.get("trade_status");
102 
103         System.out.println("outTradeNo:" + outTradeNo + " tradeStatus:" + tradeStatus);
104 
105         //3.簽名驗證(對支付寶返回的數據驗證,確定是支付寶返回的)
106         boolean signVerified = false;
107         try {
108             //3.1調用SDK驗證簽名
109             signVerified = AlipaySignature.rsaCheckV1(params, alipayProperties.getPublicKey(), alipayProperties.getCharset(), alipayProperties.getSignType());
110 
111         } catch (Exception e) {
112             e.printStackTrace();
113         }
114         System.out.println("--------------->驗簽結果:" + signVerified);
115 
116         //4.對驗簽進行處理
117 
118         if (signVerified) {
119             //驗簽通過
120             //只處理支付成功的訂單: 修改交易表狀態,支付成功
121             if ("TRADE_FINISHED".equals(tradeStatus) || "TRADE_SUCCESS".equals(tradeStatus)) {
122                 //根據訂單號查找訂單,防止多次回調的問題
123                 UserOrder orderByOrder = orderService.getOrderByOrderNo(outTradeNo);
124                 if (orderByOrder != null && orderByOrder.getOrderStatus() == OrderEnum.ORDER_STATUS_NOT_PAY.getStatus()) {
125                     //修改訂單狀態
126                     orderByOrder.setOrderStatus(OrderEnum.ORDER_STATUS_PAID.getStatus());
127                     orderByOrder.setLastUpdateTime(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
128                     orderService.updateOrder(orderByOrder);
129                 }
130                 return "success";
131             } else {
132                 return "failure";
133             }
134         } else {
135             //驗簽不通過
136             System.err.println("-------------------->驗簽失敗");
137             return "failure";
138         }
139     }
140 
141 
142 }

 

    2.9 啟動類

    

 1 package com.devin.alipay_demo;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import tk.mybatis.spring.annotation.MapperScan;
 6 
 7 @MapperScan("com.devin.alipay_demo.dao")
 8 @SpringBootApplication
 9 public class AlipayDemoApplication {
10 
11     public static void main(String[] args) {
12         SpringApplication.run(AlipayDemoApplication.class, args);
13     }
14 
15 }

 

    2.10 支付寶的配置  alipay.properties

    其中私鑰是我們生成的私鑰,支付寶公鑰可以從開發者沙盒環境拿到

     其中notifyUrl 和 returnUrl 我使用natapp ,將內網的映射到外網,以方便做測試

 1 # 應用ID,您的APPID,收款賬號既是您的APPID對應支付寶賬號
 2 appId:2016102400751401
 3 # 商戶私鑰,您的PKCS8格式RSA2私鑰
 4 privateKey:MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDncMvgR0vP05DtLHSIoboaSd7mCzVMzS3VSxl0RdHf/HPFWcqzZqAgtDOPGd9fWcr3M65HcGEY4F69Rn5SKuBHTuq+QJFkq7i2Px/EtbCjBWK1bMyk+fYwYwgFQ7YB4bYp2ssDAf6fDB0sDdylnAZY4Pr3OyRZFLRsbZvLAMpc5pymtTMa3knbIruxsKkj4Fc0QVAkOZCgnV2tD+KucZAoO88K1MBSnZyiO06cFX6vclpv1W7rb+pLs+2x6bxNNRMy4wf/LWrqkZlFnZrxRyF30FoJGaQY4rSJZ5FOHoputO/H0TAKT3hUjLOlauo9awo7oh/VJq55xMy8TQJU2tE/AgMBAAECggEBALRrEPPAgI/9nH/XZOzSLnKp3XI1kJJTbIRWq/whJY/XjCRvb/3UZcW41Gycva3mILv+dMDKEVdEKXahin3hYL8V/Rbc3Lq+xxqDMO+2t4EOBLnrm8iL92gW+zynYS4sV0ZfglzQ5D32QpOCJtyPOb91ew7Z8ubiphfUhluFPTuXK0MCt5n12tBI8kelGQsf3GP0xCEM1um6Ic3tDKOWwQjH0/CvssIZo5dzdc4WBv1Jgh1YconqT6oLOjfitLs6Py9K8jIrFLE1RWzt0/8L5fEyPqquqrmhML5Dce5qztdxeGDWVqVm/KFZJe8k5l8HtUlQYX7SaJ80G2UZEROQJ2kCgYEA9rszfwhF5rFQJNBKlrOl023IuSVhKmt0o8B/hR1d34y88I7cHGJ6a4+MMookpvKIEAOvdf0r/d0Z6MrQ1ptwkimm2Qa0jbFRSiG7GDJk3gVfpaNOvO3KdGWnbeJ4np51i1I80HGt9HeavyxGSeLI144A8CgK66vPkKF1FBX/vTUCgYEA8CKLzBdg26yG9SRRINA+ATaQM1myitggjk8p1dv7erFeYpKzzIWjvKZvH+kiFtAo0HLhTyF7a8V14m6znVU2SJ22GbBauXmFTjjhCbQvqUwgUjM57oH9EJMCxE9brIPV3VHdEtibQFhS36lg47NM6A5tGCEPb+Bt6dXhtLpJhyMCgYAeCQfpzO4FeUxSTvDli5UCOfkXYM+FRHN8g7CCWeLVleJiPmHZKrvQYDcm594yXI/nsysm59z1GHdQ+W+W0HFRubRP8xsDrLRCm/yUo33X8TuFhG3PXfspVD6fh9Q7KvsQLMCud0g/3FeAMjmUQQFGDElc8uLxcYbhCmagPVVWiQKBgHFNO3y+gxrjGoJL8mNzHe5gmkVASzerpiC/RVP8iXloesozwdX8MDdwp/n8e/MboEZKDfjSKXO+JVMDPIg9jnFQyHzycrwUlEtGFxgHBn3wx0dBmFHqz0aktqd9chnB0oSsfYzI2ufPRLr3JhoJnX3YYK0D3E7DK9kq62Xkh5DVAoGBAPW3Ltan5MT9Ry5D6W6ROPoPfl4Sy7C13FjFlujC8LcwsGoIt3+cKntDv7CJuiLoBDf+JtF9v8OSMlhYzy1ozLpVrO7Xn2k1fO76sotlXxsI3cqwnUlkcOuF7TpnHWGVnFGj7/9bPdIOEfnikdDTmxvqUSD9QdvhVtWfFECr2hlw
 5 # 支付寶公鑰,不是應用公鑰 查看地址:https://openhome.com/platform/keyManage.htm 對應APPID下的支付寶公鑰。
 6 publicKey:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqOl0nOy/amFKACzBMpO2uvibXOJbehvdMFUMxJMomtYp1RfqvTddsPtGPtX6EX8LFzKB5HC4Ew8rMlh+qvCQctcJfLOsYgK1W8dReLqRxsvMDBtrvDPGVKJwJFmRCbvqWX5b4BOj2fhCP1q0GfS9wsYTP08Xvwq2bDx4OpqdMMi04MPNomIgjgIZmUKeUepsOb0K7rUsgB0OZ6h2RxwKX8BTh2I8AiCU1bvYu6dKpikXz0x72JUg5l69gQCWe6CYHlUSu+gakTz648/GZ6pJXiMzQeemdcytczHrbzA7b3GqtnC5Fj+mxe5E3Upi5MOm82Tl6H3GOyXJ1OuKXdJj1wIDAQAB
 7 # 服務器異步通知頁面路徑需http://格式的完整路徑,不能加?id=123這類自定義參數
 8 notifyUrl:http://mf5s4k.natappfree.cc/order/notifyPayResult
 9 # 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數
10 returnUrl:http://mf5s4k.natappfree.cc/order/goPaySuccPage
11 # 簽名方式
12 signType:RSA2
13 # 字符編碼格式
14 charset:utf-8
15 # 支付寶網關
16 gatewayUrl:https://openapi.alipaydev.com/gateway.do
17 # 日志路徑
18 logPath:"d:\\data\\"

 

    2.11 應用設置application.yml

  

 1 # https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html spring\u914D\u7F6E\u7684\u6587\u6863
 2 server:
 3   port: 10086
 4 
 5 spring:
 6   servlet:
 7     multipart:
 8       max-request-size: 100MB #最大請求文件的大小
 9       max-file-size: 20MB #設置單個文件最大長度
10   mvc:
11     view:
12       prefix: /
13       suffix: .html
14   datasource:
15       platform: mysql
16       type: com.alibaba.druid.pool.DruidDataSource
17       initialSize: 3
18       minIdle: 1
19       maxActive: 500     
20       maxWait: 60000     
21       timeBetweenEvictionRunsMillis: 60000      
22       minEvictableIdleTimeMillis: 30000
23       validationQuery: select 1     
24       testOnBorrow: true      
25       poolPreparedStatements: true
26       maxPoolPreparedStatementPerConnectionSize: 20     
27       driverClassName: com.mysql.jdbc.Driver
28 
29       url: jdbc:mysql://localhost:3306/order_db?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8&useAffectedRows=true&rewriteBatchedStatements=true
30 
31       username: root
32       password: root
33 mybatis:
34 #  config-location: classpath:mybatis-config.xml
35   mapper-locations: classpath:mapper/*.xml
36   type-aliases-package: com.devin.alpay_demo.entity
37 #  configuration:
38 #    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
39 #配置分頁插件pagehelper
40 pagehelper:
41     helperDialect: mysql
42     reasonable: true
43     supportMethodsArguments: true
44     params: count=countSql

 

    2.12 下單頁面

   

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>order pay</title>
 6     <script type="text/javascript" src="/js/jquery-1.8.2.js"></script>
 7 </head>
 8 <body>
 9 <form action="/order/pay" method="post">
10     金額:<input id="orderAmount" name="orderAmount"><br>
11     <input type="submit">
12 </form>
13 </body>
14 </html>

 

     2.13 支付成功跳轉頁面

      該頁面即為上面支付寶配置的returnUrl  

    

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 充值成功!
</body>
</html>

 

  3.  測試

   啟動程序,訪問 http://localhost:10086/order/goPay,輸入金額后點擊去支付,可以看到訂單已經產生,並跳轉到支付寶掃碼支付頁面

    

   

 

 

 

 

 

 

  

 

  

  此時,我們可以去數據庫里面看到,訂單已經產生,並且此時訂單的狀態是待付款

  

 

 

 

   下載支付寶沙盒app,登錄測試賬號,掃碼付款后可以看到,可以付款成功,並且回調也調用成功,訂單狀態變為已支付。

    沙盒支付寶下載: https://sandbox.alipaydev.com/user/downloadApp.htm

    沙盒測試賬號可以在開發者平台上看到

    

 

 

 

 

 

 

 

支付后結果

 

 

  至此,支付寶的對接完成。

  完整的代碼git地址: https://github.com/devinzhang0209/alipay_demo.git

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM