关于微信支付(二维码支付)

关于微信支付(一)

微信支付有两种方式

1.第三方网站弹出二维码客户扫描支付

111

2.在微信内部H5直接发起支付

123

这篇文章先讲 第一种最常用的 弹出二维码支付

二维码支付

2

大概流程如下

用户选择支付->后台程序创建订单->请求微信同意下单接口(除了常规参数还需要一个接口这个URL是用户支付完成后通知你的接口)->提交成功后 微信返回参数其中有一个链接,这个链接转成二维码 用户扫描就可以支付了

此时支付流程已经结束

如果用户支付了 微信就会调用你的URL 通知你,你需要返回给微信 一个信息(大概意思就是 告诉微信我知道了) 不然微信会一直 请求你

<!--more-->

准备工作

URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

参数:

字段名变量名必填类型示例值描述
公众账号IDappidString(32)wxd678efh567hg6787微信支付分配的公众账号ID(企业号corpid即为此appId)
商户号mch_idString(32)1230000109微信支付分配的商户号
设备号device_infoString(32)013467007045764自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB"
随机字符串nonce_strString(32)5K8264ILTKCH16CQ2502SI8ZNMTM67VS随机字符串,长度要求在32位以内。推荐随机数生成算法
签名signString(32)C380BEC2BFD727A4B6845133519F3AD6通过签名算法计算得出的签名值,详见签名生成算法
签名类型sign_typeString(32)MD5签名类型,默认为MD5,支持HMAC-SHA256和MD5。
商品描述bodyString(128)腾讯充值中心-QQ会员充值商品简单描述,该字段请按照规范传递,具体请见参数规定
商品详情detailString(6000)商品详细描述,对于使用单品优惠的商户,改字段必须按照规范上传,详见“单品优惠参数说明”
附加数据attachString(127)深圳分店附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
商户订单号out_trade_noString(32)20150806125346商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。详见商户订单号
标价币种fee_typeString(16)CNY符合ISO 4217标准的三位字母代码,默认人民币:CNY,详细列表请参见货币类型
标价金额total_feeInt88订单总金额,单位为分,详见支付金额
终端IPspbill_create_ipString(16)123.12.12.123APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
交易起始时间time_startString(14)20091225091010订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
交易结束时间time_expireString(14)20091227091010订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。订单失效时间是针对订单号而言的,由于在请求支付的时候有一个必传参数prepay_id只有两小时的有效期,所以在重入时间超过2小时的时候需要重新请求下单接口获取新的prepay_id。其他详见时间规则建议:最短失效时间间隔大于1分钟
订单优惠标记goods_tagString(32)WXG订单优惠标记,使用代金券或立减优惠功能时需要的参数,说明详见代金券或立减优惠
通知地址notify_urlString(256)http://www.weixin.qq.com/wxpay/pay.php异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
交易类型trade_typeString(16)JSAPIJSAPI 公众号支付NATIVE 扫码支付APP APP支付说明详见参数规定
商品IDproduct_idString(32)12235413214070356458058trade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品ID,商户自行定义。
指定支付方式limit_payString(32)no_credit上传此参数no_credit--可限制用户不能使用信用卡支付
用户标识openidString(128)oUpF8uMuAJO_M2pxb1Q9zNjWeS6otrade_type=JSAPI时(即公众号支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识。openid如何获取,可参考【获取openid】。企业号请使用【企业号OAuth2.0接口】获取企业号内成员userid,再调用【企业号userid转openid接口】进行转换
-场景信息scene_infoString(256){"store_info" : {"id": "SZTX001","name": "腾大餐厅","area_code": "440305","address": "科技园中一路腾讯大厦" }}该字段用于上报场景信息,目前支持上报实际门店信息。该字段为JSON对象数据,对象格式为{"store_info":{"id": "门店ID","name": "名称","area_code": "编码","address": "地址" }} ,字段详细说明请点击行前的+展开
-门店ididString(32)SZTX001门店唯一标识
-门店名称nameString(64)腾讯大厦腾大餐厅门店名称
-门店行政区划码area_codeString(6)440305门店所在地行政区划码,详细见《最新县及县以上行政区划代码》
-门店详细地址addressString(128)科技园中一路腾讯大厦门店详细地址

举例如下:

<xml>

   <appid>wx2421b1c4370ec43b</appid>

   <attach>支付测试</attach>

   <body>JSAPI支付测试</body>

   <mch_id>10000100</mch_id>

   <detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]></detail>

   <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>

   <notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>

   <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>

   <out_trade_no>1415659990</out_trade_no>

   <spbill_create_ip>14.23.150.211</spbill_create_ip>

   <total_fee>1</total_fee>

   <trade_type>JSAPI</trade_type>

   <sign>0CB01533B8C1EF103065174F50BCA001</sign>

