微信支付-h5接入详细流程和代码

这里是具体的流程和代码,有什么疑问请参考我上一篇微信公众号接入流程的文章

1、申请一个微信服务号,这是你接入支付的前提
2、登录服务号,配置开发基本配置和网页授权权
3、申请开通微信支付,开通要使用的相关产品(公众号支付)
4、在账户中心进行相关的配置,设置秘钥

到这里前期的准备工作已经做完了,下面开始按照上面的流程开始进行代码的编写

---大戏开幕---

第一步:(我这里演示的是springmvc接入的版本)

编写controller ,在服务号中基本配置中配置的服务器地址URL

http://****/***-interface/wxPayApi/reqWxApp.htm

@Controller
@RequestMapping("/wxPayApi/")
public class WXPayApi extends BaseController{

@Autowired WXPayService wXPayService;
@Autowired OrderService orderService;

private static Logger logger = Logger.getLogger(WXPayApi.class);

         /**

扫描二维码关注公众号,回复: 2413158 查看本文章

     *

     * @Description: 用于接收get参数,返回验证参数

     * @param @param request

     * @param @param response

     * @param @param signature

     * @param @param timestamp

     * @param @param nonce

     * @param @param echostr

     * @author dapengniao

     * @date 2016年3月4日下午6:20:00

     */

    @RequestMapping(value = "reqWxApp.htm", method = RequestMethod.GET)

    public void doGet(

            HttpServletRequest request,

            HttpServletResponse response,

            @RequestParam(value = "signature", required = true) String signature,

            @RequestParam(value = "timestamp", required = true) String timestamp,

            @RequestParam(value = "nonce", required = true) String nonce,

            @RequestParam(value = "echostr", required = true) String echostr) {

        try {

            if (SignUtil.checkSignature(signature, timestamp, nonce)) {

                PrintWriter out = response.getWriter();

                out.print(echostr);

                out.close();

            } else {

                logger.info("这里存在非法请求!");

            }

        } catch (Exception e) {

            logger.error(e, e);

        }

    }


    @RequestMapping(value = "reqWxApp.htm", method = RequestMethod.POST)

    // post方法用于接收微信服务端消息

    public void  DoPost(HttpServletRequest request,HttpServletResponse response) throws IOException {

        System.out.println("这是post方法!");

        String openid = "";

        try{

               

        }catch(Exception e){

            logger.error(e,e);

        }

    }

   

}


第二步:

通过前台页面请求获取code,通过code获取页面授权的access_token,拿到openID

前台页面的代码:

var redirect_url = encodeURI("***********后台回调地址******************");

 location.href ="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx798ded0c9460ae63"+

                   "&redirect_uri="+redirect_url+"&response_type=code&scope=snsapi_base"

                   +"&state=123#wechat_redirect";


后台代码:


//预支付选择商品页面.先获取用户code,再获取openId

    @RequestMapping(value = "/getOpenId.htm", method = RequestMethod.GET)  //{guid}

    public String  getDevicePay(Model model,@RequestParam("code") String code) throws Exception  {

             Map<String, String> map= new HashMap<String, String>();

             String param = "appid=wx798ded0c9460ae63&secret=30bdad70aafa34b8dc7609d1c9b39691&code="+ code +"&grant_type=authorization_code";

             String sr=HttpRequest.sendPost("https://api.weixin.qq.com/sns/oauth2/access_token", param);

        JSONObject json = JSONObject.fromObject(sr);

        String openID = String.valueOf(json.get("openid"));

        System.out.println("========openID==============================="+openID);

        if(!openID.equals("")){

//             eventService.saveOpenId(openID);

        }

       return "redirect:http://www.axigo.cn/axigo-wap/index1.html?openID="+openID;

}


通过后台方法把获取的openID返给前台,前台进行缓存;

这其中有一个恶心之处就是redirect跳转会刷新页面,一直没有解决,望大神们给小弟指点迷经,小弟不胜感激,我现在使用的方法是写两个首页,名称不同,从一个首页重定向到领一个首页,没有好的思路,望大神指点。。。。。。。。。


微信支付的接口代码

