zoukankan      html  css  js  c++  java
  • 微信支付---服务端操作

    微信支付服务端流程:

    首先客户端调起服务端接口来进行微信的统一下单(微信统一下单要进行两次签名验证),通过验证后返回处理结果,得到成功状态码后通知客户端,并返回相应的信息。

    然后客户端发起支付,调用微信服务端。支付成功后,微信调用服务端的回调函数通知服务端支付结果,然后服务端进行一些后续处理操作。

    1--------- 微信支付统一下单及验证签名

      /**
         * 微信支付统一下单及验证签名
         * 
         * @param request
         *            请求信息
         * @return 处理结果JSON信息
         * @throws*/
        @RequestMapping(value = "/wxPayinfo", method = RequestMethod.GET)
        @ResponseBody
        public ResultTO wxPayinfo(String orderId,String memberId,HttpServletRequest request,
                HttpServletResponse response) {
            // 下单详细
            Map<String, Object> back = null;
    
            // 未输入订单ID
            if (orderId==null || orderId.isEmpty() || "".equals(orderId)) {
                // 返回未输入订单ID错误信息
                return ResultTO.newFailResultTO("参数orderId不能为空", null);
            }
    
            // 未输入用户ID
            if (memberId==null || memberId.isEmpty() || "".equals(memberId)) {
                // 返回未输入用户ID错误信息
                return ResultTO.newFailResultTO("参数memberId不能为空", null);
            }
    
            try {
                // 提交前订单信息
                Map<String,Object> map = new HashMap<String,Object>();
                map.put("orderId", orderId);
                Order oldOrder = OrderService.selectObject(map);
                
    
                if (oldOrder != null) {
                    Double amount = oldOrder.getOrderAmount().doubleValue();
                    TenPayManager tenPayManager = new TenPayManager();
             //一次签名验证 back
    = tenPayManager.weixinPay(oldOrder.getOrderSn().toString(), amount, request, response); } if(back.get("return_code").toString().equals("FAIL")){ String msg = back.get("return_msg").toString(); // 返回登录信息错误信息 return ResultTO.newFailResultTO(msg, null); } else { logger.info("++++++++++++++++++++++++++++++++++ back: "+back); //二次签名验证 TenPayManager tenPayManager = new TenPayManager(); Map<String, Object> back2 = tenPayManager.weixinSignSecond(back); logger.info("++++++++++++++++++++++++++++++++++ back2: "+back2); // 返回处理成功信息 return ResultTO.newSuccessResultTO("微信验证成功", back2); } } catch (Exception e) { // 保存错误LOG logger.error(e.getLocalizedMessage()); // 返回登录信息错误信息 return ResultTO.newFailResultTO("微信验证失败", null); } }

    2------微信工具类

    package com.util.pay.tenpay;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Random;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.jboss.logging.Logger;
    
    import com.util.AmountUtils;
    import com.util.DateUtil;
    import com.util.pay.tenpay.util.HttpPost;
    import com.util.pay.tenpay.util.MD5Weixin;
    import com.util.pay.tenpay.util.XmlParser;
    
    public class TenPayManager {
        /**
         * 发单超过系统次数支付接口
         * 
         * @param orderId
         * @param request
         * @param response
         * @return
         */
        public Map<String, Object> weixinPay(String orderSn, double amount,
                HttpServletRequest request, HttpServletResponse response) {
         //服务器IP
            String serverIP = "127.0.0.1";
    //        if(request != null){
    //            serverIP = request.getRemoteAddr();
    //        }
            String nonce_str = createNonceStr();
            String body = "订单:" + orderSn;
         //注意:微信中金额单位为分,传参值要转化为分    
            String oAmount = moneyToFen(amount);
            //要删--用于测试 start
            //oAmount = "1";
            // end
            //签名验证,拼接字符串
            String stringA = "appid=" + Constant.appID + "&body=" + body
                    + "&mch_id=" + Constant.mchID + "&nonce_str=" + nonce_str
                    + "&notify_url=" + Constant.wxNoticeUrl + "&out_trade_no="
                    + orderSn + "&spbill_create_ip=" + serverIP + "&total_fee="
                    + oAmount + "&trade_type=" + Constant.wxTradeType;
         //拼接key String stringSignTemp
    = stringA + "&key=" + Constant.key; System.out.println(stringA); System.out.println(stringSignTemp); // 签名最后全部转为大写 String sign = MD5Weixin.MD5Encode(stringSignTemp).toUpperCase(); System.out.println(sign); // 拼接xml StringBuffer xml = new StringBuffer(); xml.append("<xml>"); xml.append("<appid>").append(Constant.appID).append("</appid>"); xml.append("<body>").append(body).append("</body>"); xml.append("<mch_id>").append(Constant.mchID).append("</mch_id>"); xml.append("<nonce_str>").append(nonce_str).append("</nonce_str>"); xml.append("<notify_url>").append(Constant.wxNoticeUrl) .append("</notify_url>"); xml.append("<out_trade_no>").append(orderSn).append("</out_trade_no>"); xml.append("<spbill_create_ip>").append(serverIP) .append("</spbill_create_ip>"); xml.append("<total_fee>").append(oAmount).append("</total_fee>"); xml.append("<trade_type>").append(Constant.wxTradeType) .append("</trade_type>"); xml.append("<sign><![CDATA[").append(sign).append("]]></sign>"); xml.append("</xml>"); // System.out.println( "----------微信下单-----下单参数----------:" + // xml.toString() ); Map<String, Object> resultMap = new HashMap<String, Object>(); String retXmlStr = null; retXmlStr = HttpPost.sendPostWithXmlPara(Constant.pay_address, new String(xml.toString())); if (null != retXmlStr) { resultMap = XmlParser.xmlStrParser(retXmlStr); resultMap.put("timestamp", DateUtil.intDate()); resultMap.put("pack", "Sign=WXPay"); } return resultMap; } public static String createNonceStr() { String letter[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "S", "Y", "Z" }; String nonce_str = ""; for (int i = 0; i < 26; i++) { int num = new Random().nextInt(26); nonce_str += letter[num]; } return nonce_str; } /** * 将金额转换成分 * * @param amount * 金额 * @return String 分为单位的金额 */ public static String moneyToFen(double amount) { // 分为单位的金额 String toFenTemp = String.valueOf(amount); // 临时保存用金额 String toFen = AmountUtils.changeY2F(toFenTemp); // 返回分为单位的金额 return toFen; } /** * 微信二次签名 * * @return */ public Map<String, Object> weixinSignSecond(Map<String,Object> back) { String stringA = "appid=" + Constant.appID + "&noncestr=" + back.get("nonce_str") + "&package=Sign=WXPay" + "&partnerid=" + Constant.mchID + "&prepayid=" + back.get("prepay_id") + "&timestamp=" + DateUtil.intDate(); System.out.println(stringA); String stringSignTemp = stringA + "&key=" + Constant.key; System.out.println(stringSignTemp); // 签名最后全部转为大写 String sign = MD5Weixin.MD5Encode(stringSignTemp).toUpperCase(); System.out.println(sign); Map<String, Object> resultMap = new HashMap<String, Object>(); resultMap.put("appid", Constant.appID); resultMap.put("partnerid", Constant.mchID); resultMap.put("prepayid", back.get("prepay_id")); resultMap.put("pack", "Sign=WXPay"); resultMap.put("noncestr", back.get("nonce_str")); resultMap.put("timestamp", DateUtil.intDate()); resultMap.put("sign", sign); return resultMap; } }

    3------配置类

    package com.util.pay.tenpay;
    
    public class Constant {
        
        public static final String key = "";// 签名算法需要用到的秘钥
        public static final String appID = "";// 开放平台AppID
        public static final String mchID = "100011111";// 商户号
        public static final String pwd = "111111";// 
    //    public static final String wxBody = "微信test";//
        public static final String pay_address = "https://api.mch.weixin.qq.com/pay/unifiedorder";// 统一支付API接口地址
        public static final String check_url = "https://api.mch.weixin.qq.com/pay/orderquery";// 查询订单API接口地址
        public static final String close_url = "https://api.mch.weixin.qq.com/pay/closeorder";// 关闭订单API接口地址
        
        public static final String refund_url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; //退款
        //测试用地址
    //  public static String wxNoticeUrl = "http://xxx.xxx.xxx.xx:8080/api/wxPayReturn/wxPayNotifyReturn";
        public static String wxNoticeUrl = "http://xxx.xxx.xxx.xx:8080/api/wxPayReturn/wxPayNotifyReturn"; 
      
       public static final String wxTradeType = "APP";// 取值如下:JSAPI,NATIVE,APP }

    4-----回调函数

    package com.controller.api.;
    
    import java.io.BufferedOutputStream;
    import java.io.StringReader;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.log4j.Logger;
    import org.jdom.Document;
    import org.jdom.Element;
    import org.jdom.input.SAXBuilder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.util.StringUtils;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.xml.sax.InputSource;
    
    import com.controller.AbstractAPIController;
    import com.po.Order;
    import com.po.Store;
    import com.service.OrderService;
    import com.service.StoreService;
    import com.to.ResultTO;
    import com.util.RequestParamUtil;
    import com.util.pay.tenpay.TenPayManager;
    import com.util.pay.tenpay.bean.WxPayResult;
    
    /**
     * FileName AppCourseController.java
     * 
     * Version 1.0
     * 
     * Create by zy 2016/3/20
     * 
     * APP课程业务控制器
     */
    @Controller
    @RequestMapping("/api/wxPayReturn")
    public class WxPayReturnController extends AbstractAPIController {
    
        /** 日志文件生成器 */
        private static Logger log = Logger.getLogger(WxPayReturnController.class);
        
        @Autowired
        private OrderService OrderService;
        
        @Autowired
        private StoreService StoreService;
    
        /**
         * 微信支付回调接口
         * 
         * @author zy
         * @since Version 1.0
         * @param request
         *            请求信息
         * @return 处理结果JSON信息
         * @throws*/
        @RequestMapping(value = "/wxPayNotifyReturn")
        @ResponseBody
        public ResultTO wxPayNotifyReturn(HttpServletRequest request,
                HttpServletResponse response) {
            log.info("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-------进入微信回调函数wxPayNotifyReturn!");
            try {
                // 把如下代码贴到的你的处理回调的servlet 或者.do 中即可明白回调操作
                String inputLine;
                String notityXml = "";
                String resXml = "";
    
                try {
                    while ((inputLine = request.getReader().readLine()) != null) {
                        notityXml += inputLine;
                    }
                    request.getReader().close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                System.out.println("接收到的报文:" + notityXml);
    
                Map<String,String> m = parseXmlToList2(notityXml);
                WxPayResult wpr = new WxPayResult();
                wpr.setAppid(m.get("appid").toString());
                wpr.setBankType(m.get("bank_type").toString());
                wpr.setCashFee(m.get("cash_fee").toString());
                wpr.setFeeType(m.get("fee_type").toString());
                wpr.setIsSubscribe(m.get("is_subscribe").toString());
                wpr.setMchId(m.get("mch_id").toString());
                wpr.setNonceStr(m.get("nonce_str").toString());
                wpr.setOpenid(m.get("openid").toString());
                wpr.setOutTradeNo(m.get("out_trade_no").toString());
                wpr.setResultCode(m.get("result_code").toString());
                wpr.setReturnCode(m.get("return_code").toString());
                wpr.setSign(m.get("sign").toString());
                wpr.setTimeEnd(m.get("time_end").toString());
                wpr.setTotalFee(m.get("total_fee").toString());
                wpr.setTradeType(m.get("trade_type").toString());
                wpr.setTransactionId(m.get("transaction_id").toString());
    
                boolean payFlag = false;
                
                log.info("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-------wpr.getReturnCode():"+wpr.getReturnCode());
                
                if ("SUCCESS".equals(wpr.getReturnCode())) {
                    // 支付成功
                    resXml = "<xml>"
                            + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
    
                    payFlag = true;
                } else {
                    resXml = "<xml>"
                            + "<return_code><![CDATA[FAIL]]></return_code>"
                            + "<return_msg><![CDATA[报文为空]]></return_msg>"
                            + "</xml> ";
                }
    
                // 支付成功
                if (payFlag) {
                    log.info("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA----------------payFlag:"+payFlag);
                    //支付成功后,商户操作处理
                }
    
                BufferedOutputStream out = new BufferedOutputStream(
                        response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
            } catch (Exception e) {
                // 保存错误LOG
                log.error(e.getLocalizedMessage());
                // 返回登录信息错误信息
                return ResultTO.newFailResultTO("支付失败!", null);
            }
            // 返回处理成功信息以及课程列表
            return ResultTO.newSuccessResultTO("支付成功", null);
        }
    
        /**
         * description: 解析微信通知xml
         * 
         * @param xml
         * @return
         * @author ex_yangxiaoyi
         * @see
         */
        private static Map<String,String> parseXmlToList2(String xml) {
            Map<String,String> retMap = new HashMap<String,String>();
            try {
                StringReader read = new StringReader(xml);
                // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
                InputSource source = new InputSource(read);
                // 创建一个新的SAXBuilder
                SAXBuilder sb = new SAXBuilder();
                // 通过输入源构造一个Document
                Document doc = (Document) sb.build(source);
                Element root = doc.getRootElement();// 指向根节点
                List<Element> es = root.getChildren();
                if (es != null && es.size() != 0) {
                    for (Element element : es) {
                        retMap.put(element.getName(), element.getValue());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return retMap;
        }
    

     5、AmountUtils

    /**
         * 将元为单位的转换为分 替换小数点,支持以逗号区分的金额
         * 
         * @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();
        }
  • 相关阅读:
    ASP.NET 使用 X509Certificate2 系统找不到指定的文件
    SQL2000中TOP后不能使用变量
    补丁生成与应用工具 V1.5.4
    检测到通信错误。正在使用的通信协议:"TCP/IP"。正在使用的通信API:"SOCKETS"。检测到错误的位置:""。检测到错误的通信函数:"gethostbyname"。协议特定的错误代码:"*"、"11004"、"*"。 SQLST
    CLR 无法从 COM 上下文 0x1a2740 转换为 COM 上下文 0x1a28b0,这种状态已持续 60 秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作
    Chart 控件 for vs2008的安装
    SqlServer孤立用户解决——"因为该用户存在对象,所以不能删除该用户。"
    函数 replace 的参数 1 的数据类型 text 无效。
    安装SqlServer2000出现"有挂起的操作"提示的解决
    DB2、ORACLE SQL写法的主要区别
  • 原文地址:https://www.cnblogs.com/doufuquanjia/p/5955793.html
Copyright © 2011-2022 走看看