黑马程序员技术交流社区

标题: 石家庄校区9.10 [打印本页]

作者: 水煮鱼000    时间: 2019-9-10 14:53
标题: 石家庄校区9.10
1. 微信支付快速入门
file://E:/6%E9%A1%B9%E7%9B%AE%E4%B8%80/%E9%A1%B9%E7%9B%AE%E4%B8%80%E8%AE%B2%E4%B9%89/day18/img/10-3.png?lastModify=1568098353
1.1 微信支付申请(了解)
第一步:注册公众号(类型须为:服务号)
请根据营业执照类型选择以下主体注册:个体工商户| 企业/公司| 政府| 媒体| 其他类型
第二步:认证公众号
公众号认证后才可申请微信支付,认证费:300元/次。
第三步:提交资料申请微信支付
登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。
第四步:开户成功,登录商户平台进行验证
资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。
第五步:在线签署协议
本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。
本课程已经提供好“传智播客”的微信支付账号,学员无需申请。
完成上述步骤,你可以得到调用API用到的账号和密钥
appid:微信公众账号或开放平台APP的唯一标识  wx8397f8696b538317
mch_id:商户号  1473426802
key:商户密钥   T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
1.2 微信支付开发文档与SDK
在线微信支付开发文档:
[https://pay.weixin.qq.com/wiki/doc/api/index.html
微信支付接口调用的整体思路:
按API要求组装参数,以XML方式发送(POST)给微信支付接口(URL),微信支付接口也是以XML方式给予响应。程序根据返回的结果(其中包括支付URL)生成二维码或判断订单状态。
我们解压从官网下载的sdk ,安装到本地仓库
微信的SDK一定要从官网上下载,不要使用资料中提供的。
1.3 统一下单API
(1)新建工程,引入微信支付Api(需要提前安装到本地仓库,maven仓库中没有)
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>3.0.9</version>
</dependency>
(2)创建Config类 ,继承自抽象类WXPayConfig
当前的Config类必须要和WXPayConfig在一个包下(包名一致即可为com.github.wxpay.sdk)
public class Config extends WXPayConfig {
    String getAppID() {
        return "wx8397f8696b538317";
    }

    String getMchID() {
        return "1473426802";
    }

    String getKey() {
        return "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb";
    }

    InputStream getCertStream() {
        return null;
    }

    IWXPayDomain getWXPayDomain() {
        return new IWXPayDomain() {
            public void report(String domain, long elapsedTimeMillis, Exception ex) {

            }
            public DomainInfo getDomain(WXPayConfig config) {
                return new DomainInfo("api.mch.weixin.qq.com",true);//第二个参数为是否为主域名
            }
        };
    }
}
(3)创建测试类,编写代码
Config config=new Config();
//1.封装请求参数
Map<String,String> map=new HashMap();
map.put("appid",config.getAppID());//公众账号ID
map.put("mch_id",config.getMchID());//商户号
map.put("nonce_str",WXPayUtil.generateNonceStr());//随机字符串
map.put("body","青橙");//商品描述
map.put("out_trade_no","555552");//订单号
map.put("total_fee","1");//金额
map.put("spbill_create_ip","127.0.0.1");//终端IP
map.put("notify_url","http://www.baidu.com");//回调地址
map.put("trade_type","NATIVE");//交易类型

String xmlParam = WXPayUtil.generateSignedXml(map, config.getKey());  //xml格式的参数,参数2为config中的秘钥
System.out.println("参数:"+xmlParam);

//2.发送请求
WXPayRequest wxPayRequest=new WXPayRequest(config);
String xmlResult = wxPayRequest.requestWithCert("/pay/unifiedorder", null, xmlParam, false);//附一个参数为接口连接的URL后缀,第二个参数无意义,第三个参数为上边的请求参数
System.out.println("结果:"+xmlResult);//响应结果

//3.解析返回结果
Map<String, String> mapResult = WXPayUtil.xmlToMap(xmlResult);//解析结果
String code_url = mapResult.get("code_url");//获取结果集中的二维码
System.out.println(code_url);
在调用API的代码中,我们经常用到WXPayUtil提供的以下功能:
WXPayUtil.generateNonceStr();//获取随机字符串
WXPayUtil.generateSignedXml(param, partnerkey);//MAP转换为XML字符串(自动添加签名)
WXPayUtil.xmlToMap(result);//将XML字符串转换为MAP
WXPayRequest为API的支付请求类,封装了httpClient。
执行后返回结果
<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx8397f8696b538317]]></appid>
<mch_id><![CDATA[1473426802]]></mch_id>
<nonce_str><![CDATA[jcWWtgnQ1aYXmErr]]></nonce_str>
<sign><![CDATA[EBBB64AB3BA017B4C60C09C507E36C1B]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx23202155305471f07f6c3d398026955400]]></prepay_id>
<trade_type><![CDATA[NATIVE]]></trade_type>
<code_url><![CDATA[weixin://wxpay/bizpayurl?pr=Y3hDTZy]]></code_url>
</xml>
其中的code_url就是我们的支付URl  ,我们可以根据这个URl 生成支付二维码
1.4 二维码JS插件- QRcode.js
QRCode.js (在资料中)是一个用于生成二维码的 JavaScript 库。主要是通过获取 DOM 的标签,再通过 HTML5 Canvas 绘制而成,不依赖任何库。支持该库的浏览器有:IE6~10, Chrome, Firefox, Safari, Opera, Mobile Safari, Android, Windows Mobile, 等
我们新建页面,编写一下代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko" lang="ko">
<head>
<title>QRCode</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="qrcode.min.js"></script>
</head>
<body>
<div id="qrcode"></div>
<script type="text/javascript">
var qrcode = new QRCode(document.getElementById("qrcode"), {
    width : 200,
    height : 200
});
qrcode.makeCode("weixin://wxpay/bizpayurl?pr=Y3hDTZy");
</script>
</body>
</html>1.5 内网映射工具EchoSite
在请求统一下单接口时,有个参数notify_url ,这个是回调地址,也就是在支付成功后微信支付会自动访问这个地址,通知业务系统支付完成。但这个地址必须是互联网可以访问的(也就是有域名的)。
那么如何测试呢?我们可以借助一个工具  EchoSite 内网映射工具
(1)打开网址: https://www.echosite.cn/    注册用户,登录到控制台下载客户端。
(2)支付3元买一个域名(可以用1个月),点击域名端口---抢注域名
file://E:/6%E9%A1%B9%E7%9B%AE%E4%B8%80/%E9%A1%B9%E7%9B%AE%E4%B8%80%E8%AE%B2%E4%B9%89/day18/img/10-4.png?lastModify=1568098353
(3)下载客户端
file://E:/6%E9%A1%B9%E7%9B%AE%E4%B8%80/%E9%A1%B9%E7%9B%AE%E4%B8%80%E8%AE%B2%E4%B9%89/day18/img/1565786009316.png?lastModify=1568098353
file://E:/6%E9%A1%B9%E7%9B%AE%E4%B8%80/%E9%A1%B9%E7%9B%AE%E4%B8%80%E8%AE%B2%E4%B9%89/day18/img/1565786044360.png?lastModify=1568098353
file://E:/6%E9%A1%B9%E7%9B%AE%E4%B8%80/%E9%A1%B9%E7%9B%AE%E4%B8%80%E8%AE%B2%E4%B9%89/day18/img/1565786098890.png?lastModify=1568098353


解压下载后的压缩包得到运行文件。
file://E:/6%E9%A1%B9%E7%9B%AE%E4%B8%80/%E9%A1%B9%E7%9B%AE%E4%B8%80%E8%AE%B2%E4%B9%89/day18/img/1565786973957.png?lastModify=1568098353
(4)使用课程提供的软件echosite  ,添加config.yml
#   这是你的 EchoSite 购买域名的服务器标志
server_addr: easy.echosite.cn:4443
trust_host_root_certs: false

#填写自己的echo账号
echosite_id: 17799998888
#修改为自己的token
echosite_token: $2y$10$bY081mt/2KAFJLJXrsSNHe3f.6SM.SGfXgu1gG7aJvmPMPN9BTqrS

#   以下是你需要开启的通道,只能开启属于你的域名通道
#   以下分别是 http 和 https 以及 tcp 协议的示例
tunnels:
  name1:
    subdomain: "qingcheng" #修改为自己域名
    proto:
      http: 127.0.0.1:9102
然后在echosite目录中输入以下命令
echosite -config=config.yml start-all
这样你购买的域名就映射到127.0.0.1:9102上了。   ctrl+c  结束程序


由于门户工程使用域名来访问。那么下面的一些配置需要修改
1.qingcheng_web_portal中的cas.properties需要修改为
service_url=http://自己购买的域名.easy.echosite.cn
2.cas服务中的application.properties文件需要修改
cas.logout.redirectUrl=http://自己购买的域名.easy.echosite.cn/index.do
2. 青橙-微信支付二维码 2.1 需求分析
用户在提交订单后,如果是选择支付方式为微信支付,那应该跳转到微信支付二维码页面,用户扫描二维码可以进行支付,金额与订单金额相同。
file://E:/6%E9%A1%B9%E7%9B%AE%E4%B8%80/%E9%A1%B9%E7%9B%AE%E4%B8%80%E8%AE%B2%E4%B9%89/day18/img/10-1.png?lastModify=1568098353
2.2 实现思路
1.前端页面向后端传递订单号,后端根据订单号查询订单
2.检查是否为当前用户的未支付订单,
3.如果是则根据订单号和金额生成支付url返给前端,
4.前端得到支付url生成支付二维码。
2.3 代码实现 2.3.1 后端代码
(1)qingcheng_service_order服务 pom.xml添加依赖
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>3.0.9</version>
</dependency>
(2)创建config类
package com.github.wxpay.sdk;

import java.io.InputStream;

public  class Config extends WXPayConfig {

    public String getAppID() {
        return "wx8397f8696b538317";
    }

    public String getMchID() {
        return "1473426802";
    }

    public String getKey() {
        return "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb";
    }

    public InputStream getCertStream() {
        return null;
    }

    public IWXPayDomain getWXPayDomain() {
        return new IWXPayDomain() {
            public void report(String domain, long elapsedTimeMillis, Exception ex) {

            }
            public DomainInfo getDomain(WXPayConfig config) {
                return new DomainInfo("api.mch.weixin.qq.com",true);
            }
        };
    }
}
在spring配置文件中进行配置
    <!--微信支付配置-->
    <bean id="config" class="com.github.wxpay.sdk.Config"></bean>
(3)qingcheng_interface创建包com.qingcheng.service.pay  ,包下创建接口
/**
* 微信支付接口
*/
public interface WxPayService {

    /**
     * 生成微信支付二维码
     * @param orderId 订单号
     * @param money 金额(分)
     * @param notifyUrl 回调地址
     * @return
     */
    public Map createNative(String orderId,Integer money,String notifyUrl);
}
(4)qingcheng_service_order新增服务类
@Service
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private Config config;

    public Map createNative(String orderId, Integer money,String notifyUrl) {
      
        try {
            //1.创建参数
            Map<String,String> param=new HashMap();//创建参数
            param.put("appid", config.getAppID());//公众号
            param.put("mch_id", config.getMchID());//商户号
            param.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
            param.put("body", "青橙");//商品描述
            param.put("out_trade_no", orderId);//商户订单号
            param.put("total_fee",money+"");//总金额(分)
            param.put("spbill_create_ip", "127.0.0.1");//IP
            param.put("notify_url", notifyUrl );//微信服务调用青橙的地址
            param.put("trade_type", "NATIVE");//交易类型
            String xmlParam = WXPayUtil.generateSignedXml(param, config.getKey());
            //2.发送请求
            WXPayRequest wxPayRequest = new WXPayRequest(config);
            String result = wxPayRequest.requestWithCert("/pay/unifiedorder", null, xmlParam, false);
            //3.封装结果
            System.out.println(result);
            Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
            
            
            
            Map<String, String> map=new HashMap();
            map.put("code_url", resultMap.get("code_url"));//支付地址
            map.put("total_fee", money+"");//总金额
            map.put("out_trade_no",orderId);//订单号
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return new HashMap();
        }
    }
}
(5)qingcheng_web_portal新增WxPayController
@RestController
@RequestMapping("/wxpay")
public class WxPayController {

    @Reference
    private OrderService orderService;

    @Reference
    private WxPayService wxPayService;

    @GetMapping("/createNative")
    public Map createNative(String orderId  ){
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        Order order = orderService.findById(orderId);
        if(order!=null){
            if("0".equals(order.getPayStatus())  && "0".equals(order.getOrderStatus()) &&  username.equals(order.getUsername()) ){
                return  wxPayService.createNative(orderId,order.getPayMoney(),"http://qingcheng.easy.echosite.cn/wxpay/notify.do");
            }else{
                return null;
            }
        }else{
            return null;
        }
    }

    /**
     * 回调
     */
    @RequestMapping("/notify")
    public void notifyLogic(){
        System.out.println("支付成功回调。。。。");        
    }
}2.3.2 前端代码  
(1)qingcheng_web_portal新增weixinpay.html 、paysuccess.html、payfail.html(资源中提供)
(2)将二维码插件 qrcode.min.js 拷贝到qingcheng_web_portal下的js目录
(3)修改weixinpay.html
添加js代码
<script src="/js/vue.js"></script>
<script src="/js/axios.js"></script>
<script src="/js/qrcode.min.js"></script>
<script src="/js/util.js"></script>
<script>
    new Vue({
        el:'#app',
        data(){
            return {
                orderId:"",
                money:""
            }
        },
        created(){
            this.createNative();
        },
        methods:{
            createNative(){
                let orderId = getQueryString("orderId");//订单编号
                axios.get(`/wxpay/createNative.do?orderId=${orderId}`).then( response=>{
                    if( response.data.out_trade_no!=null ){//商户订单号
                        let qrcode = new QRCode(document.getElementById("qrcode"), {
                            width : 200,
                            height : 200
                        });//生成支付二维码1
                        qrcode.makeCode(response.data.code_url); //生成支付二维码2
                        this.orderId= response.data.out_trade_no;
                        this.money=  response.data.total_fee;
                    }else{
                        location.href="payfail.html";//失败页面
                    }
                } )
            }
        }
    });

</script>
显示订单号和金额
<div class="checkout-tit" id="app">
    <h4 class="fl tit-txt"><span class="success-icon"></span><span  class="success-info">订单提交成功,请您及时付款!订单号:{{orderId}}</span></h4>
    <span class="fr"><em class="sui-lead">应付金额:</em><em  class="orange money">¥{{ (money/100).toFixed(2) }}</em>元</span>
    <div class="clearfix"></div>
</div>
修改页面二维码部分
<div id="qrcode"></div>
(4)修改pay.html,增加Vue方法,完成到微信支付页面的跳转
methods:{
    wxPay(){
        location.href='/weixinpay.html?orderId='+this.ordersn;
    }
}
调用
<li @click="wxPay()"><img src="./img/_/pay3.jpg"></li>
2.3.3 修改配置文件并测试
修改spring-security-portal.xml,添加配置
<http pattern="/wxpay/notify.do" security="none"></http>







欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2