// @ApiOperation(value = "微信支付调用", httpMethod = "POST")

         @RequestMapping(value = "/couponsConfirm.htm", method = RequestMethod.POST)

         public @ResponseBody ResultBase couponsConfirm(HttpServletRequest request,@RequestBody Map<String, String> map) {

                  ResultBase res = new ResultBase();

                  JSONObject json = new JSONObject();

                  // 获取签名signature

                  String appId = ConfigUtil.APPID;// 取项目中配置的公众号id

                  String secret = ConfigUtil.APP_SECRECT;// 取项目中配置的公众号密钥

                  // 域名的切换

                  String domainAddr = "www.axigo.cn";// 项目中配置的网站的域名

                  Map<String, String> mapUrl = new HashMap<String, String>();

                  mapUrl.put("appid", appId);

                  mapUrl.put("secret", secret);

                  String cruurl = "";

                  if (map.containsKey("url") && CommonUtil.notEmpty(map.get("url").toString())) {

                          cruurl = map.get("url").toString();

                  }

                  String url = cruurl;

                  System.out.println("url=============================" + url);

                  mapUrl.put("url", url);

                  // 开始微信分享链接签名

                  Map<String, String> params = wXPayService.WXSignature(mapUrl);

                  json.put("params", params);

                  System.out.println("signature=============================" + String.valueOf(params.get("signature")));

                  json.put("signature", String.valueOf(params.get("signature")));

                  //=================================================================

                  String openid = "";

                  String orderNo = "";

                  String remoteAddr = request.getRemoteAddr();

                  if (CommonUtil.notEmpty(String.valueOf(map.get("openid")))) {

                          openid = String.valueOf(map.get("openid"));

                  }

                  if (CommonUtil.notEmpty(String.valueOf(map.get("orderNo")))) {

                          orderNo = String.valueOf(map.get("orderNo"));

                  }

                  System.out.println("========openid=================" + openid+ "==========================" + orderNo);

                  // openid可通过微信高级接口oath2.0网页授权接口获取到用户信息,此接口本文中就不提供了,如果有需要,请留言。

                  json.put("openid", openid);

                  // orderNo是你的商品订单号,自行生成的随机订单号,但是要保证随机性,不能有重复订单号。

                  json.put("orderNo", orderNo);

                  String timeStamp = PayCommonUtil.create_timestamp();

                  String nonceStr = PayCommonUtil.CreateNoncestr();

                  json.put("appid", ConfigUtil.APPID);

                  json.put("timestamp", timeStamp);

                  json.put("nonceStr", nonceStr);


                  String total_price = getWXPayParam(map);

                  String prepayId = WxPayUtil.unifiedorder("蒙源商城-购物支付", orderNo, openid,nonceStr,remoteAddr,total_price);

                  System.out.println("prepayId=================================>"+ prepayId);

                  // String userAgent = request.getHeader("user-agent");

                  // char agent =

                  // userAgent.charAt(userAgent.indexOf("MicroMessenger")+15);

                  // m.addAttribute("agent", new String(new

                  // char[]{agent}));//微信版本号,用于前面提到的判断用户手机微信的版本是否是5.0以上版本。


                  SortedMap<Object, Object> signParams = new TreeMap<Object, Object>();

                  signParams.put("appId", ConfigUtil.APPID);

                  signParams.put("nonceStr", nonceStr);

                  signParams.put("package", "prepay_id=" + prepayId);

                  signParams.put("timeStamp", timeStamp);

                  signParams.put("signType", "MD5");


                  // 生成支付签名,要采用URLENCODER的原始值进行SHA1算法!

                  String sign = PayCommonUtil.createSign(signParams);

                  System.out.println("paySign==============================" + sign);


                  json.put("paySign", sign);

                  json.put("signType", "MD5");


                  json.put("packageValue", "prepay_id=" + prepayId);


                  res.setObj(json);

                  res.setResult(ResultBase.RESULT_SUCC);

                  return res;

         }

   

         @RequestMapping(value = "succ.htm", produces = MediaType.APPLICATION_JSON_VALUE)

         public void wxpaySucc(HttpServletRequest request,HttpServletResponse response) throws IOException,JDOMException {

                  System.out.println("=========================微信支付回调===========================");

                  InputStream inStream = request.getInputStream();

                  ByteArrayOutputStream outSteam = new ByteArrayOutputStream();

                  byte[] buffer = new byte[1024];

                  int len = 0;

                  while ((len = inStream.read(buffer)) != -1) {

                          outSteam.write(buffer, 0, len);

                  }

                  String resultxml = new String(outSteam.toByteArray(), "utf-8");

                  System.out.println("回调=================》"+resultxml);

                  Map<String, String> params = PayCommonUtil.doXMLParse(resultxml);

                  outSteam.close();

                  inStream.close();

                  String data2 = "<xml><return_code><![CDATA[SUCCESS]]</return_code>"

                                   + "<return_msg><![CDATA[OK]]></return_msg></xml>";

                  if (!PayCommonUtil.isTenpaySign(params)) {

                          System.out.println("========支付失败==============");

//                       return "fail";

                  } else if (params.get("result_code").equals("SUCCESS")) {

                          System.out.println("===============付款成功==============");

                          // ------------------------------

                          // 处理业务开始

                         

                          Boolean falg = orderService.iswxCallBack(params);

                         

                          if (!falg) {

                                   orderService.wxCallBack(params);

                          }

                         

                          // 此处处理订单状态,结合自己的订单数据完成订单状态的更新

                          // ------------------------------


//                       String total_fee = params.get("total_fee");

//                       double v = Double.valueOf(total_fee) / 100;

//                       Long userId = Long.valueOf(params.get("out_trade_no").split("O")[0]);

                          String sign = params.get("sign");

                          String data = "<xml><return_code><![CDATA[SUCCESS]]</return_code><return_msg><![CDATA[OK]]></return_msg></xml>";

//                       response.reset();

                          response.setContentType("text/xml");

                          response.getWriter().write(data);

                          response.getWriter().flush();

                                  

                          // 更新

                          // updateUserPay(userId, String.valueOf(v));

                          // 处理业务完毕

                          // ------------------------------

//                       return data;

                  }

//              return data2;

         }

        

         private String getWXPayParam(Map<String, String> map){

                  ResultBase res = orderService.payBack(map);

                  JSONObject obj = (JSONObject) res.getObj();

                  String totalPrice = String.valueOf(obj.get("totalPrice"));

                  totalPrice = MoneyUtil.changeY2F(totalPrice);

                  return totalPrice;

         }


