2021-06-25

前言:最近对接了微信JSAPI接口(V3版本),在此记录一下。以便之后可以快速定位

接入之前的准备事项,可以先观看官方文档。把需要准备的一些信息都准备好。

传送门:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_1.shtml

1.选择接入模式

直连模式

2.参数申请如下:

​ 2.1 申请APPID

​ 2.2 申请mchid

​ 2.3 登录微信小程序后端,绑定APPID及mchid

3.配置API key

API v3密钥主要用于平台证书解密、回调信息解密,具体使用方式可参见接口规则文档中证书和回调报文解密章节。

请根据以下步骤配置API key:

  • 1登录微信商户平台,进入【账户中心 > API安全 > API安全】目录,点击【设置密钥】。

    img

  • 2在弹出窗口中点击“已沟通”。

    img

  • 3输入API密钥,内容为32位字符,包括数字及大小写字母。点击获取短信验证码。

    img

    img

  • 4输入短信验证码,点击“确认”即设置成功。

4.下载并配置商户证书

商户API证书具体使用说明可参见接口规则文档中私钥和证书章节

商户可登录微信商户平台,在【账户中心】->【API安全】->【API证书】目录下载证书

以下为具体下载步骤:

  • 1从2018年底开始,微信支付新入驻机构及商户都将使用CA签发证书,在证书申请页面上点击“下载证书”。

    img

  • 2在弹出窗口内点击“下载证书工具”按钮下载证书工具。

    img

  • 3安装证书工具并打开,选择证书需要存储的路径后点击“申请证书”。

    img

  • 4在证书工具中,将复制的商户信息粘贴并点击“下一步”。

    img

  • 5获取请求串

    img

    img

    img

  • 6生成证书串

    步骤1 在【商户平台】-“复制证书串”环节,点击“复制证书串”按钮后;

    步骤2 在【证书工具】-“复制请求串”环节,点击“下一步”按钮进入“粘贴证书串”环节;

    步骤3 在【证书工具】-“粘贴证书串”环节,点击“粘贴”按钮后;

    步骤4 点击“下一步”按钮,进入【证书工具】-“生成证书”环节

    img

    img

    img

  • 7在【证书工具】-“生成证书”环节,已完成申请证书流程,点击“查看证书文件夹”,查看已生成的证书文件。

5.配置应用

设置支付目录

支付授权目录说明

1)商户最后请求拉起微信支付收银台的页面地址我们称之为“支付目录”,例如:https://www.weixin.com/pay.php。

2)商户实际的支付目录必须和在微信支付商户平台设置的一致,否则会报错“当前页面的URL未注册:”

支付授权目录设置说明

登录【微信支付商户平台—>产品中心—>开发配置】,设置后一般5分钟内生效。

支付授权目录校验规则说明

1)如果支付授权目录设置为顶级域名(例如:https://www.weixin.com/ ),那么只校验顶级域名,不校验后缀;

2)如果支付授权目录设置为多级目录,就会进行全匹配,例如设置支付授权目录为https://www.weixin.com/abc/123/,则实际请求页面目录不能为https://www.weixin.com/abc/,也不能为https://www.weixin.com/abc/123/pay/,必须为https://www.weixin.com/abc/123/

img

设置授权域名

开发JSAPI支付时,在JSAPI下单接口中要求必传用户openid,而获取openid则需要您在微信公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。具体界面如图所示:

img

img

**开通流程:**在入驻时选择线下场所,公众号场景,PC网站场景的商户系统默认开通此功能,其他商户如有需要,可以在入驻后前往商户平台-产品中心-JSAPI支付-申请开通。

温馨提示:准备里的东西都要弄好,不然无法正常对接。(大神请忽略)

以上的参数都准备好之后,开始正式操作。

需要把证书都下载下来。放到resource文件夹中。

在这里插入图片描述

配置参数model,我是通过ConfigurationProperties注解进行注入。也可以用别的方法。

WeChatConfig.java

@Component
@ConfigurationProperties(prefix = "xxxxx")
public class WeChatConfig {
    /**
     * 微信APPID
     */
    public static String appID;

    /**
     * 微信APP密码
     */
    public static String appSecret ;

    /**
     * 商户号
     */
    public static String mchId;

    /**
     * 商户KEY
     */
    public static String mchKey;

    /**
     * 通知地址
     */
    public static String notifyUrl;

    /**
     * 证书序列号
     */
    public static String serialNo;

    /**
     * apiV3密钥
     */
    public static String apiV3Key;


    public void setSerialNo(String serialNo) {
        this.serialNo = serialNo;
    }

    public void setApiV3Key(String apiV3Key) {
        this.apiV3Key = apiV3Key;
    }

