一、支付宝支付:主要参考支付宝开放平台
1、创建应用:在支付宝开放平台( open.alipay.com)创建应用,获取appId
2、配置应用:主要是公钥和私钥,可在支付宝开放平台助手配置
3、集成并配置sdk

<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.9.71.ALL</version>
</dependency>

4、配置类

public class AlipayConfig {
    // 商户appid
    public static String APP_ID = "APP_ID";
    // 私钥 pkcs8格式的         有支付宝提供工具==支付宝开放平台开发助手==生成
    public static String APP_PRIVATE_KEY = "APP_PRIVATE_KEY ";
    // 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问,后端处理
    public static String notify_url = "notify_url ";
    // 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
// public static String return_url = "";
    // 请求网关地址
    public static String GATEWAY = "https://openapi.alipay.com/gateway.do";
    // 编码
    public static String CHARSET = "UTF-8";
    // 返回格式
    public static String FORMAT = "json";
    // 支付宝公钥
    public static String ALIPAY_PUBLIC_KEY =  "ALIPAY_PUBLIC_KEY ";
    // 日志记录目录
    public static String log_path = "/log";


    public static String RETURN_URL = "";//支付成功后返回哪个前端页面
    /**
     * 参数类型
     */
    public static String PARAM_TYPE = "json";
    /**
     * 成功标识
     */
    public static final String SUCCESS_REQUEST = "TRADE_SUCCESS";
    /**
     * 交易关闭回调(当该笔订单全部退款完毕,则交易关闭)
     */
    public static final String TRADE_CLOSED = "TRADE_CLOSED";
    /**
     * 支付宝开发平台中的支付宝账号(企业)
     */
    public static final String SELLER_ID = "";


    //签名算法类型(根据生成私钥的算法,RSA2或RSA)
    public static final String SIGNTYPE = "RSA2";
    /**
     * 支付宝请求客户端入口
     */
    private volatile static AlipayClient alipayClient = null;


    /**
     * 不可实例化
     */
    private AlipayConfig(){};