配置信息的工具类

public class ConfigUtil {

         /**

         * 服务号相关信息

         */

         public final static String APPID = "w3";//服务号的appid

         public final static String APP_SECRECT = "30bd691";//服务号的appSecrect

         public final static String TOKEN = "axen";//服务号的配置token

         public final static String MCH_ID = "14992";//开通微信支付分配的商户号

         public final static String API_KEY = "oWBEaxigo123";//商户API密钥自行去商户平台设置

         public final static String SIGN_TYPE = "MD5";//签名加密方式

         //微信支付统一接口的回调action

         public final static String NOTIFY_URL = "http://***/axigo-interface/wxPayApi/succ.htm"; //用于告知微信服务器调用成功

        

         /**

          * 微信基础接口地址

          */

          //获取token接口(GET)

          public final static String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

          //oauth2授权接口(GET)

          public final static String OAUTH2_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";

          //刷新access_token接口(GET)

          public final static String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";

         // 菜单创建接口(POST)

          public final static String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

         // 菜单查询(GET)

          public final static String MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";

         // 菜单删除(GET)

         public final static String MENU_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";

         /**

          * 微信支付接口地址

          */

         //微信支付统一接口(POST)

         public final static String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

         //微信退款接口(POST)

         public final static String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";

         //订单查询接口(POST)

         public final static String CHECK_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";

         //关闭订单接口(POST)

         public final static String CLOSE_ORDER_URL = "https://api.mch.weixin.qq.com/pay/closeorder";

         //退款查询接口(POST)

         public final static String CHECK_REFUND_URL = "https://api.mch.weixin.qq.com/pay/refundquery";

         //对账单接口(POST)

         public final static String DOWNLOAD_BILL_URL = "https://api.mch.weixin.qq.com/pay/downloadbill";

         //短链接转换接口(POST)

