微信app支付详解

阿西吧,弄了一个多小时,弄错了一点全没了,,,,,,,,啥破编辑器,醉了,重新来吧。

          咳咳,不要紧张,清理一下嗓子,在开始之前,我想说说,在完成之前,我本人就是一个菜鸟,很多地方我也不会弄呢,像我这种看开发文档就头疼的人做微信支付,对着官方文档整个人都飘了,本文就是针对一些不会做又看文档头疼的人来做的,相信只要会java的菜鸟看着都能做出来,第一次写博客,希望写点对大家有帮助的东西,  在感慨一下,其实很多程序我么您第一次做的时候都想的太复杂了,做完了之后就感觉其实也没个啥,当你们看完这篇文章完成微信支付的时候,相信第一次弄的童鞋们会和我一样有这种感慨。如果这篇文章帮助到你了,请给我赞一个夸夸我。

 废话不多说 直接开始正文

        微信支付,我们做java只是后台服务端,具体的实现流程官方写的我也看不懂,下边是我自己理解的

  客户确认商品点击支付—>后台提供前端调用的加签接口---->前端拿到后台加签的参数调起支付-->微信支付--->微信回调后台提供的回调接口    

这样微信支付就完成了,总体看起来,后台只需要做两件事

      1.给前端提供接口把订单进行加签在返还给前端

      2.给微信提供回调接口确认支付信息。

这样说的够明白了吧,相信大家已经明白后台需要做哪些事了吧。

在做微信支付之前,后台得获得3个重要的参数

微信官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1点击打开链接

1.appid  微信商户号   appkey


这几个参数都是微信支付必要的,最重要的,所以一定要根据文档找准确了,有了这几个参数,自己封装一下,下边要用到的时候自己能调用出来就行。注意,这几个参数极为重要,所以写的时候尽量封装严实一点,不然有可能有不安全因素。


封装完这几个参数以后,自己写一个供前端调用的接口,上代码:

	/**
	 * 微信app支付统一下单
	 * @param request
	 * @param orderNumber
	 * @param payMoney
	 * @param orderType
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value="/APP/weixinPay",method={RequestMethod.POST,RequestMethod.GET})
	@ResponseBody
       /**
*  ResultState  是我自己封装的一个返回结果的对象,有需要的后边我会附代码,很简单的,毕竟我本人水平也不好。
*    在这里,订单加签我让前端穿了3个参数  orderNumber 订单编号 需要提供给微信的  payMoney 用户支付金额  需要提供给微信的 orderType订单类型 确定body字段的
*  这里大家可以根据自己的业务逻辑确定参数,没必要跟我的一致,返回结果也是,大家也可应自己定义的
*/
	public  ResultState weixinUnifiedOrder( HttpServletRequest request,
			 @RequestParam("orderNumber")String orderNumber,
	                 @RequestParam("payMoney")String payMoney,
	                 @RequestParam("orderType")String orderType
	                                       ) throws Exception{
		
//这里是我自己根据类型获取body的,大家可以自己定义
		Map<String, String> result = new HashMap<>();
		String body="";
		String orderCode = "";
		String total_fee = "";
		  if(orderType.equals("1")) {
			  body="ykcz";
		  }
		  if(orderType.equals("2")) {
			  body="E卡充值";
		  }
		  if(orderType.equals("3")) {
			  body="手机充值";
		  }
		  if(orderType.equals("4")) {
			  body="油卡购买";
		  }
		  Order order = orderService.selectbyordernumber(orderNumber);
		  if(order!=null) {
			  if(order.getPaymentType().equals("1")) {
				  orderCode=orderNumber;
				 Integer money=(int)(Double.parseDouble(payMoney)*100);
				  total_fee=String.valueOf(money);
				    String[] initValue = new String[3];
				    initValue[0] = orderCode;
				    initValue[1] = total_fee;
				    initValue[2] = body;
//微信支付需要传参使用者的ip,这里获取了一下,可以自己网上找,懒得找的下边我会附代码
				    String remoteAddr = GetIp.getRemoteAddr(request);
					String ip="";
					if (remoteAddr.length()>16) {
						String[] split = remoteAddr.split(",");
						for (int i = 0; i < split.length; i++) {
							ip=split[0];
						}
					}else{
						ip=remoteAddr;
					}
//这里就是把订单信息封装好了统一下单,微信会返回一个加完签的结果,只要判断一下结果的正确性就可以吧这个结果直接返回给前端,让前端去调起支付了
//我把上边提到的几个参数封装到了ConfigUtils里,这里你取你自己的             appid                          微信商户号     上边数组封装的值,自己对应  ip            微信回调地址(自己写的,上边提到的第二部)  APP,看文档,你是什么支付就传//什么,body 上边定义的字段,必传,加签的时候有body的解释,也可以自己看微信官方文档   自己封装的appkey         
					result=WeiXinPay.weixinUnifiedOrder(ConfigUtils.WXAPPappid, ConfigUtils.WXmch_id,initValue[0], initValue[1], ip, ConfigUtils.WXnotify_url, "APP", body, ConfigUtils.WXappkey);
					if(result.get("prepay_id")!=null){
						System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"+result);
//						//result是微信返回的字段,详细见微信开发者文档
//						 Map<String, String> sign = WeiXinPay.getSign3(result);
//						 System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"+sign);
						return new ResultState(200, "生成成功",result,ignore,ignore);
					} 
			  }else {
				  return new ResultState(500, "订单已经支付过了,请勿重复支付",ignore,ignore,ignore);
			  }
		  }else {
			  return new ResultState(500, "订单不存在",ignore,ignore,ignore);
		  }
		return new ResultState(500, "签名错误",ignore,ignore,ignore);
	}
