微信的扫码支付,web(h5)支付,小程序支付,代码干货

代码都没有经过精简,是为了看起来方便,有需要可以自行修改封装

扫码支付比较简单

	/**
	 *  统一下单
	 * @throws Exception## 标题
	 */
	@RequestMapping("/wxpay/unified/order")
	@ResponseBody
	public Map<String, String> doUnifiedOrder(
			Model model) throws Exception {
		Map<String, String> resp = null;
		//wxpayConfig是自行封装的一个类  下面会放出具体属性
		WxPayConfig wxPayConfig =new WxPayConfig (“可以把支付信息存库,需要用到都从库里拿”);
		//最好对数据库查询出的信息进行一下基本的判空
		if (config == null) {
			throw new Exception("config is null");
		}
		if (config.getAppId() == null || config.getAppId().trim().length() == 0) {
			throw new Exception("appid in config is empty");
		}
		if (config.getMchId() == null || config.getMchId().trim().length() == 0) {
			throw new Exception("appid in config is empty");
		}
		if (config.getSslCert() == null) {
			throw new Exception("cert stream in config is empty");
		}
		
		WxPay wxpay = new WxPay(wxPayConfig);
		//以下四个参数要根据具体需求使用 也可以都写死 只传orderId 和金额 这样是为了封装起来 使用方便
		String orderId=request.getParameter("order_id");
		String outTradeNo=request.getParameter("out_trade_no");
		String totalFee=request.getParameter("total_fee");
		String body_desc=request.getParameter("body_desc");
		logger.info("支付提交参数:outTradeNo"+outTradeNo+"orderId:"+orderId+"totalFee:"+totalFee+"body_desc:"+body_desc);
		Map<String, String> data = new HashMap<String, String>();
		data.put("body", body_desc);//支付描述
		data.put("out_trade_no", outTradeNo);//订单号
		data.put("device_info", "");//设备号
		data.put("fee_type", "CNY");//人民币类型
		data.put("total_fee", totalFee);//总金额
		
		String ip=“”;
		//获取ip
		 InetAddress ia=null;
	        try {
	            ia=ia.getLocalHost();
	            ip=ia.getHostAddress();
	        }catch (Exception e) {
	        	e.printStackTrace();
			}
		
		data.put("spbill_create_ip",ip);//IP地址
	
		data.put("notify_url", "https://xxxx.com/xxx/xx");//完整的微信回调通知地址 需要在微信公众号后台配置		
		data.put("product_id", orderId);
		data.put("trade_type", "NATIVE");  // 此处指定为扫码支付  0
		data.put("attach", orderId);
		try {
			logger.info("支付参数为:"+data);
			//发起请求支付了 resp为返回信息
			resp = wxpay.unifiedOrder(data);
			//WxPayLog是微信支付日志的记录 有需要可以加上 就不放出来了 
			WxPayLog wxPayLog=new WxPayLog();
			wxPayLog.setOrderId(Long.parseLong(orderId));
			wxPayLog.setCodeUrl(resp.get("code_url"));
			wxPayLog.setCreateTime(new Date());
			wxPayLog.setNonceStr(resp.get("nonce_str"));
			wxPayLog.setOutTradeNo(outTradeNo);
			wxPayLog.setResultCode(resp.get("result_code"));
			wxPayLog.setReturnMsg(resp.get("return_msg"));
			wxPayLog.setSign(resp.get("sign"));
			wxPayLog.setTradeType(0);
			wxPayLog.setTotalFee(Double.parseDouble(totalFee));
			wxPayLogRep.save(wxPayLog);
		} catch (Exception e) {
			e.printStackTrace();
		}
		logger.info("支付返回:"+resp);
		return resp;
	}

WxPayConfig 实体类

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
*
*封装支付需要的相关参数
**/
@Entity
public class WxPayConfig {
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Long Id;
	private String appId;//公众账号ID
	private String  appSecret;//公众号秘钥
	private String  mchId;//商户号
	private String  appKey;//app秘钥
	private String  isvName;//服务商名称
	private String  subMchId;//子商户号
	private Integer  payType;//支付类型  0.通过I,SV渠道接入 HMAC-SHA256   (默认)  1. ***支付渠道 MD5,	
	//get set 方法补一下
}

在回调函数 也就是传给微信的‘notify_url’路径所对应的方法中,微信会回调多次这个地址,在收到支付成功的消息,需要给微信返回已收到,不然会一直回调,具体次数不太记得了。时间相差也懒得去百度了

扫码支付的微信回调方法