         public final static String SHORT_URL = "https://api.mch.weixin.qq.com/tools/shorturl";

         //接口调用上报接口(POST)

         public final static String REPORT_URL = "https://api.mch.weixin.qq.com/payitil/report";


}


请求工具类

public class CommonUtil {

         private static Logger log = LoggerFactory.getLogger(CommonUtil.class);

         /**

         * 发送https请求

         * @param requestUrl 请求地址

         * @param requestMethod 请求方式(GET、POST)

         * @param outputStr 提交的数据

         * @return 返回微信服务器响应的信息

         */

         public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {

         try {

         // 创建SSLContext对象,并使用我们指定的信任管理器初始化

         TrustManager[] tm = { new MyX509TrustManager() };

         SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");

         sslContext.init(null, tm, new java.security.SecureRandom());

         // 从上述SSLContext对象中得到SSLSocketFactory对象

         SSLSocketFactory ssf = sslContext.getSocketFactory();

         URL url = new URL(requestUrl);

         HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

         conn.setSSLSocketFactory(ssf);

         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) {

         log.error("连接超时:{}", ce);

         } catch (Exception e) {

         log.error("https请求异常:{}", e);

         }

         return null;

         }

        

         public static String urlEncodeUTF8(String source){

             String result = source;

             try {

                 result = java.net.URLEncoder.encode(source,"utf-8");

             } catch (UnsupportedEncodingException e) {

                 e.printStackTrace();

             }

             return result;

         }

}


加密工具类


public class MD5Util {

         private static String byteArrayToHexString(byte b[]) {

             StringBuffer resultSb = new StringBuffer();

             for (int i = 0; i < b.length; i++)

                 resultSb.append(byteToHexString(b[i]));


             return resultSb.toString();

         }


         private static String byteToHexString(byte b) {

             int n = b;

             if (n < 0)

                 n += 256;

             int d1 = n / 16;

             int d2 = n % 16;

             return hexDigits[d1] + hexDigits[d2];

         }


         public static String MD5Encode(String origin, String charsetname) {

             String resultString = null;

             try {

                 resultString = new String(origin);

                 MessageDigest md = MessageDigest.getInstance("MD5");

                 if (charsetname == null || "".equals(charsetname))

                     resultString = byteArrayToHexString(md.digest(resultString

                             .getBytes()));

                 else

                     resultString = byteArrayToHexString(md.digest(resultString

                             .getBytes(charsetname)));

             } catch (Exception exception) {

             }

             return resultString;

         }


         private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",

                 "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

}


元分转换工具类


public class MoneyUtil {

        

   

    /**金额为分的格式 */   

    public static final String CURRENCY_FEN_REGEX = "\\-?[0-9]+";   

       

    /**  

     * 将分为单位的转换为元并返回金额格式的字符串(除100)

     *  

     * @param amount

     * @return

     * @throws Exception  

     */   

    public static String changeF2Y(Long amount) throws Exception{   

        if(!amount.toString().matches(CURRENCY_FEN_REGEX)) {   

            throw new Exception("金额格式有误");   

        }   

           

        int flag = 0;   

        String amString = amount.toString();   

        if(amString.charAt(0)=='-'){   

            flag = 1;   

            amString = amString.substring(1);   

        }   

        StringBuffer result = new StringBuffer();   

        if(amString.length()==1){   

            result.append("0.0").append(amString);   

        }else if(amString.length() == 2){   

            result.append("0.").append(amString);   

        }else{   

            String intString = amString.substring(0,amString.length()-2);   

            for(int i=1; i<=intString.length();i++){   

                if( (i-1)%3 == 0 && i !=1){   

                    result.append(",");   

                }    

                result.append(intString.substring(intString.length()-i,intString.length()-i+1));   

            }   

            result.reverse().append(".").append(amString.substring(amString.length()-2));   

        }   

        if(flag == 1){   

            return "-"+result.toString();   

        }else{   

            return result.toString();   

        }   

    }   

       

    /**

     * 将分为单位的转换为元(除100)

     *  

     * @param amount

     * @return

     * @throws Exception  

     */   

    public static String changeF2Y(String amount) throws Exception{   

        if(!amount.matches(CURRENCY_FEN_REGEX)) {   

            throw new Exception("金额格式有误");   

        }   

        return BigDecimal.valueOf(Long.valueOf(amount)).divide(new BigDecimal(100)).toString();   

    }   

       

    /**  

     * 将元为单位的转换为分(乘100)

     *  

     * @param amount

     * @return

     */   

    public static String changeY2F(Long amount){   

        return BigDecimal.valueOf(amount).multiply(new BigDecimal(100)).toString();   

    }   

       

    /**  

     * 将元为单位的转换为分替换小数点,支持以逗号区分的金额

     *  

     * @param amount

     * @return

     */   

    public static String changeY2F(String amount){   

        String currency =  amount.replaceAll("\\$|\\¥|\\,", "");  //处理包含, ¥或者$的金额   

        int index = currency.indexOf(".");   

        int length = currency.length();   

        Long amLong = 0l;   

        if(index == -1){   

            amLong = Long.valueOf(currency+"00");   

        }else if(length - index >= 3){   

            amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));   

        }else if(length - index == 2){   

            amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);   

        }else{   

            amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");   

        }   

        return amLong.toString();   

    }   

       

    public static void main(String[] args) {   

//        try {   

//            System.out.println("结果:"+changeF2Y("-000a00"));   

//        } catch(Exception e){   

//            System.out.println("----------->>>"+e.getMessage());   

////          return e.getErrorCode();   

//        }    

//      System.out.println("结果:"+changeY2F("1.00000000001E10"));   

           

        System.out.println(MoneyUtil.changeY2F("109.99"));   

        try {

            System.out.println(MoneyUtil.changeF2Y("1322"));

        } catch (Exception e) {

            e.printStackTrace();

        }

//        System.out.println(Long.parseLong(AmountUtils.changeY2F("1000000000000000")));   

//        System.out.println(Integer.parseInt(AmountUtils.changeY2F("10000000")));   

//        System.out.println(Integer.MIN_VALUE);   

//        long a = 0;   

//        System.out.println(a);   

           

    }


}


证书检查

public class MyX509TrustManager implements X509TrustManager {

         // 检查客户端证书

         public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

         }


         // 检查服务器端证书

         public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

         }


         // 返回受信任的X509证书数组

         public X509Certificate[] getAcceptedIssuers() {

             return null;

         }

}


支付参数工具类


public class PayCommonUtil {

         /**

          * 获取支付随机码

          * @return

          */

          public static String create_nonce_str() {

                 return UUID.randomUUID().toString();

             }

   /**

    * 获取微信支付时间戳

    * @return

    */

    public static String create_timestamp() {

        return Long.toString(System.currentTimeMillis() / 1000);

    }


    /**

     * 获取预支付ID时  获取随机码

     * @param length

     * @return

     */

    public static String CreateNoncestr(int length) {

        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

        String res = "";

        for (int i = 0; i < length; i++) {

            Random rd = new Random();

            res += chars.indexOf(rd.nextInt(chars.length() - 1));

        }

        return res;

    }

    /**

     * 获取预支付ID时  获取随机码

     * @param length

     * @return

     */

    public static String CreateNoncestr() {

        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

        String res = "";

        for (int i = 0; i < 32; i++) {

            Random rd = new Random();

            res += chars.charAt(rd.nextInt(chars.length() - 1));

        }

        return res;

    }


         /**

          * @author Mark

          * @Description:sign签名

          * @param characterEncoding 编码格式

          * @param parameters 请求参数

          * @return

          */

         public static String createSign(SortedMap<Object,Object> 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=" + ConfigUtil.API_KEY);

             String sign = MD5Util.MD5Encode(sb.toString(),"UTF-8").toUpperCase();

             return sign;

         }

         /**

          * @author Mark

          * @Description:将请求参数转换为xml格式的string

          * @param parameters  请求参数

          * @return

          */

