SpringBoot微信扫码支付的实现示例
一、首先导入生成二维码和微信支付环境
com.google.zxing core 3.2.1 com.google.zxing javase 3.2.0 com.github.wxpay wxpay-sdk 0.0.3
二、在application.yml文件配置微信所有需的基本配置
1.导入
代码如下(示例):
#服务器域名地址 server: service-domain://这里写你的域名地址 #微信app支付 pay: wxpay: app: appID:微信appid mchID:商户号 key://这个key实在微信支付公众品台自己定义的key要求36位 certPath:static/cert/wxpay/apiclient_cert.p12#从微信商户平台下载的安全证书存放的路径、我放在resources下面,切记一定要看看target目录下的class文件下有没有打包apiclient_cert.p12文件 payNotifyUrl:#微信支付成功的异步通知接口这里引入你的回调接口。 //这里直接写https://域名:端口/接口地址,注意一定是线上的接口,因为微信访问不到你本地的接口
2.创建MyWXPayConfig类引入配置信息
代码如下(示例):
packagecom.example.gasstation.config; importlombok.Data; importorg.springframework.boot.context.properties.ConfigurationProperties; importorg.springframework.stereotype.Component; importjava.io.InputStream; @Data @Component @ConfigurationProperties(prefix="pay.wxpay.app") publicclassMyWXPayConfigimplementsWXPayConfig{ /** *appID */ privateStringappID; /** *商户号 */ privateStringmchID; /** *API密钥 */ privateStringkey; /** *API证书绝对路径(本项目放在了resources/cert/wxpay/apiclient_cert.p12") */ privateStringcertPath; /** *HTTP(S)连接超时时间,单位毫秒 */ privateinthttpConnectTimeoutMs=8000; /** *HTTP(S)读数据超时时间,单位毫秒 */ privateinthttpReadTimeoutMs=10000; /** *微信支付异步通知地址 */ privateStringpayNotifyUrl; /** *微信退款异步通知地址 */ privateStringrefundNotifyUrl; /** *统一下单url */ privatefinalStringUNIFIED_ORDER_URL="https://api.mch.weixin.qq.com/pay/unifiedorder"; /**这里实现了一个service层**/ @Override publicInputStreamgetCertStream(){ InputStreamcertStream=getClass().getClassLoader().getResourceAsStream(certPath); returncertStream; } //在同层级下面新建WXPayConfigservice层 packagecom.example.gasstation.config; importjava.io.InputStream; publicinterfaceWXPayConfig{ InputStreamgetCertStream();//不要问我为啥不另起一行,因为我懒 } }
三、引入WxPayServiceImpl实现类
packagecom.example.gasstation.server.impl; importcom.example.gasstation.config.MyWXPayConfig; importcom.example.gasstation.entity.Result; importcom.example.gasstation.mapper.PayMapper; importcom.example.gasstation.model.Money_transfer; importcom.example.gasstation.model.Pay; importcom.example.gasstation.server.WxPayService; importcom.example.gasstation.util.HttpClientUtil; importcom.example.gasstation.util.WXPayUtils; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.stereotype.Service; importjava.text.DecimalFormat; importjava.text.SimpleDateFormat; importjava.util.Date; importjava.util.Map; importjava.util.SortedMap; importjava.util.TreeMap; @Service publicclassWxPayServiceImplimplementsWxPayService{ @Autowired privateMyWXPayConfigwxPayAppConfig; @Autowired privatePayMapperpayMapper; @Override publicStringsave(StringorderNo,doubleamount,Stringbody,Integeruid){ SimpleDateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");//设置日期格式 //1.生成订单 //订单号,流水号,金额,付款状态,创建时间 Stringproduct_id=WXPayUtils.generateUUID(); Paypay=newPay();//这里新建一个实体类用处存入数据库 pay.setTradeNo(product_id); pay.setOutTradeNo(orderNo); pay.setBody(body); pay.setPaystatus(1); pay.setUid(uid); pay.setTotalAmount(amount); pay.setGmtCreate(df.format(newDate())); pay.setTradeStatus("0"); pay.setAppId(wxPayAppConfig.getAppID()); //生成预支付订单,保存到数据库 payMapper.insert(pay); //调用统一下单方法,返回codeUrl地址 StringcodeUrl=unifiedOrder(product_id,orderNo,amount,body); returncodeUrl; } privateStringunifiedOrder(Stringproduct_id,StringorderNo,doubleamount,Stringbody){ //生成签名 try{ SortedMapparams=newTreeMap<>(); params.put("appid",wxPayAppConfig.getAppID()); params.put("mch_id",wxPayAppConfig.getMchID()); params.put("nonce_str",WXPayUtils.generateUUID()); params.put("body",body);//商品描述 params.put("out_trade_no",orderNo);//商户订单号 params.put("total_fee",String.valueOf((int)(amount*100)));//标价金额(单位为分) params.put("spbill_create_ip","这里写服务器IP");//终端IP params.put("notify_url",wxPayAppConfig.getPayNotifyUrl());//异步接收微信支付结果通知的回调地址 params.put("trade_type","NATIVE");//交易类型 params.put("product_id",product_id);//微信支付要求NATIVE支付,此参数必填 //sign签名 Stringsign=WXPayUtils.createSign(params,wxPayAppConfig.getKey()); params.put("sign",sign); System.out.println(sign); //map转xml StringpayXml=WXPayUtils.mapToXml(params); System.out.println(payXml); //统一下单 Strings=HttpClientUtil.doPost(wxPayAppConfig.getUNIFIED_ORDER_URL(),payXml,10000); if(null==s){ returnnull; } Map unifiedOrderMap=WXPayUtils.xmlToMap(s); System.out.println(unifiedOrderMap.toString()); if(unifiedOrderMap!=null){ //前台添加定时器,进行轮询操作,直到支付完毕 returnunifiedOrderMap.get("code_url"); } }catch(Exceptione){ e.printStackTrace(); } returnnull; } }
四、引入WxPayService层
packagecom.example.gasstation.server; importcom.example.gasstation.model.Money_transfer; publicinterfaceWxPayService{ Stringsave(StringorderNo,doubleamount,Stringbody,Integeruid); booleancallBackPayUpdate(StringoutTradeNo,StringtotalFee); }
五、引入Util类
packagecom.example.gasstation.util; importcom.github.wxpay.sdk.WXPayUtil; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.w3c.dom.Node; importorg.w3c.dom.NodeList; importorg.w3c.dom.Document; importorg.w3c.dom.Element; importjavax.xml.parsers.DocumentBuilder; importjavax.xml.transform.OutputKeys; importjavax.xml.transform.Transformer; importjavax.xml.transform.TransformerFactory; importjavax.xml.transform.dom.DOMSource; importjavax.xml.transform.stream.StreamResult; importjava.io.ByteArrayInputStream; importjava.io.InputStream; importjava.io.StringWriter; importjava.util.*; /** *@Authorqjp */ publicclassWXPayUtils{ /** *XML格式字符串转换为Map * *@paramstrXMLXML字符串 *@returnXML数据转换后的Map *@throwsException */ publicstaticMapxmlToMap(StringstrXML)throwsException{ try{ Map data=newHashMap (); DocumentBuilderdocumentBuilder=WXPayXmlUtil.newDocumentBuilder(); InputStreamstream=newByteArrayInputStream(strXML.getBytes("UTF-8")); org.w3c.dom.Documentdoc=documentBuilder.parse(stream); doc.getDocumentElement().normalize(); NodeListnodeList=doc.getDocumentElement().getChildNodes(); for(intidx=0;idx data)throwsException{ Documentdocument=WXPayXmlUtil.newDocument(); Elementroot=document.createElement("xml"); document.appendChild(root); for(Stringkey:data.keySet()){ Stringvalue=data.get(key); if(value==null){ value=""; } value=value.trim(); Elementfiled=document.createElement(key); filed.appendChild(document.createTextNode(value)); root.appendChild(filed); } TransformerFactorytf=TransformerFactory.newInstance(); Transformertransformer=tf.newTransformer(); DOMSourcesource=newDOMSource(document); transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); transformer.setOutputProperty(OutputKeys.INDENT,"yes"); StringWriterwriter=newStringWriter(); StreamResultresult=newStreamResult(writer); transformer.transform(source,result); Stringoutput=writer.getBuffer().toString();//.replaceAll("\n|\r",""); try{ writer.close(); } catch(Exceptionex){ } returnoutput; } /** *生成微信支付sign */ publicstaticStringcreateSign(SortedMap params,Stringkey){ StringBuildersb=newStringBuilder(); Set >es=params.entrySet(); Iterator >it=es.iterator(); while(it.hasNext()){ Map.Entry entry=it.next(); Stringk=entry.getKey(); Stringv=entry.getValue(); if(null!=v&&!"".equals(v)&&!"sign".equals(k)&&!"key".equals(k)){ sb.append(k+"="+v+"&"); } } sb.append("key=").append(key); Stringsign=MD5Util.MD5(sb.toString()).toUpperCase(); returnsign; } /** *校验签名 *@paramparams *@paramkey *@return */ publicstaticBooleanisCorrectSign(SortedMap params,Stringkey){ Stringsign=createSign(params,key); StringwxPaySign=params.get("sign").toUpperCase(); returnwxPaySign.equals(sign); } /** *获取有序map *@parammap */ publicstaticSortedMap getSortedMap(Map map){ SortedMap sortedMap=newTreeMap<>(); Iterator it=map.keySet().iterator(); while(it.hasNext()){ Stringkey=it.next(); Stringvalue=map.get(key); Stringtemp=""; if(null!=value){ temp=value.trim(); } sortedMap.put(key,value); } returnsortedMap; } /** *日志 *@return */ publicstaticLoggergetLogger(){ Loggerlogger=LoggerFactory.getLogger("wxpayjavasdk"); returnlogger; } /** *获取当前时间戳,单位秒 *@return */ publicstaticlonggetCurrentTimestamp(){ returnSystem.currentTimeMillis()/1000; } /** *获取当前时间戳,单位毫秒 *@return */ publicstaticlonggetCurrentTimestampMs(){ returnSystem.currentTimeMillis(); } /** *生成UUID(用来表示一笔订单) *@return */ publicstaticStringgenerateUUID(){ Stringuuid=UUID.randomUUID().toString() .replaceAll("-","") .substring(0,32); returnuuid; } }
引入WXPayXmlUtil类
packagecom.example.gasstation.util; importjavax.xml.XMLConstants; importjavax.xml.parsers.DocumentBuilder; importjavax.xml.parsers.DocumentBuilderFactory; importjavax.xml.parsers.ParserConfigurationException; importorg.w3c.dom.Document; publicfinalclassWXPayXmlUtil{ publicstaticDocumentBuildernewDocumentBuilder()throwsParserConfigurationException{ DocumentBuilderFactorydocumentBuilderFactory=DocumentBuilderFactory.newInstance(); documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true); documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities",false); documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities",false); documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false); documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,true); documentBuilderFactory.setXIncludeAware(false); documentBuilderFactory.setExpandEntityReferences(false); returndocumentBuilderFactory.newDocumentBuilder(); } publicstaticDocumentnewDocument()throwsParserConfigurationException{ returnnewDocumentBuilder().newDocument(); } }
六、引入WxPayController类
提示:到这里没有报错咱们已经成功一半啦
@RestController @RequestMapping("/wxPay") publicclassWxPayController{ @Autowired privateWxPayServicewxPayService; @Autowired privateMyWXPayConfigwxPayConfig; @Autowired privateWebMvcConfigurerwebMvcConfigurer; /** *微信支付生成二维码 * *@parammoney *@return */ @GetMapping("/pay") publicvoidwxPay(Doublemoney,Stringbody,Integeruid,HttpServletResponseresponse){ Doubleamount=money;//金额 SimpleDateFormatdate=newSimpleDateFormat("yyyyMMddHHmmss"); StringorderNo=date.format(newDate())+WXPayUtils.getCurrentTimestampMs(); Stringurl_code=wxPayService.save(orderNo,amount,body,uid); System.out.println("url_code:----------"+url_code); if(url_code==null){ thrownewNullPointerException(); } try{ //生成二维码配置 Maphints=newHashMap<>(); //设置纠错等级 hints.put(EncodeHintType.ERROR_CORRECTION,ErrorCorrectionLevel.L); //编码类型 hints.put(EncodeHintType.CHARACTER_SET,"UTF-8"); BitMatrixbitMatrix=newMultiFormatWriter().encode(url_code,BarcodeFormat.QR_CODE,400,400,hints); OutputStreamoutputStream=response.getOutputStream(); MatrixToImageWriter.writeToStream(bitMatrix,"png",outputStream); }catch(Exceptione){ e.printStackTrace(); } } /** *微信支付回调接口 */ @RequestMapping("/callback") publicvoidOrderCallBack(HttpServletRequestrequest,HttpServletResponseresponse){ InputStreaminputStream=null; try{ inputStream=request.getInputStream(); //BufferedReader是包装设计模式,性能更高 BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(inputStream,"UTF-8")); StringBufferstringBuffer=newStringBuffer(); Stringline; while((line=bufferedReader.readLine())!=null){ stringBuffer.append(line); } bufferedReader.close(); inputStream.close(); Map callBackMap=WXPayUtils.xmlToMap(stringBuffer.toString()); System.out.println(callBackMap.toString()); SortedMap sortedMap=WXPayUtils.getSortedMap(callBackMap); //校验签名是否正确 if(WXPayUtils.isCorrectSign(sortedMap,wxPayConfig.getKey())){ System.out.println("签名校验成功!"); //更新订单状态 if("SUCCESS".equals(sortedMap.get("result_code"))){ StringoutTradeNo=sortedMap.get("out_trade_no");//流水号 StringtotalFee=sortedMap.get("total_fee");//交易金额 if(wxPayService.callBackPayUpdate(outTradeNo,totalFee)){//通知微信订单处理成功 response.setContentType("text/xml"); response.setContentType("content-type"); response.getWriter().println(" "); //这里说明告诉微信你已经成功啦,别给老子重复回调我的方法啦,这里有一个坑, response.setContentType("text/xml"); response.getWriter().println("SUCCESS") //本身我就只有这两句话,然后就导致微信一直回调我的方法,废了半天的劲才搞好啦, //原因就是格式不对,给他返回的值他不认识,这里可以看一下微信的支付开发文档,虽然文档写的很垃圾 } } //未成功,就都处理为失败订单 response.setContentType("text/html"); response.getWriter().println("fail"); } }catch(IOExceptione){ e.printStackTrace(); }catch(Exceptione){ e.printStackTrace(); } }
七、MD5加密
@Slf4j publicclassMD5Util{ publicstaticStringMD5(Stringsource){ returnencodeMd5(source.getBytes()); } privatestaticStringencodeMd5(byte[]source){ try{ returnencodeHex(MessageDigest.getInstance("MD5").digest(source)); }catch(NoSuchAlgorithmExceptione){ thrownewIllegalStateException(e.getMessage(),e); } } privatestaticStringencodeHex(byte[]bytes){ StringBufferbuffer=newStringBuffer(bytes.length*2); for(inti=0;i总结
有什么不对的地方欢迎各位码友指出问题,因为我也是第一次做这个微信扫码支付
回调方法返回类型是void你设置其他返回类型,就会跟你给微信返的起冲突,就会导致报错
到此这篇关于SpringBoot微信扫码支付的实现示例的文章就介绍到这了,更多相关SpringBoot微信扫码支付内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。