</xml>

这里 我发现请求参数太多了 所以我把所有请求参数 返回参数都做成了对象,首先是微信同意下单 参数接口

/**
 * 统一下单请求参数(必填)
 * @author An
 *
 */
public class UnifiedOrderRequest {
   private String appid;               //公众账号ID
    private String mch_id;              //商户号
    private String nonce_str;           //随机字符串
    private String sign;                //签名
    private String body;                //商品描述
    private String out_trade_no;        //商户订单号
    private String total_fee;           //总金额
    private String spbill_create_ip;    //终端IP
    private String notify_url;          //通知地址
    private String trade_type;          //交易类型
    
   public String getAppid() {
      return appid;
   }
   public void setAppid(String appid) {
      this.appid = appid;
   }
   public String getMch_id() {
      return mch_id;
   }
   public void setMch_id(String mch_id) {
      this.mch_id = mch_id;
   }
   public String getNonce_str() {
      return nonce_str;
   }
   public void setNonce_str(String nonce_str) {
      this.nonce_str = nonce_str;
   }
   public String getSign() {
      return sign;
   }
   public void setSign(String sign) {
      this.sign = sign;
   }
   public String getBody() {
      return body;
   }
   public void setBody(String body) {
      this.body = body;
   }
   public String getOut_trade_no() {
      return out_trade_no;
   }
   public void setOut_trade_no(String out_trade_no) {
      this.out_trade_no = out_trade_no;
   }
   public String getTotal_fee() {
      return total_fee;
   }
   public void setTotal_fee(String total_fee) {
      this.total_fee = total_fee;
   }
   public String getSpbill_create_ip() {
      return spbill_create_ip;
   }
   public void setSpbill_create_ip(String spbill_create_ip) {
      this.spbill_create_ip = spbill_create_ip;
   }
   public String getNotify_url() {
      return notify_url;
   }
   public void setNotify_url(String notify_url) {
      this.notify_url = notify_url;
   }
   public String getTrade_type() {
      return trade_type;
   }
   public void setTrade_type(String trade_type) {
      this.trade_type = trade_type;
   }
}
/**
 * 统一下单请求参数(非必填)
 * @author An
 *
 */
public class UnifiedOrderRequestExt extends UnifiedOrderRequest{
    private String device_info;         //设备号
    private String detail;              //商品详情
    private String attach;              //附加数据
    private String fee_type;            //货币类型
    private String time_start;          //交易起始时间
    private String time_expire;         //交易结束时间
    private String goods_tag;           //商品标记
    private String product_id;          //商品ID
    private String limit_pay;           //指定支付方式
    private String openid;              //用户标识
   public String getDevice_info() {
      return device_info;
   }
   public void setDevice_info(String device_info) {
      this.device_info = device_info;
   }
   public String getDetail() {
      return detail;
   }
   public void setDetail(String detail) {
      this.detail = detail;
   }
   public String getAttach() {
      return attach;
   }
   public void setAttach(String attach) {
      this.attach = attach;
   }
   public String getFee_type() {
      return fee_type;
   }
   public void setFee_type(String fee_type) {
      this.fee_type = fee_type;
   }
   public String getTime_start() {
      return time_start;
   }
   public void setTime_start(String time_start) {
      this.time_start = time_start;
   }
   public String getTime_expire() {
      return time_expire;
   }
   public void setTime_expire(String time_expire) {
      this.time_expire = time_expire;
   }
   public String getGoods_tag() {
      return goods_tag;
   }
   public void setGoods_tag(String goods_tag) {
      this.goods_tag = goods_tag;
   }
   public String getProduct_id() {
      return product_id;
   }
   public void setProduct_id(String product_id) {
      this.product_id = product_id;
   }
   public String getLimit_pay() {
      return limit_pay;
   }
   public void setLimit_pay(String limit_pay) {
      this.limit_pay = limit_pay;
   }
   public String getOpenid() {
      return openid;
   }
   public void setOpenid(String openid) {
      this.openid = openid;
   }
}

