“一码多付”,微信支付、支付宝支付,微信中控服务器
2018-01-08 15:10
706 查看
写着写着,越写越多,思绪写不下了,回头写在前面的话。此系统属个人创业项目,历时3个月,主要实现自助按摩椅、娃娃机、自动换币器功能,主要流程就是用户扫码二维码->授权获取用户信息->弹出H5界面选择相应服务->支付->控制硬件设备做对应操作。主要功能点如下:
1)微信、支付宝用户信息获取、保存会员信息。具体步骤见各自api文档,十分详细,同时坑也很多。
2)一码多付,微信公众号支付,支付宝支付,需按照步骤流程一步步走,一步步申请,设置,同时坑更多,有问题可随时沟通交流。
3)订单查询、收入明细、统计,充值管理等。4)后台系统的账户、权限、统计信息、数据导出等,用shiro
控制。
5)设备的添加和维护,二维码的生成、代金券的生成、用户批量绑定代金券,合作商管理,加盟商管理等。
6)短信网关、邮件功能。
7)微信公众号对接,自动回复,客服消息,各种事件推送。
马上年终总结了,坐等年终大奖,也没多少时间写了,想到哪里就写点吧,有疑问的话可加qq:540769049
进行交流,根据大家疑问慢慢完善代码吧,请备注来由。
回头把二维码放出来,关注公众号后回复测试账号,就能体验系统各模块功能了,比这里啰里啰嗦简单粗暴。
一:业务需求
通过一个二维码完成多种第三方支付方式支付的需求:商户打印一个静态的二维码,顾客用微信、支付宝扫这个二维码后,进入商户的一个付款页面,输入金额(或选择特定金额)后,完成支付,然后启动后续服务流程。
本demo实现一码多付(微信公众号、支付宝)支付后,控制按摩椅的业务需求。
二:业务实现
1.生成二维码生成带有设备参数(唯一性)的二维码,用于用户扫码时定位具体的设备,用户支付成功后,开启后续服务。
一般建议生成二维码的url不要太长,长度越短则生成的二维码识别率越高。二维码url示例:http//xyxspace.com/m/123456
2.扫码识别
用户扫码时,可能会有许多种软件来扫,但目前只实现了微信、支付宝扫码支付。因此需要做识别扫码来源并在页面作出提示,引导用户用支微信、支付宝进行扫码。
用户用app扫商户的二维码后,其实是用app浏览器打开到商户的页面, 商户页面通过识别浏览器header中的user-agent来判断是哪个app打开的。
常见App浏览器的user-agent 识别关键字:
支付宝: AlipayClient
微信: MicroMessenger
如果识别到不包含上述关键信息,则跳转到错误提示页面,引导用户用微信、支付宝扫码。如下图:
微信、支付宝扫码成功后,会将设备mcode提交到你的服务端,保存在session中或放在下一步授权回调地址参数中。
3.技术实现
本demo使用springmvc+mybatis3.2后台框架,mysql5.7数据库,HTML5+css3.0+bootstrap前端页面,shiro
、ehcache 、druid等技术。
4.话不多说,开始撸代码......
1.扫码入口控制类:采用springmvc架构,用户扫码后到控制类;
1)识别二维码中的mcode,保存到session中。
2)判断用户是否登录,如果没有登录,根据APP类型,获取用户信息,作为会员信息保存到数据库。
3)如果已登录,跳转到价格页面。
/** * 扫码入口控制类 * */ @Controller @RequestMapping(value = "/m") public class IndexController extends BaseController { @Resource(name = "commonService") private CommonService commonService; @Resource(name = "indexService") private IndexService indexService; /** * 扫码总入口 * * @return ModelAndView */ @RequestMapping(value = "/3*") public ModelAndView scaning() { String url = request.getRequestURL().toString(); String mcode = url.substring(url.lastIndexOf("/") + 1); session.setAttribute("mcode", mcode); String id = ""; if (Constants.WEIXIN.equals(appType)) {// 来自微信 logger.info("微信扫码..."); id = (String) session.getAttribute("openid"); } else if (Constants.ALIPAY.equals(appType)) {// 来自支付宝 logger.info("支付宝扫码..."); id = (String) session.getAttribute("user_id"); } if (StringUtils.isBlank(id)) {// session中未存在用户信息时,授权重新获取用户信息 return indexService.createRedirectURL(appType); } else { return commonService.trunView(id, mcode, basePath);// 跳转到首页价格页面 } } }
2.判断扫码APP类型
public static String IsWeixinOrAlipay(HttpServletRequest request) { if (request != null) { String userAgent = request.getHeader("user-agent"); if (StringUtils.isNotBlank(userAgent)) { userAgent = userAgent.toLowerCase(); if (userAgent.indexOf("micromessenger") > -1) {// 微信客户端 return Constants.WEIXIN; } else if (userAgent.indexOf("alipayclient") > -1) { return Constants.ALIPAY; } } } return "other"; }
3.获取微信用户信息
1) 根本客户端类型生成对应授权url
public ModelAndView createRedirectURL(String appType) { if (Constants.WEIXIN.equals(appType)) {// 微信客户端 String redirectUrl = OAuthManager.generateRedirectURI(WXConstants.REDIRECT_URI, WXConstants.SCOPE, WXConstants.STATE); return new ModelAndView("redirect:" + redirectUrl); } else if (Constants.ALIPAY.equals(appType)) {// 支付宝客户端 String redirectUrl = OAuthALiService.generateRedirectURI(AlipayConfig.REDIRECTURI, AlipayConfig.ALIPAY_SCOPE, AlipayConfig.STATE); return new ModelAndView("redirect:" + redirectUrl); } else { ModelAndView mv = new ModelAndView(); mv.setViewName("view/index/unAllow"); return mv; } }
2)获取微信授权url
/** * 网页授权获取用户基本信息 * <p> * 参考<a href="http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html">开发文档</a> * </p> * Created by xuwen on 2015/12/11. */ public class OAuthManager { private static Logger logger = Logger.getLogger(OAuthManager.class); /* 生成OAuth重定向URI(用户同意授权,获取code) */ private static final String HTTPS_OPEN_WEIXIN_QQ_COM_CONNECT_OAUTH2_AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize"; /* 通过code换取网页授权access_token */ private static final String HTTPS_API_WEIXIN_QQ_COM_SNS_OAUTH2_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token"; /* 刷新access_token(如果需要) */ private static final String HTTPS_API_WEIXIN_QQ_COM_SNS_OAUTH2_REFRESH_TOKEN = "https://api.weixin.qq.com/sns/oauth2/refresh_token"; /* 拉取用户信息(需scope为 snsapi_userinfo) */ private static final String HTTPS_API_WEIXIN_QQ_COM_SNS_USERINFO = "https://api.weixin.qq.com/sns/userinfo"; /* 检验授权凭证(access_token)是否有效 */ private static final String HTTPS_API_WEIXIN_QQ_COM_SNS_AUTH = "https://api.weixin.qq.com/sns/auth"; /** * 生成OAuth重定向URI(用户同意授权,获取code) * <p> * 参考<a href="http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code">开发文档</a> * </p> * * @param redirectURI * @param scope * @param state * @return */ public static String generateRedirectURI(String redirectURI, String scope, String state) { StringBuffer url = new StringBuffer(); url.append(HTTPS_OPEN_WEIXIN_QQ_COM_CONNECT_OAUTH2_AUTHORIZE); url.append("?appid=").append(urlEncode(Config.instance().getAppid())); url.append("&redirect_uri=").append(urlEncode(redirectURI)); url.append("&response_type=code"); url.append("&scope=").append(urlEncode(scope)); url.append("&state=").append(urlEncode(state)); url.append("#wechat_redirect"); return url.toString(); } /** * 通过code换取网页授权access_token * <p> * 参考<a href="http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.BA.8C.E6.AD.A5.EF.BC.9A.E9.80.9A.E8.BF.87code.E6.8D.A2.E5.8F.96.E7.BD.91.E9.A1.B5.E6.8E.88.E6.9D.83access_token">开发文档</a> * </p> * * @param request * @return */ public static GetAccessTokenResponse getAccessToken(GetAccessTokenRequest request) throws OAuthException { String response = post(HTTPS_API_WEIXIN_QQ_COM_SNS_OAUTH2_ACCESS_TOKEN, request); check(response); return JSONObject.parseObject(response, GetAccessTokenResponse.class); } /** * 拉取用户信息(需scope为 snsapi_userinfo) * <p> * 参考<a href="http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E5.9B.9B.E6.AD.A5.EF.BC.9A.E6.8B.89.E5.8F.96.E7.94.A8.E6.88.B7.E4.BF.A1.E6.81.AF.28.E9.9C.80scope.E4.B8.BA_snsapi_userinfo.29">开发文档</a> * </p> * * @param request * @return */ public static GetUserinfoResponse getUserinfo(GetUserinfoRequest request) throws OAuthException { String response = post(HTTPS_API_WEIXIN_QQ_COM_SNS_USERINFO, request); check(response); return JSONObject.parseObject(response, GetUserinfoResponse.class); } }
3)微信auth2.0 回调方法
@RequestMapping(value = "/oauthCallback") public ModelAndView oauthCallback() { logBefore(logger, "weixin回调方法..."); // 获取code String code = request.getParameter("code"); GetAccessTokenResponse getAccessTokenResponse; try { getAccessTokenResponse = OAuthManager.getAccessToken(new GetAccessTokenRequest(code)); GetUserinfoResponse getUserinfoResponse = OAuthManager.getUserinfo(new GetUserinfoRequest(getAccessTokenResponse.getAccess_token(), getAccessTokenResponse.getOpenid())); logger.info("oauth2获取到的用户信息:[" + getUserinfoResponse + "]"); // 保存openid到session String openid = getUserinfoResponse.getOpenid(); session.setAttribute("openid", openid); session.setAttribute("wxuser", getUserinfoResponse); // 保存用户信息 Map<String, Object> map = BeanUtil.transBean2Map(getUserinfoResponse); map.put("add_ip", getIp()); map.put("add_time", System.currentTimeMillis() / 1000); memberService.saveOrUpdateMemberOfWX(map); ModelAndView mv = this.getModelAndView(); mv.setViewName("view/index/index"); return mv; } catch (OAuthException e) { e.printStackTrace(); } return null; }
4)支付宝回调方法
/** * 授权回调方法 * * @return */ @RequestMapping(value = "/oauthCallback") public ModelAndView oauthCallback() { logger.info("ali授权回调方法"); // 2.获取授权码auth_code String auth_code = request.getParameter("auth_code"); AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest(); request.setCode(auth_code);// 授权码 request.setGrantType("authorization_code");// 授权类型 AlipaySystemOauthTokenResponse oauthTokenResponse; try { // 3.通过auth_code换取access_token及用户userId oauthTokenResponse = alipayClient.execute(request); String accessToken = oauthTokenResponse.getAccessToken(); // 4.调用接口获取用户信息.如果scope=auth_base,在第三步就可以获取到用户的userId,无需走第四步。如果scope=auth_user,才需要走第四步,通过access_token调用用户信息共享接口获取用户信息。 AlipayUserInfoShareRequest request1 = new AlipayUserInfoShareRequest(); AlipayUserInfoShareResponse userinfoShareResponse = alipayClient.execute(request1, accessToken); logger.info(userinfoShareResponse.getBody()); session.setAttribute("user_id", userinfoShareResponse.getUserId()); session.setAttribute("aliuser", userinfoSh f5bb areResponse); // 保存用户信息 Map<String, Object> map = BeanUtil.transBean2Map(userinfoShareResponse); map.put("add_ip", getIp()); map.put("add_time", System.currentTimeMillis() / 1000); memberService.saveOrUpdateMemberOfALipay(map); ModelAndView mv = this.getModelAndView(); mv.setViewName("view/index/index"); return mv; } catch (AlipayApiException e) { e.printStackTrace(); } return null; }
5)获取到的用户信息效果图
6)用户信息保存到session后,跳转到价格列表页面(可手动输入,或者选择特定的价格列表项)
微信、支付宝、UC浏览器扫码结果如下:(页面比例缩放了)
微信、支付宝用户基本信息获取基本完成了,里面有好多坑,待一个个挖,一个个填。
--明天再写
三:订单管理
本demo业务模式有充值,代金券,所以下单时先判断代金券、余额信息,如都不足,则发起在线支付。
1.微信支付
a)统一下单:
public UnifiedorderResponse putUnifiedOrder(PageData pd) { UnifiedorderResponse unifiedorderResponse = null; UnifiedorderRequest unifiedorderRequest = new UnifiedorderRequest(); unifiedorderRequest.setNonce_str(RandomStringGenerator.generate());// 随机字符串 unifiedorderRequest.setBody("xxx自助按摩-" + pd.get("remark"));// 商品描述 unifiedorderRequest.setOut_trade_no(pd.getString("order_number"));// 商户订单号 Double three_pay_amount = Double.valueOf(pd.getString("three_pay_amount")); Double pay_money = BigDemicalUtil.mul(three_pay_amount, new Double(100)); int total_free = new Double(pay_money).intValue(); unifiedorderRequest.setTotal_fee(total_free); // 钱,单位是分 //unifiedorderRequest.setTotal_fee(1); // 钱,单位是分 unifiedorderRequest.setSpbill_create_ip(pd.getString("add_ip"));// 终端IP unifiedorderRequest.setTrade_type("JSAPI");// 交易类型 unifiedorderRequest.setOpenid(pd.getString("openid"));// 用户标识 unifiedorderRequest.setNotify_url(WXConstants.PAY_CALLBACK_URL);// 通知地址,异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 unifiedorderRequest.setTime_start(pd.getString("timeStart"));// 交易起始时间 try { unifiedorderResponse = PayManager.unifiedorder(unifiedorderRequest); } catch (SignatureException e) { e.printStackTrace(); } catch (PayApiException e) { e.printStackTrace(); } catch (PayBusinessException e) { e.printStackTrace(); } return unifiedorderResponse; }
b)下单工具类PayManager
public class PayManager { private static Logger logger = Logger.getLogger(PayManager.class); /** * 统一下单 */ private static final String HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder"; /** * 查询订单 */ private static final String HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_ORDERQUERY = "https://api.mch.weixin.qq.com/pay/orderquery"; /** * 关闭订单 */ private static final String HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_CLOSEORDER = "https://api.mch.weixin.qq.com/pay/closeorder"; /** * 申请退款 */ private static final String HTTPS_API_MCH_WEIXIN_QQ_COM_SECAPI_PAY_REFUND = "https://api.mch.weixin.qq.com/secapi/pay/refund"; /** * 查询退款 */ private static final String HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_REFUNDQUERY = "https://api.mch.weixin.qq.com/pay/refundquery"; /** * 下载对账单 */ private static final String HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_DOWNLOADBILL = "https://api.mch.weixin.qq.com/pay/downloadbill"; /** * 测速上报 */ private static final String HTTPS_API_MCH_WEIXIN_QQ_COM_PAYITIL_REPORT = "https://api.mch.weixin.qq.com/payitil/report"; /** * 统一下单 * <p>参考<a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1">开发文档</p> * * @param request * @return * @throws SignatureException * @throws PayApiException * @throws PayBusinessException */ public static UnifiedorderResponse unifiedorder(UnifiedorderRequest request) throws SignatureException, PayApiException, PayBusinessException { JaxbParser requestParser = buildJAXBParser(UnifiedorderRequest.class); JaxbParser responseParser = buildJAXBParser(UnifiedorderResponse.class); request.setSign(signature(request)); String postData = requestParser.toXML(request); logger.info("post data \n" + postData); String postResult = post(HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_UNIFIEDORDER, postData); logger.info("post result \n" + postResult); checkAccess(postResult); checkBusiness(postResult); validResponseSign(postResult); UnifiedorderResponse response = (UnifiedorderResponse) responseParser.toObj(postResult); return response; } /** * 查询订单 * <p>参考<a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2">开发文档</p> * * @param request * @return * @throws SignatureException * @throws PayApiException * @throws PayBusinessException */ public static OrderqueryResponse orderquery(OrderqueryRequest request) throws SignatureException, PayApiException, PayBusinessException { JaxbParser requestParser = buildJAXBParser(OrderqueryRequest.class); JaxbParser responseParser = buildJAXBParser(OrderqueryResponse.class); request.setSign(signature(request)); String postData = requestParser.toXML(request); logger.info("post data \n" + postData); String postResult = post(HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_ORDERQUERY, postData); logger.info("post result \n" + postResult); checkAccess(postResult); checkBusiness(postResult); validResponseSign(postResult); OrderqueryResponse response = (OrderqueryResponse) responseParser.toObj(postResult); try { parseCouponsForOrderquery(postResult, response); } catch (Exception e) { logger.error("解析代金券或立减优惠失败", e); PayApiException exception = new PayApiException(PayCode.FAIL, "解析代金券或立减优惠失败"); throw exception; } return response; } /** * 关闭订单 * <p>参考<a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2">开发文档</p> * * @param request * @return * @throws SignatureException * @throws PayApiException * @throws PayBusinessException */ public static CloseorderResponse closeorder(CloseorderRequest request) throws SignatureException, PayApiException, PayBusinessException { JaxbParser requestParser = buildJAXBParser(CloseorderRequest.class); JaxbParser responseParser = buildJAXBParser(CloseorderResponse.class); request.setSign(signature(request)); String postData = requestParser.toXML(request); logger.info("post data \n" + postData); String postResult = post(HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_CLOSEORDER, postData); logger.info("post result \n" + postResult); checkAccess(postResult); checkBusiness(postResult); validResponseSign(postResult); CloseorderResponse response = (CloseorderResponse) responseParser.toObj(postResult); return response; } /** * 申请退款 * <p>参考<a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4">开发文档</p> * * @param request * @return * @throws SignatureException * @throws PayApiException * @throws PayBusinessException */ public static RefundResponse refund(RefundRequest request) throws SignatureException, PayApiException, PayBusinessException { JaxbParser requestParser = buildJAXBParser(RefundRequest.class); JaxbParser responseParser = buildJAXBParser(RefundResponse.class); request.setSign(signature(request)); String postData = requestParser.toXML(request); logger.info("post data \n" + postData); String postResult = post(HTTPS_API_MCH_WEIXIN_QQ_COM_SECAPI_PAY_REFUND, postData); logger.info("post result \n" + postResult); checkAccess(postResult); checkBusiness(postResult); validResponseSign(postResult); RefundResponse response = (RefundResponse) responseParser.toObj(postResult); return response; } /** * 查询退款 * <p>参考<a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4">开发文档</p> * * @param request * @return * @throws SignatureException * @throws PayApiException * @throws PayBusinessException */ public static RefundqueryResponse refundquery(RefundqueryRequest request) throws SignatureException, PayApiException, PayBusinessException { JaxbParser requestParser = buildJAXBParser(RefundqueryRequest.class); JaxbParser responseParser = buildJAXBParser(RefundqueryResponse.class); request.setSign(signature(request)); String postData = requestParser.toXML(request); logger.info("post data \n" + postData); String postResult = post(HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_REFUNDQUERY, postData); logger.info("post result \n" + postResult); checkAccess(postResult); checkBusiness(postResult); validResponseSign(postResult); RefundqueryResponse response = (RefundqueryResponse) responseParser.toObj(postResult); try { parseCouponsForRefundquery(postResult, response); } catch (Exception e) { logger.error("解析代金券或立减优惠失败", e); PayApiException exception = new PayApiException(PayCode.FAIL, "解析代金券或立减优惠失败"); throw exception; } return response; } /** * 下载对账单 * <p>参考<a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">开发文档</p> * * @param request * @return * @throws PayApiException */ public static String downloadbill(DownloadbillRequest request) throws PayApiException { JaxbParser requestParser = buildJAXBParser(DownloadbillRequest.class); JaxbParser responseParser = buildJAXBParser(PayApiException.class); request.setSign(signature(request)); String postData = requestParser.toXML(request); logger.info("post data \n" + postData); String postResult = post(HTTPS_API_MCH_WEIXIN_QQ_COM_PAY_DOWNLOADBILL, postData); logger.info("post result \n" + postResult); PayApiException exception = null; try { Map<String, Object> mapFromXMLString = getMapFromXMLString(postResult); exception = new PayApiException(mapFromXMLString.get("return_code").toString(), mapFromXMLString.get("return_msg").toString()); } catch (Exception e) { // 如果不是XML则说明对账单下载成功 } if (exception != null) { throw exception; } else { return postResult; } } /** * 封装支付结果通知 * <p/> * <b>注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 </b> * <p><a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7">开发文档</p> * * @param servletRequest * @return * @throws SignatureException * @throws PayApiException * @throws PayBusinessException */ public static PayResultNotifyResponse parsePayResultNotify(ServletRequest servletRequest, ServletResponse servletResponse) throws SignatureException, PayApiException, PayBusinessException { JaxbParser responseParser = buildJAXBParser(PayResultNotifyResponse.class); JaxbParser exceptionParser = buildJAXBParser(PayApiException.class); PayApiException exception = new PayApiException(PayCode.SUCCESS, "OK"); String postResult; try { int len; byte[] b = new byte[1024]; ByteArrayOutputStream stream = new ByteArrayOutputStream(); InputStream servletInputStream = servletRequest.getInputStream(); while ((len = servletInputStream.read(b)) != -1) { stream.write(b, 0, len); } postResult = stream.toString(Consts.UTF_8.name()); } catch (IOException e) { logger.error("支付结果通知数据解析失败", e); exception = new PayApiException(PayCode.FAIL, "支付结果通知数据解析失败"); responseToWechat(servletResponse, exceptionParser.toXML(exception)); throw exception; } logger.info("result data \n" + postResult); checkAccess(postResult); try { validResponseSign(postResult); } catch (SignatureException e) { exception = new PayApiException(PayCode.FAIL, "签名校验失败"); responseToWechat(servletResponse, exceptionParser.toXML(exception)); throw e; } checkBusiness(postResult); PayResultNotifyResponse response = (PayResultNotifyResponse) responseParser.toObj(postResult); try { parseCouponsForPayResultNotify(postResult, response); } catch (Exception e) { logger.error("解析代金券或立减优惠失败", e); exception = new PayApiException(PayCode.FAIL, "解析代金券或立减优惠失败"); responseToWechat(servletResponse, exceptionParser.toXML(exception)); throw exception; } responseToWechat(servletResponse, exceptionParser.toXML(exception)); return response; } /** * 商户处理支付结果通知后同步返回给微信参数 * * @param servletResponse * @param postData * @throws PayApiException */ private static void responseToWechat(ServletResponse servletResponse, String postData) throws PayApiException { try { servletResponse.getOutputStream().write(postData.getBytes(Consts.UTF_8)); servletResponse.getOutputStream().flush(); servletResponse.getOutputStream().close(); } catch (IOException e) { throw new PayApiException(PayCode.FAIL, "支付结果通知同步返回失败"); } } /** * 构造H5调用支付的参数对象 * * @param timeStamp * @param nonceStr * @param prepayId * @return */ public static H5PayParam buildH5PayConfig(String timeStamp, String nonceStr, String prepayId) { H5PayParam config = new H5PayParam(); config.setTimeStamp(timeStamp); config.setNonceStr(nonceStr); config.setPackageWithPrepayId("prepay_id=" + prepayId); config.setPaySign(signature(config)); return config; } }
c)微信前台支付页面
//提交订单 $('#pay_btn').click(function () { $('#pay_btn').val("提交中..."); $('#pay_btn').attr("disabled","disabled"); var wechatInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i) ; if ( wechatInfo[1] < "5.0" ) { toastr.warning("请升级微信至5.0以上版本!"); return ; } var coupon = $("#coupon").val(); var type=${type}; isused = $(this).find("a").hasClass("active"); $.ajax({ url: '<%=basePath%>/order/payOrder.do', data: {isused:isused,type:type,coupon:coupon}, type: 'POST', cache:false, // async:false, dataType: 'JSON', timeout: 5000, error: function(textStatus){ $('#pay_btn').removeAttr("disabled"); $('#pay_btn').val("立即支付"); toastr.error('信息错误,请重试!'); }, success: function(result){ $('#pay_btn').removeAttr("disabled"); $('#pay_btn').val("立即支付"); var data=eval(result); data=data[0]; var wx_config=eval(data.config); appId = wx_config.appid; timeStamp = wx_config.timeStamp; nonceStr = wx_config.nonceStr; pg = wx_config.packageWithPrepayId; signType = wx_config.signType; paySign = wx_config.paySign; order_number=data.orderNumber; //唤起微信支付 pay(); } }); }); //唤起微信支付 function pay(){ if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } }else{ onBridgeReady(); } } //开始支付 function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : appId, //公众号名称,由商户传入 "timeStamp": timeStamp+"", //时间戳,自1970年以来的秒数 "nonceStr" : nonceStr, //随机串 "package" : pg, "signType" : signType, //微信签名方式: "paySign" : paySign //微信签名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { //回到用户订单列表 window.location.href="xxx/paySuccess.do?orderNumber="+order_number; }else if (res.err_msg == "get_brand_wcpay_request:cancel") { //alert("支付过程中用户取消"); }else{ //支付失败 //alert(res.err_msg) } } ); }
d)效果图(前端使用了toastr通知插件)
三:支付宝支付
a)支付宝下单
if (Constants.ALIPAY.equals(appType)) {// 支付宝 Map<String, String> aliPayMap = new HashMap<String, String>(); aliPayMap.put("orderNumber", orderNumber);// 商户订单号 aliPayMap.put("subject", "xxx自助按摩-" + remark);// 商品的标题/交易标题/订单标题/订单关键字等 aliPayMap.put("amount", three_pay_amount + "");// 订单总金额,单位为元,精确到小数点后两位 aliPayMap.put("boby", Constants.getPriceTypeLongMsg().get(type));// 对一笔交易的具体描述信息。 aliPayMap.put("returnUrl", "xxx/paySuccess.do?orderNumber=" + orderNumber);// 对一笔交易的具体描述信息。 // form表单生产 String form = alipayService.aliPay(aliPayMap, basePath); response.setContentType("text/html;charset=" + AlipayConfig.CHARSET); response.getWriter().write(form);// 直接将完整的表单html输出到页面 response.getWriter().flush(); response.getWriter().close(); }
b)下单工具类
public String aliPay(Map<String, String> map, String basePath) { String orderNumber = map.get("orderNumber"); String subject = map.get("subject"); String amount = map.get("amount"); String boby = map.get("boby"); String returnUrl = map.get("returnUrl"); AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest(); // 封装请求支付信息 AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); model.setOutTradeNo(orderNumber);// 商户订单号 model.setSubject(subject);// 商品的标题/交易标题/订单标题/订单关键字等 model.setTotalAmount(amount);// 订单总金额,单位为元,精确到小数点后两位 //model.setTotalAmount(0.01 + "");// 订单总金额,单位为元,精确到小数点后两位 model.setBody(boby);// 对一笔交易的具体描述信息 model.setTimeoutExpress("10m");// 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d model.setProductCode("QUICK_WAP_PAY");// 销售产品码,商家和支付宝签约的产品码。该产品请填写固定值:QUICK_WAP_WAY alipay_request.setBizModel(model); // 设置异步通知地址 alipay_request.setNotifyUrl(AlipayConfig.NOTIFY_URL); // 设置同步地址 alipay_request.setReturnUrl(returnUrl); // form表单生产 String form = ""; try { // 调用SDK生成表单 form = alipayClient.pageExecute(alipay_request).getBody(); } catch (AlipayApiException e) { e.printStackTrace(); } return form; }
c)效果
四:订单页面
五:收入明细
六:收入统计
七:代金券
八:余额充值
九:微信中控服务器
10:mysql5.7 保存微信emoj表情
11.redis数据库的使用
12.短信网关、邮件系统
13.系统部署在阿里云上
14.域名的备案
15.微信重复请求
and so on...
3个月的撸码,回头过来,能写的东西太多,垮过的坑更多,忙着年终总结+发奖金,没空写了,先开个头,有疑问的随时沟通交流吧,qq:540769049,备注来由。
相关文章推荐
- 【JS】jQuery设置定时器,访问服务器(PHP示例)配合微信、支付宝原生支付,跳转web网页
- 微信公众号中的支付宝支付与微信支付 && 支付宝支付问题(微信bug)
- 一份前端支付宝,微信支付及微信下面的支付充值接口
- 微信连WIFI认证、微信支付、支付宝支付需配置的白名单
- Android 仿「微信」「支付宝」的支付密码布局
- 微信支付或者支付宝支付的时候参数ASCII码排序
- Laravel 中使用支付宝、银联支付、微信支付进行支付
- 微信、支付宝的支付系统,帮您管钱挣钱
- [置顶] iOS支付(包括支付宝、微信、银联)封装
- 关于android微信支付 和 支付宝支付的集成
- 支付接口 - 微信,支付宝
- 《IOS 9 支付宝 and 微信 支付的集成》
- [置顶] 实现APP支付QQ,微信,支付宝三方的后端服务------php实现微信APP支付
- JavaWEB后端支付银联,支付宝,微信对接
- java支付宝和微信app支付(服务端处理)
- 微信支付——调用微信客户端支付之【服务端】开发详解
- 微信/支付宝安卓端和苹果端支付集合 Java版
- 支付流程(微信,支付宝)
- php做微信支付和支付宝支付的方法
- 关于支付(支付宝和微信)