100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 第三方支付接入(微信 支付宝)

第三方支付接入(微信 支付宝)

时间:2023-07-04 02:31:55

相关推荐

第三方支付接入(微信 支付宝)

第三方API

时间 3月30

目前很多企业在做支付的时候为了方便已经开始直接对接第四方了

但是也有一些开源大神们对支付甚至是整个微信开发提供了API

笔者公司的微信支付目前使用的第三方API是binarywang

<dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-pay</artifactId><version>${github.binarywang.version}</version></dependency>

这位大神将微信整个模块的开发都做成了API开源出来,感兴趣的可以去Github学习

支付宝支付对接其实蛮简单清晰的,可能就是在微信支付的时候会有一些坑,但是在使用这个API之后问题就没有那么多了. 用起来还是蛮简单的,而且它支持多商户切换

QY

最近工作中安排了三方支付接入(一般就是微信,支付宝,银联),目前接入的是微信和支付宝;

阶段接近尾声并且测试很OK,现在记录一下开发过程.

目前只是对接了

支付宝的PC,H5;

微信的PC,H5,JSAPI这几种

APP的支付暂时没有需求,所以没做考虑

大家在对接过程中如果遇到问题,欢迎留言,我看到会及时回复的.发私信也可以.希望对大家有帮助;

对接前提

你需要在支付宝或微信平台创建自己的应用,得到我们后续需要用到的各种id和secret

支付宝是有SDK的,记得引入依赖

至于怎么在微信和支付宝的管理平台创建应用,大家自己百度一下吧.o(╥﹏╥)o

思考

对接外部接口,其实很简单,只需要不停尝试就好了,哈哈. 当前网上有很多资源都是相当可取的;

需要注意的是,支付宝所需要的公钥和私钥的生成方式,

此处需要特别注意下,开发者私钥,即我们通过支付宝的生成工具生成的应用私钥

而公钥,如下图

是我们通过上面生成的应用公钥,进行填写,保存之后,支付宝生成的,切记!!! 不然调不通接口的哦.

支付宝生成秘钥

其次

说白了,不管支付宝还是微信,支付逻辑无在乎一去一回这两下.

先做统一下单的操作,然后通过返回数据,做具体的逻辑处理

要注意的是,

支付宝的PC和H5支付返回给我们的是完整的form表单,我们只需要将其响应给前端,让前端做submit即可进行调起真正的支付动作;

而微信则有稍微不同, PC支付返回给我们的是一个二维码url,需要前端将其生成二维码展示; H5返回给我们的是一个web的url,由前端对其进行访问;

开发的时候本地可以,但是调试的时候,如果你没有调通接口,那么建议你线上进行调试;

类梳理

我业务中的controllerservice就不罗列了

PayPlatformService姑且称之为收银台接口AliPayServiceImpl支付宝服务,实现了上面的收银台接口WeChatPayServiceImpl微信服务,实现了上面的收银台接口PayCommons支付用到的通用属性PayProperties支付相关的配置参数

具体实现

PayConstant

public interface PayConstant {/*** 由谁支付 0 企业 1 个人*/int PAY_SIDE_CORP = 0;int PAY_SIDE_PERSONAL = 1;/*** 支付方式*/String PAY_TYPE_WX = "wcpay";String PAY_TYPE_ALI = "alipay";/*** 微信支付类型*/String TRADE_TYPE_WX_JSAPI = "JSAPI";String TRADE_TYPE_WX_NATIVE = "NATIVE";String TRADE_TYPE_WX_APP = "APP";String TRADE_TYPE_WX_MWEB = "MWEB";}

PayCommons

@Data@Accessors(chain = true)public class PayCommons {public static final String TRADE_TYPE_PC = "pc";public static final String TRADE_TYPE_H5 = "h5";/*** sec_account_receivable的id*/private Integer sarId;/*** 订单标题*/private String subject;/*** 第三方(对于支付宝,微信来说)的订单号*/private String securityOrderNo;/*** 订单总金额*/private Integer totalAmount;private BigDecimal fromTotalAmount;/*** 支付方式,PC还是WAP等等*/private String tradeType;/*** 交易该笔订单的设备IP*/private String clientIp;/*** 支付方,企业:0 还是个人:1*/private Integer paySide;/*** alipay:支付宝 wcpay:微信*/private String payType;/*** 业务类型 充值:RECHARGE*/private String bizType;/*** 业务单号*/private String bizNum;/*** 附件*/private String attach;/*** 微信获取token的code*/private String wxCode;/*** 微信的openId*/private String wxOpenId;}

