SpringBoot整合微信支付

微信支付简介

商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付。
在这里插入图片描述
业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。

(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;

(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。

(4)商户后台系统根据返回的code_url生成二维码。

(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。

(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。

(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。

(8)微信支付系统根据用户授权完成支付交易。

(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。

(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。

(11)未收到支付通知的情况,商户后台系统调用【查询订单API】(查单实现可参考:支付回调和查单实现指引)。

(12)商户确认订单已支付后给用户发货。

生成微信支付二维码

应用场景
除付款码支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易会话标识后再按Native、JSAPI、APP等不同场景生成交易串调起支付。
本次按Native
状态机
在这里插入图片描述
接口链接
URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

URL地址:https://api2.mch.weixin.qq.com/pay/unifiedorder(备用域名)见跨城冗灾方案

是否需要证书:否
具体要传入参数,参考下面文档
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

SpringBoot工程搭建

引入依赖

<dependencies>
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
             <version>1.2.28</version>
        </dependency>
         <!--httpclient-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
             <version>4.5.1</version>
        </dependency>

    </dependencies>

工具类

1.根据时间和随机生成数组合成订单号

**
 * 订单号工具类
 *
 * @author qy
 * @since 1.0
 */
public class OrderNoUtil {

    /**
     * 获取订单号
     * @return
     */
    public static String getOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String newDate = sdf.format(new Date());
        String result = "";
        Random random = new Random();
        for (int i = 0; i < 3; i++) {
            result += random.nextInt(10);
        }
        return newDate + result;
    }

}

2.发送请求类 HttpClient

/**
 * http请求客户端
 * 
 * @author qy
 * 
 */
public class HttpClient {
	private String url;
	private Map<String, String> param;
	private int statusCode;
	private String content;
	private String xmlParam;
	private boolean isHttps;

	public boolean isHttps() {
		return isHttps;
	}

	public void setHttps(boolean isHttps) {
		this.isHttps = isHttps;
	}

	public String getXmlParam() {
		return xmlParam;
	}

	public void setXmlParam(String xmlParam) {
		this.xmlParam = xmlParam;
	}

	public HttpClient(String url, Map<String, String> param) {
		this.url = url;
		this.param = param;
	}

	public HttpClient(String url) {
		this.url = url;
	}

	public void setParameter(Map<String, String> map) {
		param = map;
	}

	public void addParameter(String key, String value) {
		if (param == null)
			param = new HashMap<String, String>();
		param.put(key, value);
	}

	public void post() throws ClientProtocolException, IOException {
		HttpPost http = new HttpPost(url);
		setEntity(http);
		execute(http);
	}

	public void put() throws ClientProtocolException, IOException {
		HttpPut http = new HttpPut(url);
		setEntity(http);
		execute(http);
	}

	public void get() throws ClientProtocolException, IOException {
		if (param != null) {
			StringBuilder url = new StringBuilder(this.url);
			boolean isFirst = true;
			for (String key : param.keySet()) {
				if (isFirst)
					url.append("?");
				else
					url.append("&");
				url.append(key).append("=").append(param.get(key));
			}
			this.url = url.toString();
		}
		HttpGet http = new HttpGet(url);
		execute(http);
	}

	/**
	 * set http post,put param
	 */
	private void setEntity(HttpEntityEnclosingRequestBase http) {
		if (param != null) {
			List<NameValuePair> nvps = new LinkedList<NameValuePair>();
			for (String key : param.keySet())
				nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
			http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
		}
		if (xmlParam != null) {
			http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
		}
	}

	private void execute(HttpUriRequest http) throws ClientProtocolException,
			IOException {
		CloseableHttpClient httpClient = null;
		try {
			if (isHttps) {
				SSLContext sslContext = new SSLContextBuilder()
						.loadTrustMaterial(null, new TrustStrategy() {
							// 信任所有
							public boolean isTrusted(X509Certificate[] chain,
									String authType)
									throws CertificateException {
								return true;
							}
						}).build();
				SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
						sslContext);
				httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
						.build();
			} else {
				httpClient = HttpClients.createDefault();
			}
			CloseableHttpResponse response = httpClient.execute(http);
			try {
				if (response != null) {
					if (response.getStatusLine() != null)
						statusCode = response.getStatusLine().getStatusCode();
					HttpEntity entity = response.getEntity();
					// 响应内容
					content = EntityUtils.toString(entity, Consts.UTF_8);
				}
			} finally {
				response.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			httpClient.close();
		}
	}

	public int getStatusCode() {
		return statusCode;
	}

	public String getContent() throws ParseException, IOException {
		return content;
	}

}

controller

@ApiOperation(value = "根据订单编号生成支付二维码")
    @GetMapping("createNative/{orderNo}")
    public R createNative(@PathVariable String orderNo){
        Map<String,Object> map= payLogService.createNative(orderNo);
        return R.ok().data(map);
    }

service

//根据订单编号生成支付二维码
    @Override
    public Map<String, Object> createNative(String orderNo) {
        try {
            //1查询订单信息
            QueryWrapper<TOrder> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("order_no", orderNo);
            TOrder order = orderService.getOne(queryWrapper);
            //1.1校验订单
            if (order == null) {
                throw new GuliException(20001, "订单失效");
            }
            //2封装支付参数
            Map m = new HashMap();
            //设置支付参数
            m.put("appid", "wx74862e0dfcf69954");//必填应用id
            m.put("mch_id", "1558950191");//必填商户号
            m.put("nonce_str", WXPayUtil.generateNonceStr());//必填微信生成随机字符串
            m.put("body", order.getCourseTitle());//自己的业务内容课程名称
            m.put("out_trade_no", orderNo);//订单编号
            m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue() + "");//交易金额
            m.put("spbill_create_ip", "127.0.0.1");//终端ip
            m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");//必填回调地址
            m.put("trade_type", "NATIVE");//交易类型
            //3通过httpclient发送请求,参数转化成xml
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");//官方请求地址

            //client设置参数
            client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));//必填商户密钥
            client.setHttps(true);
            client.post();
            //4 获取返回值
            String xml = client.getContent();
            System.out.println("xml=" + xml);
            //解析返回map集合
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
            //5、封装返回结果集

            Map map = new HashMap<>();
            map.put("out_trade_no", orderNo);//订单号
            map.put("course_id", order.getCourseId());//自定义的商品id
            map.put("total_fee", order.getTotalFee());//金额
            map.put("result_code", resultMap.get("result_code"));//支付结果码
            map.put("code_url", resultMap.get("code_url"));//支付二维码链接
            return map;

        } catch (Exception e) {
            e.printStackTrace();
            throw new GuliException(20001, "获取二维码失败");

        }


    }

返回的结果例子如下:

<xml>
   <appid>wx2421b1c4370ec43b</appid>
   <attach>支付测试</attach>
   <body>JSAPI支付测试</body>
   <mch_id>10000100</mch_id>
   <detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]></detail>
   <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
   <notify_url>https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>
   <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
   <out_trade_no>1415659990</out_trade_no>
   <spbill_create_ip>14.23.150.211</spbill_create_ip>
   <total_fee>1</total_fee>
   <trade_type>JSAPI</trade_type>
   <sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>

最后把返回的code_url支付二维码链接,放进前端的二维码里面即可

查询支付情况

应用场景
该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。

需要调用查询接口的情况:

◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知(查单实现可参考:支付回调和查单实现指引);
◆ 调用支付接口后,返回系统错误或未知交易状态情况;
◆ 调用付款码支付API,返回USERPAYING的状态;
◆ 调用关单或撤销接口API之前,需确认支付状态;

接口链接
URL地址:https://api.mch.weixin.qq.com/pay/orderquery

URL地址:https://api2.mch.weixin.qq.com/pay/orderquery(备用域名)见跨城冗灾方案

是否需要证书:不需要
请求参数看文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_2

controller

@GetMapping("queryPayStatus/{orderNo}")
    @ApiOperation(value = "根据订单编号查询支付状态")
    public R queryPayStatus(@PathVariable String orderNo) {
        //1调用微信接口查询支付状态
        Map<String, String> map = payLogService.queryPayStatus(orderNo);
        //2判断支付状态
        if (map == null) {
            return R.error().message("支付出错");
        }
        if ("SUCCESS".equals(map.get("trade_state"))) {
            //3 支付成功后,更新订单状态,记录支付日志
            payLogService.updateOrderStatus(map);
            return R.ok().message("支付成功");
        }
        return R.ok().code(25000).message("支付中");
    }

service


    //调用微信接口查询支付状态
    @Override
    public Map<String, String> queryPayStatus(String orderNo) {

        try {
            //1封装支付参数
            Map m = new HashMap();
            //设置支付参数
            m.put("appid", "wx74862e0dfcf69954");//必填应用id
            m.put("mch_id", "1558950191");//必填商户号
            m.put("out_trade_no", orderNo);//必填订单号
            m.put("nonce_str", WXPayUtil.generateNonceStr());//微信工具生成随机字符
            //2、设置请求
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");//官方查询请求地址
            client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));//商户密钥
            client.setHttps(true);
            client.post();
            //3、返回第三方的数据
            String xml = client.getContent();
            System.out.println("订单状态="+xml);
            //转义成map
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
            //6、转成Map
            //7、返回
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuliException(20001,"查询订单状态失败");
        }


    }

返回结果例子:

<xml>
   <appid>wx2421b1c4370ec43b</appid>
   <mch_id>10000100</mch_id>
   <nonce_str>ec2316275641faa3aacf3cc599e8730f</nonce_str>
   <transaction_id>1008450740201411110005820873</transaction_id>
   <sign>FDD167FAA73459FD921B144BAF4F4CA2</sign>
</xml>

提示

前端可以设置定时器每隔几秒查询一次支付状态,直到支付成功或失败

//每隔5秒钟,查询一下订单支付状态
  //需要创建定时器setIntervar(()=>{},5000)
  data() {
    return {
      timer1: ""
    };
  },
  mounted() {
    this.timer1 = setInterval(() => {
      this.queryPayStatusInfo();
    }, 5000);
  },
  methods: {
    queryPayStatusInfo() {
      pay.queryPayStatus(this.orderNo).then(response => {
        if (response.data.success) {
          //如果支付成功,清除定时器
          clearInterval(this.timer1);
          //提示成功
          this.$message({
            type: "success",
            message: "支付成功!"
          });
          //跳转到课程详情页面观看视频
          this.$router.push({ path: "/course/" + this.payObj.course_id });
        }
      });
    }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值