    public void setAppID(String appID) {
        this.appID = appID;
    }

    public void setAppSecret(String appSecret) {
        this.appSecret = appSecret;
    }

    public void setMchId(String mchId) {
        this.mchId = mchId;
    }

    public void setMchKey(String mchKey) {
        this.mchKey = mchKey;
    }

    public void setNotifyUrl(String notifyUrl) {
        this.notifyUrl = notifyUrl;
    }

}

配置工具类

payUtil.java(工具类可以通过下载官方demo获得里面的方法)

public class PayUtil {

    // 统一下单(JSAPI)
    public static final String ORDER_PAY_JSAPI = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";

    /**
     * 创建支付随机字符串
     *
     * @return
     */
    public static String getNonceStr() {
        return IdUtils.fastSimpleUUID().replaceAll("-", "");
    }

    /**
     * V3  SHA256withRSA 签名.
     *
     * @param appId       请求方法  GET  POST PUT DELETE 等
     * @param timestamp    当前时间戳   因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持一致
     * @param nonceStr     随机字符串  要和TOKEN中的保持一致
     * @return the string
     */
    public static String sign(String appId, long timestamp, String nonceStr,String packageKey)
            throws Exception {
        String signatureStr = buildMessage(appId,timestamp,nonceStr,packageKey);
        Signature sign = null;
        PrivateKey privateKey = getPrivateKey("xxxxxxxxxx.pem");
        sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(signatureStr.getBytes("utf-8"));
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    /**
     * 配置请求头的签名
     */
    public static CloseableHttpClient wxClient() throws IOException {

        //excel模板路径
        ClassPathResource cpr = new ClassPathResource("xxxxxxxxxx.pem");
        // IO流
        InputStream ioStream = cpr.getInputStream();
        byte[] getData = readInputStream(ioStream);
        ioStream.read(getData);
        String content = new String(getData);

        // 加载商户私钥(privateKey:私钥字符串)
        PrivateKey merchantPrivateKey = PemUtil
                .loadPrivateKey(new ByteArrayInputStream(
                        content.getBytes(StandardCharsets.UTF_8)));;

        // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3秘钥)
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(WeChatConfig.mchId,
                        new PrivateKeySigner(WeChatConfig.serialNo,
                                merchantPrivateKey)), WeChatConfig.apiV3Key.getBytes(StandardCharsets.UTF_8));

        // 初始化httpClient
        return WechatPayHttpClientBuilder.create()
                .withMerchant(WeChatConfig.mchId, WeChatConfig.serialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();
    }

    /**
     * 获取私钥。
     *
     * @param filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException {

        //excel模板路径
        ClassPathResource cpr = new ClassPathResource(filename);
        // IO流
        InputStream ioStream = cpr.getInputStream();
        byte[] getData = readInputStream(ioStream);
        ioStream.read(getData);
        String content = new String(getData);
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }

    public static  byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }

    private static String buildMessage(String appId, long timestamp, String nonceStr, String packageKey) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packageKey + "\n";
    }

}

调用JSAPI统一下单接口获取preparey_id

Map<String, Object> param2 = new LinkedHashMap<String, Object>();
// 应用ID
param2.put("appid", WeChatConfig.appID);
// 直连商户号
param2.put("mchid", WeChatConfig.mchId);
// 通知地址
param2.put("description", "xxxxx");
// 通知地址
param2.put("notify_url", WeChatConfig.notifyUrl);
// 商户订单号
param2.put("out_trade_no", uuid);
// 订单金额
Map<String,Object> moneyMap = new LinkedHashMap<String, Object>();
moneyMap.put("total",amounts); // 金额
param2.put("amount",moneyMap);
// 支付者
Map<String,Object> payerMap = new LinkedHashMap<String, Object>();
payerMap.put("openid",openid);
param2.put("payer",payerMap);

// 请求微信获取预支付信息
String json =  JSON.toJSONString(param2);

HttpPost httpPost = new HttpPost(PayUtil.ORDER_PAY_JSAPI);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type","application/json; charset=utf-8");

httpPost.setEntity(new StringEntity(json, StandardCharsets.UTF_8));
/*打开wx链接,配置请求头签名*/
CloseableHttpClient client = PayUtil.wxClient();
CloseableHttpResponse response = client.execute(httpPost);

/*返回数据*/
String bodyAsString = EntityUtils.toString(response.getEntity());
client.close();

/*请求状态code*/
int statusCode = response.getStatusLine().getStatusCode();
response.close();

if (statusCode == 200) {
                    JSONObject jsonObject = JSON.parseObject(bodyAsString);
                    /*获取主要信息*/
                    String preperId = jsonObject.getString("prepay_id");

                    // 返回参数示例
                    Map<String,Object> returnParams = new LinkedHashMap<>();
                    // 参数
                    String appId = WeChatConfig.appID;
                    Long timestamp = System.currentTimeMillis() / 1000;
                    String nonceStr = PayUtil.getNonceStr();

                    // 返回前台参数
                    returnParams.put("package","prepay_id="+preperId);
                    returnParams.put("appId",appId);
                    returnParams.put("billId",bill.getId());
                    returnParams.put("timeStamp",timestamp);
                    returnParams.put("nonceStr",nonceStr);
                    returnParams.put("signType","RSA");
                    returnParams.put("paySign",PayUtil.sign(appId,timestamp,nonceStr,String.valueOf(returnParams.get("package"))));
                    // 返回请求参数
                    return AjaxResult.success(returnParams);
    else{
                    return AjaxResult.error("请求微信获取预支付信息 不正确");
                }

如果获得了正确的preparey_id,把所需的参数返回前端。前端根据参数调起支付收银台即可。我用的是uniapp。uniapp有封装。所以我前段是这么调用的。

// 仅作为示例,非真实参数信息。
uni.requestPayment({
    provider: 'wxpay',
    timeStamp: 返回的timeStamp,
    nonceStr: '返回的nonceStr',
    package: '返回的package',
    signType: '返回的signType',
    paySign: '',
    success: function (res) {
        console.log('success:' + JSON.stringify(res));
    },
    fail: function (err) {
        console.log('fail:' + JSON.stringify(err));
    }
});

完接撒花!!!!!!!!!!!!!!!!

有一个小坑的地方。如果出现下面的问题。是因为JRE本身中自带的“local_policy.jar ”和“US_export_policy.jar”只支持128位密钥的加密算法
在这里插入图片描述
解决办法:下载 Java Security(JCE)

下载地址:
链接: https://pan.baidu.com/s/1MP8i8TsOaXKMqBpdR89utw 提取码: 5nyg

使用方式
下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt

4.2 如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件 (可以先备份原先的)
4.3 如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用python的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
06-03
这里是使用 Python 的 PyMySQL 完成上述任务的代码: ```python import pymysql # 连接数据库 conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', database='test') # 创建游标 cur = conn.cursor() # 创建 users 表 cur.execute(''' CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(20), age INT ) ''') # 创建 orders 表 cur.execute(''' CREATE TABLE orders ( id INT PRIMARY KEY, order_date DATE, amount INT, user_id INT, FOREIGN KEY (user_id) REFERENCES users(id) ) ''') # 插入数据 users_data = [ (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28) ] orders_data = [ (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4) ] for user in users_data: cur.execute('INSERT INTO users VALUES (%s, %s, %s)', user) for order in orders_data: cur.execute('INSERT INTO orders VALUES (%s, %s, %s, %s)', order) # 提交事务 conn.commit() # 查询语句 # 1. 查询订单总金额 cur.execute('SELECT SUM(amount) FROM orders') print(cur.fetchone()[0]) # 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 cur.execute('SELECT ROUND(AVG(age), 2) FROM users') print(cur.fetchone()[0]) # 3. 查询订单总数最多的用户的姓名和订单总数。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_orders DESC LIMIT 1 ''') print(cur.fetchone()) # 4. 查询所有不重复的年龄。 cur.execute('SELECT DISTINCT age FROM users') print([row[0] for row in cur.fetchall()]) # 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 cur.execute('SELECT SUM(amount) FROM orders WHERE order_date BETWEEN "2021-09-01" AND "2021-09-04"') print(cur.fetchone()[0]) # 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders FROM users JOIN orders ON users.id = orders.user_id WHERE age <= 25 GROUP BY users.id ORDER BY total_orders DESC ''') print(cur.fetchall()) # 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC LIMIT 3 ''') print(cur.fetchall()) # 8. 查询订单总金额最大的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC LIMIT 1 ''') print(cur.fetchone()) # 9. 查询订单总金额最小的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount ASC LIMIT 1 ''') print(cur.fetchone()) # 10. 查询所有名字含有“李”的用户,按照名字升序排序。 cur.execute('SELECT * FROM users WHERE name LIKE "%李%" ORDER BY name ASC') print(cur.fetchall()) # 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 cur.execute('SELECT * FROM users WHERE age > 20 ORDER BY age DESC LIMIT 5') print(cur.fetchall()) # 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC ''') print(cur.fetchall()) # 关闭游标和连接 cur.close() conn.close() ``` 注意:在运行代码之前,需要先安装 PyMySQL 模块,可以使用以下命令进行安装: ``` pip install pymysql ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值