支付宝,微信支付问题

1. 新版的支付宝支付简化了代码,省去了自己去签名配置参数,拼接参数的烦恼,简单明了。

    public static String buildAlipayRequest(AlipayVo alipayVo) {
        String alipayInfo = null;
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(ALIPAY_URL, alipayVo.getAppId(), alipayVo.getAppPrivateKey(),
                FORMAT, CHARSET_UTF8, alipayVo.getAlipayPublicKey(), SIGN_TYPE);
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody("AlipayTrade");
        model.setSubject(alipayVo.getSubject());
        model.setOutTradeNo(alipayVo.getOutTradeNo());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(alipayVo.getTotalAmount());
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(alipayVo.getNotifyUrl());
        try {
            //这里和普通的接口调用不同,使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            log.info(response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理。
            alipayInfo = response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return alipayInfo;
    }

2. 因为项目使用到了过滤器,导致签名的sign数据中“+”被替换成了“ ”,无法获取原本的sign

java.security.SignatureException: Signature length not correct: got 253 but was expecting 256

    简单处理,就是替换,将空格替换成加号

sign = sign.replace(" ", "+");

3.  相对于支付宝文档,微信的开发比较繁琐,很多都需要自己开发实现。微信工具类,仅供参考。

public class WxpayUtil {

    private static final Logger log = LoggerFactory.getLogger(WxpayUtil.class);
    private static final String GATEURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";


    /**
     * 获取微信预支付prepayid
     * @param weixinpayVo
     * @return
     */
    public static JSONObject buildWxpayRequest(WeixinpayVo weixinpayVo){

        String noncestr = getNonceStr();

        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("appid", weixinpayVo.getAppid());// 分车企--微信分配的公众账号ID(企业号corpid即为此appId)
        parameters.put("mch_id", weixinpayVo.getMchid());// 分车企--微信商户号
        parameters.put("nonce_str", noncestr);// 随机字符串
        parameters.put("body", weixinpayVo.getSubject());// 支付内容
        parameters.put("out_trade_no", weixinpayVo.getOutTradeNo());// 商户订单号
        parameters.put("total_fee", change2Fen(weixinpayVo.getTotalAmount()));// 支付金额,单位为分
        parameters.put("spbill_create_ip", weixinpayVo.getSpbillCreateIp());// 终端IP
        parameters.put("notify_url", weixinpayVo.getNotifyUrl());// 异步请求地址
        parameters.put("trade_type", "APP");// 交易类型App支付
        String sign = creatingSign(weixinpayVo.getPartnerKey(), parameters);//分车企--
        parameters.put("sign", sign);

        // 调用统一接口返回的值转换为XML格式
        log.info("微信支付请求参数:"+parameters.toString());
        String xmlString = sendPost(GATEURL, parameters);
        Map<String, String> map = doXMLParse(xmlString);
        log.info("微信支付请求参数:"+(map==null?null:map.toString()));
        String prepayid = map.get("prepay_id");// 获取prepayId

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("prepayid", prepayid);
        jsonObject.put("noncestr", noncestr);
        return jsonObject;
    }

    /**
     * POST请求,Map形式数据
     * @param url 请求地址
     * @param param 请求数据
     * @param charset 编码方式
     */
    public static String sendPost(String url, Map<Object, Object> param) {

        StringBuffer buffer = new StringBuffer();
        buffer.append("<xml>");
        if (param != null && !param.isEmpty()) {
            for (Map.Entry<Object, Object> entry : param.entrySet()) {
                if(entry.getKey().equals("attach") || entry.getKey().equals("body") || entry.getKey().equals("sign")){
                    buffer.append("<"+entry.getKey()+">");
                    buffer.append("<![CDATA["+entry.getValue()+"]]>");
                    buffer.append("</"+entry.getKey()+">");
                }else{
                    buffer.append("<"+entry.getKey()+">");
                    buffer.append(entry.getValue());
                    buffer.append("</"+entry.getKey()+">");
                }
            }
        }
        buffer.append("</xml>");
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(buffer);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 生成签名
     * @param PartnerKey
     * @param characterEncoding
     * @param parameters
     * @return https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
     */
    public static String creatingSign(String PartnerKey, SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        Iterator it = parameters.entrySet().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=" + PartnerKey);
        return  MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
    }
    /**
     * 金额元-> 分
     * @param money
     * @return
     */
    public static int change2Fen(String money){
        if(null==money){
            return 0;
        }
        return new BigDecimal(money).multiply(new BigDecimal(100)).intValue();
    }

    /**
     * <P>(将分为单位的转换为元 (除100) )</P>
     */
    /**金额为分的格式 */
    public static final String CURRENCY_FEN_REGEX = "\-?[0-9]+";
    public static String change2Yuan(String amount) throws Exception{
        return String.valueOf(new BigDecimal(amount).divide(new BigDecimal(100)));
    }

    /**
     * <P>(32位内的随机串,防重发)</P>
     */
    public static String getNonceStr() {
        Random random = new Random();
        return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8");
    }

    /**
     * 获取时间戳
     * @return
     */
    public static String getTimeStamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    /**
     * 获取ip地址
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 解析String类型的xml流对象InputStream
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static Map<String,String> doXMLParse(String strxml){
        if(null == strxml || "".equals(strxml)) {
            return null;
        }

        Map<String,String> map = new HashMap<String,String>();
        InputStream in =null;
       try{
           in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
           SAXBuilder builder = new SAXBuilder();
           builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
           builder.setFeature("http://xml.org/sax/features/external-general-entities", false);
           builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
           builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
           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);
               }
               map.put(k, v);
           }
       }catch (Exception e){
            e.printStackTrace();
       }finally {
            if(in!=null){
                //关闭流
                IOUtils.closeQuietly(in);
            }
       }
       return map;
    }

    /**
     * 获取子结点的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();
    }


    public static String setResultXML(String return_code, String return_msg) {
        return "<xml><return_code><![CDATA[" + return_code
                + "]]></return_code><return_msg><![CDATA[" + return_msg
                + "]]></return_msg></xml>";
    }
}
View Code

4. 微信支付的过程,统一下单获取prepayid,然后组装请求参数返回手机端发起支付。

  • 需要注意的是,noncestr随机字符串参数在两次请求中是一样的
  • 微信签名参数partnerkey, key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
  • 微信的金额是以为单位的
原文地址:https://www.cnblogs.com/yangjiming/p/11410282.html