/**
	 * 微信支付回调处理
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping("/wxpay/notify")//具体url自行在发起支付的时候配置
	@ResponseBody
	public String wxNotify() throws Exception {
		logger.info("微信回调了");
		//获取微信传回的信息
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		response.setHeader("Access-Control-Allow-Origin", "*");

		InputStream in = request.getInputStream();
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = in.read(buffer)) != -1) {
			out.write(buffer, 0, len);
		}
		out.close();
		in.close();
		String content = new String(out.toByteArray(), "utf-8");// 微信传回的信息是xml数据
		Map<String, String> map =xmlToMap(content);
		String resultCode = map.get("result_code");
		String outTradeNo=map.get("out_trade_no");
		String totalFee=map.get("total_fee");
		logger.info("微信返回数据:"+"resultCode:"+resultCode+"outTradeNo:"+outTradeNo+"totalFee:"+totalFee);
		WxPayLog payLog = new WxPayLog (‘找到支付之前存库的WxPayLog ,可以使用outTradeNo去库里查找’);
		// 可以根据当前payLog.getOrderId()去判断是哪一个支付的订单 或者具体是用哪一个参数去做的订单绑定都可以
			logger.info("订单Id:"+payLog.getOrderId());
			if (resultCode.equalsIgnoreCase("FAIL")) {//支付失败
			
			//将相对应订单状态修改一下,并返回给客户 ,暂时没遇到过支付失败,不过不代表没有
			
		  } else if (resultCode.equalsIgnoreCase("SUCCESS")) {// 支付成功
				logger.info("支付成功了");
				if(‘对比订单金额和微信返回金额是否一致‘) {
				}else {
				//支付金额不一致!
				}
			//  这里处理自己数据库中的订单表业务
		logger.info("返回数据为:"+JSON.toJSONString(map));
		//支付成功通知微信已接受到返回信息
		if(resultCode.equalsIgnoreCase("SUCCESS")) {
			String resSuccessXml = "<xml><return_code>SUCCESS</return_code></xml>";
			return resSuccessXml;
		}
		String resFailXml = "<xml><return_code>FAIL</return_code></xml>";
		return resFailXml;

	}

xml转换成map的方法

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) {
			throw ex;
		}
	}
扫码支付差不多就就这样,如果有坑可以留言

接下来web支付和小程序支付,两者几乎没差别,写在一起

/**
	 *web, 小程序支付
	 * @param request
	 * @return
	 */
	@RequestMapping(value="/wx/wxPayment")
	@ResponseBody
	public JSON payOut(HttpServletRequest request) {
		JSONObject map= new JSONObject();
		
		logger.info("进入微信支付请求");
	//可以继续使用上文的 WxPayConfig 
		WxPayConfig wxPayConfig= new WxPayConfig ();
		if (wxConfig == null) {
			map.put("code", 0);
			map.put("msg", "微信配置错误");
			return map;
		}
		String wxAppId = wxPayConfig.getWxAppId();
		String mchId = wxPayConfig.getMchId();
		String key = wxPayConfig.getPayKey();
		try {
			String appSecret=wxPayConfig.getWxAppSecret();
			Random random = new Random();
			String nonceStr = "";
			while (nonceStr.length() < 32) {
				int i = random.nextInt(35);
				nonceStr += randomStr[i];
			}
			SimpleDateFormat sdf2=new SimpleDateFormat("yyyyMMddHHmmss");
			String orderId =“”;//orderId可以用时间加上一个用户的id 这里随意 但是要保证微信回调的时候可以判断是哪一个用户发起的支付
			String openId=“”;//对应用户openId
	
			String body = "";// 此处填告知用户支付了什么业务 比如某某超市什么的,中文有可能报错,如果报错就使用英文试试排除这个错误,不过下文也有对参数进行编码,一般不会出错
			String totalFee =String.valueOf(product.getTotal());
			//金额单位转换为“分”
			float floatTotalFee = Float.parseFloat(totalFee); 
			int intTotalFee = (int) (floatTotalFee * 100);
			totalFee = "" + intTotalFee;
			String tradeType = "JSAPI";
		
			String spBillCreateIP = request.getRemoteAddr();
			
			//设置回调地址
			String notifyUrl = "";//和上文扫码支付一样的配置就好了,要注意商户后台的支付域名配置 最好是
			/*
			比如支付是:https://xxxx.com/wxpay/payment
			那回调的就要是:https://xxxx.com/wxpay/notify
			商户后台的支付域名配置:https://xxxx.com/wxpay 就要这样配置到最后"/"的上一级
			*/

			String sign =WxPayUtil.MD5("appid=" + wxAppId + "&body=" + body + "&mch_id=" + mchId + "&nonce_str=" + nonceStr
					+ "&notify_url=" + notifyUrl + "&openid=" + openId + "&out_trade_no=" +orderId
					+ "&spbill_create_ip=" + spBillCreateIP + "&total_fee=" + totalFee + "&trade_type=" + tradeType
					+ "&key=" + key);
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			// 创建Document
			Document document = builder.newDocument();
			// 创建Element
			Element xml = document.createElement("xml");
			xml.appendChild(makeElement("appid", wxAppId, document));
			xml.appendChild(makeElement("body", body, document));
			xml.appendChild(makeElement("mch_id", mchId, document));
			xml.appendChild(makeElement("nonce_str", nonceStr, document));
			xml.appendChild(makeElement("notify_url", notifyUrl, document));
			xml.appendChild(makeElement("openid", openId, document));
			xml.appendChild(makeElement("out_trade_no", orderId, document));
			xml.appendChild(makeElement("spbill_create_ip", spBillCreateIP, document));
			xml.appendChild(makeElement("total_fee", totalFee, document));
			xml.appendChild(makeElement("trade_type", tradeType, document));
			xml.appendChild(makeElement("sign", sign, document));
			document.appendChild(xml);
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer t = tf.newTransformer();
			t.setOutputProperty("encoding", "UTF-8");
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			t.transform(new DOMSource(document), new StreamResult(bos));
			String xmlStr = bos.toString("UTF-8");
			// 发送支付请求 HttpUtils 这个共具类很普遍 有需要请自行百度
			String result = HttpUtils.doPost("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlStr);
			logger.info("微信支付返回:"+result);
			// 解析
			StringReader sr = new StringReader(result);
			InputSource is = new InputSource(sr);
			DocumentBuilderFactory factory2 = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder2 = factory2.newDocumentBuilder();
			Document doc = builder2.parse(is);
			String returnCode = doc.getElementsByTagName("return_code").item(0).getFirstChild().getNodeValue();
			System.out.println("returnCode:"+returnCode);
			//web,和小程序支付都会有一个预订单Id  prepay_id
			if (returnCode.equals("SUCCESS")) {
				String prepayId = doc.getElementsByTagName("prepay_id").item(0).getFirstChild().getNodeValue();//getChileElementValue(element, "prepay_id");
				map.put("appId", wxAppId);
				String timeStamp = Long.toString(System.currentTimeMillis());
				timeStamp = timeStamp.substring(0, 10);
				map.put("timeStamp", timeStamp);
				map.put("nonceStr", nonceStr);
				String packageStr = "prepay_id=" + prepayId;
				map.put("package", packageStr);
				map.put("signType", "MD5");
				//MD5加密 具体规则查询微信支付API
				String paySign = MD5("appId=" + wxAppId + "&nonceStr=" + nonceStr + "&package=" + packageStr
						+ "&signType=MD5&timeStamp=" + timeStamp + "&key=" + key);
				map.put("paySign", paySign);
				
				logger.info("调起支付:"+map);
				/* 小程序支付
				到这一步将map这个参数传给小程序端,小程序端根据以上参数就可以发起支付 
				返回签名错误的时候,就要检查paySign 参数是否有错,参数可以打印出来看看 方便找错
				*/
					/* web支付
				将map转换成json传到界面
				*/
				
				return map;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("catch");
		}
		map.put("code", 0);
		map.put("msg", "系统错误");
		return map;
	}

web(h5)支付js

//先判断是否在微信环境下
if (typeof WeixinJSBridge == "undefined"){  
				            
				            alert("请在微信中打开网站进行支付");
				   
						    if( document.addEventListener ){
						    	//addEventListener() 方法用于向指定元素添加事件句柄。
						        document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
						    }else if (document.attachEvent){
						        document.attachEvent('WeixinJSBridgeReady', jsApiCall);
						        document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
						    }
					}else{
						   jsApiCall();
					}
//使用ajax访问上文的支付接口 返回的信息调用下文方法
	function jsapiPay (payment){
				 WeixinJSBridge.invoke(
					       'getBrandWCPayRequest', {
					           "appId":payment.appId,     //公众号名称,由商户传入     
					           "timeStamp":payment.timeStamp,         //时间戳,自1970年以来的秒数     
					           "nonceStr":payment.nonceStr, //随机串     
					           "package":payment.package1,     
					           "signType":"MD5",         //微信签名方式:     
					           "paySign":payment.paySign //微信签名 
					       },
					       function(res){     
					           if(res.err_msg == "get_brand_wcpay_request:ok" ) {
					           //表示支付成功
					        	   //更新相对应支付订单
					           }     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。 
					       }
					   );
			}

web支付,小程序支付回调函数

/**
	 * 微信支付回调
	 * @param request
	 * @return
	 */
	@RequestMapping(value="/wxPayNotify")
	public void wxNotify(HttpServletRequest request, HttpServletResponse response) {
		logger.info("微信支付回调");
		String postData = "";
		try {
			BufferedReader reader = null;
			StringBuilder buf = new StringBuilder();
			try {
				String line;
				reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
				while ((line = reader.readLine()) != null) {
					buf.append(line).append("\n");
				}
			} catch (Exception e) {
				throw e;
			}
			postData = buf.toString();
			logger.info("微信支付回调结果:"+postData);
		} catch (Exception e) {
			return ;//"success";
		}
		if (postData != null && !postData.equals("")) {
			StringReader sr = new StringReader(postData);
			InputSource is = new InputSource(sr);
			DocumentBuilderFactory factory2 = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder2 = null;
			try {
				builder2 = factory2.newDocumentBuilder();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Document doc = null;
			try {
				doc = builder2.parse(is);
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String returnCode = doc.getElementsByTagName("return_code").item(0).getFirstChild().getNodeValue();
			System.out.println("支付成功返回:"+doc);
			if (returnCode.equalsIgnoreCase("SUCCESS")) {


				// ͨ解析
				String resultCode = doc.getElementsByTagName("result_code").item(0).getFirstChild().getNodeValue();

				String orderId = doc.getElementsByTagName("out_trade_no").item(0).getFirstChild().getNodeValue();
				//支付是否成功
				if (resultCode.equalsIgnoreCase("success")) {
					String merchantId =doc.getElementsByTagName("mch_id").item(0).getFirstChild().getNodeValue();
					String wxOrderId =doc.getElementsByTagName("transaction_id").item(0).getFirstChild().getNodeValue(); 
					String payTime =doc.getElementsByTagName("time_end").item(0).getFirstChild().getNodeValue();
					String tradeType =doc.getElementsByTagName("trade_type").item(0).getFirstChild().getNodeValue();
					String bankType =doc.getElementsByTagName("bank_type").item(0).getFirstChild().getNodeValue(); 
					String totalFee =doc.getElementsByTagName("total_fee").item(0).getFirstChild().getNodeValue(); 
					String feeType = doc.getElementsByTagName("fee_type").item(0).getFirstChild().getNodeValue();
					String cashFee = doc.getElementsByTagName("cash_fee").item(0).getFirstChild().getNodeValue();
					String cashFeeType = "CNY";//doc.getElementsByTagName("cash_fee_type").item(0).getFirstChild().getNodeValue();
					String sign = doc.getElementsByTagName("sign").item(0).getFirstChild().getNodeValue();
					/**
						进行相关订单操作和验证
					*/
					//获取签名要用到的key
				
					WxPayConfig wxPayConfig = new WxPayConfig ('支付的相关参数');
					if (wxPayConfig == null) {
						return ;
					}
					String mchId = wxPayConfig.getMch_Id();
					String key = wxPayConfig.getPay_Key();
					//签名认证
					Map<String , String> map = new HashMap<String,String>();
					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;
							map.put(element.getNodeName(), element.getTextContent());
						}
					}
					String newSign = generateSignature(map, key);
					if(!sign.equals(newSign)) {
						return ;
					}
					payTime = payTime.substring(0, 4) + "-" + payTime.substring(4, 6) + "-" + payTime.substring(6, 8)
					+ " " + payTime.substring(8, 10) + ":" + payTime.substring(10, 12) + ":"
					+ payTime.substring(12, 14);
					java.sql.Timestamp timeStamp = java.sql.Timestamp.valueOf(payTime);
				//	根据具体支付流程去处理支付成功后的操作
					//支付日志存库
						WxPayNotify wxPayNotify = new WxPayNotify ();
						wxPayNotify.setMerchantId(merchantId);
						wxPayNotify.setWxOrderId(wxOrderId);
						wxPayNotify.setPayTime(timeStamp);
						wxPayNotify.setTradeType(tradeType);
						wxPayNotify.setBankType(bankType);
						wxPayNotify.setTotalFee(totalFee);
						wxPayNotify.setFeeType(feeType);
						wxPayNotify.setCashFee(cashFee);
						wxPayNotify.setFeeType(cashFeeType);
						wxPayNotify.setOrderId(orderId);
					//保存支付日志
					
					//修改订单状态
					
					response.setContentType("text/plain");
					try {
					//告知微信 收到支付成功的消息
						Writer out = response.getWriter();
						out.write("<xml>");
						out.write("<return_code><![CDATA[SUCCESS]]></return_code>");
						out.write("<return_msg><![CDATA[OK]]></return_msg>");
						out.write("</xml>");
						out.flush();
					} catch (IOException e) {
					}
				} else {
				}
			}
		}
		return ;
	}
/**
	 * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
	 * @param data 待签名数据
	 * @param key API**
	 * @return 签名
	 */
	public static String generateSignature(final Map<String, String> data, String key)  {
		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("sign")) {
				continue;
			}
			if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
				sb.append(k).append("=").append(data.get(k).trim()).append("&");
		}
		sb.append("key=").append(key);
		return MD5(sb.toString()).toUpperCase();
	}

有问题请留言,勿喷,只是为了记录一下微信支付注意事项

猜你喜欢