PayProperties

这个类可以放到配置文件中,后续我们会将其中一些配置移至Apollo配置中心

public class PayProperties {/**============================支付宝==========================================*//*** URL*/public static String ALI_PAY_BASE_URL = "/gateway.do";/*** 对接支付宝时创建的应用*/public static String ALI_PAY_APPID = "";/*** 支付宝分配的商户号(账户中心,主账户ID)*/public static String ALI_SELLER_ID = "";/*** 开发者私钥,由开发者自己生成*/public static String ALI_PAY_APP_PRIVATE_KEY = "";/*** 开发者公钥,由支付宝生成*/public static String ALI_PAY_APP_PUBLIC_KEY = "";/*** 销售产品码,商家和支付宝签约的产品码* 1、app支付product_code:QUICK_MSECURITY_PAY;* 2、手机网站支付product_code:QUICK_WAP_WAY;* 3、电脑网站支付product_code:FAST_INSTANT_TRADE_PAY;* 4、统一收单交易支付接口product_code:FACE_TO_FACE_PAYMENT;* 5、周期扣款签约product_code:CYCLE_PAY_AUTH;*/public static String ALI_WAP_PAY_PRODUCT_CODE = "QUICK_WAP_WAY";public static String ALI_PAGE_PAY_PRODUCT_CODE = "FAST_INSTANT_TRADE_PAY";/*** 参数返回格式*/public static String ALI_PAY_FORMAT = "json";/*** 编码集*/public static String ALI_PAY_CHARSET = "UTF-8";/*** 签名方式*/public static String ALI_PAY_SIGN_TYPE = "RSA2";/**异步* 回调接口*/public static String ALI_PAY_NOTIFY_URL = "";/*** 用户付款中途退出,返回商户网站的地址*/public static String ALI_PAY_QUIT_URL = "";/**同步* 用户支付成功返回的地址*/public static String ALI_PAY_PAGE_RETURN_URL = "";public static String ALI_PAY_WAP_RETURN_URL = "";/*** 支付接口*/public static String ALI_PAY_WAP_PAY = "alipay.trade.wap.pay";/**** ============================微信=======================================*//*** 统一下单*/public static String WX_PAY_PAY_UNIFIEDORDER_URL = "https://api.mch./pay/unifiedorder";/*** 订单查询*/public static String WX_PAY_PAY_ORDERQUERY_URL = "https://api.mch./pay/orderquery";/*** 微信支付appid*/public static String WX_PAY_APPID = "";/*** 微信支付商户ID*/public static String WX_PAY_MCHID = "";/*** 商户秘钥* API秘钥*/public static String WX_PAY_SIGN_SECRET_KEY = "";/*** 微信支付AppSecret*/public static String WX_PAY_APP_SECRET = "";/*** 微信支付回调*/public static String WX_PAY_NOTIFY_URL = "";/*** 微信H5支付成功之后返回的页面*/public static String WX_WAP_PAY_RETURN_URL = "";}

AliPayClientFactory

当你阅读过支付宝文档之后你会发现,文档中明确说明,当AlipayClient创建完成之后,可以重复使用,因此我们在这里做一个单例的操作,算是代码的一个优化吧, 微信也会有类似的处理;

public class AliPayClientFactory {private volatile static AlipayClient aliPayClient = null;/*** 私有化构造器*/private AliPayClientFactory(){}/*** 获取对象*/public static AlipayClient getInstance(){if (aliPayClient == null){synchronized (AliPayClientFactory.class){if (aliPayClient == null){aliPayClient = new DefaultAlipayClient(PayProperties.ALI_PAY_BASE_URL,PayProperties.ALI_PAY_APPID,PayProperties.ALI_PAY_APP_PRIVATE_KEY,PayProperties.ALI_PAY_FORMAT,PayProperties.ALI_PAY_CHARSET,PayProperties.ALI_PAY_APP_PUBLIC_KEY,PayProperties.ALI_PAY_SIGN_TYPE);}}}return aliPayClient;}}

通用结果类Result