这个是微信支付加签,有了这个微信支付也算完成一半了,下边是微信支付回调了,
/**
	 * 微信支付成功回调
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
//微信支付要在服务起上正式环境调试,所以这个回调接口必须是在外网上可以访问到的,不能加任何参数的
	@ResponseBody
	@RequestMapping(value="weiXinPayCallback")
//这里是微信支付回调,支付完成后,微信会回调这个接口,确定是否支付成功,支付成功给微信返回一个success,让微信知道成功支付了,不然微信会隔几分钟回调一次,对于你处理成功业务逻辑很麻烦
	public  String weiXinPayCallback(HttpServletRequest request,HttpServletResponse response) throws Exception{
              //获取微信支付回调结果
		String result = WeiXinPayUtil.getPostStr(request);
		System.out.println(result);
		Map<String, String> resuleMap = WeiXinPayUtil.xmlToMap(result);
		if(resuleMap.get("result_code")!=null && "SUCCESS".equals(resuleMap.get("result_code"))){
			//成功
			//获取实际支付的钱数
			String totalFee = resuleMap.get("total_fee");
			//获取订单号
			String orderNo = resuleMap.get("out_trade_no").split("_")[0];
			//获取交易流水号
			String tradeNo = resuleMap.get("transaction_id");
			//修改订单状态
			//这里是我根据订单编号修改我的订单信息,更多的字段意思看微信官方文档给出的返回结果来获取你想要的信息
			 Order order=orderService.selectbyordernumber(orderNo);
             order.setPaymentType("2");            //支付完成
             order.setPayMoney(order.getCurrent());
             order.setSerialNumber(tradeNo); 
             order.setOrderStatus(2);
             Integer zhifuddoilb=0;
             int returnResult = orderService.updateByPrimaryKeySelective(order);    //更新交易表中状态
             //判断订单表数据是否更新成功
             if(returnResult>0){
            	//在这里处理你支付成功的业务逻辑。
            	 return  "success";
             }else {
            	 return "fail";
             }
		}
		return "fail";
	}

这样,微信支付就完成了






哈哈,骗你的,如果不往下看上边代码很多地方你都不知道在哪里找了吧,看这里

package com.union.yxj.util;

import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import org.apache.log4j.Logger;

/**
 * 微信支付
 * @author zhuozhuo
 *
 */
public class WeiXinPay {
	
	/**
	 * 日志记录
	 */
	private static Logger logger = Logger.getLogger(WeiXinPay.class);
	
