uniapp H5如何支持微信扫码支付

5 篇文章 0 订阅
4 篇文章 0 订阅

1.背景

通常使用到微信扫描支付的场景,基本是在PC端,或者Android大屏端, 如京东商城PC端购物,或者在大街上饮料机购买饮料,都会用到扫码支付。那么如何

2.疑问:uniapp H5如何支持微信扫描支付

微信h5下单流程图
在流程图的第2步,商家后台向微信后台申请统一支付订单,微信后台会返回一个支付url(形式通常是weixin://wxpay/bizpayurl?pr=xxxxxx), 这个支付url就是支付的入口, 这个支付url在浏览器通常是不能访问的,它往往呈现在用户面前的是一个二维码, 那么如何转换呢?

3.两种方法转换

3.1 方法1: 在客户端转换

在浏览器端,收到收到url后,使用 js (如QRCode.js) 对支付url 进行转换,并显示相应的图片。

3.2 方法2: 在服务端转换

在商家后台端,收到url后,用相应的库(java的通常使用com.google.zxing),把支付url 转换成二维码图片,然后浏览器端显示该图片。

由于方法2,更具普适性,后面的样例代码只提供方法2的,方法1的自行度娘了。
扫码支付页面
使用微信客户端,扫描以上二维码,扫码的结果是 weixin://wxpay/bizpayurl?pr=f9qZqIJzz ,微信客户端会识别该url, 并按流程唤起微信支付。

4.参考代码

4.1 uniApp端

<template>
	<view class="container">
		<top-layout topTitle="支付"></top-layout>

		<main-layout :alignLeft="false">
			<template v-slot:contentPage>

				<total-layout btnText='确认支付' :isShowPrice="false" :btnBackFunc="goBack" :btnWantToFunc="confirmPay"
					:price="totalPrice">
					<template v-slot:page>

						<view class="list" :style="{height: windowHeight + 'px'}">
							<view class="price-area">
								<view class="price-title">应付金额:</view>
								<view class="shop-price">
									<text>¥</text>
									<text class="shop-price-text">{{ integerPriceStr }}</text>
									<text>{{ decimalPriceStr }}</text>
								</view>
							</view>

							<uni-section style="margin-top: 8px;" title="请选择支付方式" type="line">
								<view class="uni-list">
									<radio-group @change="payModeChange">
										<label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in payModes" :key="item.value">
											<view>
												<radio :value="item.value" :checked="index === currPayModeIndex" />
											</view>
											<image class="payImg" :src="item.imgUrl" mode="aspectFill"></image>
											<view>{{item.text}}</view>
										</label>
									</radio-group>
								</view>

							</uni-section>
						</view>

						<uni-popup ref="popupQrCode" type="bottom" :is-mask-click="false" background-color="white" :round="10">
							<view class="payCode-title">请使用微信扫码完成支付</view>
							<view style="text-align: center;">
								<image class="payCode-img" :src="payCodeImgUrl" mode="widthFix"></image>
							</view>

							<view class="woodsbtn_cancle uni-bg-red" @click="cancelQrCodePay">取消支付</view>
							<view class="woodsbtn_finish" @click="finishPay">支付完成,通知商家</view>
						</uni-popup>


					</template>
				</total-layout>

			</template>
		</main-layout>


	</view>
</template>
	export default {
		data() {
			return {
				windowHeight: 0,

				orderName: "", //订单名称
				orderNo: "", //订单号
				orderType: 0, //订单类型, 0-未知,10-商城订单
				totalPrice: 0, //订单合计
				totalNum: 0, //订单商品总数量

				integerPriceStr: "0",
				decimalPriceStr: ".00",

				goods: [],

				payModes: [],

				currPayModeIndex: 0,

				payCodeImgUrl: "",

				loginPageUrl: "",
			};
		},
		onLoad(options) {
			const sys = uni.getSystemInfoSync()
			this.windowHeight = sys.windowHeight
			this.payModes = [{
				text: '微信扫码支付',
				value: "20",
				imgUrl: "/static/images/pay/wx.png",
			}];		
		},

		confirmPay(orderNo, user) {
			let that = this

			let orderData = {}
			orderData.memberId = user.id;
			orderData.memberName = user.name;
			orderData.orderNo = orderNo; //订单号
			orderData.payMode = that.payModes[that.currPayModeIndex].value; //支付方式

			//正式请求支付信息
			request({
				url: '/mallOrder/requestPay',
				data: orderData,
				method: 'POST'
			}).then((res) => {
				if (res.code === '0') {
					let orderPayInfo = res.data;
					console.log('商城订单请求支付成功.订单号=' + orderPayInfo.orderNo);


					if (orderPayInfo.payMode === 20) {
						//微信扫码支付
						if (orderPayInfo.payStatus === 10) {
							//10-未支付, 弹出扫码窗口。
							console.info('支付URL=' + orderPayInfo.payCodeUrl);

							if (orderPayInfo.payCodeImgUrl) {
								that.payCodeImgUrl = config.QRCODE_BASE_URL + orderPayInfo.payCodeImgUrl;
							}

							that.openPopupQrCode()


						} else {
							uni.showToast({
								title: '支付失败!' + res.msg,
								icon: 'error',
								duration: 2000
							});

						}
					} 
				} else {
					uni.showToast({
						title: '提交商城订单支付失败.' + res.msg,
						icon: 'error',
						duration: 2000
					});

				}
			});

		},
	}

4.2 java 后台端

    /**
     * 生成二维码到Image
     * @author madifu
     * @param text			文字内容
     * @param logoPath		LOGO文件路径,如果没有LOGO可填空白
     * @param note			说明
     * @return	= null 表示失败
     * @throws WriterException
     * @throws IOException
     */
    private static BufferedImage drawQRCodeImage(String text, String logoPath, String note ) throws WriterException, IOException {
        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        // 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
        BitMatrix bm = multiFormatWriter.encode(text, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        BufferedImage outImage = new BufferedImage(QRCODE_SIZE, QRCODE_SIZE, BufferedImage.TYPE_INT_RGB);

        // 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色
        for (int x = 0; x < QRCODE_SIZE; x++) {
            for (int y = 0; y < QRCODE_SIZE; y++) {
                outImage.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }

        int width = outImage.getWidth();
        int height = outImage.getHeight();
        if (checkImageExist(logoPath)) {
            // 构建绘图对象
            Graphics2D g = outImage.createGraphics();
            // 读取Logo图片
            BufferedImage logo = ImageIO.read(new File(logoPath));
            // 开始绘制logo图片
            g.setBackground(Color.WHITE);
            g.clearRect(width * 2 / 5, height * 2 / 5, width * 2 / 10, height * 2 / 10);
            g.drawImage(logo, width * 2 / 5, height * 2 / 5, width * 2 / 10, height * 2 / 10, null);
            g.dispose();
            logo.flush();
        }

        // 自定义文本描述
        if (!StringUtils.isEmpty(note)) {
            // 新的图片,把带logo的二维码下面加上文字
            BufferedImage noteImage = new BufferedImage(QRCODE_SIZE, QRCODE_SIZE+40, BufferedImage.TYPE_4BYTE_ABGR);
            Graphics2D outg = noteImage.createGraphics();
            // 画二维码到新的面板
            outg.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
            // 画文字到新的面板
            outg.setColor(Color.BLACK);
            outg.setFont(new Font("宋体", Font.BOLD, 30)); // 字体、字型、字号
            int strWidth = outg.getFontMetrics().stringWidth(note);
            if (strWidth >= QRCODE_SIZE) {
                // //长度过长就截取前面部分
                // 长度过长就换行
                String note1 = note.substring(0, note.length() / 2);
                String note2 = note.substring(note.length() / 2, note.length());
                int strWidth1 = outg.getFontMetrics().stringWidth(note1);
                int strWidth2 = outg.getFontMetrics().stringWidth(note2);
                outg.drawString(note1, (QRCODE_SIZE - strWidth1)/ 2, height + (noteImage.getHeight() - height) / 2 + 12);
                BufferedImage noteImage2 = new BufferedImage(QRCODE_SIZE, QRCODE_SIZE+80, BufferedImage.TYPE_4BYTE_ABGR);
                Graphics2D outg2 = noteImage2.createGraphics();
                outg2.drawImage(noteImage, 0, 0, noteImage.getWidth(), noteImage.getHeight(), null);
                outg2.setColor(Color.BLACK);
                outg2.setFont(new Font("宋体", Font.BOLD, 30)); // 字体、字型、字号
                outg2.drawString(note2, 200 - strWidth2 / 2,
                        noteImage.getHeight() + (noteImage2.getHeight() - noteImage.getHeight()) / 2 + 5);
                outg2.dispose();
                noteImage2.flush();
                noteImage = noteImage2;
            } else {
                //outg.drawString(note, 200 - strWidth / 2, height + (outImage.getHeight() - height) / 2 + 12); // 画文字
                outg.drawString(note, (QRCODE_SIZE - strWidth) / 2, height + (noteImage.getHeight() - height) / 2 + 12); // 画文字

            }
            outg.dispose();
            noteImage.flush();
            outImage = noteImage;
        }
        outImage.flush();

        return outImage;
    }

5.参考文章

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码递夫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值