         public static String getRequestXml(SortedMap<Object,Object> parameters){

             StringBuffer sb = new StringBuffer();

             sb.append("<xml>");

             Set es = parameters.entrySet();

             Iterator it = es.iterator();

             while(it.hasNext()) {

                 Map.Entry entry = (Map.Entry)it.next();

                 String k = (String)entry.getKey();

                 String v = (String)entry.getValue();

                 if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)) {

                     sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");

                 }else {

                     sb.append("<"+k+">"+v+"</"+k+">");

                 }

             }

             sb.append("</xml>");

             return sb.toString();

         }

         /**

          * @author Mark

          * @Description:返回给微信的参数

          * @param return_code 返回编码

          * @param return_msg  返回信息

          * @return

          */

         public static String setXML(String return_code, String return_msg) {

             return "<xml><return_code><![CDATA[" + return_code

                     + "]]></return_code><return_msg><![CDATA[" + return_msg

                     + "]]></return_msg></xml>";

         }

        

         //xml解析

    public static Map doXMLParse(String strxml) throws JDOMException, IOException {

          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;

    }

   

         /**

          * 验证回调签名

          *

          * @param packageParams

          * @param key

          * @param charset

          * @return

          */

         public static boolean isTenpaySign(Map<String, String> map)

                          throws UnsupportedEncodingException {

                  String charset = "utf-8";

                  String signFromAPIResponse = map.get("sign");

                  if (signFromAPIResponse == null || signFromAPIResponse.equals("")) {

                          System.out.println("API返回的数据签名数据不存在,有可能被第三方篡改!!!");

                          return false;

                  }

                  System.out.println("服务器回包里面的签名是:" + signFromAPIResponse);

                  // 过滤空设置 TreeMap

                  SortedMap<Object, Object> packageParams = new TreeMap<>();

                  StringBuffer sb = new StringBuffer();

                  for (String parameter : map.keySet()) {

                          String parameterValue = map.get(parameter);

                          String v = "";

                          if (null != parameterValue) {

                                   v = parameterValue.trim();

                          }

                          packageParams.put(parameter, v);

                  }

                  String resultSign = PayCommonUtil.createSign(packageParams);

                  System.out.println("1====" + resultSign);

                  // 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较

                  // 算出签名

                  String tenpaySign = ((String) packageParams.get("sign")).toUpperCase();

                  return tenpaySign.equals(resultSign);

         }

   

    public 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();

  }

   

   public static void main(String[] args) throws JDOMException, IOException, DocumentException, SAXException, ParserConfigurationException {

            String data = "<xml><return_code><![CDATA[SUCCESS]]</return_code><return_msg><![CDATA[OK]]></return_msg></xml>";

            StringReader sr = new StringReader(data);

            InputSource is = new InputSource(sr);

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

            DocumentBuilder builder=factory.newDocumentBuilder();

                  // XML转字符串

            String text = builder.parse(is).toString();

            System.out.println(text);

 }

   

}


Sha1加密


public class Sha1 {

         public static String getSha1Sign(String decript) {   

        try {   

            MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1");   

            try {

                digest.update(decript.getBytes("UTF-8"));

            } catch (UnsupportedEncodingException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }   

            byte messageDigest[] = digest.digest();   

            // Create Hex String   

            StringBuffer hexString = new StringBuffer();   

            // 字节数组转换为十六进制数   

            for (int i = 0; i < messageDigest.length; i++) {   

                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);   

                if (shaHex.length() < 2) {   

                    hexString.append(0);   

                }   

                hexString.append(shaHex);   

            }   

            return hexString.toString();   

             

        } catch (NoSuchAlgorithmException e) {   

            e.printStackTrace();   

        }   

        return "";   

    }   

}


TokenUtil工具类

public class TokenUtil {

          private static Logger log = LoggerFactory.getLogger(TokenUtil.class);


             // 凭证获取(GET)

             public final static String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";


             /**

              * 发送https请求

              *

              * @param requestUrl 请求地址

              * @param requestMethod 请求方式(GET、POST)

              * @param outputStr 提交的数据

              * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)

              */