	/**
	 * 微信统一下单
	 * @param appid 微信开发者id/微信公众号id
	 * @param mch_id 商户号
	 * @param key 签名密匙
	 * @param openid	appid为微信公众号id时为用户标识,appid微信开发者id为null
	 * @param orderCode	订单号
	 * @param total_fee	总价 单位为分
	 * @param attach	自定义数据
	 * @param ip	终端ip
	 * @param notify_url	回调地址
	 * @param trade_type	支付类型(APP,JSAPI)
	 * @param body	支付描述
	 * @return
	 * @throws Exception
	 */
	public static Map<String, String> weixinUnifiedOrder(String appid,String mch_id,String orderCode,String total_fee,String ip,String notify_url,String trade_type,String body,String key) throws Exception{
		 SortedMap<String, String> condition = new TreeMap<String, String>();
		//1应用ID
		condition.put("appid", appid);
		System.out.println(appid);
		//2商户号
		condition.put("mch_id", mch_id);
		System.out.println(mch_id);
		//3随机字符串
		condition.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
		System.out.println(UUID.randomUUID().toString().replace("-", ""));
		//4商品描述
		condition.put("body", body);
		System.out.println(body);
		//5商户订单号
		condition.put("out_trade_no", orderCode+"_"+OrderNumber.getRandom(5));
		System.out.println(orderCode+"_"+OrderNumber.getRandom(5));
		//6订单总金额,单位为分
		condition.put("total_fee", total_fee);
		System.out.println( total_fee);
		//7终端IP
		condition.put("spbill_create_ip", ip);
		System.out.println(ip);
		//8接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
		condition.put("notify_url", notify_url);
		System.out.println(notify_url);
		//9支付类型
		condition.put("trade_type", trade_type);
		System.out.println(trade_type);
		//签名
		String sign = WeiXinPayUtil.createSign("UTF-8",condition);
		System.out.println(condition);
		condition.put("sign", sign);
		System.out.println("!!!!!!"+sign);
		String xml = WeiXinPayUtil.ArrayToXml(condition);
		System.out.println();
		String result = WeiXinPayUtil.httpsRequest(ConfigUtils.weixinUnifiedOrderUrl, "POST", xml);
		Map<String, String> resuleMap = WeiXinPayUtil.xmlToMap(result);
		resuleMap.put("ip", ip);
		logger.info(result);
		if (result.indexOf("SUCCESS") != -1) {
			if(resuleMap.get("return_code")!=null && "SUCCESS".equals(resuleMap.get("return_code"))){
				//成功
				return resuleMap;
			}else{
				return resuleMap;
			}
		}else{
			return resuleMap;
		}
	}
	
	/**
	 * 生成签名
	 * @param map
	 * @return
	 */
	public static Map<String,String> getSign3(Map<String,String> map){
		try {
			if (map!=null) {
				HashMap<String, String> signMap = new HashMap<>();
				String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
				String packages = "prepay_id="+map.get("prepay_id");
				signMap.put("appId", map.get("appid"));
				signMap.put("timeStamp", timestamp);
				signMap.put("nonceStr", map.get("nonce_str"));
				signMap.put("package", packages);
				signMap.put("signType", "MD5");
				String sign = WeiXinPayUtil.getSign(signMap, ConfigUtils.WXappkey);
				signMap.put("paySign", sign);
				return signMap;
			}
		} catch (Exception e) {
		}
		return null;
	}
}

你以为这就完了?还有呢,

package com.union.yxj.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;


public class WeiXinPayUtil {
	