准备两个工具类

1.MD5加密工具类

public class WeChatMD5{
   /**
    * 
    * @see    MD5加密
    * @param origin 被加密字符串
    * @param input_charset 字符串编码方式
    * @return
    */
   public static String MD5Encode(String origin,String input_charset){
      return DigestUtils.md5Hex(getContentBytes(origin, input_charset));
   }
   
   /**
     * 签名字符串
     * @param text 需要签名的字符串
     * @param sign 签名结果
     * @param key 密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static boolean verify(String text, String sign, String input_charset) {
       String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset)).toUpperCase();
       if(mysign.equals(sign)) {
          return true;
       }
       else {
          return false;
       }
    }
    
   /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException 
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }
}

2.微信支付工具类

public class WeChatPayUtil {
   /**
    * 生成随机字符串
    * @param length 长度
    * @return
    */
    public static String getRandomString(int length) {  
           String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";         
           Random random = new Random();         
           StringBuffer sb = new StringBuffer();      
           for (int i = 0; i < length; i++) {         
               int number = random.nextInt(base.length());         
               sb.append(base.charAt(number));         
           }         
           return sb.toString();         
     }
    /**
     * 统一下单生成签名
     * @param unifiedOrderRequest
     * @return
     */
    public static String createSign(UnifiedOrderRequestExt unifiedOrderRequest) {
        //根据规则创建可排序的map集合
        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", unifiedOrderRequest.getAppid());
        packageParams.put("body", unifiedOrderRequest.getBody());
        packageParams.put("mch_id", unifiedOrderRequest.getMch_id());
        packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());
        packageParams.put("notify_url", unifiedOrderRequest.getNotify_url());
        packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());
        packageParams.put("spbill_create_ip", unifiedOrderRequest.getSpbill_create_ip());
        packageParams.put("trade_type", unifiedOrderRequest.getTrade_type());
        packageParams.put("total_fee", unifiedOrderRequest.getTotal_fee());
        packageParams.put("attach", unifiedOrderRequest.getAttach());
        if(unifiedOrderRequest.getOpenid()!=null){
           packageParams.put("openid",unifiedOrderRequest.getOpenid());
        }
        StringBuffer sb = new StringBuffer();
        Set<Entry<String, String>> es = packageParams.entrySet();//字典序
        Iterator<Entry<String, String>> it = es.iterator();
        while (it.hasNext()) {
           Entry<String, String> entry = (Entry<String, String>) it.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            //为空不参与签名、参数名区分大小写
            if (null != value && !"".equals(value) && !"sign".equals(key)
                    && !"key".equals(key)) {
                sb.append(key + "=" + value + "&");
            }
        }
        //微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
        String key=Config.getStringValue("key");
        System.out.println(packageParams);
        sb.append("key=" +key);
        String sign = WeChatMD5.MD5Encode(sb.toString(), "utf-8") .toUpperCase();//MD5加密
        System.out.println(sign);
        return sign;
    }
   
    public static String createSign(UnifiedOrderSelect unifiedOrderRequest) {
       //根据规则创建可排序的map集合
        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", unifiedOrderRequest.getAppid());
        packageParams.put("mch_id", unifiedOrderRequest.getMch_id());
        packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());
        packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());
        StringBuffer sb = new StringBuffer();
        Set<Entry<String, String>> es = packageParams.entrySet();//字典序
        Iterator<Entry<String, String>> it = es.iterator();
        while (it.hasNext()) {
           Entry<String, String> entry = (Entry<String, String>) it.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            //为空不参与签名、参数名区分大小写
            if (null != value && !"".equals(value) && !"sign".equals(key)
                    && !"key".equals(key)) {
                sb.append(key + "=" + value + "&");
            }
        }
        //微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
        String key=Config.getStringValue("key");
        System.out.println(packageParams);
        sb.append("key=" +key);
        String sign = WeChatMD5.MD5Encode(sb.toString(), "utf-8") .toUpperCase();//MD5加密
        System.out.println(sign);
        return sign;
   }
}

