微信小程序支付java后台案例(公众号支付同适用)(及签名错误解决)

前言

1.微信小程序支付官方接口文档:[点击查看微信开放平台api开发文档]
2.遇到的坑:预支付统一下单签名结果返回[签名错误]失败,建议用官方[签名验证工具]检查签名是否存在问题.
3.遇到的坑:签名格式正确但统一下单接口依旧返回签名错误,解决方法=>去微信[商户平台]重新生成商户支付api密钥(文中提到的appKey),使用新的密钥进行调用接口。一般第一次生成的密钥是不可用的,需重新生成第二次后再试。

 

4.涉及的数据库表结构在最后面贴上

1.1 小程序支付说明

1.2 引入小程序轻量级支付jar包,里面封装了常用的接口方法(jar源码作者egan

       <dependency>
            <groupId>com.egzosn</groupId>
            <artifactId>pay-java-common</artifactId>
            <version>2.12.1</version>
        </dependency>
        <dependency>
            <groupId>com.egzosn</groupId>
            <artifactId>pay-java-wx</artifactId>
            <version>2.12.1</version>
        </dependency>

 

1.3 初始化微信支付配置存储类


private WxPayService wxUserPayService;
/**
     * 微信支付必要信息初始化
     * @param appId
     */
private void wxUserPayServiceInit(String appId) { if (wxUserPayService == null) { WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage(); wxPayConfigStorage.setMchId(mchId);//支付商户号 wxPayConfigStorage.setAppid(appId);//小程序appid // wxPayConfigStorage.setKeyPublic("转账公钥,转账时必填"); wxPayConfigStorage.setSecretKey(appKey);// 商户支付密钥 wxPayConfigStorage.setNotifyUrl(domain + "/wx/userpaycallback");//支付结果回调接口地址,必须外网可访问的完整url地址 wxPayConfigStorage.setSignType("MD5"); wxPayConfigStorage.setInputCharset("utf-8"); // https证书设置,退款必须 方式一 /*HttpConfigStorage httpConfigStorage = new HttpConfigStorage(); httpConfigStorage.setKeystorePath(keystorePath);//apiclient_cert.p12证书存放路径,填写绝对路径 httpConfigStorage.setStorePassword(mchId); httpConfigStorage.setPath(true); httpConfigStorage.setMaxTotal(20); httpConfigStorage.setDefaultMaxPerRoute(10); wxUserPayService = new WxPayService(wxPayConfigStorage, httpConfigStorage);*/ wxUserPayService = new WxPayService(wxPayConfigStorage); } }

 

1.4 付款前生成微信预支付交易单,返回正确的预支付交易参数信息,供给微信小程序前端开发者调用付款API

       String title =  "开通会员";//支付下单标题
            double total_fee = vipConfigInfoService.getInfo().getPrice();//实际支付金额
            // 测试默认都是
//            if (settingActive.equals("test")) {
//                total_fee = 0.01;
//            }
            
            // 添加支付记录信息,生成商户订单号,这里用支付记录id
            String out_trade_no = payService.representVip(type, appId, openId, userId, total_fee, title);
            
            wxUserPayServiceInit(appId);//初始化微信支付配置存储类
            PayOrder order = new PayOrder(title, type, new BigDecimal(total_fee), out_trade_no);
            order.setTransactionType(WxTransactionType.JSAPI);
            order.setOpenid(openId);
            order.setSpbillCreateIp(spbill_create_ip);//终端ip,调用微信支付API的机器IP
            order.setAddition(type);
            JSONObject result = wxUserPayService.unifiedOrder(order);//微信统一下单接口,此方法在引入的jar中,直接传入必填的信息调用即可
            System.out.println("请求微信支付统一下单结果:" + result.toString());
            String timeStamp = System.currentTimeMillis() / 1000 + "";
            JSONObject json = new JSONObject();
            json.put("nonceStr", result.getString("nonce_str"));
            json.put("package", "prepay_id=" + result.getString("prepay_id"));
            json.put("timeStamp", timeStamp);
            String stringSignTemp = "appId=" + appId + "&nonceStr=" + result.getString("nonce_str")
                    + "&package=prepay_id=" + result.getString("prepay_id") + "&signType=MD5&timeStamp="
                    + timeStamp;
            json.put("paySign", wxUserPayService.createSign(stringSignTemp, "utf-8"));

            return json;//接口方法返回预支付交易信息,小程序前端获取返回参数,调用对应的付款接口

 

1.5 支付回调(付款后微信服务器后台回调支付结果信息)

/**
     * 
     * 支付回调接口
     */
    @RequestMapping("/userpaycallback")
    public String wxUserPaycallback(HttpServletRequest request) {
        try {

            Map<String, Object> params = wxUserPayService.getParameter2Map(request.getParameterMap(),
                    request.getInputStream());
            if (null == params) {
                throw new Exception("回调参数为空");
            }
            // 校验
            if (!wxUserPayService.verify(params)) {
                throw new Exception("校验失败");
            }
            payDone(params);//支付处理
            return wxUserPayService.getPayOutMessage("SUCCESS", "成功").toMessage();

        } catch (Exception e) {
            e.printStackTrace();
            return wxUserPayService.getPayOutMessage("FALL", "失败").toMessage();
        }
    }


   /**
     * 支付结果处理
     */
    private void payDone(Map<String, Object> dataMap) throws Exception {
        System.out.println("支付回调:" + JSON.toJSONString(dataMap));
        // {"transaction_id":"4200000109201805293331420304","nonce_str":"402880e963a9764b0163a979a16e0002","bank_type":"CFT","openid":"oXI6G5Jc4D44y2wixgxE3OPwpDVg","sign":"262978D36A3093ACBE4B55707D6EA7B2","fee_type":"CNY","mch_id":"1491307962","cash_fee":"10","out_trade_no":"14913079622018052909183048768217","appid":"wxa177427bc0e60aab","total_fee":"10","trade_type":"JSAPI","result_code":"SUCCESS","time_end":"20180529091834","is_subscribe":"N","return_code":"SUCCESS"}
        String result_code = dataMap.get("result_code").toString();//支付结果code
        String out_trade_no = dataMap.get("out_trade_no").toString();//商户交易订单id,此为支付记录id

        if (!result_code.equals("SUCCESS")) {
            throw new Exception("支付回调失败:" + JSON.toJSONString(dataMap));
        }
        Pay pay = payService.getById(out_trade_no);//获取支付记录
        if (pay == null || pay.getStatus() != 10) {//10=可用/待支付 20=支付成功 30=支付失败
            throw new Exception("支付记录已经处理");
        }
        payService.pay(out_trade_no, result_code.equals("SUCCESS") ? 20 : 30);//根据回调结果更改支付结果状态
        // 升级成会员的数据处理
        if(result_code.equals("SUCCESS")) {//支付结果SUCCESS,支付成功开通会员,进行下一步操作
            Document doc=new Document();
            doc.put("vipStatus", 20);//状态20开通会员
            doc.put("vipCreateTime", new Date());
            doc.put("expireTime", StringUtil.getMonthNextOrBeforeDate(3));//设置过期时间为3个月后
            userService.updateUserVip(pay.getUserId(),doc);
        }
        
    }

 

 2.1数据库表

 支付记录表Pay

字段

名称

类型

备注

_id 唯一标识 String  
type 支付订单类型 String  
orderId 关联订单Id String  
remark 备注 String  
openId 微信用户openId String  
account 金额 double  
status 状态 int 10=可用/待支付 20=支付成功 30=支付失败
createTime 创建时间 Date  
callBackTime 回调时间 Date  
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 


 

3.1需要引用的类class

import com.egzosn.pay.common.bean.PayOrder;
import com.egzosn.pay.common.util.XML;
import com.egzosn.pay.wx.api.WxPayConfigStorage;
import com.egzosn.pay.wx.api.WxPayService;
import com.egzosn.pay.wx.bean.WxTransactionType;

 

结尾:此示例是用户开通vip的接口方法,重要的代码都有贴上。有疑问欢迎各位留言或联系邮箱laifw@foxmail.com,请多多指教

posted @ 2019-02-16 17:16  学不会丶  阅读(3450)  评论(3编辑  收藏  举报