	/**
	 * 日志记录
	 */
	private static Logger logger = Logger.getLogger(WeiXinPayUtil.class);
	
	
	
	
	/**
	 * 签名
	 * @param params
	 * @param paternerKey
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String getSign(Map<String, String> params, String paternerKey )
			throws UnsupportedEncodingException {
		String string1 = createSign(params, false);
		String stringSignTemp = string1 + "&key=" + paternerKey;
		System.out.println(stringSignTemp);
		String signValue = MD5.MD5Encode(stringSignTemp).toUpperCase();
		return  signValue;
	}
	
	/**
	 * 签名2
	 * @param params
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String getSign2(Map<String, String> params)
			throws UnsupportedEncodingException {
		String string1 = createSign(params, false);
		String signValue = MD5.MD5Encode(string1).toUpperCase();
		return  signValue;
	}
	
	 public static String createSign(String characterEncoding,SortedMap<String,String> parameters){
	        StringBuffer sb = new StringBuffer();
	        Set es = parameters.entrySet();
	        Iterator it = es.iterator();
	        while(it.hasNext()) {
	            Map.Entry entry = (Map.Entry)it.next();
	            String k = (String)entry.getKey();
	            Object v = entry.getValue();
	            if(null != v && !"".equals(v)
	                    && !"sign".equals(k) && !"key".equals(k)) {
	                sb.append(k + "=" + v + "&");
	            }
	        }
	        sb.append("key=" + ConfigUtils.WXappkey);//最后加密时添加商户密钥,由于key值放在最后,所以不用添加到SortMap里面去,单独处理,编码方式采用UTF-8
	        String aa=sb.toString();
	        String sign = MyMD5Util.MD5(aa.trim()).toUpperCase();
	        return sign;
	    }
	
	
	/**
	 * 排序
	 * @param params
	 * @param encode
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException {
	    Set<String> keysSet = params.keySet();
	    Object[] keys = keysSet.toArray();
	    Arrays.sort(keys);
	    StringBuffer temp = new StringBuffer();
	    boolean first = true;
	    for (Object key : keys) {
	        if (first) {
	            first = false;
	        } else {
	            temp.append("&");
	    }
	    temp.append(key).append("=");
	    Object value = params.get(key);
	    String valueString = "";
	    if (null != value) {
	        valueString = value.toString();
	    }
	    if (encode) {
	        temp.append(URLEncoder.encode(valueString, "UTF-8"));
	        } else {
	            temp.append(valueString);
	        }
	    }
	    return temp.toString();
	}
	
	/**
	 * 将map转换为xml
	 * @param arr
	 * @return
	 */
	public static String ArrayToXml(Map<String, String> arr) {
		String xml = "<xml>";

		Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<String, String> entry = iter.next();
			String key = entry.getKey();
			String val = entry.getValue();
			xml += "<" + key + ">" + val + "</" + key + ">";
		}

		xml += "</xml>";
		return xml;
	}
	
	
	/**
	 * 解析xml为map
	 * @param xml
	 * @return
	 * @throws Exception 
	 * @throws XmlPullParserException
	 * @throws IOException
	 */
	public static Map<String, String> xmlToMap(String xml) throws Exception{
		if(ValidateUtils.isValid(xml)){
			Map<String, String> map = new HashMap<>();
			Document document = DocumentHelper.parseText(xml); 
			Element root = document.getRootElement(); 
			for (Iterator iterator = root.elementIterator(); iterator.hasNext();) { 
	            Element e = (Element) iterator.next(); 
	            map.put(e.getName(), e.getText()); 
	            System.out.println(e.getName()+"="+e.getText());
	        } 
			return map;
		}else{
			return null;
		}
	}
	
	public static void main(String[] args) throws Exception {
		Map<String, String> xmlToMap = xmlToMap("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[openid is invalid]]></return_msg></xml>");
		System.err.println(xmlToMap);
	}
	
	
    /**
     * 请求方法
     * @param requestUrl
     * @param requestMethod
     * @param outputStr
     * @return
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {  
          try {  
               
              URL url = new URL(requestUrl);  
              HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
              
              conn.setDoOutput(true);  
              conn.setDoInput(true);  
              conn.setUseCaches(false);  
              // 设置请求方式(GET/POST)  
              conn.setRequestMethod(requestMethod);  
              conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");  
              // 当outputStr不为null时向输出流写数据  
              if (null != outputStr) {  
                  OutputStream outputStream = conn.getOutputStream();  
                  // 注意编码格式  
                  outputStream.write(outputStr.getBytes("UTF-8"));  
                  outputStream.close();  
              }  
              // 从输入流读取返回内容  
              InputStream inputStream = conn.getInputStream();  
              InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
              BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  
              String str = null;  
              StringBuffer buffer = new StringBuffer();  
              while ((str = bufferedReader.readLine()) != null) {  
                  buffer.append(str);  
              }  
              // 释放资源  
              bufferedReader.close();  
              inputStreamReader.close();  
              inputStream.close();  
              inputStream = null;  
              conn.disconnect();  
              return buffer.toString();  
          } catch (ConnectException ce) {  
              logger.info("连接超时:{}"+ ce);  
          } catch (Exception e) {  
        	  logger.info("https请求异常:{}"+ e);  
          }  
          return null;  
      } 
	    
	/**
	 * 微信回调参数解析
	 * @param request
	 * @return
	 */
	public static String getPostStr(HttpServletRequest request){
    	 StringBuffer sb = new StringBuffer();
    	 try {
         InputStream is = request.getInputStream();  
         InputStreamReader isr = new InputStreamReader(is, "UTF-8");  
         BufferedReader br = new BufferedReader(isr);  
         String s = "";  
        
			while ((s = br.readLine()) != null) {  
			     sb.append(s);  
			 }
		} catch (IOException e) {			
			e.printStackTrace();
		}  
         String xml = sb.toString(); //次即为接收到微信端发送过来的xml数据  
         logger.info(xml+"========================");
         return xml;
    }
}

