微信小程序微信支付功能--java代码

1. 微信官方文档

微信支付开发api文档

2. 初步流程

首先一个最简单的支付功能,大体分为三步
这里写图片描述

  1. 预支付,后台系统跟微信后台交互,给小程序返回参数 统一下单
  2. 小程序拿到参数进行预支付
  3. 用户确认支付,//跟微信后台交互,这一步我们不需要管
  4. 微信后台回调我们的后台系统的接口, 处理我们自己的业务逻辑 回调处理支付结果

3.代码

这里用到了github上的一个依赖,相当于支付的工具包

<dependency>
    <groupId>com.github.javen205groupId>
    <artifactId>IJPayartifactId>
    <version>1.1.3version>
dependency>

这边从前端小程序传过来的参数有:
orderId – 我们系统这边的订单id
openId – 小程序传过来的用户标识
我们配置文件中配置的固定参数有:
appid – 小程序id
mchId – 商户号
notify_url – 支付成功以后回调的我们写的接口地址
partnerKey – 商户平台设置的密钥key

封装返回结果的vo对象AjaxJson

/**
 * $.ajax后需要接受的JSON
 * 
 * @author
 * 
 */
public class AjaxJson implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private boolean success = true;// 是否成功

    private String msg = "操作成功";// 提示信息

    private Object obj = null;// 其他信息

    private ConcurrentMap attributes;// 其他参数

    private String errorCode;// 错误码

    private Integer totalSize;// 错误码

    getter...setter方法

}

控制层

  1. 统一下单
/**
* 小程序微信支付的第一步,统一下单
* @return
 * @author zgd
 * @time 2018年7月9日17:53:35
 */
 @RequestMapping("/createUnifiedOrder")
 @ResponseBody
 public AjaxJson createUnifiedOrder(HttpServletRequest request) {
    AjaxJson aj = new AjaxJson();
    aj.setSuccess(false);
    String orderId = request.getParameter("orderId");
    //接受参数(openid)
    String openid = request.getParameter("openid");
    if (StringUtils.isAnyBlank(orderId,openid)){
        aj.setMsg("支付失败,支付所需参数缺失");
        return aj;
     }
     //这里调用service层根据订单id获取订单数据,这里省略不表
    Map<String, String> mapBasic = getOrderInfoById(orderId);
    if (mapBasic == null) {
        aj.setMsg("支付失败,暂时无法获取到您的订单数据,请稍后再试");
        return aj;
     }
     String return_msg = "统一订单失败";
try {

            //支付金额 **金额不能有小数点,单位是分!!**
            BigDecimal price = new BigDecimal(mapBasic.get("payAmount").toString());
            BigDecimal beishu = new BigDecimal("100");
            BigDecimal priceFee=price.multiply(beishu);
            //商家订单号
            String orderNo = mapBasic.get("orderNo").toString();

            //创建 时间戳
            String timeStamp = Long.valueOf(System.currentTimeMillis()).toString();
            //生成32位随机数
            UUID uuid = UUID.randomUUID();
            String nonceStr = uuid.toString().replaceAll("-","");
            //商品描述
            String body = "XX商城-支付订单";
            //创建hashmap(用户获得签名)
            SortedMap<String, String> paraMap = new TreeMap<String, String>();
            //设置请求参数(小程序ID)
            paraMap.put("appid", appid);
            //设置请求参数(商户号)
            paraMap.put("mch_id", mchId);
            //设置请求参数(随机字符串)
            paraMap.put("nonce_str", nonceStr);
            //设置请求参数(商品描述)
            paraMap.put("body", body);
            //设置请求参数(商户订单号)
            paraMap.put("out_trade_no", orderNo);
            //设置请求参数(总金额)
            paraMap.put("total_fee", priceFee.toBigInteger().toString());
            //设置请求参数(终端IP) 如果是springmvc,或者能获取到request的servlet,用下面这种
            paraMap.put("spbill_create_ip", request.getRemoteAddr());
            //设置请求参数(通知地址)
            paraMap.put("notify_url",notify_url);
            //设置请求参数(交易类型)
            paraMap.put("trade_type", String.valueOf(WxPayApi.TradeType.JSAPI));
            //设置请求参数(openid)(在接口文档中 该参数 是否必填项 但是一定要注意 如果交易类型设置成'JSAPI'则必须传入openid)
            paraMap.put("openid", openid);
            //MD5运算生成签名,这里是第一次签名,用于调用统一下单接口
            String sign = PaymentKit.createSign(paraMap, partnerKey);
            paraMap.put("sign", sign);
            //统一下单,向微信api发送数据
            logger.info("微信小程序统一下单发送的数据: "+paraMap.toString());
            String xmlResult = WxPayApi.pushOrder(false, paraMap);
            logger.info("微信小程序统一下单接受返回的结果: "+xmlResult);
            //转成xml
            Map<String, String> map = PaymentKit.xmlToMap(xmlResult);
            //返回状态码
            String return_code = (String) map.get("return_code");
            return_msg = return_msg+", "+ (String) map.get("return_msg");
            //返回给小程序端需要的参数
            Map<String, String> returnMap = new HashMap<String, String>();
            if(Constants.SUCCESS.equals(return_code)){
                //返回的预付单信息
                returnMap.put("appId",appid);
                returnMap.put("nonceStr", nonceStr);
                String prepay_id = (String) map.get("prepay_id");
                returnMap.put("package", "prepay_id=" + prepay_id);
                returnMap.put("signType","MD5");
                //这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误
                returnMap.put("timeStamp", timeStamp);
                //拼接签名需要的参数
                //再次签名,这个签名用于小程序端调用wx.requesetPayment方法
                String paySign = PaymentKit.createSign(returnMap, partnerKey).toUpperCase();
                returnMap.put("paySign", paySign);
                aj.setObj(returnMap);
                aj.setMsg("操作成功");
                aj.setSuccess(true);
                return aj;
            }else{
                aj.setMsg(getMsgByCode(return_code));
                logger.error(Thread.currentThread().getStackTrace()[1].getMethodName()+">>>"+return_msg);
            }
        } catch (Exception e) {
            logger.error(Thread.currentThread().getStackTrace()[1].getMethodName() +"发生的异常是: ",e);
            aj.setMsg("微信支付下单失败,请稍后再试");
        }
        return aj;
    }

