java--spring boot微信支付服务端实现含代码(app支付、扫码支付等)

来源:互联网 发布:信广立诚贷之家数据 编辑:程序博客网 时间:2024/05/17 04:54

最近在弄支付宝、微信支付等的事,发现这两家的文档都写得很差,demo也让人看的云里雾里。所以写篇博客,来尽量减少后来的同学走的弯路。

首先,若是要做app支付的话,在微信第三方平台申请APP,若是安卓的话上传你的keystore和包名,ios上传bundle id,微信会生成相应的签名。

然后前往微信商户平台,拿到要做支付必要的各种id和密钥。

请看以下配置代码:

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

要想调用微信sdk的话,请记得在你项目中的pom文件中加入以下:

        <dependency>            <groupId>com.github.wxpay</groupId>            <artifactId>wxpay-sdk</artifactId>            <version>0.0.3</version>        </dependency>
先说app支付,前端访问服务器端,服务器端返回生成签名后的订单信息。

如何生成订单信息呢?以下是代码:

controller:

 @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<String,String> 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<String,String> 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中的方法,若是扫码支付的话只要把trade_type改成NATIVE即可,具体以微信官方文档为准:

 @Override    public Map<String, String> dounifiedOrder(String attach, String out_trade_no, String total_fee,String spbill_create_ip,int type) throws Exception {        Map<String, String> fail = new HashMap<>();        WXMyConfigUtil config = new WXMyConfigUtil();        WXPay wxpay = new WXPay(config);        Map<String, String> data = new HashMap<String, String>(); //      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<String, String> 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<String,String> 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;    }

若是支付成功,微信会给你的服务器发送异步通知。所以如何处理此通知也告诉大家:

controller:

 /**     * 订单支付异步通知     */    @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 "<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>";            return result;        }catch (Exception e){            logger.error("手机支付回调通知失败",e);            String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";            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<String, String> 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 = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";                    }else {                        logger.info("微信手机支付回调失败订单号:{}",out_trade_no);                        xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";                    }                }                return xmlBack;            }            else {                // 签名错误,如果数据里没有sign字段,也认为是签名错误                logger.error("手机支付回调通知签名错误");                xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";                return xmlBack;            }        } catch (Exception e) {            logger.error("手机支付回调通知失败",e);            xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";        }        return xmlBack;    }
要给微信服务器返回处理成功的xml格式的字符串,我在代码中已经写得很清楚了。

我相信以上代码不难看懂,如果有问题的同学评论问我我再做补充。

顺便把用到的工具类一起给大家:

MD5生成签名算法:

package com.kyd.callcenter.util.weixin;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.Map;import java.util.Set;public class MD5Util {    public String getSign(Map<String, String> data) throws Exception {        WXMyConfigUtil config = new WXMyConfigUtil();        Set<String> 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();    }}






阅读全文
1 0
原创粉丝点击