             public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {

                 JSONObject jsonObject = null;

                 try {

                     // 创建SSLContext对象,并使用我们指定的信任管理器初始化

                     TrustManager[] tm = { new MyX509TrustManager() };

                     SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");

                     sslContext.init(null, tm, new java.security.SecureRandom());

                     // 从上述SSLContext对象中得到SSLSocketFactory对象

                     SSLSocketFactory ssf = sslContext.getSocketFactory();


                     URL url = new URL(requestUrl);

                     HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

                     conn.setSSLSocketFactory(ssf);

                    

                     conn.setDoOutput(true);

                     conn.setDoInput(true);

                     conn.setUseCaches(false);

                     // 设置请求方式(GET/POST)

                     conn.setRequestMethod(requestMethod);


                     // 当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();

                     jsonObject = JSONObject.fromObject(buffer.toString());

                 } catch (ConnectException ce) {

                     log.error("连接超时:{}", ce);

                 } catch (Exception e) {

                     log.error("https请求异常:{}", e);

                 }

                 return jsonObject;

             }


             /**

              * 获取接口访问凭证

              *

              * @param appid 凭证

              * @param appsecret 密钥

              * @return

              */

             public static Token getToken(String appid, String appsecret) {

                 Token token = null;

                 String requestUrl = token_url.replace("APPID", appid).replace("APPSECRET", appsecret);

                 // 发起GET请求获取凭证

                 JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);


                 if (null != jsonObject) {

                     try {

                         token = new Token();

                         token.setAccessToken(jsonObject.getString("access_token"));

                         token.setExpiresIn(jsonObject.getInt("expires_in"));

                     } catch (JSONException e) {

                         token = null;

                         // 获取token失败

                         log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));

                     }

                 }

                 return token;

             }

}


微信支付工具类


public class WxPayUtil {

         @SuppressWarnings("unchecked")

         public static String unifiedorder(String body,String out_trade_no,String openid,String nonceStr,String remoteAddr,String total_price) {

                  System.out.println("remoteAddr===================="+remoteAddr);

             SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();

             parameters.put("appid", ConfigUtil.APPID);


             parameters.put("mch_id", ConfigUtil.MCH_ID);

             parameters.put("device_info", "WEB");

             parameters.put("nonce_str", nonceStr);

             parameters.put("body", body);

             parameters.put("out_trade_no", out_trade_no);

             parameters.put("total_fee", total_price);

             parameters.put("spbill_create_ip",remoteAddr);

             parameters.put("notify_url", ConfigUtil.NOTIFY_URL);

             parameters.put("trade_type", "JSAPI");

             parameters.put("openid", openid);

             String sign = PayCommonUtil.createSign(parameters);

             System.out.println("diyige   =========== sign===="+sign);

             parameters.put("sign", sign);

             String requestXML = PayCommonUtil.getRequestXml(parameters);

             System.out.println(requestXML.toString());

             String result =CommonUtil.httpsRequest(ConfigUtil.UNIFIED_ORDER_URL, "POST", requestXML);

             System.out.println(result.toString());

             Map<String, String> map=new HashMap<String, String>();

             try {

                 map = XMLUtil.doXMLParse(result);

             } catch (JDOMException e) {

                 // TODO Auto-generated catch block

                 e.printStackTrace();

             } catch (IOException e) {

                 // TODO Auto-generated catch block

                 e.printStackTrace();

             }//解析微信返回的信息,以Map形式存储便于取值

             return map.get("prepay_id").toString();

         }

}


XML转换工具类


public class XMLUtil {

         /**

         * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。

         * @param strxml

         * @return

         * @throws JDOMException

         * @throws IOException

         */

         public static Map doXMLParse(String strxml) throws JDOMException, IOException {

         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 = XMLUtil.getChildrenText(children);

        }


        m.put(k, v);

    }


    //关闭流

    in.close();


    return m;

}


/**

 * 获取子结点的xml

 * @param children

 * @return String

 */

public 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(XMLUtil.getChildrenText(list));

            }

            sb.append(value);

            sb.append("</" + name + ">");

        }

    }


    return sb.toString();

}

}


获取signtrue 签名


@Service("wXPayService")

public class WXPayServiceImpl implements WXPayService {

        

         @Autowired TokenDao tokenDao;

        

         @Override

