小程序微信支付请求,java服务端接口编写

来源:互联网 发布:sql的存储过程 编辑:程序博客网 时间:2024/06/05 00:39

请求过程:  小程序端,先提交微信支付请求,服务端获取请求。然后再向微信发生支付请求,微信获取服务端提交的支付请求。根据api文档里的notify_url(设置接收反馈结果的路径)返回给服务端。服务器接收到微信端的结果之后,再把相应参数返回给小程序,小程序端再请调取微信支付接口,生成订单,最后客户完成支付。然后通知微信支付成功,整个过程就是这样,下面贴出详细的代码;

小程序微信支付api文档 :https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1


//首先服务端得有个接口,来接收 小程序端来 提交支付请求

/**
     *   微信付款接口
     * 
     * @param params
     * @return
     */
    @RequestMapping(value = "addWaybillTest", produces ="application/json;charset=UTF-8")    
    @ResponseBod

public Map addWaybillTest(HttpServletRequest request,HttpServletResponse response,@RequestBody   MlApiEntity mlApiEntity) {
            Map<String, Object> resultMap=new HashMap();
        try {            //得到一个时间戳
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
                        String str = sdf.format(new Date());
                
                    
                        
                        String  body="MLSystem"+"矿泉水2瓶测试";
                        String total_fee="1";
                    String notify_url="获取微信支付通知接口URL,自定义" ;
                        String openId=WxCommon.getOpenId(mlApiEntity.getCode());
                        //先微信支付
                        resultMap    =WxCommon.wexinPlace( body, "220", total_fee, request, notify_url, openId);
                        
                        
                    
        
        } catch (Exception e) {
            e.printStackTrace();
            loger.info("checkLogin=============error====" + e);
            resultMap.put("result", "系统服务器繁忙,请稍候!");
            e.printStackTrace();
        }
        return resultMap;    
    }


//微信支付工具类
public class WxCommon {
     
        private static String appid="";
        private static String secret="";
        private static String mch_id="";
        private static String key="";
    
