spring boot微信app支付后台java代码

不得不吐槽下微信的开发文档,实在是太烂。还是支付宝的开发文档靠谱

首先说下我踩过的坑:

1.签名错误,首先看自己的签名是否正确,可以用微信的签名校验工具检测https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1

2.微信的证书放到项目里边导致部署到服务器无法获取,放到项目外解决

3.返回app端的"package","Sign=WXPay");不能去掉,不然app无法拉起微信支付

 

首先是pom文件

        
            com.github.wxpay
            wxpay-sdk
            0.0.3
        

微信app支付的流程官网已经说的比较明确了,后台常用的就是两个接口:生成预支付订单和支付回调

contorller生成预支付订单

 @RequestMapping(value = "/pay", method = {RequestMethod.GET, RequestMethod.POST})
    public String orderPay(/*@RequestParam(required = true,value = "user_id")String user_id,
                           @RequestParam(required = true,value = "coupon_id")String coupon_id,
            @RequestParam(required = true,value = "out_trade_no")String out_trade_no,
                         @RequestParam(required = true,value = "total_fee")String total_fee,*/
                           HttpServletRequest req, HttpServletResponse response) throws Exception {
        System.err.println("进入微信支付申请");
        Date now = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");//可以方便地修改日期格式
        String hehe = dateFormat.format(now);
 
        String out_trade_no=hehe+"wxpay";  //777777 需要前端给的参数
        String total_fee="1";              //7777777  微信支付钱的单位为分
        String user_id="1";               //77777
        String coupon_id="7";               //777777
 
        String attach=user_id+","+coupon_id;
        WXMyConfigUtil config = new WXMyConfigUtil();
//        String spbill_create_ip = GetIPAddrUtil.getIpAddr(req);
        String spbill_create_ip="10.4.21.78";
        System.err.println(spbill_create_ip);
        Map result = wxPayService.dounifiedOrder(attach,out_trade_no,total_fee,spbill_create_ip,1);
        String nonce_str = (String)result.get("nonce_str");
        String prepay_id = (String)result.get("prepay_id");
        Long time =System.currentTimeMillis()/1000;
        String timestamp=time.toString();
 
        //签名生成算法
        MD5Util md5Util = new MD5Util();
        Map map = new HashMap<>();
        map.put("appid",config.getAppID());
        map.put("partnerid",config.getMchID());
        map.put("package","Sign=WXPay");
        map.put("noncestr",nonce_str);
        map.put("timestamp",timestamp);
        map.put("prepayid",prepay_id);
        String sign = md5Util.getSign(map);
 
        String resultString="{\"appid\":\""+config.getAppID()+"\",\"partnerid\":\""+config.getMchID()+"\",\"package\":\"Sign=WXPay\"," +
                "\"noncestr\":\""+nonce_str+"\",\"timestamp\":"+timestamp+"," +
                "\"prepayid\":\""+prepay_id+"\",\"sign\":\""+sign+"\"}";
        System.err.println(resultString);
 
        return resultString;    //给前端app返回此字符串,再调用前端的微信sdk引起微信支付
 
    }

service生成预支付订单

 @Override
    public Map dounifiedOrder(String attach, String out_trade_no, String total_fee,String spbill_create_ip,int type) throws Exception {
        Map fail = new HashMap<>();
        WXMyConfigUtil config = new WXMyConfigUtil();
        WXPay wxpay = new WXPay(config);
        Map data = new HashMap();
 //      data.put("appid", config.getAppID());
//        data.put("mch_id", config.getMchID());
//        data.put("nonce_str",WXPayUtil.generateNonceStr());
//        data.put("nonce_str","6128be982a7f40daa930025dedd1a90d");
        String body="订单支付";
        data.put("body", body);
        data.put("out_trade_no", out_trade_no);
        data.put("total_fee", total_fee);
        data.put("spbill_create_ip",spbill_create_ip);
        //异步通知地址(请注意必须是外网)
        data.put("notify_url", "http://1y8723.51mypc.cn:21813/api/wxpay/notify");
 
        data.put("trade_type", "APP");
        data.put("attach", attach);
//        data.put("sign", md5Util.getSign(data));
        StringBuffer url= new StringBuffer();
        try {
            Map resp = wxpay.unifiedOrder(data);
            System.out.println(resp);
            String returnCode = resp.get("return_code");    //获取返回码
            String returnMsg = resp.get("return_msg");
 
            if("SUCCESS".equals(returnCode)){       //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
                String resultCode = (String)resp.get("result_code");
                String errCodeDes = (String)resp.get("err_code_des");
                System.out.print(errCodeDes);
                if("SUCCESS".equals(resultCode)){
                    //获取预支付交易回话标志
                    Map map = new HashMap<>();
                    String prepay_id = resp.get("prepay_id");
                    String signType = "MD5";
                    map.put("prepay_id",prepay_id);
                    map.put("signType",signType);
                    String sign = md5Util.getSign(map);
                    resp.put("realsign",sign);
                    url.append("prepay_id="+prepay_id+"&signType="+signType+ "&sign="+sign);
                    return resp;
                }else {
                    logger.info("订单号:{},错误信息:{}",out_trade_no,errCodeDes);
                    url.append(errCodeDes);
                }
            }else {
                logger.info("订单号:{},错误信息:{}",out_trade_no,returnMsg);
                url.append(returnMsg);
            }
 
        } catch (Exception e) {
            System.out.println("aaaaaaaaaaaaa");
            System.out.println(e);
            logger.info(e.getMessage());
        }
        return fail;
    }