         public Map<String, String> WXSignature(Map<String, String> map) {

                    //查看缓存数据是否存在

                    PageModel pm = tokenDao.searchResult(1, 10);

                    List<Token> datas = (List<Token>)pm.getDatas();

                    Token token = datas.get(0);

               //生成签名

               SortedMap<Object,Object> params = new TreeMap<Object,Object>();           

               params.put("timestamp", Long.toString(new Date().getTime()/1000));

               params.put("noncestr", this.CreateNoncestr());

               params.put("jsapi_ticket",token.getTicket());

               params.put("url",map.get("url"));//url地址

               StringBuffer sb = new StringBuffer();

               Set es = params.entrySet();

               Iterator it = es.iterator();

               while(it.hasNext()) {

                   Map.Entry entry = (Map.Entry)it.next();

                   String k = (String)entry.getKey();

                   Object v = entry.getValue();

                   sb.append(k + "=" + v + "&");

               }

               String  signStr = sb.toString().substring(0, sb.toString().length()-1);

               String sign = Sha1.getSha1Sign(signStr);//签名   

               Map<String, String> result = new HashMap<String,String>();

               result.put("timestamp",(String)params.get("timestamp"));

               result.put("noncestr", (String)params.get("noncestr"));

               result.put("signature", sign);

               result.put("appId",map.get("appid"));

               return result;

           }

        

        

          private  String CreateNoncestr() {

             String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

             String res = "";

             for (int i = 0; i < 16; i++) {

                 Random rd = new Random();

                 res += chars.charAt(rd.nextInt(chars.length() - 1));

             }

             return res;

         }

}


因为普通的access_token   7200秒过期,所以我们要每隔两个小时刷新一次,在这里我是通过定时任务去获取的,你也可以线程的方式去获取,最主要的是获取access_token。


public class UpdateAccessTokenJob {


         @Resource TokenService tokenService;

        

  //服务号

         public static final String appid = "wx798ded0c9460ae63";

         public static final String appsecret = "30bdad70aafa34b8dc7609d1c9b39691";

   

    public static Token accessToken = null;

   

         /**

          * 每两个小时更新access_token一次

          */

         public void task(){

                  accessToken = TokenUtil.getToken(appid, appsecret);

                  System.out.println("access_token:"+accessToken.getAccessToken());

        String requestUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken.getAccessToken()+"&type=jsapi";

        JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);

        if (null != jsonObject) {

            try {

                    System.out.println("ticket=================>"+jsonObject.getString("ticket"));

                    accessToken.setTicket(jsonObject.getString("ticket"));

            } catch (JSONException e) {

                    accessToken = null;

                // 获取token失败

                    System.out.println(e);

//                log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));

            }

        }

        if (null != accessToken) {

            //调用存储到数据库

                tokenService.saveOrUpdate(accessToken);

        }

         }

        

         /**

     * 发送https请求

     *

     * @param requestUrl 请求地址

     * @param requestMethod 请求方式(GET、POST)

     * @param outputStr 提交的数据

     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)

     */

    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {

        JSONObject jsonObject = null;

        try {

            // 创建SSLContext对象,并使用我们指定的信任管理器初始化

            TrustManager[] tm = { new MyX509TrustManager() };

            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");

            sslContext.init(null, tm, new java.security.SecureRandom());

            // 从上述SSLContext对象中得到SSLSocketFactory对象

            SSLSocketFactory ssf = sslContext.getSocketFactory();


            URL url = new URL(requestUrl);

            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

            conn.setSSLSocketFactory(ssf);

           

            conn.setDoOutput(true);

            conn.setDoInput(true);

            conn.setUseCaches(false);

            // 设置请求方式(GET/POST)

            conn.setRequestMethod(requestMethod);


            // 当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();

            jsonObject = JSONObject.fromObject(buffer.toString());

        } catch (ConnectException ce) {

//            log.error("连接超时:{}", ce);

        } catch (Exception e) {

//            log.error("https请求异常:{}", e);

        }

        return jsonObject;

    }

}


到这里所有的微信流程就都走完了,当时我发现微信另外一个坑爹的地方,你妈,文档上说的是支付成功后,给微信返回一个success的字符串就不会不停地给你发回调信息,
这个方法试了,并没有什么卵用,按照文档来,返回一个xml格式的响应文本,我擦,还是他妈的不行,我都醉了,只能使用迂回的方法进行了处理,有知道怎么回事的仁兄,麻烦指点一下

猜你喜欢

转载自blog.csdn.net/guojun13598079464/article/details/81165072