结束了?不行,要坚挺!!!

package com.union.yxj.util;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.UUID;

/**
 * 随机生成订单号
 * @author 张卓
 *
 */
public class OrderNumber{
	
 
  
    /**
     * 生成订单编号  时间+8位uuid
     * @return 返回订单
     */
    public static String getOrderNo1() {  
        String str = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());  
        String uuid = UUID.randomUUID().toString();
        uuid = uuid.substring(0, 8);
        return str+uuid;
    }  
    
    /**
     * 生成订单编号  时间
     * @return 返回订单
     */
    public static String getOrderNo2() {  
        //String str = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());  
    	String str = new SimpleDateFormat("HHmmssSSS").format(new Date()); 
        return str;
    }  
    
    
    
    /**
     * 产生num位随机数
     * @param num
     * @return
     */
    public static String getRandom(int num) {  
        String code = "";
        for (int i = 0; i < num; i++) {
        	int x = new Random().nextInt(9);
        	code = code + String.valueOf(x);
		}
        return code;
    }  
    public static String getRandom2() {  
    	Random ran = new Random();  
        StringBuffer sb = new StringBuffer();  
        while(sb.length()<16) {  
            int rand = ran.nextInt()&0x7FFFFFFF;  
            sb.append(Integer.toString(rand, 36));  
        }  
        String result = sb.substring(0, 16);  
        return result;
    }
    
    
    
    public static void main(String[] args) {
		System.out.println(getOrderNo1());
		int x = new Random().nextInt(2);
		System.out.println(x);
		
	}
}

,你以为这就完了?再来点好的。

package com.union.yxj.vo;

import lombok.Data;

@Data
public class ResultState {
	/**
	 * 结果状态(200:成功 500:失败)
	 */
	private int  code;

	/**
	 * 结果信息
	 */
	private String msg;
	
	/**
	 * 封装对象
	 * @return
	 */

	private Object object;
	private Object obj;
	private Object ob;
	

	public ResultState(int code, String msg) {
		super();
		this.code = code;
		this.msg = msg;
	}

	public ResultState(int code, String msg, Object object) {
		super();
		this.code = code;
		this.msg = msg;
		this.object = object;
	}
	public ResultState(int code, String msg, Object object,Object obj) {
		super();
		this.code = code;
		this.msg = msg;
		this.object = object;
		this.obj=obj;
	}
	

	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public Object getObject() {
		return object;
	}

	public void setObject(Object object) {
		this.object = object;
	}

	public ResultState(int code, String msg, Object object, Object obj, Object ob) {
		super();
		this.code = code;
		this.msg = msg;
		this.object = object;
		this.obj = obj;
		this.ob = ob;
	}
	
	
	
}

其实我还能在坚挺一会的。。。。。。。

/**
	 * 生成签名
	 * @param map
	 * @return
	 */
	public static Map<String,String> getSign3(Map<String,String> map){
		try {
			if (map!=null) {
				HashMap<String, String> signMap = new HashMap<>();
				String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
				String packages = "prepay_id="+map.get("prepay_id");
				signMap.put("appId", map.get("appid"));
				signMap.put("timeStamp", timestamp);
				signMap.put("nonceStr", map.get("nonce_str"));
				signMap.put("package", packages);
				signMap.put("signType", "MD5");
				String sign = WeiXinPayUtil.getSign(signMap, ConfigUtils.WXappkey);
				signMap.put("paySign", sign);
				return signMap;
			}
		} catch (Exception e) {
		}
		return null;
	}

这..下..大家.......满........足......了........吧.........吧...........吧..............

哈哈,开个小玩笑,到这里,微信支付就算是完成了,如果这篇文章帮助到你了,记得点赞哦!!!

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页