contorller支付回调

 /**
     * 订单支付异步通知
     */
    @ApiOperation(value = "手机订单支付完成后回调")
    @RequestMapping(value = "/notify",method = {RequestMethod.GET, RequestMethod.POST})
    public String WXPayBack(HttpServletRequest request,HttpServletResponse response){
        String resXml="";
        System.err.println("进入异步通知");
        try{
            //
            InputStream is = request.getInputStream();
            //将InputStream转换成String
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line = null;
            try {
                   while ((line = reader.readLine()) != null) {
                            sb.append(line + "\n");
                          }
                 } catch (IOException e) {
                      e.printStackTrace();
                   } finally {
               try {
                    is.close();
                    } catch (IOException e) {
                     e.printStackTrace();
                     }
            }
            resXml=sb.toString();
            System.err.println(resXml);
           String result = wxPayService.payBack(resXml);
//            return " ";
            return result;
        }catch (Exception e){
            logger.error("手机支付回调通知失败",e);
            String result = "" + "" + "" + " ";
            return result;
        }
    }

service支付回调

 /**
     *  支付结果通知
     * @param notifyData    异步通知后的XML数据
     * @return
     */
    @Override
    public String payBack(String notifyData) {
        WXMyConfigUtil config = null;
        try {
            config = new WXMyConfigUtil();
        } catch (Exception e) {
            e.printStackTrace();
        }
        WXPay wxpay = new WXPay(config);
        String xmlBack="";
        Map notifyMap = null;
        try {
            notifyMap = WXPayUtil.xmlToMap(notifyData);         // 转换成map
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
                // 签名正确
                // 进行处理。
                // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
                String  return_code = notifyMap.get("return_code");//状态
                String out_trade_no = notifyMap.get("out_trade_no");//订单号
 
                if(return_code.equals("SUCCESS")){
                    if(out_trade_no!=null){
                        //处理订单逻辑
                        /**
                         *          更新数据库中支付状态。
                         *          特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功。
                         *          此处需要判断一下。后面写入库操作的时候再写
                         *
                         */
                      
                        System.err.println(">>>>>支付成功");
 
                        logger.info("微信手机支付回调成功订单号:{}",out_trade_no);
                        xmlBack = "" + "" + "" + " ";
                    }else {
                        logger.info("微信手机支付回调失败订单号:{}",out_trade_no);
                        xmlBack = "" + "" + "" + " ";
                    }
 
                }
                return xmlBack;
            }
            else {
                // 签名错误,如果数据里没有sign字段,也认为是签名错误
                logger.error("手机支付回调通知签名错误");
                xmlBack = "" + "" + "" + " ";
                return xmlBack;
            }
        } catch (Exception e) {
            logger.error("手机支付回调通知失败",e);
            xmlBack = "" + "" + "" + " ";
        }
        return xmlBack;
    }

签名算法工具类

package com.hrhs.wxpay;
 
import com.github.wxpay.sdk.WXPayConstants;
 
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
 
public class MD5Util {
 
    public static String getSign(Map data) throws Exception {
        WXMyConfigUtil config = new WXMyConfigUtil();
        Set keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals(WXPayConstants.FIELD_SIGN)) {
                continue;
            }
            if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(config.getKey());
        /*MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        byte[] array = new byte[0];
        try {
            array = md.digest(sb.toString().getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        StringBuilder sb2 = new StringBuilder();
        for (byte item : array) {
            sb2.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb2.toString().toUpperCase();*/
        String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); 
        return sign;
    }
    public static String createSign(String characterEncoding, SortedMap packageParams) throws Exception {  
    	 WXMyConfigUtil config = new WXMyConfigUtil();
    	StringBuffer sb = new StringBuffer();  
        Set es = packageParams.entrySet();  
        Iterator it = es.iterator();  
        while (it.hasNext()) {  
            Map.Entry entry = (Map.Entry) it.next();  
            String k = (String) entry.getKey();  
            String v = (String) entry.getValue();  
//            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k) && !"notify_url".equals(k)&& !"out_trade_no".equals(k)&& !"spbill_create_ip".equals(k)&& !"total_fee".equals(k)&& !"trade_type".equals(k)) { 
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k) ) {  
                sb.append(k + "=" + v + "&");  
            }  
        }  
        sb.append("key=" + config.getKey());  
//        String stringA="appid=wxc7b425229b570867&mch_id=1406330002&nonce_str=1702585759&key=ab42e0b7aa6bce35164a2d14855d7264";
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
//        String sign = MD5Util.MD5Encode(stringA, characterEncoding).toUpperCase();
//        System.out.println(sign);
//        System.out.println(MD5Util.MD5Encode("appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA&key=192006250b4c09247ec02edce69f6a2d", characterEncoding).toUpperCase());
//        System.out.println(sign);
        return sign;  
    }  
    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }
    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }
    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}

微信的各种配置,一定不要写错

package com.kyd.callcenter.util.weixin;
 
import com.github.wxpay.sdk.WXPayConfig;
 
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
 
public class WXMyConfigUtil implements WXPayConfig {
    private byte[] certData;
 
    public WXMyConfigUtil() throws Exception {
        String certPath = "证书地址";//从微信商户平台下载的安全证书存放的目录
 
        File file = new File(certPath);
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }
 
    @Override
    public String getAppID() {
        return "填写你的appid";
    }
 
    //parnerid
    @Override
    public String getMchID() {
        return "填写商户id";
    }
 
    @Override
    public String getKey() {
        return "填写api密钥";
    }
 
    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }
 
    @Override
    public int getHttpConnectTimeoutMs() {
        return 8000;
    }
 
    @Override
    public int getHttpReadTimeoutMs() {
        return 10000;
    }
}

 

你可能感兴趣的:(spring boot微信app支付后台java代码)