@Datapublic class Result<T> {private String code;private String mesg;private T data;private Result() {this.code = "000000";this.mesg = "success";this.data = null;}private Result(T data) {this.code = "000000";this.mesg = "success";this.data = data;}private Result(TaurusErrorCodeEnum tec) {if (tec==null){return;}this.code = tec.getCode();this.mesg = tec.getDescription();}/*** 成功时调用* @param <T>* @return*/public static <T> Result<T> success(){return new Result();}/*** 成功时调用* @param data* @param <T>* @return*/public static <T> Result<T> success(T data){return new Result<T>(data);}/*** 失败时调用* @param* @param <T>* @return*/public static <T> Result<String> fail(){Result<String> result = new Result<>();result.setCode("2000");result.setMesg("系统异常");return result;}/*** 失败时调用* @param* @param <T>* @return*/public static <T> Result<String> fail(String code, String msg){Result<String> result = new Result<String>();result.setCode(code);result.setMesg(msg);return result;}/*** 失败时调用* @param tec* @param <T>* @return*/public static <T> Result<T> fail(TaurusErrorCodeEnum tec){return new Result<T>(tec);}}

PayPlatformService

public interface SecurityPayPlatformService {/*** 支付* @param pc* @return*/Result securityPay(PayCommons pc);/*** 处理回调* @param request* @return*/Result handleNotify(HttpServletRequest request);/*** 查询订单状态* @param payCommons* @return*/Result selectOrderInfo(PayCommons payCommons);}

AliPayServiceImpl

