欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-15 09:31:03
...

1. 微信官方文档

微信支付开发api文档

2. 初步流程

首先一个最简单的支付功能,大体分为三步
微信小程序微信支付功能--java代码

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

3.代码

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

<dependency>
    <groupId>com.github.javen205</groupId>
    <artifactId>IJPay</artifactId>
    <version>1.1.3</version>
</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<String, Object> 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<String, String> 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);}
            }
        }
    }