写着写着,越写越多,思绪写不下了,回头写在前面的话。此系统属个人创业项目,历时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回调方法...");// 获取codeString 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到sessionString 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_codeString 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及用户userIdoauthTokenResponse = 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", userinfoShareResponse);// 保存用户信息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"));// 终端IPunifiedorderRequest.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~15dmodel.setProductCode("QUICK_WAP_PAY");// 销售产品码,商家和支付宝签约的产品码。该产品请填写固定值:QUICK_WAP_WAYalipay_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个月的撸码,回头过来,能写的东西太多,垮过的坑更多,忙着年终总结+发奖金,没空写了,先开个头,get系统源码发邮件至 540769049@qq.com,备注来由。

“一码多付”,微信支付、支付宝支付相关推荐

  1. 微信和支付宝支付模式详解及实现(.Net标准库)

    支付基本上是很多产品都必须的一个模块,大家最熟悉的应该就是微信和支付宝支付了,不过更多的可能还是停留在直接sdk的调用上,甚至和业务系统高度耦合,网上也存在各种解决方案,但大多形式各异,东拼西凑而成. ...

  2. 微信和支付宝支付模式详解及实现(.Net标准库)- OSS开源系列

    2019独角兽企业重金招聘Python工程师标准>>> 支付基本上是很多产品都必须的一个模块,大家最熟悉的应该就是微信和支付宝支付了,不过更多的可能还是停留在直接sdk的调用上,甚至 ...

  3. 微信,支付宝支付,微信公众号小程序授权等

    微信,支付宝支付,微信公众号小程序授权等 前言 微信支付 微信授权 maven依赖(更新) 前言 最近在公司也做了很多移动端项目,如今微信公众号,小程序又特别火爆,免不了要接触支付,授权这类的业务需求 ...

  4. Android项目内简单集成微信和支付宝支付功能

    最近自己公司的项目需要集成微信和支付宝支付,我是个初学者,然后就开始在网上各种搜索相关Demo.最后找了一个自我感觉还不错的Demo,挺适合初学者使用的.在使用之前一定要在微信平台和蚂蚁金服申请权限, ...

  5. 关于银联、微信、支付宝支付的相关信息

    一. 银联支付 本地没有其他的环境配置,只需要在支付时从服务器获取交易流水号(TN),然后调取支付控件,支付完成之后会通知商户后台以及客户端,,相关demo和SDK见官网.银联支付. 二. 微信支付 ...

  6. 微信和支付宝支付实战

    最近的项目中要用到移动支付.在此总结下 1.微信支付 :因为需求是扫码支付即时到账,用的是native方式.按照官方文档的说法,调用"https://api.mch.weixin.qq.co ...

  7. 微擎支付返回商户单号_微信、支付宝支付动态库PayApiFun.dll说明

    微信.支付宝支付动态库PayApiFun.dll说明 PayApiFun.dll这个动态库中包含了:微信付款码支付.生成微信支付二维码扫码支付.按商户单号查询微信支付状态.关闭未支付的微信订单.支付宝 ...

  8. Android Study 之 6分钟妥妥集成微信以及支付宝支付

    LZ-Says:来说俩件事儿: 1.一心只为一人用,一言只为一人说~ 2.今天坐公交,末班车,车上只有司机和我,阴森森的,吓死LZ了...一路小跑!!! 前言 (浪费一分钟) 今天,不讲这个,也不讲那 ...

  9. H5页面中调用微信和支付宝支付

    最近在工作中,有个H5页面需要实现微信支付和支付宝支付的功能,现在已经完成,抽个时间写出来,分享给有需要的人. 第一步:先判断当前环境 判断用户所属环境,根据环境不同,执行不同的支付程序. if (/ ...

  10. Android 微信支付支付宝支付

    由于项目需求,加入这2个功能记录一些需要注意的地方 一.微信支付 微信支付在2016年4月份左右稍微调整了一下支付过程,但是文档却没怎么更新,这也是百度上为什么那么多开发者都说微信是个大坑. 身为一个 ...

最新文章

  1. 270个开源项目,总计24w星,帮你快速找代码
  2. ios6.x越狱将不会再呈现了
  3. 全球首个知识增强千亿大模型鹏城-百度·文心发布
  4. excel有必要用python_为什么Python比VBA更适合自动化处理Excel数据?
  5. 19年8月 字母哥 第三章 spring boot 配置原理实战 用热点公司网不行
  6. nullnullicon 小图标
  7. 【c语言】关键字存储类型讲解(auto,extern,static,register,const)
  8. android编辑框显示,android – 如何在屏幕上显示文本编辑框?
  9. asp.net 设置敲回车触发按钮
  10. c语言中位运算符及用法
  11. springboot闲置衣物捐赠系统毕业设计源码021009
  12. 初次学习Docker没什么经验记录下的笔记
  13. 卫星运行的规律与卫星定位原理
  14. 汇顶2018年 IC校招笔试题目
  15. OSChina 周五乱弹 ——程序员脱单攻略!
  16. tmshutdown: internal error: CMDTUX_CAT:766: ERROR: must run on master node
  17. 来自千里之外祖国的关爱
  18. 【实战经验】Greenplum集群Master與Segment节点故障检测与恢复
  19. 倾角传感器组成和应用
  20. edxp已激活模块_安卓系统神器Edxposed Framework安装使用教程及微X模块分享!

热门文章

  1. 安卓适配 全面屏的适配(小米MIX2 的适配)
  2. android 开源 高斯模糊_android高斯模糊特效
  3. Python实现程序自动发送短信
  4. 光亮剂与增亮剂_新型增光增亮剂(配方)
  5. GWAS曼哈顿图总结
  6. 2. 代价函数与梯度下降
  7. ceph存储 ceph集群监视器设置
  8. 扣扣飞车手游好久没登不显示服务器,qq飞车手游为什么进不去 解决方法
  9. Vb+access工资管理系统(系统+答辩PPT+论文+开题报告+外文翻译)
  10. 如何制作俄罗斯方块(作业第三部分)