微信支付---服务端操作

微信支付服务端流程:

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

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

 

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

 

posted @ 2017-05-22 09:11  豆腐全家  阅读(2042)  评论(0编辑  收藏  举报