其中有一个生成随机字符串的 函数还有一个签名的函数,签名一会用到在讲

@Component
public class WeChatPay {
   
   static Log log =LogFactory.getLog(WeChatPay.class);
   
   //同意下单API
   public static final String PAYURL="https://api.mch.weixin.qq.com/pay/unifiedorder";
   //查询订单API
   public static final String SELECT="https://api.mch.weixin.qq.com/pay/orderquery";
   
   
   public static void main(String[] args) {
      
   }
   /**
    * 生成订单方法
    * @param body 订单详情
    * @param orderId 订单号
    * @param money 价格/元
    * @param ip 用户端IP
    * @return
    */
   public String createOrderInfo(String body,String orderId,float money,String key,String tradeType,String openid) {
      String ip="";
      //生成订单对象
      String resule="";
      try {
         ip = InetAddress.getLocalHost().getHostAddress().toString();
         log.info("=.=生成订单开始(body="+body+",orderId="+orderId+",money="+money+",ip="+ip+")=.=");
         String appid=Config.getStringValue("appID");
         String mchId=Config.getStringValue("mch_id");
         UnifiedOrderRequestExt unifiedOrderRequest = new UnifiedOrderRequestExt();
         unifiedOrderRequest.setAppid(appid);//公众账号ID
         unifiedOrderRequest.setMch_id(mchId);//商户号
         if(openid!=null){
            unifiedOrderRequest.setOpenid(openid);
         }
         unifiedOrderRequest.setAttach(orderId+","+key);//自定义参数 通知的时候修改成功和支付时间
         unifiedOrderRequest.setNonce_str(WeChatPayUtil.getRandomString(11));//随机字符串
         unifiedOrderRequest.setBody(body);//商品描述
         unifiedOrderRequest.setOut_trade_no(orderId);//商户订单号
         Float f = new Float(money*100);
         int money1 = f.intValue();
         unifiedOrderRequest.setTotal_fee(money1+""); //单位分所以成100
         unifiedOrderRequest.setSpbill_create_ip(ip);//终端IP
         unifiedOrderRequest.setNotify_url(Config.getStringValue("notifyUrl"));//通知地址
         unifiedOrderRequest.setTrade_type(tradeType);//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
         unifiedOrderRequest.setSign(WeChatPayUtil.createSign(unifiedOrderRequest));//签名
         //将订单对象转为xml格式
         XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));
         xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml
         resule = xStream.toXML(unifiedOrderRequest);
         System.out.println("XML="+resule);
      } catch (Exception e) {
         log.info("=.=创建订单异常"+e.getMessage());
         e.printStackTrace();
      }
       log.info("=.=生成订单结束=.=");
       return resule;
   }
   /**
    * 统一下单
    * @param orderInfo 订单信息
    * @return
    */
   public static UnifiedOrderRespose httpOrder(String orderInfo) {
       try {
          log.info("=.=同意下单开始=.=");
           HttpURLConnection conn = (HttpURLConnection) new URL(PAYURL).openConnection();
           //加入数据  
           conn.setRequestMethod("POST");  
           conn.setDoOutput(true);  
           BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());  
           buffOutStr.write(orderInfo.getBytes());
           buffOutStr.flush();  
           buffOutStr.close();  
           //获取输入流  
           BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));  
           String line = null;  
           StringBuffer sb = new StringBuffer();  
           while((line = reader.readLine())!= null){  
               sb.append(line);  
           }  
           XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));
           //将请求返回的内容通过xStream转换为UnifiedOrderRespose对象
           xStream.alias("xml", UnifiedOrderRespose.class);
           UnifiedOrderRespose unifiedOrderRespose = (UnifiedOrderRespose) xStream.fromXML(sb.toString());
           //根据微信文档return_code 和result_code都为SUCCESS的时候才会返回code_url
           if(null!=unifiedOrderRespose  && "SUCCESS".equals(unifiedOrderRespose.getReturn_code())  && "SUCCESS".equals(unifiedOrderRespose.getResult_code())){
              log.info("=.=同意下单成功=.=");
              return unifiedOrderRespose;
           }else{
              log.info("=.=调用微信参数错误=.="+unifiedOrderRespose.getReturn_msg()+"code"+unifiedOrderRespose.getReturn_code());
               return null;
           }
       } catch (Exception e) {
          log.info("=.=调用统一下单接口异常"+e.getLocalizedMessage());
           e.printStackTrace();
       }
       return null;
   }
   
   /**
    * 创建查询订单
    * @param outTradeNo
    * @return
    */
   public String createOrderSelect(String outTradeNo){
      //String ip="";
      //生成订单对象
      String resule="";
      try {
         String appid=Config.getStringValue("appID");
         String mchId=Config.getStringValue("mch_id");
         UnifiedOrderSelect unifiedOrderRequest = new UnifiedOrderSelect();
         unifiedOrderRequest.setAppid(appid);//公众账号ID
         unifiedOrderRequest.setMch_id(mchId);//商户号
         unifiedOrderRequest.setNonce_str(WeChatPayUtil.getRandomString(11));//随机字符串
         unifiedOrderRequest.setOut_trade_no(outTradeNo);//商户订单号
         unifiedOrderRequest.setSign(WeChatPayUtil.createSign(unifiedOrderRequest));//签名
         //将订单对象转为xml格式
         XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));
         xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml
         resule = xStream.toXML(unifiedOrderRequest);
         System.out.println("XML="+resule);
      } catch (Exception e) {
         log.info("=.=创建订单异常"+e.getMessage());
         e.printStackTrace();
      }
       log.info("=.=生成订单结束=.=");
       return resule;
   }
   
   /**
    * 请求查询订单
    * @param orderInfo
    */
   public static UnifiedOrderSelectRespose httpSelectOrder(String orderInfo){
      try {
          log.info("=.=查询订单开始=.=");
           HttpURLConnection conn = (HttpURLConnection) new URL(SELECT).openConnection();
           log.info("SELECT"+SELECT);
           //加入数据  
           conn.setRequestMethod("POST");  
           conn.setDoOutput(true);  
           BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());  
           buffOutStr.write(orderInfo.getBytes());
           buffOutStr.flush();  
           buffOutStr.close();  
           //获取输入流  
           BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));  
           String line = null;  
           StringBuffer sb = new StringBuffer();  
           while((line = reader.readLine())!= null){  
               sb.append(line);  
           }  
           XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));
           //将请求返回的内容通过xStream转换为UnifiedOrderRespose对象
           xStream.alias("xml", UnifiedOrderSelectRespose.class);
           log.info("xml="+sb.toString());
           UnifiedOrderSelectRespose unifiedOrderSelectRespose = (UnifiedOrderSelectRespose) xStream.fromXML(sb.toString());
           //根据微信文档return_code 和result_code都为SUCCESS的时候才会返回code_url
           if(null!=unifiedOrderSelectRespose  && "SUCCESS".equals(unifiedOrderSelectRespose.getReturn_code())  && "SUCCESS".equals(unifiedOrderSelectRespose.getResult_code())){
              log.info("=.=查询订单成功=.=");
              return unifiedOrderSelectRespose;
           }else{
              log.info("=.=调用微信参数错误=.="+unifiedOrderSelectRespose.getReturn_msg()+"code"+unifiedOrderSelectRespose.getReturn_code());
               return null;
           }
       } catch (Exception e) {
          log.info("=.=调用统一下单接口异常"+e.getLocalizedMessage());
           e.printStackTrace();
       }
       return null;
   }
}

