All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.binarywang.wxpay.bean.result.BaseWxPayResult Maven / Gradle / Ivy

The newest version!
package com.github.binarywang.wxpay.bean.result;

import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.github.binarywang.wxpay.util.XmlConfig;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

/**
 * 
 * 微信支付结果共用属性类.
 * Created by Binary Wang on 2016-10-24.
 * 
* * @author Binary Wang */ @Data public abstract class BaseWxPayResult { /** * 返回状态码. */ @XStreamAlias("return_code") protected String returnCode; /** * 返回信息. */ @XStreamAlias("return_msg") protected String returnMsg; //当return_code为SUCCESS的时候,还会包括以下字段: /** * 业务结果. */ @XStreamAlias("result_code") private String resultCode; /** * 错误代码. */ @XStreamAlias("err_code") private String errCode; /** * 错误代码描述. */ @XStreamAlias("err_code_des") private String errCodeDes; /** * 错误代码. */ @XStreamAlias("error_code") private String errorCode; /** * 错误代码描述. */ @XStreamAlias("error_message") private String errorMessage; /** * 公众账号ID. */ @XStreamAlias("appid") private String appid; /** * 商户号. */ @XStreamAlias("mch_id") private String mchId; /** * 服务商模式下的子公众账号ID. */ @XStreamAlias("sub_appid") private String subAppId; /** * 服务商模式下的子商户号. */ @XStreamAlias("sub_mch_id") private String subMchId; /** * 随机字符串. */ @XStreamAlias("nonce_str") private String nonceStr; /** * 签名. */ @XStreamAlias("sign") private String sign; //以下为辅助属性 /** * xml字符串. */ private String xmlString; /** * xml的Document对象,用于解析xml文本. * make xmlDoc transient to ensure toString() can work. */ private transient Document xmlDoc; /** * 将单位分转换成单位圆. * * @param fen 将要被转换为元的分的数值 * @return the string */ public static String fenToYuan(Integer fen) { return BigDecimal.valueOf(Double.valueOf(fen) / 100).setScale(2, RoundingMode.HALF_UP).toPlainString(); } /** * 从xml字符串创建bean对象. * * @param the type parameter * @param xmlString the xml string * @param clz the clz * @return the t */ public static T fromXML(String xmlString, Class clz) { if (XmlConfig.fastMode) { try { BaseWxPayResult t = clz.newInstance(); t.setXmlString(xmlString); Document doc = t.getXmlDoc(); t.loadBasicXML(doc); t.loadXml(doc); return (T) t; } catch (Exception e) { throw new WxRuntimeException("parse xml error", e); } } XStream xstream = XStreamInitializer.getInstance(); xstream.processAnnotations(clz); xstream.setClassLoader(BaseWxPayResult.class.getClassLoader()); T result = (T) xstream.fromXML(xmlString); result.setXmlString(xmlString); return result; } /** * 从XML文档中加载属性,供子类覆盖加载额外的属性 * * @param d Document */ protected abstract void loadXml(Document d); /** * 从XML文档中加载基础属性 * * @param d Document */ private void loadBasicXML(Document d) { returnCode = readXmlString(d, "return_code"); returnMsg = readXmlString(d, "return_msg"); resultCode = readXmlString(d, "result_code"); errCode = readXmlString(d, "err_code"); errorCode = readXmlString(d, "error_code"); errCodeDes = readXmlString(d, "err_code_des"); appid = readXmlString(d, "appid"); mchId = readXmlString(d, "mch_id"); subAppId = readXmlString(d, "sub_appid"); subMchId = readXmlString(d, "sub_mch_id"); nonceStr = readXmlString(d, "nonce_str"); sign = readXmlString(d, "sign"); } protected static Integer readXmlInteger(Node d, String tagName) { String content = readXmlString(d, tagName); if (content == null || content.trim().length() == 0) { return null; } return Integer.parseInt(content); } protected static String readXmlString(Node d, String tagName) { if (!d.hasChildNodes()) { return null; } NodeList childNodes = d.getChildNodes(); for (int i = 0, j = childNodes.getLength(); i < j; i++) { Node node = childNodes.item(i); if (tagName.equals(node.getNodeName())) { if (!node.hasChildNodes()) { return null; } return node.getFirstChild().getNodeValue(); } } return null; } public static String readXmlString(Document d, String tagName) { NodeList elements = d.getElementsByTagName(tagName); if (elements == null || elements.getLength() == 0) { return null; } Node node = elements.item(0).getFirstChild(); if (node == null) { return null; } return node.getNodeValue(); } protected static Integer readXmlInteger(Document d, String tagName) { String content = readXmlString(d, tagName); if (content == null || content.trim().length() == 0) { return null; } return Integer.parseInt(content); } protected static Long readXmlLong(Document d, String tagName) { String content = readXmlString(d, tagName); if (content == null || content.trim().length() == 0) { return null; } return Long.parseLong(content); } /** * Gets logger. * * @return the logger */ protected Logger getLogger() { return LoggerFactory.getLogger(this.getClass()); } @Override public String toString() { return WxGsonBuilder.create().toJson(this); } /** * 将bean通过保存的xml字符串转换成map. * * @return the map */ public Map toMap() { if (StringUtils.isBlank(this.xmlString)) { throw new WxRuntimeException("xml数据有问题,请核实!"); } Map result = Maps.newHashMap(); Document doc = this.getXmlDoc(); try { NodeList list = (NodeList) XPathFactory.newInstance().newXPath() .compile("/xml/*") .evaluate(doc, XPathConstants.NODESET); int len = list.getLength(); for (int i = 0; i < len; i++) { result.put(list.item(i).getNodeName(), list.item(i).getTextContent()); } } catch (XPathExpressionException e) { throw new WxRuntimeException("非法的xml文本内容:" + xmlString); } return result; } /** * 将xml字符串转换成Document对象,以便读取其元素值. */ private Document getXmlDoc() { if (this.xmlDoc != null) { return this.xmlDoc; } xmlDoc = openXML(xmlString); return xmlDoc; } protected Document openXML(String content) { try { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setExpandEntityReferences(false); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); return factory.newDocumentBuilder().parse(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); } catch (Exception e) { throw new WxRuntimeException("非法的xml文本内容:\n" + this.xmlString, e); } } /** * 获取xml中元素的值. * * @param path the path * @return the xml value */ protected String getXmlValue(String... path) { Document doc = this.getXmlDoc(); String expression = String.format("/%s//text()", Joiner.on("/").join(path)); try { return (String) XPathFactory .newInstance() .newXPath() .compile(expression) .evaluate(doc, XPathConstants.STRING); } catch (XPathExpressionException e) { throw new WxRuntimeException("未找到相应路径的文本:" + expression); } } /** * 获取xml中元素的值,作为int值返回. * * @param path the path * @return the xml value as int */ protected Integer getXmlValueAsInt(String... path) { String result = this.getXmlValue(path); if (StringUtils.isBlank(result)) { return null; } return Integer.valueOf(result); } /** * 校验返回结果签名. * * @param wxPayService the wx pay service * @param signType 签名类型 * @param checkSuccess 是否同时检查结果是否成功 * @throws WxPayException the wx pay exception */ public void checkResult(WxPayService wxPayService, String signType, boolean checkSuccess) throws WxPayException { //校验返回结果签名 Map map = toMap(); if (getSign() != null && !SignUtils.checkSign(map, signType, wxPayService.getConfig().getMchKey())) { this.getLogger().debug("校验结果签名失败,参数:{}", map); throw new WxPayException("参数格式校验错误!"); } //校验结果是否成功 if (checkSuccess) { List successStrings = Lists.newArrayList(WxPayConstants.ResultCode.SUCCESS, ""); if (!successStrings.contains(StringUtils.trimToEmpty(getReturnCode()).toUpperCase()) || !successStrings.contains(StringUtils.trimToEmpty(getResultCode()).toUpperCase())) { StringBuilder errorMsg = new StringBuilder(); if (getReturnCode() != null) { errorMsg.append("返回代码:").append(getReturnCode()); } if (getReturnMsg() != null) { errorMsg.append(",返回信息:").append(getReturnMsg()); } if (getResultCode() != null) { errorMsg.append(",结果代码:").append(getResultCode()); } if (getErrCode() != null) { errorMsg.append(",错误代码:").append(getErrCode()); } if (getErrorCode() != null) { errorMsg.append(",错误代码:").append(getErrorCode()); } if (getErrCodeDes() != null) { errorMsg.append(",错误详情:").append(getErrCodeDes()); } this.getLogger().error("\n结果业务代码异常,返回结果:{},\n{}", map, errorMsg); throw WxPayException.from(this); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy