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

 

posted @ 2020-05-12 16:54  devin_w_zhang  阅读(3175)  评论(0编辑  收藏  举报