创建订单

createOrderInfo(String body,String orderId,float money,String key,String tradeType,String openid)

这个方法就是创建订单,等同于拼XML只不过我这里是封装成对象 然后利用XStream讲对象转成XML

其中有一个OpenId 这个是为了便于以后 微信号内部支付的暂时用不到,所以穿null,这里

商品详情 会显示在用户扫码后提示给用户 你购买的是什么

orderId必须是唯一的,不然同样的订单号无法生成

money是商品价格单位分

key 这里是我的一个参数,我利用WebSocket即使修改页面 告诉用户支付完成

tradeType 类型 SAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付 这里我们传NATIVE

微信签名

这个方法没什么说的,无非是set set set 其中unifiedOrderRequest.setSign(WeChatPayUtil.createSign(unifiedOrderRequest))

微信的签名是一个比较重要的东西

这里可以看我微信工具类的代码

具体流程如下

第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特别注意以下重要规则:

  1. ◆ 参数名ASCII码从小到大排序(字典序);
  2. ◆ 如果参数的值为空不参与签名;
  3. ◆ 参数名区分大小写;
  4. ◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
  5. ◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段

第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。

说白了 就是把你所有参数 按照字典序 排序一下 然后拼上key 然后MD5运算一下得到一个字符串

如果签名总是错误可以利用 签名验证工具