@Servicepublic class AliPayServiceImpl implements PayPlatformService{private static final Logger log = LoggerFactory.getLogger(AliPayServiceImpl.class);@Autowiredprivate SecAccountReceivableService secAccountReceivableService;/*** 支付宝支付充值* @param payParam* @return*/@Overridepublic Result securityPay(PayCommons payParam) {if (null == payParam) {return Result.fail().setMesg("参数未传");}AlipayClient alipayClient = AliPayClientFactory.getInstance();//转义携带参数JSONObject attach = (JSONObject)JSON.parse(payParam.getAttach());StringBuilder attachSB = new StringBuilder();attachSB.append("bizType=").append(attach.get("bizType")).append("&paySide=").append(attach.get("paySide"));payParam.setAttach(attachSB.toString());//0企业支付page 1 个人支付wapif (payParam.getTradeType().equals(PayCommons.TRADE_TYPE_PC)){return this.doPagePayRequest(alipayClient,payParam);}else {return this.doWapPayRequest(alipayClient,payParam);}}/*** 处理回调* @param request* @return*/@Overridepublic Result handleNotify(HttpServletRequest request) {try {Enumeration<String> names = request.getParameterNames();HashMap<String, String> resData = new HashMap<>();while (names.hasMoreElements()){String name = names.nextElement();resData.put(name,request.getParameter(name));}log.info("======支付宝支付的异步回调通知参数:{}",resData.toString());//1.验签boolean flag = AlipaySignature.rsaCheckV1(resData, PayProperties.ALI_PAY_APP_PUBLIC_KEY, "UTF-8", "RSA2");if (!flag){return Result.fail().setMesg("验签失败");}//2.必要参数非空验证String tradeStatus = resData.get("trade_status");//己方单号String secTradeNo = resData.get("out_trade_no");//商户号String sellerId = resData.get("seller_id");String totalAmount = resData.get("total_amount");String appId = resData.get("app_id");if (StringUtils.isAnyBlank(tradeStatus, secTradeNo, sellerId, totalAmount, appId)){return Result.fail().setMesg("解析非空参数trade_status,out_trade_no,seller_id,total_amount,app_id部分为空");}//数据匹配验证List<SecAccountReceivable> list = secAccountReceivableService.getList(new SecAccountReceivableQuery().setAccountNum(secTradeNo));if (CollectionUtils.isEmpty(list)){return Result.fail().setMesg("secTradeNo no found:"+secTradeNo);}SecAccountReceivable sar = list.get(0);if (!(sellerId.equals(PayProperties.ALI_SELLER_ID) && secTradeNo.equals(sar.getAccountNum())&& appId.equals(PayProperties.ALI_PAY_APPID) && totalAmount.equals(sar.getAccountAmount().toString()))){return Result.fail().setMesg("数据匹配失败,当前回调数据与查询数据不一致");}//sar_id 是我们应收账单的id,此处可以忽略,删除resData.put("sar_id",String.valueOf(sar.getId()));return Result.success(resData);}catch (Exception e){e.printStackTrace();log.error("支付宝支付的异步回调处理出现错误:{}",e.getStackTrace());return Result.fail().setMesg("支付宝支付的异步回调处理出现错误");}}/*** 查詢支付宝订单信息* @param payCommons* @return*/@Overridepublic Result selectOrderInfo(PayCommons payCommons) {AlipayClient client = AliPayClientFactory.getInstance();AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();JSONObject bizContent = new JSONObject();bizContent.put("out_trade_no",payCommons.getSecurityOrderNo());request.setBizContent(bizContent.toJSONString());AlipayTradeQueryResponse response;try {response = client.execute(request);log.info("支付宝订单【{}】---查詢結果:{}",payCommons.getSecurityOrderNo(),response.getBody());}catch (Exception e){e.printStackTrace();log.error("调用支付宝查询接口异常");return Result.fail().setMesg("调用支付宝查询接口异常");}String body = response.getBody();if (StringUtils.isBlank(body)){return Result.fail();}JSONObject bodyObj = JSON.parseObject(body);JSONObject bodybody = bodyObj.getJSONObject("alipay_trade_query_response");//sar_id 是我们应收账单的id,此处可以忽略,删除bodybody.put("sar_id",payCommons.getSarId());return Result.success(bodybody.toString());}//=====================private method===========================/*** 处理PC支付* @param alipayClient* @param payParam* @return*/private Result doPagePayRequest(AlipayClient alipayClient,PayCommons payParam) {AlipayTradePagePayRequest pagePayRequest = new AlipayTradePagePayRequest();JSONObject bizContent = new JSONObject();Result result = null;//回调接口,PC支付方式,returnUrl如果没有必要可以不必配置//pagePayRequest.setReturnUrl(PayProperties.ALI_PAY_PAGE_RETURN_URL);//异步通知调用接口pagePayRequest.setNotifyUrl(PayProperties.ALI_PAY_NOTIFY_URL);/*** 以下必传项*/bizContent.put("subject",payParam.getSubject());bizContent.put("out_trade_no",payParam.getSecurityOrderNo());bizContent.put("total_amount",payParam.getFromTotalAmount());bizContent.put("product_code",PayProperties.ALI_PAGE_PAY_PRODUCT_CODE);/*** 以下选传项*///公共回传参数,如果请求时传递了该参数,支付宝只会在同步返回和异步通知时将该参数原样返回try {String encodeAttach = URLEncoder.encode(payParam.getAttach(), PayProperties.ALI_PAY_CHARSET);bizContent.put("passback_params",encodeAttach);}catch (Exception e){log.error("ali pay passBackParams encode exception:{}",e.getStackTrace());}pagePayRequest.setBizContent(bizContent.toJSONString());String form = "";try {form = alipayClient.pageExecute(pagePayRequest,"get").getBody();result = Result.success(form);}catch (Exception e){e.printStackTrace();//调用异常log.error("调用支付宝PC支付异常,信息:{}",e.getMessage());result = Result.fail().setMesg("支付宝PC支付出现异常");}return result;}/*** 处理H5支付* @param alipayClient* @param payParam* @return*/private Result doWapPayRequest(AlipayClient alipayClient, PayCommons payParam) {AlipayTradeWapPayRequest wapPayRequest = new AlipayTradeWapPayRequest();Result result = null;//支付成功访问接口wapPayRequest.setReturnUrl(PayProperties.ALI_PAY_WAP_RETURN_URL);//异步通知调用接口wapPayRequest.setNotifyUrl(PayProperties.ALI_PAY_NOTIFY_URL);/*** 以下必传项*/SortedMap<String, Object> bizContent = new TreeMap<>();bizContent.put("subject",payParam.getSubject());bizContent.put("out_trade_no",payParam.getSecurityOrderNo());BigDecimal amount = payParam.getFromTotalAmount().setScale(2,BigDecimal.ROUND_HALF_UP);bizContent.put("total_amount",amount);bizContent.put("product_code",PayProperties.ALI_WAP_PAY_PRODUCT_CODE);/*** 以下选传项*///公共回传参数,如果请求时传递了该参数,支付宝只会在同步返回和异步通知时将该参数原样返回try {String encodeAttach = URLEncoder.encode(payParam.getAttach(), PayProperties.ALI_PAY_CHARSET);bizContent.put("passback_params",encodeAttach);}catch (Exception e){log.error("ali pay passBackParams encode exception:{}",e.getStackTrace());}wapPayRequest.setBizContent(JSON.toJSONString(bizContent));try {String form = alipayClient.pageExecute(wapPayRequest).getBody();result = Result.success().setData(form);}catch (AlipayApiException e){e.printStackTrace();//调用异常log.error("调用支付宝WAP支付异常,信息:{}",e.getMessage());result = Result.fail().setMesg("支付宝WAP支付出现异常");}return result;}}

微信支付,需要一个特殊工具类,在此贴出来WXPayUtil

WXPayUtil

public class WXPayUtil {public static Logger log = LoggerFactory.getLogger(WXPayUtil.class);/*** 获取随机串*/public static String createNonceStr() {String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";String res = "";for (int i = 0; i < 16; i++) {Random rd = new Random();res += chars.charAt(rd.nextInt(chars.length() - 1));}return res;}/*** 获取client_ip** @param request* @return*/public static String getRemoteHost(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}String[] ips = ip.split(",");return ips[0].equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ips[0];}/*** @param key* @param characterEncoding* @param parameters* @return*/public static String createSign(String key, String characterEncoding, SortedMap<String, Object> parameters) {StringBuffer sb = new StringBuffer();Set es = parameters.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();Object v = entry.getValue();if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + key);String sign = MD5Util.encode(sb.toString()).toUpperCase();return sign;}/*** @param characterEncoding 编码格式* @param parameters 请求参数* @return* @Description:创建sign签名*/public static String createSign(String characterEncoding, SortedMap<String, Object> parameters) {StringBuffer sb = new StringBuffer();Set es = parameters.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();Object v = entry.getValue();if ("attach".equalsIgnoreCase(k)) {sb.append(k + "=" + v + "&");} else if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + PayProperties.WX_PAY_SIGN_SECRET_KEY);String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();return sign;}/*** 封装xml request*/public static String getRequestXml(SortedMap<String, Object> parameters) {StringBuffer sb = new StringBuffer();sb.append("<xml>");Set es = parameters.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();Object v = entry.getValue();if ("sign".equalsIgnoreCase(k)) {} else if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k)) {sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");} else {sb.append("<" + k + ">" + v + "</" + k + ">");}}sb.append("<" + "sign" + ">" + "<![CDATA[" + parameters.get("sign") + "]]></" + "sign" + ">");sb.append("</xml>");return sb.toString();}/*** 封装xml 通知返回*/public static String getnotifyRespXml(String isSuccess, String reason) {SortedMap<String, Object> parameters = new TreeMap<>();parameters.put("return_code", isSuccess);parameters.put("return_msg", reason);StringBuffer sb = new StringBuffer();sb.append("<xml>");Set<Map.Entry<String, Object>> es = parameters.entrySet();Iterator<Map.Entry<String, Object>> it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if ("sign".equalsIgnoreCase(k)) {} else if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "return_code".equalsIgnoreCase(k) || "return_msg".equalsIgnoreCase(k)) {sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");} else {sb.append("<" + k + ">" + v + "</" + k + ">");}}sb.append("</xml>");return sb.toString();}public static SortedMap<String, Object> startWXPay(String result) throws Exception {SecurityWXPayConfig wxPayConfig = SecurityWXPayConfig.getInstance();Map<String, String> map = doXMLParse(result);String prepayId = map.get("prepay_id");SortedMap<String, Object> parameterMap = new TreeMap<>();parameterMap.put("appId", wxPayConfig.getWxAppId());parameterMap.put("timeStamp", String.valueOf(System.currentTimeMillis()));parameterMap.put("nonceStr", map.get("nonce_str"));parameterMap.put("package", "prepay_id=" + prepayId);parameterMap.put("signType","MD5");String sign = createSign("UTF-8", parameterMap);parameterMap.put("paySign", sign);parameterMap.putAll(map);return parameterMap;}/*** xml 解析** @param strxml* @return*/public static Map doXMLParse(String strxml) throws Exception {strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");if (StringUtils.isBlank(strxml)) {return null;}Map map = new HashMap();InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));SAXBuilder saxBuilder = new SAXBuilder();Document doc = saxBuilder.build(in);Element rootEle = doc.getRootElement();List childrenList = rootEle.getChildren();Iterator it = childrenList.iterator();while (it.hasNext()) {Element element = (Element) it.next();String k = element.getName();String v = "";List children = element.getChildren();if (children.isEmpty()) {v = element.getTextNormalize();} else {v = getChildrenText(children);}map.put(k, v);}//关闭流in.close();return map;}private static String getChildrenText(List children) {StringBuffer sb = new StringBuffer();if (!children.isEmpty()) {Iterator it = children.iterator();while (it.hasNext()) {Element e = (Element) 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("</" + name + ">");}}return sb.toString();}/*** 接收微信的异步通知,取出参数** @param request* @return*/public static String reciverWx(HttpServletRequest request) throws IOException {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();return sb.toString();}/*** 是否签名正确* 规则:按参数名称a-z排序,遇到空值的参数不参与签名** @param characterEncoding* @param packageParams* @return*/public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, SecurityWXPayConfig payConfig) {StringBuffer sb = new StringBuffer();Set<Map.Entry<Object, Object>> es = packageParams.entrySet();Iterator<Map.Entry<Object, Object>> it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (!"sign".equals(k) && null != v && !"".equals(v)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + payConfig.getWxSecretKey());//算出摘要String mySign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();String sign = ((String) packageParams.get("sign")).toLowerCase();return sign.equals(mySign);}/*** 测试main方法** @param args*/public static void main(String[] args) {String 测试 = "<xml><return_code><![CDATA[FAIL]]></return_code>\n" +"<return_msg><![CDATA[签名错误]]></return_msg>\n" +"</xml>";try {Map sortedMap = WXPayUtil.doXMLParse(测试);String string = JSON.toJSONString(sortedMap);System.out.println("jsonString:" + string);} catch (Exception e) {e.printStackTrace();}}}

