在蚂蚁金服开发平台下载demo
打开 TradePayDemo 项目,里面的main可以直接运行,在配置文件zfbinfo.properties中改为自己支付宝的信息
# 支付宝网关名、partnerId和appId
open_api_domain = https://openapi.alipay.com/gateway.do
mcloud_api_domain =
pid =
appid = #申请应用并签约后会有一个有效的appid,应用名称一个月只能修改一次
# RSA私钥、公钥和支付宝公钥
private_key =
public_key = #这里的公钥为支付宝产生的应用公钥
#SHA1withRsa对应支付宝公钥
alipay_public_key =
# 签名类型: RSA->SHA1withRsa,RSA2->SHA256withRsa
sign_type = RSA2
# 当面付最大查询次数和查询间隔(毫秒)
max_query_retry = 5
query_duration = 5000
# 当面付最大撤销次数和撤销间隔(毫秒)
max_cancel_retry = 3
cancel_duration = 2000
# 交易保障线程第一次调度延迟和调度间隔(秒)
heartbeat_delay = 5
heartbeat_duration = 900
二维码预下单,修改必要信息即可直接运行
package com.ys.demo.serviceImpl;
import com.alipay.api.*;
import com.alipay.api.request.AlipayTradeCancelRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeCancelResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayMonitorService;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayMonitorServiceImpl;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.service.impl.AlipayTradeWithHBServiceImpl;
import com.ys.demo.domain.Order;
import com.ys.demo.service.AlipayService;
import com.ys.demo.utils.payUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
public class AlipayServiceImpl implements AlipayService {
private static Log log = LogFactory.getLog(AlipayServiceImpl.class);
// 支付宝当面付2.0服务
private static AlipayTradeService tradeService;
// 支付宝当面付2.0服务(集成了交易保障接口逻辑)
@SuppressWarnings("unused")
private static AlipayTradeService tradeWithHBService;
// 支付宝交易保障接口服务,供测试接口api使用,请先阅读readme.txt
@SuppressWarnings("unused")
private static AlipayMonitorService monitorService;
static {
/** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
* Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是否在classpath目录
*/
Configs.init("zfbinfo.properties");
/** 使用Configs提供的默认参数
* AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new
*/
tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
// 支付宝当面付2.0服务(集成了交易保障接口逻辑)
tradeWithHBService = new AlipayTradeWithHBServiceImpl.ClientBuilder().build();
/** 如果需要在程序中覆盖Configs提供的默认参数, 可以使用ClientBuilder类的setXXX方法修改默认参数 否则使用代码中的默认设置 */
monitorService = new AlipayMonitorServiceImpl.ClientBuilder()
.setGatewayUrl("http://mcloudmonitor.com/gateway.do").setCharset("GBK")
.setFormat("json").build();
}
/**
* 支付宝二维码
* @param order
* @author joke
*/
@Override
public String aliPay(Order order) throws Exception {
// (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线,
String outTradeNo = order.getOrderId();
// (必填) 订单标题,粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
String subject = "消费";
// (必填) 订单总金额,单位为元,不能超过1亿元
// 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
String totalAmount = String.valueOf(order.getPrice());//总金额,单位元
// (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段
// 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
String undiscountableAmount = "0";
// 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)
// 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
String sellerId = "";
// 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元"
String body = "消费";
// 商户操作员编号,添加此参数可以为商户操作员做销售统计
String operatorId = order.getOrderId();
// (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
String storeId = "test_store_id";
// 业务扩展参数,目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法),详情请咨询支付宝技术支持
ExtendParams extendParams = new ExtendParams();
extendParams.setSysServiceProviderId("");
// 支付超时,定义为1分钟
String timeoutExpress = "1m";
// 商品明细列表,需填写购买商品详细信息,
List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();
// 创建一个商品信息,参数含义分别为商品id(使用国标)、名称、单价(单位为分)、数量,如果需要添加商品类别,详见GoodsDetail
GoodsDetail goods1 = GoodsDetail.newInstance(order.getOrderId(), "消费", order.getPrice(), 1);
// 创建好一个商品后添加至商品明细列表
goodsDetailList.add(goods1);
// 创建扫码支付请求builder,设置请求参数
AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
.setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
.setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
.setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
.setTimeoutExpress(timeoutExpress)
.setNotifyUrl("")//支付宝回调地址
.setGoodsDetailList(goodsDetailList);
AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
String alipayUrl = null;
switch (result.getTradeStatus()) {
case SUCCESS:
log.info("支付宝预下单成功: )");
AlipayTradePrecreateResponse response = result.getResponse();
dumpResponse(response);
alipayUrl = response.getQrCode();
// 需要修改为运行机器上的路径
// String filePath = String.format("D:/qr-%s.png",
// response.getOutTradeNo());
// log.info("filePath:" + filePath);
// ZxingUtils.getQRCodeImge(response.getQrCode(), 256, filePath);
break;
case FAILED:
log.error("支付宝预下单失败!!!");
break;
case UNKNOWN:
log.error("系统异常,预下单状态未知!!!");
break;
default:
log.error("不支持的交易状态,交易返回异常!!!");
break;
}
return alipayUrl;
}
// 简单打印应答
@Override
public void dumpResponse(AlipayResponse response) {
if (response != null) {
log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
if (StringUtils.isNotEmpty(response.getSubCode())) {
log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
response.getSubMsg()));
}
log.info("body:" + response.getBody());
}
}
/**
* 支付宝退款
* @param
* @author joke
*/
@Override
public String refund(Order order) throws AlipayApiException{
AlipayClient alipayClient = new DefaultAlipayClient(Configs.getOpenApiDomain(),Configs.getAppid(),Configs.getPrivateKey(),"json","UTF-8",Configs.getAlipayPublicKey(),"RSA2");
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"" + order.getOrderId() + "\"," +
"\"refund_amount\":\"" + order.getPrice() + "\"," +
"\"refund_currency\":\"" + payUtil.REFUND_FEE_TYPE + "\"," +
"\"refund_reason\":\"" + payUtil.REFUND_DESC + "\"," +
"\"out_request_no\":\"" + order.getOutRefundNo() + "\"," +
" }");
AlipayTradeRefundResponse response = alipayClient.execute(request);
String result = "success";
if(response.isSuccess()){
System.out.println("调用成功");
} else {
result = "failure";
System.out.println("调用失败");
}
return result;
}
/**
* 支付宝撤销
* @param order
* @author joke
*/
@Override
public String revoke(Order order)throws AlipayApiException {
//AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","UTF-8","alipay_public_key","RSA2");
AlipayClient alipayClient = new DefaultAlipayClient(Configs.getOpenApiDomain(),Configs.getAppid(),Configs.getPrivateKey(),"json","UTF-8",Configs.getAlipayPublicKey(),"RSA2");
AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
request.setBizContent("{" +
"\"out_trade_no\":" + "\"" + order.getOrderId()+ "\"" + " }");
String result = "1";
AlipayTradeCancelResponse response = alipayClient.execute(request);
if(response.isSuccess()){
System.out.println("调用成功");
} else {
result = "0";
System.out.println("调用失败");
}
return result;
}
}
支付宝回调接口,ip需与域名绑定
package com.ys.demo.controller;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.ys.demo.domain.Order;
import com.ys.demo.service.OrderService;
import com.ys.demo.serviceImpl.MQTTPublish;
import com.ys.demo.utils.AlipayConfig;
import com.ys.demo.utils.AlipayNotifyParam;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@RestController
public class AlipayCallbackController {
private static Log logger = LogFactory.getLog(AlipayCallbackController.class);
@Autowired
private AlipayConfig alipayConfig; // 支付宝支付配置
@Autowired
private OrderService orderService;
@Autowired
private MQTTPublish mqttPublish;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private ExecutorService executorService = Executors.newFixedThreadPool(20);
@RequestMapping("alipayTest")
public String method(){
logger.info("Alipay callback!");
return "Alipay callback!";
}
/**
* <pre>
* 第一步:验证签名,签名通过后进行第二步
* 第二步:按一下步骤进行验证
* 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
* 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
* 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
* 4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
* 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
* 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
* </pre>
*
* @param request
* @return
*/
@RequestMapping("alipayCallback")
public String callback(HttpServletRequest request) throws Exception{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Map<String, String> params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中
String paramsJson = JSON.toJSONString(params);///支付宝回调的参数
logger.info("支付宝回调,{}", new Throwable(paramsJson));
String trade_status = params.get("trade_status");支付返回结果
try {
// 调用SDK验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipay_public_key(),
alipayConfig.getCharset(), alipayConfig.getSigntype());
if (signVerified) {
logger.info("支付宝回调签名认证成功");
// 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1/2/3/4二次校验,校验成功后在response中返回success,校验失败返回failure
this.check(params);
// 另起线程处理业务
executorService.execute(new Runnable() {
@Override
public void run() {
try{
// 支付成功业务逻辑处理
if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
/业务逻辑处理
} else {
///业务逻辑处理
}
}catch (Exception e){
logger.error("Business handling exception!");
}
}
});
return "success";
} else {
logger.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}"+ paramsJson);
//认证签名失败,业务逻辑处理
return "failure";
}
} catch (AlipayApiException e) {
logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}"+ paramsJson, e);
}
}
// 将request中的参数转换成Map
private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
Map<String, String> retMap = new HashMap<String, String>();
Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
for (Map.Entry<String, String[]> entry : entrySet) {
String name = entry.getKey();
String[] values = entry.getValue();
int valLen = values.length;
if (valLen == 1) {
retMap.put(name, values[0]);
} else if (valLen > 1) {
StringBuilder sb = new StringBuilder();
for (String val : values) {
sb.append(",").append(val);
}
retMap.put(name, sb.toString().substring(1));
} else {
retMap.put(name, "");
}
}
return retMap;
}
private AlipayNotifyParam buildAlipayNotifyParam(Map<String, String> params) {
String json = JSON.toJSONString(params);
return JSON.parseObject(json, AlipayNotifyParam.class);
}
/**
* 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
* 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
* 3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
* 4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
* 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
* 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
*
* @param params
* @throws AlipayApiException
*/
private void check(Map<String, String> params) throws AlipayApiException {
String outTradeNo = params.get("out_trade_no");
// 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
Order order = orderService.selectByOrderId(outTradeNo);
if (order == null) {
logger.error("out_trade_no错误" + sdf);
throw new AlipayApiException("out_trade_no错误");
}
// 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
// 3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
// 第三步可根据实际情况省略
// 4、验证app_id是否为该商户本身。
if (!params.get("app_id").equals(alipayConfig.getAppid())) {
logger.error(outTradeNo + ",app_id不一致" + sdf);
throw new AlipayApiException("app_id不一致");
}
}
public MqttMessage getMsg(MqttMessage msg, String jsonS) {
msg.setQos(1);
msg.setRetained(true);
msg.setPayload(jsonS.getBytes());
return msg;
}
}
微信二维码支付
package com.ys.demo.serviceImpl;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.ys.demo.domain.Order;
import com.ys.demo.service.WeChatService;
import com.ys.demo.utils.wechat.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.util.Hashtable;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
@Service
public class WeChatServiceImpl implements WeChatService {
private WXPayConstants.SignType signType;
private boolean autoReport;
private boolean useSandbox;
@SuppressWarnings("unused")
private String notifyUrl;
private WXPayRequest wxPayRequest;
/**
* 作用:预下单<br>
* 场景:扫码支付<br>
* @param order 读超时时间,单位是毫秒
* @return API返回数据
* @throws Exception
*/
@Override
public String weixinPay(Order order) throws Exception {
try{
//String out_trade_no = "" + System.currentTimeMillis(); //订单号 (调整为自己的生产逻辑)
// 账号信息
String appid = PayConfigUtil.APP_ID; // appid
//String appsecret = PayConfigUtil.APP_SECRET; // appsecret
String mch_id = PayConfigUtil.MCH_ID; // 商业号
String key = PayConfigUtil.API_KEY; // key
String currTime = PayToolUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayToolUtil.buildRandom(4) + "";
String nonce_str = strTime + strRandom;
// 获取发起电脑 ip
String spbill_create_ip = PayConfigUtil.CREATE_IP;
// 回调接口
String notify_url = PayConfigUtil.NOTIFY_URL;
String trade_type = "NATIVE";
SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
packageParams.put("appid", appid);
packageParams.put("mch_id", mch_id);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", "消费"); //(调整为自己的名称)
packageParams.put("out_trade_no", order.getOrderId());
packageParams.put("total_fee", String.valueOf(order.getPrice())); //价格的单位为分
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", notify_url);
packageParams.put("trade_type", trade_type);
//packageParams.put("", "");
String sign = PayToolUtil.createSign("UTF-8", packageParams,key); //签名
packageParams.put("sign", sign);
String requestXML = PayToolUtil.getRequestXml(packageParams); //将请求参数转换为xml格式的string
String resXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML); //连接微信,并返回result
@SuppressWarnings("rawtypes")
Map map = XMLUtil4jdom.doXMLParse(resXml);
String urlCode = (String) map.get("code_url");
// QRUtil.qwqe(urlCode);
return urlCode;
}catch (Exception e){
System.out.println("ss"+ e.getMessage());
}
return null;
}
public void qrcode(String code) throws Exception {
try {
int width = 300;
int height = 300;
//二维码的图片格式
String format = "gif";
Hashtable hints = new Hashtable();
//内容所使用编码
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
BitMatrix bitMatrix;
try {
bitMatrix = new MultiFormatWriter().encode(code, BarcodeFormat.QR_CODE, width, height, hints);
File file = new File("d:"+File.separator+"new.gif");
// QRUtil.writeToStream(bitMatrix, format, file);
} catch (WriterException e) {
e.printStackTrace();
}
} catch (Exception e) {
}
}
/**
* 作用:申请退款<br>
* 场景:刷卡支付、公共号支付、扫码支付、APP支付<br>
* 其他:需要证书
* @param reqData 向wxpay post的请求数据
* @param connectTimeoutMs 连接超时时间,单位是毫秒
* @param readTimeoutMs 读超时时间,单位是毫秒
* @return API返回数据
* @throws Exception
*/
@Override
public String refund(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = WXPayConstants.SANDBOX_REFUND_URL_SUFFIX;
}
else {
url = WXPayConstants.REFUND_URL_SUFFIX;
}
String respXml = this.requestWithCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
return this.processResponseXml(respXml);
}
/**
* 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign <br>
* 该函数适用于商户适用于统一下单等接口,不适用于红包、代金券接口
*
* @param reqData
* @return
* @throws Exception
*/
@Override
public Map<String, String> fillRequestData(Map<String, String> reqData) throws Exception {
//reqData.put("appid", config.getAppID());
reqData.put("appid", PayConfigUtil.APP_ID);
//reqData.put("mch_id", config.getMchID());
reqData.put("mch_id", PayConfigUtil.MCH_ID);
reqData.put("nonce_str", WXPayUtil.generateNonceStr());
if (WXPayConstants.SignType.MD5.equals(this.signType)) {
reqData.put("sign_type", WXPayConstants.MD5);
}
else if (WXPayConstants.SignType.HMACSHA256.equals(this.signType)) {
reqData.put("sign_type", WXPayConstants.HMACSHA256);
}
//reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
reqData.put("sign", WXPayUtil.generateSignature(reqData, PayConfigUtil.API_KEY, this.signType));
return reqData;
}
/**
* 需要证书的请求
* @param urlSuffix String
* @param reqData 向wxpay post的请求数据 Map
* @param connectTimeoutMs 超时时间,单位是毫秒
* @param readTimeoutMs 超时时间,单位是毫秒
* @return API返回数据
* @throws Exception
*/
@Override
public String requestWithCert(String urlSuffix, Map<String, String> reqData,
int connectTimeoutMs, int readTimeoutMs) throws Exception {
String msgUUID= reqData.get("nonce_str");
String reqBody = WXPayUtil.mapToXml(reqData);
String resp = this.wxPayRequest.requestWithCert(urlSuffix, msgUUID, reqBody, connectTimeoutMs, readTimeoutMs, this.autoReport);
return resp;
}
/**
* 处理 HTTPS API返回数据,转换成Map对象。return_code为SUCCESS时,验证签名。
* @param xmlStr API返回的XML格式数据
* @return Map类型数据
* @throws Exception
*/
// @Override
// public Map<String, String> processResponseXml(String xmlStr) throws Exception {
// String RETURN_CODE = "return_code";
// String return_code;
// Map<String, String> respData = WXPayUtil.xmlToMap(xmlStr);
// if (respData.containsKey(RETURN_CODE)) {
// return_code = respData.get(RETURN_CODE);
// }
// else {
// throw new Exception(String.format("No `return_code` in XML: %s", xmlStr));
// }
//
// if (return_code.equals(WXPayConstants.FAIL)) {
// return respData;
// }
// else if (return_code.equals(WXPayConstants.SUCCESS)) {
// if (this.isResponseSignatureValid(respData)) {
// return respData;
// }
// else {
// throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr));
// }
// }
// else {
// throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr));
// }
// }
@Override
public String processResponseXml(String xmlStr) throws Exception {
String RETURN_CODE = "return_code";
String return_code;
Map<String, String> respData = WXPayUtil.xmlToMap(xmlStr);
if (respData.containsKey(RETURN_CODE)) {
return_code = respData.get(RETURN_CODE);
}
else {
return "failure";
//throw new Exception(String.format("No `return_code` in XML: %s", xmlStr));
}
if (return_code.equals(WXPayConstants.FAIL)) {
return "failure";
}
else if (return_code.equals(WXPayConstants.SUCCESS)) {
if (this.isResponseSignatureValid(respData)) {
return "success";
}
else {
return "failure";
//throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr));
}
}
else {
return "failure";
//throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr));
}
}
/**
* 判断xml数据的sign是否有效,必须包含sign字段,否则返回false。
*
* @param reqData 向wxpay post的请求数据
* @return 签名是否有效
* @throws Exception
*/
@Override
public boolean isResponseSignatureValid(Map<String, String> reqData) throws Exception {
// 返回数据的签名方式和请求中给定的签名方式是一致的
return WXPayUtil.isSignatureValid(reqData, PayConfigUtil.API_KEY, this.signType);
}
}
微信回调接口,域名和ip需绑定,否则不能回调
package com.ys.demo.controller;
import com.ys.demo.domain.Order;
import com.ys.demo.utils.wechat.PayConfigUtil;
import com.ys.demo.utils.wechat.PayToolUtil;
import com.ys.demo.utils.wechat.XMLUtil4jdom;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.jdom2.JDOMException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.*;
@RestController
public class PayCallBackController{
private static Log logger = LogFactory.getLog(PayCallBackController.class);
// @Autowired
// private OrderService orderService;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@RequestMapping("wxpayTtest")
public String method(){
logger.info("wxpay callback!");
return "wxpay callback!";
}
/*
* 微信回调函数
* */
@RequestMapping("weixinNotify")
public void wechatCallBack(HttpServletRequest request, HttpServletResponse response,
ModelMap modelMap) throws JDOMException, Exception{
logger.info("微信回调");
MqttMessage msg = new MqttMessage();
//读取参数
InputStream inputStream ;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s ;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
inputStream.close();
/* 解析xml成map */
Map<String, String> m = new HashMap<String, String>();
m = XMLUtil4jdom.doXMLParse(sb.toString());
//过滤空 设置 TreeMap
SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
Iterator it = m.keySet().iterator();
while (it.hasNext()) {
String parameter = (String) it.next();
String parameterValue = m.get(parameter);
String v = "";
if(null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}
// 账号信息
String key = PayConfigUtil.API_KEY; //key
String orderId = (String)packageParams.get("out_trade_no");
// Order order = orderService.selectByOrderId(orderId);
// if (StringUtils.isEmpty(order)){
// return;
// }
String price = (String)packageParams.get("price");
if(PayToolUtil.isTenpaySign("UTF-8", packageParams,key)) {
String resXml = "";
if("SUCCESS".equals((String)packageParams.get("result_code"))){
//执行自己的业务逻辑
request.getSession().setAttribute("_PAY_RESULT", "OK");
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
//执行自己的业务逻辑
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} else{
logger.error(sdf+"通知签名验证失败:"+packageParams);
}
}
}