创建订单后 就该提交订单了调用UnifiedOrderRespose(Stirng info) 方法

调用同意下单接口

讲上一步拼接后的XML提交给UnifiedOrderRespose

UnifiedOrderRespose 也没什么说的这里我把接收到的值也转换成了对象

/**
 * 统一下单返回参数
 * @author An
 *
 */
public class UnifiedOrderRespose {
   private String return_code;             //返回状态码
    private String return_msg;              //返回信息
   /* 以下字段在return_code为SUCCESS的时候有返回*/
   private String appid;                   //公众账号ID
   private String mch_id;                  //商户号
   private String device_info;             //设备号
   private String nonce_str;               //随机字符串
   private String sign;                    //签名
   private String result_code;             //业务结果
   private String err_code;                //错误代码
   private String err_code_des;           //错误代码描述
   /* 以下字段在return_code 和result_code都为SUCCESS的时候有返回  */
   private String trade_type;              //交易类型
   private String prepay_id;               //预支付交易会话标识
   private String code_url;                //二维码链接
    
   public String getReturn_code() {
      return return_code;
   }
   public void setReturn_code(String return_code) {
      this.return_code = return_code;
   }
   public String getReturn_msg() {
      return return_msg;
   }
   public void setReturn_msg(String return_msg) {
      this.return_msg = return_msg;
   }
   public String getAppid() {
      return appid;
   }
   public void setAppid(String appid) {
      this.appid = appid;
   }
   public String getMch_id() {
      return mch_id;
   }
   public void setMch_id(String mch_id) {
      this.mch_id = mch_id;
   }
   public String getDevice_info() {
      return device_info;
   }
   public void setDevice_info(String device_info) {
      this.device_info = device_info;
   }
   public String getNonce_str() {
      return nonce_str;
   }
   public void setNonce_str(String nonce_str) {
      this.nonce_str = nonce_str;
   }
   public String getSign() {
      return sign;
   }
   public void setSign(String sign) {
      this.sign = sign;
   }
   public String getResult_code() {
      return result_code;
   }
   public void setResult_code(String result_code) {
      this.result_code = result_code;
   }
   public String getErr_code() {
      return err_code;
   }
   public void setErr_code(String err_code) {
      this.err_code = err_code;
   }
   public String getErr_code_des() {
      return err_code_des;
   }
   public void setErr_code_des(String err_code_des) {
      this.err_code_des = err_code_des;
   }
   public String getTrade_type() {
      return trade_type;
   }
   public void setTrade_type(String trade_type) {
      this.trade_type = trade_type;
   }
   public String getPrepay_id() {
      return prepay_id;
   }
   public void setPrepay_id(String prepay_id) {
      this.prepay_id = prepay_id;
   }
   public String getCode_url() {
      return code_url;
   }
   public void setCode_url(String code_url) {
      this.code_url = code_url;
   }
    
}

这里的 code_url 就是二维码链接 你可以用你的方式转换成二维码,如果没有好的解决方案,可以参考我的其他博客 将URL利用JS 转换成二维码 填充DIV

注意:prepay_id这个参数是微信内部支付需要的东西

接收支付信息

这样二维码就弹出来了,客户开始扫码 如果扫码支付成功,微信就会调用我们的通知接口