SecurityWXPayConfig该类是微信的公共参数生成类

public class SecurityWXPayConfig{/*** 微信支付appid*/private String wxAppId;/*** 微信支付商户ID*/private String wxMchId;/*** 微信支付回调*/private String wxNotifyUrl;/*** 微信支付AppSecret*/private String wxAppSecret;/*** 微信支付秘钥*/private String wxSecretKey;/*** 微信包名*/private String wxPkg;private String sceneInfo;private static volatile SecurityWXPayConfig securityWXPayConfig = null;private SecurityWXPayConfig() {this.wxAppId = PayProperties.WX_PAY_APPID;this.wxNotifyUrl = PayProperties.WX_PAY_NOTIFY_URL;this.wxAppSecret = PayProperties.WX_PAY_APP_SECRET;this.wxMchId = PayProperties.WX_PAY_MCHID;this.wxSecretKey = PayProperties.WX_PAY_SIGN_SECRET_KEY;Map<String,Object> map = new HashMap<>();Map<String,String> infoMap = new HashMap<>();infoMap.put("type","Wap");infoMap.put("wap_url","/safe/");infoMap.put("wap_name","xx");map.put("h5_info",infoMap);this.sceneInfo = JSON.toJSONString(map);}public static SecurityWXPayConfig getInstance(){if (securityWXPayConfig == null){synchronized (SecurityWXPayConfig.class){if (securityWXPayConfig == null){securityWXPayConfig = new SecurityWXPayConfig();}}}return securityWXPayConfig;}public String getWxAppId() {return wxAppId;}public String getWxMchId() {return wxMchId;}public String getWxNotifyUrl() {return wxNotifyUrl;}public String getWxAppSecret() {return wxAppSecret;}public String getWxSecretKey() {return wxSecretKey;}public String getWxPkg() {return wxPkg;}public String getSceneInfo() {return sceneInfo;}}