getMsgByCode

 /**
     * 判断返回的return_code,给前端相应的提示
     * @param return_code
     * @return
     * @author zgd
     * @time 2018年7月9日17:53:13
     */
    private String getMsgByCode(String return_code) {
        switch (return_code){
            case "NOTENOUGH":return "您的账户余额不足";
            case "ORDERPAID":return "该订单已支付完成,请勿重复支付";
            case "ORDERCLOSED":return "当前订单已关闭,请重新下单";
            case "SYSTEMERROR":return "系统超时,请重新支付";
            case "OUT_TRADE_NO_USED":return "请勿重复提交该订单";
            default:return  "网络正在开小差,请稍后再试";
        }
    }

2.回调

比如上面配置的notify_url是http://系统的ip和端口/wxPay/notify

@RequestMapping("/wxPay")
public class WxPayController{

    private String paternerKey = "XXXXXX";

    @RequestMapping("/notify")
    public void notify(HttpServletRequest request){
        //获取所有的参数
        StringBuffer sbf=new StringBuffer();

        // 支付结果通用通知文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
        String xmlMsg = HttpKit.readData(request);
        System.out.println("支付通知="+xmlMsg);
        Map params = PaymentKit.xmlToMap(xmlMsg);
        String result_code  = params.get("result_code");

        //校验返回来的支付结果,根据已经配置的密钥
        if(PaymentKit.verifyNotify(params, paternerKey)){
            //Constants.SUCCESS="SUCCESS"
             if ((Constants.SUCCESS).equals(result_code)) {
                 校验通过. 更改订单状态为已支付, 修改库存
             }
        }
    }

}

拼接参数为字符串的工具方法

public static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder ret;
            br = request.getReader();

            String line = br.readLine();
            if (line != null) {
                ret = new StringBuilder();
                ret.append(line);
            } else {
                return "";
            }

            while ((line = br.readLine()) != null) {
                ret.append('\n').append(line);
            }

            return ret.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            if (br != null) {
                try {br.close();} catch (IOException e) {LogKit.error(e.getMessage(), e);}
            }
        }
    }

你可能感兴趣的:(支付)