一、支付宝支付:主要参考支付宝开放平台
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、证书、密钥等内容
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/用户,登陆,进入如下页面,点击创建隧道
![在这里插入图片描述](
bbd0b1a5ca8fb00.png)![在这里插入图片描述](
2、下载客户端,选择对应自己系统的版本
3、双击运行
4、启动后输入隧道id,回车进入
5、出现如下界面
红框里面对应的就是外网可以放为的地址,用它来代替ip+端口,即可异步回调成功