    /**
     * 双重锁单例
     * @return 支付宝请求客户端实例
     */
    public static AlipayClient getAlipayClient(){
        if (alipayClient == null){
            synchronized (AlipayConfig.class){
                if (alipayClient == null){
                    alipayClient = new DefaultAlipayClient(GATEWAY,APP_ID,APP_PRIVATE_KEY,PARAM_TYPE,CHARSET,ALIPAY_PUBLIC_KEY,SIGNTYPE);
                }
            }
        }
        return alipayClient;
    }

5、调用示例

AlipayClient alipayClient =  new  DefaultAlipayClient(URL,APP_ID,APP_PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);

支付宝开发文档示例代码:
public   void   doPost (HttpServletRequest httpRequest,
                      HttpServletResponse httpResponse)   throws  ServletException, IOException  {
    AlipayClient alipayClient =  new  DefaultAlipayClient( "https://openapi.alipay.com/gateway.do" , APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);  //获得初始化的AlipayClient
    AlipayTradePagePayRequest alipayRequest =  new  AlipayTradePagePayRequest(); //创建API对应的request
    alipayRequest.setReturnUrl( "http://domain.com/CallBack/return_url.jsp" );
    alipayRequest.setNotifyUrl( "http://domain.com/CallBack/notify_url.jsp" ); //在公共参数中设置回跳和通知地址
    alipayRequest.putOtherTextParam("app_auth_token", "201611BB8xxxxxxxxxxxxxxxxxxxedcecde6");//如果 ISV 代商家接入电脑网站支付能力,则需要传入 app_auth_token,使用第三方应用授权;自研开发模式请忽略
    alipayRequest.setBizContent( "{"  +
         "    \"out_trade_no\":\"20150320010101001\","  +
         "    \"product_code\":\"FAST_INSTANT_TRADE_PAY\","  +
         "    \"total_amount\":88.88,"  +
         "    \"subject\":\"Iphone6 16G\","  +
         "    \"body\":\"Iphone6 16G\","  +
         "    \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\","  +
         "    \"extend_params\":{"  +
         "    \"sys_service_provider_id\":\"2088511833207846\""  +
         "    }" +
         "  }" ); //填充业务参数
    String form= "" ;
     try  {
        form = alipayClient.pageExecute(alipayRequest).getBody();  //调用SDK生成表单
    }  catch  (AlipayApiException e) {
        e.printStackTrace();
    }
    httpResponse.setContentType( "text/html;charset="  + CHARSET);
    httpResponse.getWriter().write(form); //直接将完整的表单html输出到页面
    httpResponse.getWriter().flush();
    httpResponse.getWriter().close();
}
项目示例代码:
public static String pagePay(String out_trade_no,Double money) {
    /*int money = 100;//充值金额
    //逻辑
    long timeStart = Calendar.getInstance().getTimeInMillis();
    String out_trade_no = timeStart + "";// 订单号*/
    // 获得初始化的AlipayClient
    AlipayClient alipayClient = AlipayConfig.getAlipayClient();
    // 创建API对应的request
    AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
    alipayRequest.setReturnUrl(AlipayConfig.RETURN_URL);// 回跳地址
    alipayRequest.setNotifyUrl(AlipayConfig.notify_url);// 通知地址notify_url
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("out_trade_no", out_trade_no);// 订单号
    map.put("product_code", "FAST_INSTANT_TRADE_PAY");// 销售产品码
    map.put("total_amount", money);// 交易金额,单位:元
    map.put("subject", "工会食堂");// 订单标题
    alipayRequest.setBizContent(JSON.toJSONString(map));
    String form = "";
    try {
        // 调用SDK生成表单
        form = alipayClient.pageExecute(alipayRequest).getBody();
        // 就是orderString可以直接给客户端请求,无需再做处理。
        //System.out.println("---------支付宝扫码---------> " + form);
        return form;
    } catch (AlipayApiException e) {
        e.printStackTrace();
    }
    return form;
}


异步回调
@RequestMapping("/alinotify")
public void alinotify(HttpServletRequest request,HttpServletResponse httpResponse){
    //获取支付宝返回的支付信息
    Map<String, String> params = new HashMap<String, String>();
    Map<String, String[]> requestParams = request.getParameterMap();
    Set<String> keySet = requestParams.keySet();
    String out_trade_no = "";
    String trade_status = "";
    String total_amount = "";
    String refund_fee = "";
    Integer orderId;
    for (String key : keySet) {
        StringBuffer buffer = new StringBuffer();
        for (String string : requestParams.get(key)) {
            buffer.append(string);
        }
        params.put(key, buffer.toString());
        if (key.equals("out_trade_no")) {
            out_trade_no = buffer.toString();// 商户订单号
            //System.out.println(key + " : " + buffer.toString());
        } else if (key.equals("trade_status")) {
            trade_status = buffer.toString();// 交易状态
            //System.out.println(key + " : " + buffer.toString());
        }/* else if (key.equals("total_amount")) {
            total_amount = buffer.toString().substring(0,buffer.toString().length()-3) + "";// 充值金额
            System.out.println(key + " : " + total_amount);
        }else if (key.equals("refund_fee")) {
            refund_fee = buffer.toString();// 退款总额
            System.out.println(key + " : " + refund_fee);
        }*/
    }
    //支付异步回调
    try {
        // 计算得出通知验证结果
        boolean verify_result = AlipaySignature.rsaCheckV1(params, AliPayConfig.ALIPAY_PUBLIC_KEY,
                AliPayConfig.CHARSET, AliPayConfig.SIGNTYPE);
        if (verify_result) {// 验证成功
            if (trade_status.equals("TRADE_SUCCESS")) { // 交易支付成功
                //逻辑
                httpResponse.getWriter().println("success");
                if (out_trade_no!=null){
                    System.out.println("支付成功,异步回调成功");
                }
            }
            /*if (!AegisCommonUtils.isNull(refund_fee)) {
                if (trade_status.equals("REFUND_SUCCESS")) { // 交易退款成功
                    //逻辑
                    httpResponse.getWriter().println("success");
                    if (!AegisCommonUtils.isNull(out_trade_no)) {
                        nwgl011CanteenUserService.cancelOrderByout_trade_no(out_trade_no);
                    }


                }
            }
            if (!AegisCommonUtils.isNull(refund_fee)){
                if (trade_status.equals("TRADE_CLOSED")) { // 交易退款成功(全部退款)
                    //逻辑
                    httpResponse.getWriter().println("success");
                    if (!AegisCommonUtils.isNull(out_trade_no)){
                        nwgl011CanteenUserService.cancelOrderByout_trade_no(out_trade_no);
                    }




                }
            }*/
        } else {// 验证失败
            httpResponse.getWriter().println("fail");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

例如扫码支付
@ResponseBody
    @RequestMapping(value = "/pcAliPay")
    public static String alipay() throws AlipayApiException {
        AlipayClient alipayClient = AliPayConfig.getAlipayClient();
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类
        Map<String,Object> map=new HashMap<String,Object>();
        //设置回调地址
        request.setReturnUrl(AliPayConfig.notify_url);// 回跳地址
        request.setNotifyUrl(AliPayConfig.RETURN_URL);// 通知地址
        //根据订单号查询订单信息
        Map<String,Object> maps=new HashMap<String,Object>();
        long timeStart = Calendar.getInstance().getTimeInMillis();
        String out_trade_no =  timeStart +"";
        maps.put("out_trade_no",out_trade_no);
        maps.put("total_amount","0.01");
        maps.put("subject","工会食堂");//订单标题
        maps.put("timeout_express","5m");
        //把订单信息转换为json对象的字符串
        String postdata = JSONObject.toJSON(maps).toString();
        request.setBizContent(postdata);
//        request . setBizContent ( "{"   +
//                "    \"out_trade_no\":\"20150320010101002\","   + //商户订单号
//                "    \"total_amount\":\"88.88\","   +
//                "    \"subject\":\"Iphone6 16G\","   +
//                "    \"store_id\":\"NJ_001\","   +
//                "    \"timeout_express\":\"2m\"}" ); //订单允许的最晚付款时间
        AlipayTradePrecreateResponse response = alipayClient.execute(request);
        String body = response.getBody();
        JSONObject jsonObject = JSONObject.parseObject(body);
        String qr_code = jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code");
        map.put("qr_code", qr_code);
        return qr_code;
    }

二、微信支付:主要参考微信开放平台

1、注册微信账户

2、接入前的准备:需要去微信公众平台申请接入,需要用到企业账号,获取到商户号、appid、证书、密钥等内容

java 内网穿透获取外网ip springboot 内网穿透_java 内网穿透获取外网ip

3、集成并配置sdk

<dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>

4、配置类

package com.css.oa.canteen.util;

import com.css.oa.component.utils.DictUtil;
import com.github.wxpay.sdk.WXPayConfig;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.ClassPathResource;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class MyWxConfig implements WXPayConfig {

    @Override
    public String getAppID() {
        return APP_ID;//微信应用ID(APP ID)
    }

    @Override
    public String getMchID() {
        return MCH_ID;//微信商户号
    }

    @Override
    public String getKey() {
        return KEY;//API密钥
    }

    /**
     * 获取商户证书内容
     * @return
     */
    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    private byte[] certData;
    public MyWxConfig() throws Exception{
        //读取cert文件,这个文件放到resource下
        String certPath = "apiclient_cert.p12";
        File file = new File(this.getClass().getClassLoader().getResource(certPath).getFile());
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }

    @Override
    public int getHttpConnectTimeoutMs() {
        return 8000;
    }

    @Override
    public int getHttpReadTimeoutMs() {
        return 10000;
    }
    //异步通知地址
    public static String notify_url = "NOTIFY_URL"
    public static final String APP_ID = "APP_ID";
    public static final String MCH_ID = "MCH_ID";
    public static final String KEY = "KEy";
}

5、应用示例

1、pc网站二维码支付(NATIVE)

控制层:
Map wxPayResult = new HashMap();
wxMap.put("out_trade_no",out_trade_no);
String total_fee = String.valueOf((int)(allPrice*100));
wxMap.put("total_fee",Integer.valueOf(total_fee));
wxMap.put("spbill_create_ip","123.12.123.12");
wxMap.put("trade_type","NATIVE");// 此处指定为扫码支付,NATIVE是在电脑网站,购物商场网站上发起的支付
wxMap.put("notify_url",MyWxConfig.notify_url);//回调地址
if (payTy == 1){
    payResult = pagePay(out_trade_no,allPrice);
}else{
    wxPayResult = nwgl011CanteenUserService.wxPagePay(wxMap);
}
if(payTy == 1){
    return new JsonResult<>("200","success",payResult);
}else{
    return new JsonResult<>("200","success",wxPayResult);
}
service层:
Map wxPagePay(Map<String, Object> wxMap) throws Exception;
实现类:
public Map wxPagePay(Map<String, Object> wxMap) throws Exception {
        Map<String,String>resultMap = new HashMap<>();
        try{
            //初始化微信支付
            MyWxConfig config = new MyWxConfig();
            WXPay wxPay = new WXPay(config);
            //data中存放请求参数,例如商品名、金额等
            Map<String,String> data = new HashMap<>();
            data.put("appid",config.getAppID());
            data.put("mch_id",config.getMchID());
            data.put("body","腾讯QQ会员");//商品描述
            data.put("out_trade_no", String.valueOf(wxMap.get("out_trade_no")));//商户订单号,商户系统内部订单号
            data.put("total_fee", String.valueOf(wxMap.get("total_fee")));//标价金额,单位为【分】
            data.put("spbill_create_ip",String.valueOf(wxMap.get("spbill_create_ip")));//用户终端ip
            data.put("notify_url",String.valueOf(wxMap.get("notify_url")));//服务器异步通知地址,必须外网能访问,且不能带参数
            data.put("trade_type", String.valueOf(wxMap.get("trade_type")));  //支付类型
            data.put("product_id", String.valueOf(wxMap.get("out_trade_no")));//trade_type为native时必传,商户自行定义,可以将订单号传过来
            data.put("nonce_str", com.github.wxpay.sdk.WXPayUtil.generateNonceStr());//随机字符串
            data.put("sign",com.github.wxpay.sdk.WXPayUtil.generateSignature(data,config.getKey(), WXPayConstants.SignType.MD5));//签名,这里用md5类型
            resultMap = wxPay.unifiedOrder(data);//接收返回参数,使用官方api请求预付订单
//            Map<String,String>responseMap = new HashMap<>();
//            Map<String,String>returnMap = new HashMap<>();
//            if(WXPayConstants.SUCCESS.equals(resultMap.get("return_code"))){
//                //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
//                if(WXPayConstants.SUCCESS.equals(resultMap.get("result_code"))){
//                    responseMap = resultMap;
//                }
//            }
            if(WXPayConstants.SUCCESS.equals(resultMap.get("return_code"))&&WXPayConstants.SUCCESS.equals(resultMap.get("result_code"))){
                resultMap.put("package","Sign=WXPay");
                resultMap.put("timestamp", String.valueOf((System.currentTimeMillis()/1000)));
                resultMap.put("sign",WXPayUtil.generateSignature(resultMap,config.getKey(),WXPayConstants.SignType.MD5));
            }
//            returnMap.put("appid",responseMap.get("appid"));
//            returnMap.put("partnerid",responseMap.get("mch_id"));
//            returnMap.put("prepayid",responseMap.get("prepay_id"));
//            returnMap.put("package","Sign=WXPay");
//            returnMap.put("noncestr",responseMap.get("nonce_str"));
//            returnMap.put("timestamp", String.valueOf((System.currentTimeMillis()/1000)));
//            returnMap.put("sign", WXPayUtil.generateSignature(returnMap,config.getKey(),WXPayConstants.SignType.MD5));
        }catch(Exception e){
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return resultMap;
    }
    2、回调,如果想在本地测试回调,需要配置内网穿透,配置过程见前文

控制层:
@RequestMapping(value = "/wxnotify",method = RequestMethod.POST)
public void wxnotify(HttpServletRequest request,HttpServletResponse response){
    String notifyData = "";// 支付结果通知的xml格式数据
    try{
        InputStream inputStream = request.getInputStream();
        //将InputStream转换成xmlString
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder stringBuilder = new StringBuilder();
        String line = null;
        try{
            while(!AegisCommonUtils.isNull((line = reader.readLine()))){
                stringBuilder.append(line+"\n");
            }
        }catch(IOException e){
            log.error(e.getMessage());
        }finally{
            try{
                inputStream.close();
            }catch(IOException ez) {
                ez.printStackTrace();
            }
        }
        notifyData = stringBuilder.toString();
        String result = nwgl011CanteenUserService.wxPayBack(notifyData);
        BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        outputStream.write(result.getBytes());
        outputStream.flush();
        outputStream.close();
    } catch (Exception ex) {
        ex.printStackTrace();
        log.error("微信支付失败"+ex.getMessage());
    }
}
service层:
String wxPayBack(String notifyData) throws Exception;
实现类:
public String wxPayBack(String notifyData) throws Exception {
    //初始化微信支付
    MyWxConfig config = new MyWxConfig();
    WXPay wxPay = new WXPay(config);
    String xmlBack = "";
    Map<String,String>notifyMap = new HashMap<>();
    try{
        notifyMap = WXPayUtil.xmlToMap(notifyData);//调用sdk转换成map类型数据
        if(wxPay.isPayResultNotifySignatureValid(notifyMap)){//验证签名是否有效
            String return_code = notifyMap.get("return_code");//返回状态码
            if(WXPayConstants.SUCCESS.equals(return_code)) {//这个状态码只是判断通信状态,如果return_code的结果为success,再进行下一步判断
                String result_code = notifyMap.get("result_code");
                String out_trade_no = notifyMap.get("out_trade_no");
                if (WXPayConstants.SUCCESS.equals(result_code)) {//交易状态为success,再判断其他
                    if (!AegisCommonUtils.isNull(out_trade_no)) {//交易成功,改变订单状态
                        String payType = "微信";
                        paymentOrder(out_trade_no, payType);
                        log.info("微信支付回调成功,订单号:{}", out_trade_no);
                        xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    } else {
                        log.info("微信支付回调失败,订单号:{}", out_trade_no);
                        xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                    }
                }
            }
            return xmlBack;
        }else {
            log.error("微信支付回调通知签名错误");
            xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            return xmlBack;
        }
    }catch(Exception e){
        log.error("回调失败"+e.getMessage());
        xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
    }
    return xmlBack;
}
3、退款申请(这里是我抽出来的测试类,具体实现参照业务)

控制层:
@RequestMapping("/wxRefund")
@ResponseBody
public JsonResult wxRefund(@RequestBody CanteenOrder canteenOrder) throws Exception {
    String code = nwgl011CanteenUserService.wxRefund(canteenOrder);
    if("SUCCESS".equals(code)){
        return new JsonResult("200","成功",code);
    }else{
        return new JsonResult("100","失败",code);
    }
}
实现类:
public String wxRefund(CanteenOrder canteenOrder) throws Exception {
    String code = WXPayConstants.FAIL;
    Map<String,String> responseMap = new HashMap<>();
    Map<String,String> requestMap = new HashMap<>();
    MyWxConfig config = new MyWxConfig();
    WXPay wxPay = new WXPay(config);
    requestMap.put("appid",config.getAppID());
    requestMap.put("mch_id",config.getMchID());
    requestMap.put("out_trade_no",canteenOrder.getOutTradeNo());
    requestMap.put("out_refund_no",canteenOrder.getOutTradeNo());//这两个参数微信没有规定,由商户决定,可以一样
    String money = String.valueOf((int)(canteenOrder.getTotalPrice()*100));
    requestMap.put("total_fee",money);
    requestMap.put("refund_fee",money);
    requestMap.put("nonce_str", com.github.wxpay.sdk.WXPayUtil.generateNonceStr());//随机字符串
    requestMap.put("sign",WXPayUtil.generateSignature(requestMap,config.getKey(),WXPayConstants.SignType.MD5));
    try{
        responseMap = wxPay.refund(requestMap);//调用sdk的退款接口
    }catch(Exception e){
        log.error("调用微信退款接口sdk失败"+e.getMessage());
    }
    String return_code = responseMap.get("return_code");
    String return_msg = responseMap.get("return_msg");
    if(WXPayConstants.SUCCESS.equals(return_code)){//返回状态码,通信标识
        String result_code = responseMap.get("result_code");
        String err_code_des = responseMap.get("err_code_des");
        if(WXPayConstants.SUCCESS.equals(result_code)){//业务结果成功,退款申请成功的标识
            //查询退款状态
            Map<String,String>reqMap = new HashMap<>();
            reqMap.put("appid",config.getAppID());
            reqMap.put("mch_id",config.getMchID());
            reqMap.put("nonce_str",WXPayUtil.generateNonceStr());
            reqMap.put("out_trade_no",canteenOrder.getOutTradeNo());
            reqMap.put("sign",WXPayUtil.generateSignature(reqMap,config.getKey(),WXPayConstants.SignType.MD5));
            Map<String,String>resMap = wxPay.refundQuery(reqMap);
            String return_code_q = resMap.get("return_code");
            if(WXPayConstants.SUCCESS.equals(return_code_q)){
                String result_code_q = resMap.get("result_code");
                if(WXPayConstants.SUCCESS.equals(result_code_q)){
                    String refund_status_0 = resMap.get("refund_status_0");
                    if(WXPayConstants.SUCCESS.equals(refund_status_0)){
                        code = WXPayConstants.SUCCESS;
                        return code;
                    }
                }
            }
        }else{
            code = WXPayConstants.FAIL;
            log.error("调用退款查询,订单号:{}错误信息:{}",canteenOrder.getOutTradeNo(),err_code_des);
            return code;
        }
    }
    log.error("调用退款,订单号:{}错误信息:{}", canteenOrder.getOutTradeNo(), return_msg);
    return code;
}
4、支付查询

控制层:
@RequestMapping("queryWxPay")
@ResponseBody
public JsonResult queryWxPay(@RequestBody Map<String,String>params) throws Exception {
    String out_trade_no = params.get("out_trade_no");
    String tradeState = nwgl011CanteenUserService.queryWxPay(out_trade_no);
    if(WXPayConstants.SUCCESS.equals(tradeState)){
        return new JsonResult("200","",tradeState);
    }
    return new JsonResult("100","",tradeState);
}
实现类:
public String queryWxPay(String out_trade_no) throws Exception {
    MyWxConfig config = new MyWxConfig();
    WXPay wxPay = new WXPay(config);
    Map<String,String>requestMap = new HashMap<>();
    String trade_state = "";
    requestMap.put("appid", config.getAppID());
    requestMap.put("mch_id",config.getMchID());
    requestMap.put("out_trade_no",out_trade_no);
    requestMap.put("nonce_str",WXPayUtil.generateNonceStr());
    requestMap.put("sign",WXPayUtil.generateSignature(requestMap,config.getKey(),WXPayConstants.SignType.MD5));
    try{
        Map<String,String>responseMap = wxPay.orderQuery(requestMap);
        String return_code = responseMap.get("return_code");//通信标识
        if(WXPayConstants.SUCCESS.equals(return_code)){//通信成功,才有下面的一系列返回参数
            String result_code = responseMap.get("result_code");
            if(WXPayConstants.SUCCESS.equals(result_code)){
               trade_state  = responseMap.get("trade_state");
            }
        }
    }catch(Exception e){
        log.error(e.getMessage());
        e.printStackTrace();
    }
    return trade_state;
}
5、退款查询

控制层:
@RequestMapping("/wxRefundQuery")
@ResponseBody
public JsonResult wxRefundQuery(@RequestBody CanteenOrder canteenOrder) throws Exception {
    String code = nwgl011CanteenUserService.queryWxRefund(canteenOrder);
    if("SUCCESS".equals(code)){
        return new JsonResult("200","退款成功",code);
    }
    return new JsonResult("100","退款失败",code);
}
实现类:
public String queryWxRefund(CanteenOrder canteenOrder) throws Exception {
        MyWxConfig config = new MyWxConfig();
        WXPay wxPay = new WXPay(config);
        String code = "";
        Map<String,String>reqMap = new HashMap<>();
        reqMap.put("appid",config.getAppID());
        reqMap.put("mch_id",config.getMchID());
        reqMap.put("nonce_str",WXPayUtil.generateNonceStr());
        reqMap.put("out_trade_no",canteenOrder.getOutTradeNo());
        reqMap.put("sign",WXPayUtil.generateSignature(reqMap,config.getKey(),WXPayConstants.SignType.MD5));
        Map<String,String>resMap = wxPay.refundQuery(reqMap);
        String return_code_q = resMap.get("return_code");
        if(WXPayConstants.SUCCESS.equals(return_code_q)){
            String result_code_q = resMap.get("result_code");
            log.error("进入判断result_code_q:{}",result_code_q);
            log.error("err_code:{}",resMap.get("err_code"));
            log.error("err_code_des:{}",resMap.get("err_code_des"));
            if(WXPayConstants.SUCCESS.equals(result_code_q)){
                String refund_status_$n = resMap.get("refund_status_$n");
//                if(WXPayConstants.SUCCESS.equals(refund_status_$n)){
//                    code = WXPayConstants.SUCCESS;
//                    return code;
//                }
                log.info(refund_status_$n);
                code = refund_status_$n;
            }
        }
        return code;
    }
6、app支付(唤起微信)

逻辑同pc支付,只不过支付方式由NATIVE变为APP

三、配置沙箱环境和内网穿透测试

1、注册http://www.ngrok.cc/用户,登陆,进入如下页面,点击创建隧道

![在这里插入图片描述](

java 内网穿透获取外网ip springboot 内网穿透_微信开放平台_02


bbd0b1a5ca8fb00.png)![在这里插入图片描述](

java 内网穿透获取外网ip springboot 内网穿透_阿里云_03

2、下载客户端,选择对应自己系统的版本

java 内网穿透获取外网ip springboot 内网穿透_微信开放平台_04

3、双击运行

java 内网穿透获取外网ip springboot 内网穿透_java 内网穿透获取外网ip_05

4、启动后输入隧道id,回车进入

java 内网穿透获取外网ip springboot 内网穿透_微信开放平台_06

5、出现如下界面

java 内网穿透获取外网ip springboot 内网穿透_阿里云_07

红框里面对应的就是外网可以放为的地址,用它来代替ip+端口,即可异步回调成功

java 内网穿透获取外网ip springboot 内网穿透_spring boot_08