//用于回信回调更改支付状态
@RequestMapping("/weChatUpdRecharge")
public void weChatUpdRecharge(HttpServletRequest request,HttpServletResponse response){
   log.info("=.=微信异步通知开始=.=");
   // 获取post传输的数据
   String request_xml = "";
   UnifiedOrderCallback unifiedOrderCallback=null;
   try {
      ServletInputStream inputStram = request.getInputStream();
      BufferedReader br = new BufferedReader(new InputStreamReader(
            inputStram));
      String temp = "";
      while ((temp = br.readLine()) != null) {
         request_xml = request_xml + temp;
      }
      log.info("=.=微信返回结果=.=" + request_xml);
      XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));
        //将请求返回的内容通过xStream转换为UnifiedOrderRespose对象
        xStream.alias("xml", UnifiedOrderCallback.class);
        unifiedOrderCallback = (UnifiedOrderCallback) xStream.fromXML(request_xml);
        WechatCallback wechatCallback=new WechatCallback();
        wechatCallback.setId(0);
        wechatCallback.setBankType(unifiedOrderCallback.getBank_type());
        wechatCallback.setErrCode(unifiedOrderCallback.getErr_code());
        wechatCallback.setErrCodeDes(unifiedOrderCallback.getErr_code_des());
        wechatCallback.setOpenid(unifiedOrderCallback.getOpenid());
        wechatCallback.setOutTradeNo(unifiedOrderCallback.getOut_trade_no());
        wechatCallback.setRechargeNumber(unifiedOrderCallback.getAttach().split(",")[0]);
        wechatCallback.setResultCode(unifiedOrderCallback.getResult_code());
        wechatCallback.setTimeEnd(unifiedOrderCallback.getTime_end());
        wechatCallback.setTotalFee(Integer.parseInt(unifiedOrderCallback.getTotal_fee()));
        wechatCallback.setTransactionId(unifiedOrderCallback.getTransaction_id());
        log.info("=.=记录交易记录=.=");
        wechatCallbackMapper.insert(wechatCallback);
        log.info("=.=修改订单信息=.=");
        log.info("=.=判断该订单是否被手动支付完成=.=");
        Recharge recharge= rechargeService.selRechargeByNum(wechatCallback.getRechargeNumber());
        if(recharge.getStatus()==0){
            rechargeService.updRechargeSuccess(wechatCallback.getRechargeNumber(),unifiedOrderCallback.getTime_end());
        }else{
           log.info("=.=该订单已被手动完成=.=订单号:"+wechatCallback.getRechargeNumber());
        }
       //通知webSocket支付成功,刷新 页面通知用户您已支付成功
        log.info("=.=开始通知页面刷新支付已成功=.=");
        String websocketKey=unifiedOrderCallback.getAttach().split(",")[1];
        Session session=(Session) ChatServer.map.get(websocketKey);
        System.out.println("session==========="+session);
        session.getAsyncRemote().sendText("=.=");
        ChatServer.map.remove(websocketKey);
   } catch (Exception e) {
      log.info("=.=异常了=.="+e.getMessage());
   } finally{
      log.info("=.=告诉微信,我已经知道了=.=");
      try {
         response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
   
}

这样一套流程就走完了

public class UnifiedOrderCallback {

   private String appid;//应用ID
   private String mch_id;//mch_id
   private String device_info;//设备号
   private String nonce_str;//随机字符串
   private String sign;//签名
   private String result_code;//业务结果
   private String err_code;//错误代码
   private String err_code_des;//错误代码描述
   private String openid;//用户标识
   private String is_subscribe;//是否关注公众账号
   private String trade_type;//交易类型
   private String bank_type;//付款银行    
   private String total_fee;//总金额
   private String fee_type;//货币种类
   private String cash_fee;//现金支付金额
   private String cash_fee_type;//现金支付货币类型
   private String coupon_fee;//代金券金额
   private String coupon_count;//代金券使用数量
   private String coupon_id_$n;//代金券ID
   private String coupon_fee_$n;//单个代金券支付金额
   private String transaction_id;//微信支付订单号
   private String out_trade_no;//商户订单号
   private String attach;//商家数据包
   private String time_end;//支付完成时间
   private String return_code;//返回状态码
   private String return_msg;//返回信息
   
   public String getDevice_info() {
      return device_info;
   }
   public void setDevice_info(String device_info) {
      this.device_info = device_info;
   }
   public String getErr_code() {
      return err_code;
   }
   public void setErr_code(String err_code) {
      this.err_code = err_code;
   }
   public String getErr_code_des() {
      return err_code_des;
   }
   public void setErr_code_des(String err_code_des) {
      this.err_code_des = err_code_des;
   }
   public String getCash_fee_type() {
      return cash_fee_type;
   }
   public void setCash_fee_type(String cash_fee_type) {
      this.cash_fee_type = cash_fee_type;
   }
   public String getCoupon_fee() {
      return coupon_fee;
   }
   public void setCoupon_fee(String coupon_fee) {
      this.coupon_fee = coupon_fee;
   }
   public String getCoupon_count() {
      return coupon_count;
   }
   public void setCoupon_count(String coupon_count) {
      this.coupon_count = coupon_count;
   }
   public String getCoupon_id_$n() {
      return coupon_id_$n;
   }
   public void setCoupon_id_$n(String coupon_id_$n) {
      this.coupon_id_$n = coupon_id_$n;
   }
   public String getCoupon_fee_$n() {
      return coupon_fee_$n;
   }
   public void setCoupon_fee_$n(String coupon_fee_$n) {
      this.coupon_fee_$n = coupon_fee_$n;
   }
   public String getReturn_msg() {
      return return_msg;
   }
   public void setReturn_msg(String return_msg) {
      this.return_msg = return_msg;
   }
   public String getAppid() {
      return appid;
   }
   public void setAppid(String appid) {
      this.appid = appid;
   }
   public String getAttach() {
      return attach;
   }
   public void setAttach(String attach) {
      this.attach = attach;
   }
   public String getBank_type() {
      return bank_type;
   }
   public void setBank_type(String bank_type) {
      this.bank_type = bank_type;
   }
   public String getCash_fee() {
      return cash_fee;
   }
   public void setCash_fee(String cash_fee) {
      this.cash_fee = cash_fee;
   }
   public String getFee_type() {
      return fee_type;
   }
   public void setFee_type(String fee_type) {
      this.fee_type = fee_type;
   }
   public String getIs_subscribe() {
      return is_subscribe;
   }
   public void setIs_subscribe(String is_subscribe) {
      this.is_subscribe = is_subscribe;
   }
   public String getMch_id() {
      return mch_id;
   }
   public void setMch_id(String mch_id) {
      this.mch_id = mch_id;
   }
   public String getNonce_str() {
      return nonce_str;
   }
   public void setNonce_str(String nonce_str) {
      this.nonce_str = nonce_str;
   }
   public String getOpenid() {
      return openid;
   }
   public void setOpenid(String openid) {
      this.openid = openid;
   }
   public String getOut_trade_no() {
      return out_trade_no;
   }
   public void setOut_trade_no(String out_trade_no) {
      this.out_trade_no = out_trade_no;
   }
   public String getResult_code() {
      return result_code;
   }
   public void setResult_code(String result_code) {
      this.result_code = result_code;
   }
   public String getReturn_code() {
      return return_code;
   }
   public void setReturn_code(String return_code) {
      this.return_code = return_code;
   }
   public String getSign() {
      return sign;
   }
   public void setSign(String sign) {
      this.sign = sign;
   }
   public String getTime_end() {
      return time_end;
   }
   public void setTime_end(String time_end) {
      this.time_end = time_end;
   }
   public String getTotal_fee() {
      return total_fee;
   }
   public void setTotal_fee(String total_fee) {
      this.total_fee = total_fee;
   }
   public String getTrade_type() {
      return trade_type;
   }
   public void setTrade_type(String trade_type) {
      this.trade_type = trade_type;
   }
   public String getTransaction_id() {
      return transaction_id;
   }
   public void setTransaction_id(String transaction_id) {
      this.transaction_id = transaction_id;
   }
   
}

转载于:https://my.oschina.net/yanhaohub/blog/3065906

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值