    //获取oppenid
    public  static String getOpenId(String code){
        Map<String, String>params=new HashMap();
        params.put("appid", appid);
        params.put("secret",secret );
        params.put("js_code", code);
        params.put("grant_type", "authorization_code");
        String result=HttpXmlClient.post("https://api.weixin.qq.com/sns/jscode2session", params);
        
        JSONObject jsonObj = JSONObject.fromObject(result);
        if(jsonObj.has("openid")){
                String openid=jsonObj.getString("openid");
                if("".equals(openid)){
                    return "invalidCode";
                }else{
                    return openid;
                }
        }else{
            return "invalidCode";
        }
        
    
    }
  

     
        
        
        //统一下单
  public  static Map wexinPlace(  String body,String waybillNo,String total_fee,HttpServletRequest request,String notify_url,String account){
            Map<String, String> paramMap=new HashMap();
            paramMap.put("appid", appid);
            paramMap.put("mch_id", mch_id);
            paramMap.put("device_info", "WEB");
            paramMap.put("nonce_str", GeneratePwd.genRandomNum(32));
            paramMap.put("sign_type","MD5");
            paramMap.put("body",body);
            paramMap.put("out_trade_no",waybillNo);
            paramMap.put("total_fee",total_fee);
            paramMap.put("spbill_create_ip",getIpAddr(request));
            paramMap.put("notify_url",notify_url);
            paramMap.put("trade_type","JSAPI");
            paramMap.put("openid",account);
            paramMap.put("sign",  createSign(paramMap));
              // 把参数转换成XML数据格式
            String xmlWeChat = assembParamToXml(paramMap);
     String resXml = HttpUtil.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlWeChat);
            Map<String, String> resMap = null;
            if (!StrUtil.isBlank(resXml)) {
                try {
                    resMap = parseXMLToMap(resXml);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (JDOMException e) {
                    e.printStackTrace();
                }
            }

            Map<String, String> map = new HashMap();
            if (resMap == null) {
                map.put("status", "false");
                return map;
            }
            String return_code = resMap.get("return_code");
            if (return_code.equalsIgnoreCase("FAIL")) {
                map.put("message", resMap.get("return_msg"));
                map.put("status", "false");
                return map;
            } else if (return_code.equalsIgnoreCase("SUCCESS")) {
                String err_code = resMap.get("err_code");
                if (!StrUtil.isBlank(err_code)) {
                    map.put("status", "false");
                    map.put("message", resMap.get("err_code_des"));
                } else if (resMap.get("result_code").equalsIgnoreCase("SUCCESS")) {
                    map.put("appId",appid);
                    // 时间戳 当前的时间 需要转换成秒
                    map.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                    // 随机字符串 不长于32位
                    map.put("nonceStr", GeneratePwd.genRandomNum(32));
                    // 订单详情扩展字符串 统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
                    map.put("package", "prepay_id=" + resMap.get("prepay_id"));
                    // 签名方式 签名算法,暂支持MD5
                    map.put("signType", "MD5");
                    // 签名
                    map.put("paySign", createSign(map));
                    map.remove("appId");
                    map.put("status", "true");
                }else {
                    map.put("status", "false");
                }
            }
            return map;
        
        }
        /**
         * 微信支付签名sign
         */
        public static String createSign(Map<String, String> param) {
            //签名步骤一:按字典排序参数
            List list = new ArrayList(param.keySet());
            Object[] ary = list.toArray();
            Arrays.sort(ary);
            list = Arrays.asList(ary);
            String str = "";
            for (int i = 0; i < list.size(); i++) {
                str += list.get(i) + "=" + param.get(list.get(i) + "") + "&";
            }
            //签名步骤二:加上key
            str += "key=" + key;
            System.err.println(str);
            //步骤三:加密并大写
            str = MD5Util.md5(str).toUpperCase();
            return str;
        }
        /**
         * 获取访问者IP
         * <p>
         * 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。
         * <p>
         * 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割),
         * 如果还不存在则调用Request .getRemoteAddr()。
         *
         * @param request
         * @return
         */
        public static String getIpAddr(HttpServletRequest request) {
            String ip = request.getHeader("X-Real-IP");
            if (!StrUtil.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
                if (ip.contains("../") || ip.contains("..\\")) {
                    return "";
                }
                return ip;
            }
            ip = request.getHeader("X-Forwarded-For");
            if (!StrUtil.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
                // 多次反向代理后会有多个IP值,第一个为真实IP。
                int index = ip.indexOf(',');
                if (index != -1) {
                    ip = ip.substring(0, index);
                }
                if (ip.contains("../") || ip.contains("..\\")) {
                    return "";
                }
                return ip;
            } else {
                ip = request.getRemoteAddr();
                if (ip.contains("../") || ip.contains("..\\")) {
                    return "";
                }
                if (ip.equals("0:0:0:0:0:0:0:1")) {
                    ip = "127.0.0.1";
                }
                return ip;
            }
        }
     // 通知微信正确接收
        public static void noticeWeChatSuccess(String weiXinPayUrl) {
            Map<String, String> parames = new HashMap<String, String>();
            parames.put("return_code", "SUCCESS");
            parames.put("return_msg", "OK");
            // 将参数转成xml格式
            String xmlWeChat = assembParamToXml(parames);
            try {
                if (!StrUtil.isBlank(weiXinPayUrl)) {
                    String s = HttpUtil.post(weiXinPayUrl, xmlWeChat);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 通知微信错误
        public static void noticeWeChatFAIL(String weiXinPayUrl) {
            Map<String, String> parames = new HashMap<String, String>();
            parames.put("return_code", "FAIL");
            parames.put("return_msg", "校验错误");
            // 将参数转成xml格式
            String xmlWeChat = assembParamToXml(parames);
            try {
                if (!StrUtil.isBlank(weiXinPayUrl)) {
                    String s = HttpUtil.post(weiXinPayUrl, xmlWeChat);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
         */
        public static Map parseXMLToMap(String strxml) throws IOException, JDOMException {
            strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
            if (null == strxml || "".equals(strxml)) {
                return null;
            }
            Map m = new HashMap();
            InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(in);
            Element root = doc.getRootElement();
            List list = root.getChildren();
            Iterator it = list.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String k = e.getName();
                String v = "";
                List children = e.getChildren();
                if (children.isEmpty()) {
                    v = e.getTextNormalize();
                } else {
                    v = getChildrenText(children);
                }
                m.put(k, v);
            }
            //关闭流
            in.close();
            return m;
        }
        /**
         * 获取子结点的xml
         *
         * @param children
         * @return String
         */
        private static String getChildrenText(List children) {
            StringBuffer sb = new StringBuffer();
            if (!children.isEmpty()) {
                Iterator it = children.iterator();
                while (it.hasNext()) {
                    Element e = (Element) it.next();
                    String name = e.getName();
                    String value = e.getTextNormalize();
                    List list = e.getChildren();
                    sb.append("<" + name + ">");
                    if (!list.isEmpty()) {
                        sb.append(getChildrenText(list));
                    }
                    sb.append(value);
                    sb.append("</" + name + ">");
                }
            }
            return sb.toString();
        }
        /**
         * 将需要传递给微信的参数转成xml格式
         *
         * @param parameters
         * @return
         */
        private static String assembParamToXml(Map<String, String> parameters) {
            StringBuffer sb = new StringBuffer();
            sb.append("<xml>");
            Set<String> es = parameters.keySet();
            List<Object> list = new ArrayList<Object>(es);
            Object[] ary = list.toArray();
            Arrays.sort(ary);
            list = Arrays.asList(ary);
            Iterator<Object> it = list.iterator();
            while (it.hasNext()) {
                String key = (String) it.next();
                String val = (String) parameters.get(key);
 if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
                    sb.append("<" + key + ">" + "<![CDATA[" + val + "]]></" + key + ">");
                } else {
                    sb.append("<" + key + ">" + val + "</" + key + ">");
                }
            }
            sb.append("</xml>");
            return sb.toString();
        }
        /**
         * 处理xml请求信息
         */
        public static String getWeiXinResponse(HttpServletRequest request) {
            BufferedReader bis = null;
            String result = "";
            try {
                bis = new BufferedReader(new InputStreamReader(request.getInputStream()));
                String line = null;
                while ((line = bis.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return result;
        }
     
}


/**
     *接收微信支付结果通知  成功付款 则新增订单
     * 
     * @param params
     * @return
     */
    @RequestMapping(value = "wxPayResult", produces ="application/json;charset=UTF-8")    
    @ResponseBody
    public void wxPayResult(HttpServletRequest request,HttpServletResponse response)throws Exception {
            String resXml=WxCommon.getWeiXinResponse(request);//字节流 转换成 字符流
              Map<String, String> resMap = null;
            
         if (!StrUtil.isBlank(resXml)) {
                try {
                    resMap = WxCommon.parseXMLToMap(resXml);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (JDOMException e) {
                    e.printStackTrace();
                }
            }
          Map<String, String> map = new HashMap();
            if (resMap != null) {
                  String return_code = resMap.get("return_code");
                  if(return_code.equals("FAIL")){
                      String return_msg="";
                      return_msg=resMap.get("return_msg");
                
                      loger.info("===========================微信支付接口调用失败,返回结果=====================" +return_msg);
                   }else if(return_code.equals("SUCCESS")){
                       String result_code=resMap.get("result_code");
                       if(result_code.equals("SUCCESS")){
                           String sign=resMap.get("sign");
                           resMap.remove("sign");
                           String result=WxCommon.createSign(resMap);
                           if(sign.equals(result)){
                              String out_trade_no=resMap.get("out_trade_no");
                                  
                          
                               WxCommon.noticeWeChatSuccess("https://api.mch.weixin.qq.com/pay/unifiedorder");//支付成功后我们要通知微信
                              
loger.info("===========================微信支付成=====================");
             }
                 }else{
                            
loger.info("===========================微信支付失=====================" );
                           }
                           
                           
                         }else if(result_code.equals("FAIL")){
                              String err_code=resMap.get("err_code");
                                 if(!StrUtil.isBlank(err_code)){
                                   
             loger.info("===========================微信支付失败:错误返回的信息描述:====================="+err_code );
                                     String err_code_des=resMap.get("err_code_des");
                                     if(!StrUtil.isBlank(err_code_des)){
                                       
                                        loger.info("===========================微信支付失败:错误返回的信息描述:====================="+err_code_des );
                                     }
                                   
                                 }else{
                                     
                                     
                                 }
                         }
                     
                      
                      
                  }
            }
     }