摘要:本文将带你了解开发微信小程序代码准备,希望本文对大家学微信有所帮助。
开发微信小程序流程 接入微信小程序 > 代码开发 > 提交审核和发布
接入
接入是指在微信平台注册和相关身份信息认证
1:微信公众平台(https://mp.weixin.qq.com/) 注册小程序,获取唯一标识AppId ,和相关身份信息认证
2:微信商户平台(https://pay.weixin.qq.com/) 注册,获取商户信息,支付场景用到
开发准备
· IDE:官方提供的 微信开发者工具,方便可以直接使用微信提供的各种API,解决自己电脑开发环境需要指定ip,提供平台认证繁琐流程
· 后台API: 安全起见,相关的登录和统一下单支付交由后台后台接口实现, 小程序发送后台请求需要再头部传入token,进行省份信息确认
代码开发
小程序代码结构图
------img 图片资源相关
------pages
.------- 模块代码实现
------utils
http.js 微信请求包装类
wx.js 登录包装类
------app.js 主入口,
------app.json 主入口配置
------app.wxss 样式
app.js,里面存放全局常量参数,其他模块可以直接通过getApp() 来获取下面信息
//app.js App({ onLaunch: function () { //调用API从本地缓存中获取数据 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()); wx.setStorageSync('logs', logs); }, config: { baseUrl: "********", key: "**********", appid: "**********" } }) app.json 置顶小程序路由跳转(pages) ,基本信息(window), 底部导航菜单(tabBar) { "pages":[ "pages/index/index", "pages/romance/romance", "pages/release/release", ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor":"#fea213", "navigationBarTitleText":"第一个小程序", "navigationBarTextStyle":"#fff" }, "tabBar":{ "color":"#dddddd", "selectedColor":"#3cc51f", "borderStyle":"white", "backgroundColor":"#ffffff", "list":[{ "pagePath":"pages/index/index", "iconPath":"img/home.png", "selectedIconPath":"img/home1.png", "text":"首页" }, { "pagePath":"pages/romance/romance", "iconPath":"img/manager.png", "selectedIconPath":"img/manager1.png", "text":"个人中心" } ] } } http.js 封装rest服务包装类,其他模块方便直接调用,不用写繁琐代码 classHttp { app; constructor() { this.app =getApp(); } get(url,callback) { var instance =this; wx.request({ url: instance.app.config.baseUrl +url, data: {}, method: 'GET', header: { 'token':encodeURI(wx.getStorageSync("token")), 'content-type':'application/json' }, success: function (res) { if (res.data.errorCode =='user_not_login') { wx.clearStorageSync(); } if (callback)callback(res); }, fail: function (res) { console.log(res); } }) } post(url,data,callback) { var instance =this; wx.request({ url: instance.app.config.baseUrl +url, data: data, method: 'POST', header: { 'token':encodeURI(wx.getStorageSync("token")), 'content-type':'application/json' }, success: function (res) { if (res.data.errorCode =='user_not_login') { wx.clearStorageSync(); } if (callback)callback(res); }, fail: function (res) { console.log(res); } }); } } module.exports =Http; wx.js 用来实现微信登录,获取用户基本信息 ,调用后台接口 url: app.config.baseUrl + "user/wxlogin",,取得关键的openId, class WxService { app; constructor() { this.app =getApp(); } login(app,callback) { var page =this; wx.login({ success: function (re) { if (re.code) { wx.getUserInfo({ success: function (res) { wx.setStorageSync('userInfo',res.userInfo); var data = { 'username':re.code, 'userSaveBean': {'username':'','password':'','name':res.userInfo.nickName,'birth':newDate().getTime,'address':res.userInfo.city,'mobile':13111111111,'headimg':res.userInfo.avatarUrl } } wx.request({ url: app.config.baseUrl +"user/wxlogin", data: data, method: 'POST', header: { 'content-type':'application/json' }, success: function (res) { var yxNum =res.data.responseBody.username; wx.setStorageSync('yxNum',yxNum); wx.setStorageSync('openId',res.data.responseBody.openid); var token =page.pwd(res.data.responseBody.openid,app.config.code,app.config.key); wx.setStorageSync('token',token); if (callback) callback(); }, fail: function (res) { console.log(res); } }); } }); } else { console.log('获取用户登录态失败!' +res.errMsg) } } }) } } module.exports =WxService;
代码模块实现官网文档有大量详细说明,比如html的编写,组件,样式,和各种api的使用
就不做过多描述,这里说下支付
支付分两步 : 统一下单 > 发起字符
通过统一下单接口,获取微信返回的prepay_id ,再把prepay_id和其他相关信息提供支付接口,支付
var preOrderUrl ="order/prepay?amount=1&articleId=" +aid +"&totalFee=" +total_fee +"&openid=" +openid; http.get(preOrderUrl,function (res) {//调用后台统一下单接口,获取prepay_id if (res.data.errorCode) { wx.hideLoading(); wx.showModal({ title: '失败!', content: res.data.errorMsg.substring(0,res.data.errorMsg), showCancel: false }) return; } var paymentTS ="" +newDate().getTime(); var paymentNS ="" +newDate().getTime(); var prepayId =res.data.responseBody.prepay_id; var paymentPack ='prepay_id=' +res.data.responseBody.prepay_id; var orderId =res.data.responseBody.orderId; var strPaymentSign ="appId=" +appid +"&nonceStr=" +paymentNS +"&package=" +paymentPack +"&signType=MD5&timeStamp=" +paymentTS +"&key=" +key; var paySign =ma5Helper.toMd5(strPaymentSign).toUpperCase(); wx.requestPayment(//调用微信支付接口,付款 { timeStamp: paymentTS, nonceStr: paymentNS, package: paymentPack, signType: 'MD5', paySign: paySign, success: function (res) { //提交订单到服务器,保存数据 var orderUrl =app.config.baseUrl +"order"; var orderData = {flag:true,orderId:orderId,prepayId:prepayId,msg:"" }; http.post("order",orderData,function (res) { wx.hideLoading(); if (res.data.errorCode) { wx.showModal({ title: '订单提交失败!', content: res.data.errorMsg.substring(0,res.data.errorMsg.indexOf('[')), showCancel: false }) } else { //支付成功 wx.showToast({ title: '支付成功', icon: 'success', duration: 3000, success: function () { wx.switchTab({ url: '../romance/romance', }) } }) } }); }, fail: function (res) { }, complete: function (res) { } }) }
统一下单
@GetMapping("/prepay")public ResponseBean createOrderTemp(HttpServletRequest request, @ModelAttribute OrderTempSaveBean saveBean){ saveBean.setSpbill_create_ip(okhttpService.getIpAddress(request)); return success(orderTempService.createOrderTemp(userFromToken(request),saveBean));} /** * 统一下单 * @param user * @param saveBean * @return */@Transactionalpublic Map createOrderTemp(User user,OrderTempSaveBean saveBean) { String orderNumber= (new Random().nextInt(100))+""+DateTime.now().toString(DateUtils.pattern.defualt_2.getContent())+user.getId(); if(saveBean.getTransType() == null) throw new BusinessException(ErrorCode.invalid_request,"编码未设置"); OrderTempWithBLOBs orderTemp=new OrderTempWithBLOBs(); orderTemp.setFlag(true); orderTemp.setStatus(OrderStatus.onCreate.name()); saveBean.setOpenid(user.getOpenid()); saveBean.setNonceStr(orderNumber); saveBean.setOutTradeNo(orderNumber); saveBean.setSpbill_create_ip(saveBean.getSpbill_create_ip() == null ? "1.1.1.1": saveBean.getSpbill_create_ip()); if(saveBean.getTotalFee() == null && saveBean.getTotalFee() <=0) throw new BusinessException(ErrorCode.invalid_request,"交易金额不对"); if(saveBean.getTransType().equals(TransType.C004)){ if(saveBean.getAmount() == null && saveBean.getAmount() <=0) throw new BusinessException(ErrorCode.invalid_request,"数量不对"); Article article = articleMapper.selectByPrimaryKey(saveBean.getArticleId()); if(article ==null) throw new BusinessException(ErrorCode.article_not_found,"未找到"); if(new DateTime(article.getEndTime()).compareTo(new DateTime()) <0) throw new BusinessException(ErrorCode.invalid_request,"已经结束") ; saveBean.setBody("标题-"+article.getThemeTitle()); }else if (saveBean.getTransType().equals(TransType.C001)){ saveBean.setAmount(1); saveBean.setArticleId(-9999); saveBean.setBody("浪漫之旅-充值"); }else{ throw new BusinessException(ErrorCode.invalid_request,"无效请求") ; } Map unifiedorderMap=null; try { unifiedorderMap= mWxPayService.createOrderTemp(saveBean); logger.info("=============> createOrderTemp success : "+JSON.toJSONString(unifiedorderMap)); if(!"SUCCESS".equals(unifiedorderMap.get("return_code"))){ throw new BusinessException(ErrorCode.invalid_request,unifiedorderMap.get("return_msg").toString()); } orderTemp.setPrepayId(String.valueOf(unifiedorderMap.get("prepay_id"))); }catch (BusinessException e){ orderTemp.setFlag(false); throw new BusinessException(e.getErrorCode(),e.getMessage()); }catch (Exception e){ orderTemp.setFlag(false); orderTemp.setMsg(e.getMessage()); e.printStackTrace(); logger.info("=============> createOrderTemp Exception : "+e.getMessage()); throw new BusinessException(ErrorCode.sys_error,"下单失败了!"); }finally { orderTemp.setCreateTime(new Timestamp(System.currentTimeMillis())); orderTemp.setParam(JSONObject.toJSONString(saveBean)); orderTemp.setCreateBy(user.getNickname() ==null ? "":user.getNickname()); orderTemp.setUserId(user.getId()); orderTemp.setOutTradeNo(orderNumber); orderTemp.setAmount(saveBean.getAmount()); orderTemp.setArticleId(saveBean.getArticleId()); orderTemp.setBody(saveBean.getBody()); orderTemp.setPrice(saveBean.getTotalFee()); orderTemp.setSpbillCreateIp(saveBean.getSpbill_create_ip()); orderTemp.setMsg(JSONObject.toJSONString(unifiedorderMap)); orderTempMapper.insert(orderTemp); unifiedorderMap.put("orderId",orderTemp.getId()); } return unifiedorderMap;} mWxPayService.createOrderTemp(saveBean) 实现 public Map createOrderTemp(OrderTempSaveBean saveBean) throws Exception { Map reqData = WxPayConfig.genUnifiedorder(); reqData.put("body", saveBean.getBody()); reqData.put("nonce_str", saveBean.getNonceStr()); reqData.put("out_trade_no", saveBean.getOutTradeNo()); reqData.put("total_fee",saveBean.getTotalFee().toString()); reqData.put("spbill_create_ip", saveBean.getSpbill_create_ip()); reqData.put("openid",saveBean.getOpenid()); reqData.put("sign", WXPayUtil.generateSignature(reqData, Const.key, SignType.MD5)); String reqXml = WXPayUtil.mapToXml(reqData); String response = okhttpService.post(Const.UNIFIEDORDER_URL_SUFFIX, reqXml); return WXPayUtil.xmlToMap(response);} WXPayUtil.generateSignature(reqData, Const.key, SignType.MD5))实现 public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception { Set<String> keySet = data.keySet(); String[] keyArray = keySet.toArray(new String[keySet.size()]); Arrays.sort(keyArray); StringBuilder sb = new StringBuilder(); for (String k : keyArray) { if (k.equals(Const.FIELD_SIGN)) { continue; } if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名 sb.append(k).append("=").append(data.get(k).trim()).append("&"); } sb.append("key=").append(key); if (SignType.MD5.equals(signType)) { return MD5(sb.toString()).toUpperCase(); } else if (SignType.HMACSHA256.equals(signType)) { return HMACSHA256(sb.toString(), key); } else { throw new Exception(String.format("Invalid sign_type: %s", signType)); } } WXPayUtil.mapToXml(reqData) 实现 /** * 将Map转换为XML格式的字符串 * * @param data Map类型数据 * @return XML格式的字符串 * @throws Exception */public static String mapToXml(Map<String, String> data) throws Exception { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); org.w3c.dom.Document document = documentBuilder.newDocument(); org.w3c.dom.Element root = document.createElement("xml"); document.appendChild(root); for (String key: data.keySet()) { String value = data.get(key); if (value == null) { value = ""; } value = value.trim(); org.w3c.dom.Element filed = document.createElement(key); filed.appendChild(document.createTextNode(value)); root.appendChild(filed); } TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); DOMSource source = new DOMSource(document); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); transformer.transform(source, result); String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", ""); try { writer.close(); } catch (Exception ex) { } return output;} okhttpService.post(Const.UNIFIEDORDER_URL_SUFFIX, reqXml) 实现 /** * post * @param url * @param json * @return * @throws IOException */public String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } WXPayUtil.xmlToMap(response) 实现 /** * XML格式字符串转换为Map * * @param strXML XML字符串 * @return XML数据转换后的Map * @throws Exception */public static Map<String, String> xmlToMap(String strXML) throws Exception { try { Map<String, String> data = new HashMap<String, String>(); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8")); org.w3c.dom.Document doc = documentBuilder.parse(stream); doc.getDocumentElement().normalize(); NodeList nodeList = doc.getDocumentElement().getChildNodes(); for (int idx = 0; idx < nodeList.getLength(); ++idx) { Node node = nodeList.item(idx); if (node.getNodeType() == Node.ELEMENT_NODE) { org.w3c.dom.Element element = (org.w3c.dom.Element) node; data.put(element.getNodeName(), element.getTextContent()); } } try { stream.close(); } catch (Exception ex) { // do nothing } return data; } catch (Exception ex) { WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML); throw ex; } }
最终效果就是一个支付的页面了,
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之微信频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号