E企盈营销工具技术服务商 热线:4006-838-530

微信小程序登录+支付(后台Java)Demo实战(环境搭建+源码)

E企盈直播平台营销卖货系统

读者要求:已经学过微信小程序的入门官方教程,即其简易教程。另外:如您的小程序需要进行微信支付,则首先需要完成微信认证(个人号不支持微信认证):【登录小程序】—>【设置】—>【微信认证详情】,同时,申请微信支付:微信认证后,可以在小程序后台,点击微信支付菜单项,选择申请微信支付。申请完成后,会发送微信支付商户号,商户平台用户名密码等信息到注册者邮箱。如下介绍一个可运行的微信小程序登录+支付的demo。接触了小程序简易教程的,想必都知道我们必然有自己的后台应用服务器,来处理我们自己的业务逻辑、请求微信服务完成一定的功能。在此,我们的后台采用java环境,本文将首先介绍环境搭建的过程,随后介绍登录+支付的流程及代码。一、后台web服务环境搭建1. 安装jdk、tomcat,ICP备案的域名准备。    Linux安装jdk:https://blog.csdn.net/zhang918784312/article/details/79751283    Linux 安装tomcat:https://www.cnblogs.com/EasonJim/p/7202844.html    经过icp备案的域名,请自行准备。 2.配置https,由于小程序请求url必须是https,故而必须配置支持https请求。本人采用的是在阿里云购买的域名,故而采用的证书也是阿里云生成的ssl证书,可参考如下两篇博文进行配置。当然,你也可以通过别的方式生成证书,更或者通过nginx作反向代理到你的服务器。    https://blog.csdn.net/qq_28189091/article/details/75078164    https://blog.csdn.net/z_xuewen/article/details/78176509    同时,务必将您的小程序域名绑定在小程序后端。登入小程序后台,【设置】-【开发设置】-【服务器域名】 3. 部署web服务     如上两步完成后,请务必确认通过你的域名(https://…)可以展示tomcat的默认页之后,开始部署我们的web服务。在此,就简单粗暴的在webapps下建立小程序的根目录,我命名为wechatserver,在此目录下,创建WEB-INFO,下面的目录结构如下: classes存放自己写的类的classes文件,lib存放我们项目依赖的jar包,logs用于存放我们的日志输出,web.xml是我们这个项目的配置。 demo中,我们只有一个servlet接收小程序前端请求,web.xml中增加配置如下:<servlet>        <servlet-name>WechatServlet</servlet-name>        <servlet-class>com.icbc.servlet.WechatServlet</servlet-class>    </servlet>    <servlet-mapping>        <servlet-name>WechatServlet</servlet-name>        <url-pattern>/servlet/WechatServlet</url-pattern>    </servlet-mapping>4. log4j 应用   在开发调试中,我们免不了需要通过打印日志进行调试,因此在此增加了日志的使用。web.xml中增加配置:<context-param>      <param-name>log4jConfigLocation</param-name>      <param-value>classes/log4j.properties</param-value>  </context-param>  在classes增加文件,log4j.properties,内容如下:log4j.rootLogger = INFO,toConsole,D,Elog4j.appender.toConsole=org.apache.log4j.ConsoleAppender log4j.appender.toConsole.Target=System.out  log4j.appender.toConsole.layout=org.apache.log4j.PatternLayout log4j.appender.toConsole.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%p] %m%n log4j.appender.D = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.D.file = 你的目录/common.loglog4j.appender.D.Append = truelog4j.appender.D.Threshold = info log4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] – [ %p ]  %m%nlog4j.appender.D.DatePattern=’.’yyyy-MM-dd’.log’log4j.appender.E = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.E.file = 你的目录/error.log log4j.appender.E.Append = truelog4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayoutlog4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] – [ %p ]  %m%nlog4j.appender.D.DatePattern=’.’yyyy-MM-dd’.log’log4j 在java中的引用、使用: public static Logger logger = Logger.getLogger(WechatServlet.class); logger.info(“打印信息”);二、微信小程序登录+支付1. 小程序前端目录准备基于微信小程序工具生成的默认hello world程序,pages下先建立目录order,随后在order目录生成一个新的page,命名为order,结构如下图: 在index中增加按钮,进入order。 index.wxml <view>    <navigator class=”index-intro__btn btn btn-danger btn-md” url=”/pages/order/order”>进入商城</navigator>  </view>order.xml中描述商品信息,增加支付按钮 order.js 支付事件处理。2. 登录+支付 code流程大概分为几步: 1)登录,获取code(一个code只能用一次) 2)通过code获取openid(通过请求服务器,由服务器请求微信获取并返回小程序)。微信登录+获取openid接口3)小程序请求服务器进行预下单,上送商品详情、金额、openid。 4)服务器端接收请求,根据请求订单数据、生成第三方订单号,调用微信的统一下单接口。 5)服务器收到预下单信息后,签名并组装支付数据,返回给小程序。所需数据见:小程序支付接口 6)小程序前端发起支付,并支付完成 7)服务器收到回调。2.1 登录,获取code、  onLoad: function (options) {    // 登录    wx.login({      success: function (res) {        // 发送 res.code 到后台换取 openId, sessionKey, unionId        var that = this;        if (res.code) {          console.log(‘获取用户登录态success!’ + res.code)          app.globalData.code = res.code        } else {          console.log(‘获取用户登录态失败!’ + res.errMsg)        }      }    })    },2.2 通过code 获取openid(前端)getOpenId:function(that, code){    console.log(code);    let operFlag = “getOpenid”;    console.log(operFlag);    wx.request({      url: ‘https://xxx/wechatserver/servlet/WechatServlet’,      data: {        code:code,        operFlag:operFlag      },      header: { ‘content-type’: ‘application/json’ },      success: function (res) {        console.log(res);         var openid = res.data.openid;        console.log(openid);        that.paypay(that, openid); //预下单并支付      },      fail: function (res) {        console.log(res.data.errmsg);        console.log(res.data.errcode);      },      complete:function(res){      }    })  },2.2 服务器端servlet(复写HttpServlet的doGet  doPost函数)doPost的代码片段:        //获取操作类型,根据类型执行不同操作        String operFlag = request.getParameter(“operFlag”);        logger.info(“operFlag=” + operFlag);        String results = “”;        if(“getOpenid”.equals(operFlag)){            String code = request.getParameter(“code”);            logger.info(“code=” + code);            String url = “https://api.weixin.qq.com/sns/jscode2session?appid=” + appid                     + “&secret=” + secretKey + “&js_code=” + code + “&grant_type=authorization_code”;            logger.info(“url=” + url);            results = sendGetReq(url);//发送http请求    }        logger.info(“results = ” + results);        response.setContentType(“application/json;charset=UTF-8”);        response.setHeader(“catch-control”, “no-catch”);        PrintWriter out = response.getWriter();        out.write(results);        out.flush();        out.close();2.3 前端上送订单信息、openid请求预下单(在此,为方便,订单信息直接写死在服务器端了),若成功,则根据服务器端返回数据发起支付。paypay: function (that, openid) {    let operFlag = ‘pay’;    wx.request({      url: ‘https://xxx/wechatserver/servlet/WechatServlet’,      data: {        openid: openid,        operFlag: operFlag      },      header: { ‘content-type’: ‘application/json’ },      success: function (res) {        console.log(res);        wx.requestPayment({          ‘timeStamp’: res.data.timeStamp,          ‘nonceStr’: res.data.nonceStr,          ‘package’: res.data.package,          ‘signType’: ‘MD5’,          ‘paySign’: res.data.sign,          ‘success’: function (res) {            if (res.errMsg == “requestPayment:ok”) {              wx.showToast({                title: ‘支付成功’              })            }          },          ‘fail’: function (res) {          }        })      },      fail: function (res) {        console.log(res.data.errmsg);        console.log(res.data.errcode);      },      complete: function (res) {      }    })  },2.4 服务器端预下单,2.5并签名返回支付请求数据if(“pay”.equals(operFlag)){            String openid = request.getParameter(“openid”);            logger.info(“openid = ” + openid);            String url = “https://api.mch.weixin.qq.com/pay/unifiedorder”;            String reqStr = getReqStr(openid); //组装预下单的请求数据            logger.info(“reqStr=” + reqStr);            results = sendPost(url,reqStr);//发送post数据到微信预下单            logger.info(“prepay from weixin: ” + results);            Map<String,String> return_data = null;            try {                return_data = WXPayUtil.xmlToMap(results);//微信的一个工具类            } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();                logger.error(e.getMessage());            }            String return_code = return_data.get(“return_code”);            logger.info(“return_code=” + return_code);            if(“SUCCESS”.equals(return_code)){                String prepay_id = return_data.get(“prepay_id”);                results = conPayParam(prepay_id); //组装返回数据            }else{                results =”{“return_code”:”fail”}”;            }        }附函数//组装预下单的请求数据    public static String getReqStr(String openid){        Map<String,String> data = new HashMap<String,String>();        String out_trade_no = setTradeNo();//        //        data.put(“appid”, appid);        data.put(“mch_id”,mer_id);        data.put(“nonce_str”, WXPayUtil.generateUUID());        data.put(“sign_type”, “MD5”);        data.put(“body”, “spy test”);        data.put(“out_trade_no”, out_trade_no);        data.put(“device_info”, “”);        data.put(“fee_type”, “CNY”);        data.put(“total_fee”, “1”);//1分钱        data.put(“spbill_create_ip”, “123.12.12.123”);        data.put(“notify_url”, “http://xxx/wxpay/notify”);        data.put(“trade_type”, “JSAPI”);        data.put(“product_id”, “12”);        data.put(“openid”, openid);        try {            String sign = WXPayUtil.generateSignature(data, merKey, SignType.MD5);            data.put(“sign”, sign);        } catch (Exception e) {            e.printStackTrace();            logger.error(“sign error”);        }        String reqBody = null;        try {            reqBody = WXPayUtil.mapToXml(data);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return reqBody;    }//保证唯一    public static String setTradeNo(){        String orderid = “20211909105011”+ getRandom(6);        logger.info(“orderid = ” + orderid);        return orderid;    }    //组装返回客户端的请求数据    public static String conPayParam(String prepayid){        logger.info(“根据当前的prepayid构造返回参数= ” + prepayid);        String results = “”;        Map<String,String> map = new HashMap<String,String>();        map.put(“appId”, appid);        LocalDateTime time = LocalDateTime.now();        map.put(“timeStamp”,  WXPayUtil.getCurrentTimestamp()+””);        map.put(“nonceStr”, WXPayUtil.generateUUID() );        map.put(“package”, “prepay_id=” + prepayid);        map.put(“signType”, “MD5”);        String sign;        try {            sign = WXPayUtil.generateSignature(map, merKey, SignType.MD5);            map.put(“sign”, sign);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();            logger.error(e.getMessage());        }        return JSON.toJSONString(map);    }2.6 服务器端返回数据到微信小程序客户端后,发起微信支付,代码在2.3章节已附。 2.7 服务器端收到微信的支付成功通知(省略)三、实战中遇到的问题预下单和支付请求中,签名的密钥使用的是商户密钥,但是用code获取openid是使用小程序对应的secret key,这个可以在小程序的后台看到。微信小程序前端发起post请求到服务器端时,服务器端收不到请求参数。原因是:微信API接口wx.request中: a) 对于 GET 方法的数据,会将数据转换成 query string(encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)…) b1) 对于 POST 方法且 header[‘content-type’] 为 application/json 的数据,会对数据进行 JSON 序列化 b2) 对于 POST 方法且 header[‘content-type’] 为 application/x-www-form-urlencoded 的数据,会将数据转换成 query string (encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)…)所以,如果post请求,为省去服务器端反序列化的操作时,可使用header[‘content-type’] 为 application/x-www-form-urlencoded 的数据。 3. 如果部署了servlet后,tomcat重启后,需要等几分钟才能生效(原因是我的机器内存比较小,而tomcat又很占用内存资源),待熟悉tomcat 调优。微信小程序

赞(0) 打赏
未经允许不得转载:E企盈小程序开发-热线:4006-838-530 » 微信小程序登录+支付(后台Java)Demo实战(环境搭建+源码)
分享到: 更多 (0)
E企盈小程序直播营销卖货系统
E企盈直播平台营销卖货系统

评论 抢沙发

E企盈小程序开发

联系我们联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