WeChatPayServiceImpl

@Servicepublic class WeChatPayServiceImpl implements SecurityPayPlatformService {private static final Logger log = LoggerFactory.getLogger(AliPayServiceImpl.class);//业务类,应收账单,用来检验异步通知的数据准确性@Autowiredprivate SecAccountReceivableService secAccountReceivableService;/*** 支付充值** @param payParam* @return*/@Overridepublic Result securityPay(PayCommons payParam) {if (null == payParam) {return Result.fail().setMesg("参数必传");}//获取微信公共配置SecurityWXPayConfig wxPayConfig = SecurityWXPayConfig.getInstance();SortedMap<String, Object> parameterMap = new TreeMap<>();//获取随机串String nonceStr = WXPayUtil.createNonceStr();parameterMap.put("appid", wxPayConfig.getWxAppId());parameterMap.put("mch_id", wxPayConfig.getWxMchId());parameterMap.put("notify_url", wxPayConfig.getWxNotifyUrl());//随机字符串parameterMap.put("nonce_str", nonceStr);//商品描述parameterMap.put("body", payParam.getSubject());parameterMap.put("out_trade_no", payParam.getSecurityOrderNo());//单位:分//payCommons.setTotalAmount();int totalAmount = payParam.getFromTotalAmount().multiply(new BigDecimal("100")).intValue();parameterMap.put("total_fee", totalAmount);parameterMap.put("spbill_create_ip", payParam.getClientIp());parameterMap.put("attach", payParam.getAttach());String tradeType = payParam.getTradeType();if (tradeType.equals(PayCommons.TRADE_TYPE_PC)){tradeType = PayConstant.TRADE_TYPE_WX_NATIVE;}else if (tradeType.equals(PayCommons.TRADE_TYPE_H5)){tradeType = PayConstant.TRADE_TYPE_WX_MWEB;}else if (tradeType.equals(PayConstant.TRADE_TYPE_WX_JSAPI)){parameterMap.put("openid",payParam.getWxOpenId());}payParam.setTradeType(tradeType);parameterMap.put("trade_type", tradeType);//{"h5_info": {"type":"Wap","wap_url": "","wap_name": "腾讯充值"}}//wap_url 是用工卫士的url wap_name 是用工卫士的nameparameterMap.put("scene_info", wxPayConfig.getSceneInfo());//生成签名String sign = WXPayUtil.createSign("UTF-8", parameterMap);//签名parameterMap.put("sign", sign);//map转xmlString requestXml = WXPayUtil.getRequestXml(parameterMap);log.info("请求微信支付xml参数requestXml:{}", requestXml);//http post 请求String result = HttpUtils.post(PayProperties.WX_PAY_PAY_UNIFIEDORDER_URL, requestXml);log.info("微信支付请求结果:{}", result);if (StringUtils.isBlank(result)) {log.error("调用微信支付接口失败:返回结果为空");return Result.fail().setMesg("微信支付接口调用失败");}SortedMap<String, Object> map = null;try {map = WXPayUtil.startWXPay(result);} catch (Exception e) {e.printStackTrace();log.error("pay error WeChatPayServiceImpl:{}", e.getMessage());return Result.fail().setMesg("请求结果解析有误");}//对result转成的map进行解析if (map.get("return_code").equals("FAIL")) {log.error("调用微信支付接口失败:{}", map.get("return_msg").toString());return Result.fail().setMesg("微信支付接口调用失败");}if (map.get("return_code").equals("SUCCESS")&& map.get("result_code").equals("FAIL")) {log.error("微信支付出现错误,错误代码:{},错误描述:{}", map.get("err_code"), map.get("err_code_des"));return Result.fail().setMesg("微信支付出现错误");}map.put("accountNumber", payParam.getSecurityOrderNo());//此处只有H5支付有的需求if (payParam.getTradeType().equals(PayConstant.TRADE_TYPE_WX_MWEB)){String mwebUrl = (String)map.get("mweb_url");String encodeReturnUrl = "";try {encodeReturnUrl = URLEncoder.encode(PayProperties.WX_WAP_PAY_RETURN_URL+"?out_trade_no="+payParam.getSecurityOrderNo(), "UTF-8");}catch (Exception e){e.printStackTrace();}if (StringUtils.isBlank(encodeReturnUrl)){encodeReturnUrl = PayProperties.WX_WAP_PAY_RETURN_URL+"?out_trade_no="+payParam.getSecurityOrderNo();}map.put("mweb_url",mwebUrl+"&redirect_url="+encodeReturnUrl);}log.info("微信支付请求数据处理,返回前端结果:{}", map);return Result.success(map);}/*** 处理回调** @param request* @return*/@Overridepublic Result handleNotify(HttpServletRequest request) {Result result = Result.fail();String notifyXml = "";try {notifyXml = WXPayUtil.reciverWx(request);} catch (Exception e) {e.printStackTrace();return result.setMesg("参数格式校验错误,reciverWx()方法出现异常");}//参数为空if (StringUtils.isBlank(notifyXml)) {//这里返回一个参数错误的xml字符串return result.setMesg("参数格式校验错误" + "解析的请求参数为空");}try {Map map = WXPayUtil.doXMLParse(notifyXml);log.info("wx handleNotify doXMLParse result:{}", map);SecurityWXPayConfig payConfig = SecurityWXPayConfig.getInstance();//过滤空 设置 treeMapSortedMap<Object, Object> packageParams = new TreeMap<>();Iterator it = map.keySet().iterator();while (it.hasNext()) {String parameter = (String) it.next();String parameterVal = (String) map.get(parameter);String v = "";if (StringUtils.isNotBlank(parameterVal)) {v = parameterVal.trim();}packageParams.put(parameter, v);}//判断签名是否正确 isTenpaySignif (!WXPayUtil.isTenpaySign("UTF-8", packageParams, payConfig)) {//返回参数格式校验错误return result.setMesg("签名失败");}//如果通讯异常,即return_code为fail,返回参数格式校验错误if (StringUtils.isBlank((String) packageParams.get("return_code")) ||"FAIL".equals(packageParams.get("return_code"))) {//返回参数格式校验错误return result.setMesg("参数格式校验错误" + "return_code" + "为空或返回为FAIL");}String mchId = (String) packageParams.get("mch_id");String securityTradeNo = (String) packageParams.get("out_trade_no");String totalFee = (String) packageParams.get("total_fee");//查询应收账单,用来对通知中的单号,金额等做验证,此操作可以放到外面,使支付更加通用List<SecAccountReceivable> list = secAccountReceivableService.getList(new SecAccountReceivableQuery().setAccountNum(securityTradeNo));if (CollectionUtils.isEmpty(list)) {return result.setMesg("未查询到相应out_trade_no的订单");}SecAccountReceivable sar = list.get(0);//验证商户ID和价格,以防止篡改金额BigDecimal accountAmount = sar.getAccountAmount().multiply(new BigDecimal(100));if (StringUtils.isAnyBlank(mchId, totalFee) || !payConfig.getWxMchId().equals(mchId)|| (pareTo(new BigDecimal(totalFee)) != 0)) {//这里返回一个参数错误的xml字符串return result.setMesg("参数格式校验错误,mchId,totalFee为空,或者其中一个与我方所持资源不匹配");}map.put("sar_id", sar.getId());return Result.success().setData(map);} catch (Exception e) {e.printStackTrace();//这里返回一个参数错误return result.setMesg("参数格式校验错误,出现异常");}}/*** 查询订单状态* @param payCommons* @return*/@Overridepublic Result selectOrderInfo(PayCommons payCommons) {SortedMap<String,Object> paramMap = new TreeMap<>();paramMap.put("appid",PayProperties.WX_PAY_APPID);paramMap.put("mch_id",PayProperties.WX_PAY_MCHID);paramMap.put("out_trade_no",payCommons.getSecurityOrderNo());paramMap.put("nonce_str",WXPayUtil.createNonceStr());//获取签名String sign = WXPayUtil.createSign("UTF-8", paramMap);paramMap.put("sign",sign);String requestXml = WXPayUtil.getRequestXml(paramMap);String result = HttpUtils.post(PayProperties.WX_PAY_PAY_ORDERQUERY_URL, requestXml);log.info("查询单号【{}】結果:{}",payCommons.getSecurityOrderNo(),result);if (StringUtils.isBlank(result)){return Result.fail().setMesg("单号:"+payCommons.getSecurityOrderNo()+"查询结果为空");}SortedMap<String, Object> map = null;try {map = WXPayUtil.startWXPay(result);} catch (Exception e) {e.printStackTrace();log.error("微信支付订单号:{},查询结果解析异常",payCommons.getSecurityOrderNo());return Result.fail().setMesg("请求结果解析有误");}//对result转成的map进行解析if (map.get("return_code").equals("FAIL")) {log.error("微信订单查询接口调用失败,原因:{}", map.get("return_msg").toString());return Result.fail().setMesg("微信支付接口调用失败");}if (map.get("return_code").equals("SUCCESS")&& map.get("result_code").equals("FAIL")) {log.error("微信订单查询错误,错误代码:{},错误描述:{}", map.get("err_code"), map.get("err_code_des"));return Result.fail().setMesg("微信支付出现错误");}map.put("sar_id",payCommons.getSarId());return Result.success(map);}}

FAQ

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。