目前支付宝支付和微信支付是算是目前app的标配了
支付宝支付在更新过后有了官方专门的sdk和demo,所以相对而言比较简单,而微信支付稍微复杂一点,下面的文章会附实例代码,微信支付也是参考的github上的某位大神级人物的代码。
首先是微信支付
先准备各种数据,我一般都是放到配置类中,当然也可以放到数据库或者配置文件中
`public final class WxpayConfig {
/**
*商家可以考虑读取配置文件
*/
//微信开发平台应用id
public static final String APP_ID = "wx8888888888888888";
//财付通商户号
public static final String PARTNER = "1900000109";//app请求的商户号
public static final String MCHID = "1900000109";//预支付请求的商户号
//商户号对应的密钥
public static final String PARTNER_KEY = "";
//预支付接口
public static final String PREPAY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//查询订单接口
public static final String QUERY_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
//签名算法常量值
public static final String SIGN_METHOD = "sha1";
//异步通知地址
public static final String NOTIFY_URL = “”;
//交易类型
public static final String TRADE_TYPE = "APP";
//暂定包值
public static final String PACKAGE = "Sign=WXPay";
//返回状态成功
public static final String SUCCESS = "SUCCESS";
//返回状态失败
public static final String FAIL = "FAIL";
}`
这是关于微信支付的封装的工具类,其中httpclient和md5加密的需要自己去封装工具类
`public class WxpayUtil {
/**
*随机串
* @return
*/
public static String getNonceStr() {
Random random = new Random();
return MD5Util.getMD5String(String.valueOf(random.nextInt(10000)));
}
/**
*时间戳
* @return
*/
public static String getTimeStamp() {
return String.valueOf(System.currentTimeMillis() / 1000);
}
/**
*解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
@SuppressWarnings("unchecked")
public static Map parseToMap(String strXml) throws JDOMException, IOException {
strXml = strXml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if(null == strXml || "".equals(strXml)) {
return null;
}
Map m = new HashMap<>();
InputStream in = new ByteArrayInputStream(strXml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while(it.hasNext()) {
Element e = it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if(children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
/**
*获取子结点的xml
* @param children
* @return String
*/
@SuppressWarnings("unchecked")
private static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if(!children.isEmpty()) {
Iterator it = children.iterator();
while(it.hasNext()) {
Element e = it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if(!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("");
}
}
return sb.toString();
}
/**
*只支持String,并且value非空
* @param map
* @return
*/
public static String parseToXml(Map map){
StringBuffer sb = new StringBuffer("");
for(Map.Entry entry : map.entrySet()){
sb.append("<"+entry.getKey()+">");
sb.append("");
sb.append("");
}
sb.append("");
return sb.toString();
}
/**
* POST提交XML对象
* @param document
*/
public static String postXmlClient(String url,String xmlParams) throws Exception {
// return HttpUtils.postXmlEntity(url, xmlParams).getContent();
return HttpClient.postRequest(url, xmlParams);
}
}
这是关于微信支付一些参数处理的方法
public class WxpayHelper {
/**
*除去数组中的空值和签名参数
* @param sArray签名参数组
* @return去掉空值与签名参数后的新签名参数组
*/
public static Map paraFilter(Map sArray) {
Map result = new HashMap();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("key")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
*把数组所有元素,并按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param params需要参与字符拼接的参数组
* @param sorts 是否需要排序 true 或者false
* @return拼接后字符串
*/
public static String createLinkString(Map params) {
List keys = new ArrayList(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
/**
*验签响应签名
* @param paras
* @return
*/
public static boolean verify(Map paras){
String sign = paras.get("sign");
if(StringUtils.isBlank(sign)) return false;
return sign.equals(WxpayBuilder.buildRequestMysign(paraFilter(paras)));
}
/**
*响应成功
* @param loggerAgent -日志代理
* @return String
*/
/*public static String yes(ILoggerAgent loggerAgent){
Map return_wx = new HashMap<>();
return_wx.put("return_code", WxpayConfig.SUCCESS);
loggerAgent.payParamsLogger(null , "WX-NOTIFY", false, return_wx);
return WxpayUtil.parseToXml(return_wx);
}*/
}
public class WxpayBuilder {
/**
*生成签名结果
* @param sPara要签名的数组
* @return签名结果字符串
*/
public static String buildRequestMysign(Map sPara) {
String prestr = WxpayHelper.createLinkString(sPara)+"&key="+WxpayConfig.PARTNER_KEY;
LogFactory.getInstance().getLogger().debug("微信支付签名的字符串:"+prestr);
return MD5Util.getMD5String(prestr).toUpperCase();
}
public static Map buildRequestPara(Map sParaTemp) {
//除去数组中的空值和签名参数
Map sPara = WxpayHelper.paraFilter(sParaTemp);
//生成签名结果
String mysign = buildRequestMysign(sPara);
LogFactory.getInstance().getLogger().debug("微信支付签名数据:"+mysign);
//签名结果与签名方式加入请求提交参数组中
sPara.put("sign", mysign);
return sPara;
}
}`
使用例程
其中业务接口信息,参考https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7&index=3
` /**
*微信订单逻辑
*
* @throws Exception
*/
public
Map wxPayLogic() throws Exception {
//微信业务代码
Map xmlData = new HashMap();
xmlData.put("appid", WxpayConfig.APP_ID);
xmlData.put("mch_id", WxpayConfig.MCHID);
xmlData.put("nonce_str", WxpayUtil.getNonceStr());
xmlData.put("out_trade_no",);
xmlData.put("total_fee",);
xmlData.put("spbill_create_ip",“”);
//从数据字典里面去主机地址
DataDictionary dataDictionary = dataDictionaryService.getDicByKey("PAY_CALLBACK");
xmlData.put("notify_url", dataDictionary.getValue() + WxpayConfig.NOTIFY_URL);
xmlData.put("trade_type", WxpayConfig.TRADE_TYPE);
xmlData.put("body", "");
//少写签名
Map result = WxpayBuilder.buildRequestPara(xmlData);
// Map result = WxpayHelper.paraFilter(xmlData);
String xmlParams = WxpayUtil.parseToXml(result);
LogFactory.getInstance().getLogger().debug("微信支付请求报文:" + xmlParams);
String xmlResult = WxpayUtil.postXmlClient(WxpayConfig.PREPAY_URL, xmlParams);
Map map = WxpayUtil.parseToMap(xmlResult);
LogFactory.getInstance().getLogger().debug("微信支付返回报文:" + JsonHelper.toJson(map));
//返回时SUCCESS
if (WxpayConfig.SUCCESS.equals(map.get("return_code"))) {
//验证返回是否成功
if (WxpayConfig.SUCCESS.equals(map.get("result_code"))) {
//除去签名和空值
Map paraFilter = WxpayHelper.paraFilter(map);
//获得签名
String mysign = WxpayBuilder.buildRequestMysign(paraFilter);
//验证签名
if (mysign.equals(map.get("sign"))) {
String prepay_id = map.get("prepay_id");
//验证签名成功
//进行操作
} else {
//签名验证失败
LogFactory.getInstance().getLogger().debug("微信支付验证签名失败");
}
} else {
// result_code返回失败
String err_code = map.get("err_code");
String err_code_des = map.get("err_code_des");
chargeRecord.setCauses(err_code+err_code_des);
LogFactory.getInstance().getLogger().debug("微信支付结果失败:失败码为"+err_code+",失败原因是"+err_code_des);
chargeRecord.setState(2);
}
} else {
// return_code返回失败
String return_msg = map.get("return_msg");
LogFactory.getInstance().getLogger().debug("微信支付返回失败:返回消息为:" + return_msg);
return null;
}
//微信支付
Map mapBack = new HashMap<>();
mapBack.put("appid", WxpayConfig.APP_ID);
mapBack.put("partnerid", WxpayConfig.PARTNER);
mapBack.put("prepayid", chargeRecord.getOpenId());
mapBack.put("package", WxpayConfig.PACKAGE);
mapBack.put("noncestr", WxpayUtil.getNonceStr());
mapBack.put("timestamp", WxpayUtil.getTimeStamp());
return WxpayBuilder.buildRequestPara(mapBack);
}`
支付异步回传
接收到异步通知之后,才算是付款成功
`@Controller
@RequestMapping(value = "/api")
public class WxPayCallbackController extends BaseController {
@Autowired
OrderLogic orderLogic;
@Autowired
RedisFactory redisFactory;
@Autowired
ApplicationContext applicationContext;
@RequestMapping(value = "/wxPayCallback", method = RequestMethod.POST)
@ResponseBody
public String wxPayCallback(@RequestBody String body) {
MDC.put("seqID", SeqIdGenerator.generate());//日志序列
LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的异步支付结果通知信息data=" + body);
Map resultMap = new HashMap<>();
if (StringUtils.isNotBlank(body)) {
try {
Map map = WxpayUtil.parseToMap(body);
//返回代码
if (WxpayConfig.SUCCESS.equals(map.get("return_code"))) {
//验证签名
if (WxpayHelper.verify(map)) {
//验证业务结果是否成功
String outTradeNo = map.get("out_trade_no");
if (WxpayConfig.SUCCESS.equals(map.get("result_code"))) {
//设置支付类型,1为支付宝,2为微信
map.put("payType","2");
//通过所有验证,启动事件,通过spring的监听器进行监听,并执行付款成功后的业务
applicationContext.publishEvent(new OrderFinishEvent(map));
} else {
//业务结果失败
LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的异步支付业务结果失败");
orderLogic.updateState(outTradeNo,2);
resultMap.put("return_code", WxpayConfig.SUCCESS);
}
} else {
//签名失败
LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的异步支付签名失败");
resultMap.put("return_code", WxpayConfig.FAIL);
resultMap.put("return_msg", "签名失败");
}
} else {
//返回结果失败
LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的异步支付返回结果失败");
resultMap.put("return_code", WxpayConfig.FAIL);
resultMap.put("return_msg", "参数格式校验错误");
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
//返回结果为空
LogFactory.getInstance().getPayCallbackLogger().info("参数格式校验错误");
resultMap.put("return_code", WxpayConfig.FAIL);
resultMap.put("return_msg", "参数格式校验错误");
}
return WxpayUtil.parseToXml(resultMap);
}
}`
付款成功统一处理事件监听
`@Component
public class OrderFinishLister {
@EventListener
public void onApplicationEvent(OrderFinishEvent event){//这里不能抛出异常,外层无法处理,会造成中断
try {
Map params = (HashMap) event.getSource();
String payType = params.get("payType");
String outTradeNo = params.get("out_trade_no");
String trade_no = null;
String buyerLogonId = null;
String buyerId = null;
String transactionId = null;
UserOrder order = null;
if("1".equals(payType)){
//支付宝
trade_no = params.get("trade_no");
buyerLogonId = params.get("buyer_logon_id");
buyerId = params.get("buyer_id");
//执行付款成功后的业务逻辑
LogFactory.getInstance().getLogger().debug("支付宝获取支付更新状态:" + outTradeNo);
}else if("2".equals(payType)){
//微信
transactionId = params.get("transaction_id");
//执行微信付款成功后的业务逻辑
LogFactory.getInstance().getLogger().debug("微信获取支付更新状态:" + outTradeNo);
}
}catch (Exception e){
e.printStackTrace();
}
}
}`
这就是单独的微信支付业务流程