1.1请先完成微信APP支付接入商户服务中心
1.2详情请参考微信官方文档:https://open.weixin.qq.com/

2.application.yml文件的配置如下

#微信支付配置
tenpayconfig:#商户APPIDappId: asdfg12345#商户号mchId: 12345678#商户的key(API密匙)key: qwertyuiop#API支付请求地址payUrl: https://api.mch.weixin.qq.com/pay/unifiedorder#API查询请求地址queryUrl: https://api.mch.weixin.qq.com/pay/orderquery#packagepackageValue: Sign=WXPay

3.配置文件对应的TenpayConfig,若没集成lombok请自行生成get/set方法

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;@Data
@Component
@ConfigurationProperties(prefix = "tenpayconfig")
public class TenpayConfig {//appIdprivate String appId;//商户号private String mchId;//商户的key(API密匙)private String key;//API支付请求地址private String payUrl;//API查询请求地址private String queryUrl;//Sign=WXPayprivate String packageValue;
}    

3.1新建一个TenPayVO

import java.math.BigDecimal;
import lombok.Data;@Data
public class TenPayVO {//商户订单号private String outTradeNo;//业务结果private String resultCode;//签名方式private String signType;//签名private String sign;//交易类型private String tradeType;//交易状态private String tradeState;//商户号private String mchId;//付款银行private String bankType;//支付金额private BigDecimal totalFee;//币种private String feeType;//微信支付订单号private String transactionId;//支付完成时间private String timeEnd;
}    

3.2由于微信支付和回调的报文都是xml,先在maven中添加xstream的jar依赖

<!--xstream-->
<dependency><groupId>com.thoughtworks.xstream</groupId><artifactId>xstream</artifactId><version>1.4.7</version>
</dependency>

3.3TenPayUtils工具类,直接拿去用吧

import com.github.pagehelper.util.StringUtil;
import com.huaku.ecom.common.config.TenpayConfig;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.Map.Entry;@Component
public class TenPayUtils {private static TenPayUtils tenPayUtils;@Autowiredprivate TenpayConfig tenpayConfig;@PostConstructpublic void init(){tenPayUtils = this;tenPayUtils.tenpayConfig = this.tenpayConfig;}public String createSign(SortedMap<String, Object> paramsMap, String charSetName) throws UnsupportedEncodingException,NoSuchAlgorithmException {StringBuffer buffer = new StringBuffer();//参数按照ACCSII排序(升序)Set set = paramsMap.entrySet();Iterator iterator = set.iterator();while (iterator.hasNext()){Map.Entry entry = (Map.Entry) iterator.next();String key = (String) entry.getKey();String value = (String) entry.getValue();if(!key.equals("sign") && StringUtil.isNotEmpty(value)){buffer.append(key + "=" + value + "&");}}buffer.append("key=" + tenPayUtils.tenpayConfig.getKey());String sign = MDUtils.MD5EncodeForHex(buffer.toString(), charSetName).toUpperCase();return sign;}public static String tenPayXmlInfo(SortedMap<String, Object> paramsMap){StringBuffer buffer = new StringBuffer();if(paramsMap != null){buffer.append("<xml>");for(Map.Entry<String, Object> entry : paramsMap.entrySet()){buffer.append("<").append(entry.getKey()).append("><![CDATA[").append(entry.getValue()).append("]]></").append(entry.getKey()).append(">");}buffer.append("</xml>");}return buffer.toString();}public static String httpsRequest(String requestUrl, String requestMethod, String output) throws Exception {URL url = new URL(requestUrl);HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();connection.setDoOutput(true);connection.setDoInput(true);connection.setUseCaches(false);connection.setRequestMethod(requestMethod);if(StringUtil.isNotEmpty(output)){OutputStream outputStream = connection.getOutputStream();outputStream.write(output.getBytes("UTF-8"));outputStream.close();}InputStream inputStream = connection.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;StringBuffer buffer = new StringBuffer();while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}bufferedReader.close();inputStreamReader.close();inputStream.close();connection.disconnect();return buffer.toString();}public static Object readXml(String xml, String rootName, String rowName){XStream xStream = new XStream(new DomDriver());xStream.alias(rootName, Map.class);xStream.registerConverter(new TenPayUtils.MapEntryConverter(rowName));Object object = xStream.fromXML(xml);return object;}public static class MapEntryConverter implements Converter {private String rowName;public MapEntryConverter(String rowName) {this.rowName = rowName;}public boolean canConvert(Class clazz) {return Map.class.isAssignableFrom(clazz) || LinkedHashMap.class.isAssignableFrom(clazz);}public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {this._marshal(value, writer, context);}private void _marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {Iterator i$;Object object;if (value instanceof Map) {Map map = (Map) value;for (i$ = map.entrySet().iterator(); i$.hasNext(); writer.endNode()) {object = i$.next();Entry entry = (Entry) object;Object _key = entry.getKey();Object _value = entry.getValue();writer.startNode(entry.getKey().toString());if (_value instanceof Map) {this._marshal(_value, writer, context);} else if (_value instanceof List) {this._marshal(_value, writer, context);} else {writer.setValue(entry.getValue().toString());}}} else if (value instanceof List) {List list = (List) value;for (i$ = list.iterator(); i$.hasNext(); writer.endNode()) {object = i$.next();writer.startNode(this.rowName);if (!(object instanceof Map) && !(object instanceof List)) {writer.setValue(object.toString());} else {this._marshal(object, writer, context);}}}}public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {return this._unmarshal(reader, context);}public Object _unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {Map map = new HashMap();List list = new ArrayList();boolean isList;for (isList = false; reader.hasMoreChildren(); reader.moveUp()) {reader.moveDown();String nodeName = reader.getNodeName();if (reader.hasMoreChildren()) {if (isList) {list.add(this._unmarshal(reader, context));} else if (map.containsKey(nodeName)) {isList = true;list.add(map.remove(nodeName));list.add(this._unmarshal(reader, context));} else if (this.rowName.equals(nodeName)) {isList = true;list.add(this._unmarshal(reader, context));} else {map.put(nodeName, this._unmarshal(reader, context));}} else {String value = reader.getValue();if (isList) {list.add(value);} else if (map.containsKey(nodeName)) {isList = true;list.add(map.remove(nodeName));list.add(value);} else if (this.rowName.equals(nodeName)) {isList = true;list.add(value);} else {map.put(nodeName, value);}}}return isList ? list : map;}}
}

4.1发起支付请求

  @Overridepublic Map<String, String> payRequest(String payType, String outTradeNo, BigDecimal totalAmount) throws Exception {Map<String, String> map = new HashMap<String, String>();switch (PayTypeEnum.valueOf(payType)) {case TENPAY://财付通SortedMap<String, Object> paramsMap = new TreeMap<String, Object>();//公众账号IDparamsMap.put("appid", tenpayConfig.getAppId());//商户号paramsMap.put("mch_id", tenpayConfig.getMchId());//随机字符串paramsMap.put("nonce_str", Convert.getUUID());//描述paramsMap.put("body", "名绘优家订单支付");//商户订单号(支付编号)paramsMap.put("out_trade_no", outTradeNo);//支付金额,金额单位为 分double price = totalAmount.doubleValue();int totalFee = (int) (price * 100);paramsMap.put("total_fee", String.valueOf(totalFee));//回调地址paramsMap.put("notify_url", ConstantInfo.TENPAY_ORDER_CALLBACK);//交易类型paramsMap.put("trade_type", "APP");//用户端ipString spbillCreateIp = "";InetAddress inetAddress = InetAddress.getLocalHost();if (inetAddress != null) {spbillCreateIp = inetAddress.getHostAddress();}paramsMap.put("spbill_create_ip", spbillCreateIp);TenPayUtils tenPayUtils = new TenPayUtils();//sign签名String sign = tenPayUtils.createSign(paramsMap, "UTF-8");paramsMap.put("sign", sign);//请求报文String requestXml = TenPayUtils.tenPayXmlInfo(paramsMap);//logger.info("微信支付请求报文: " + requestXml);//发送微信支付post请求String tenPayPost = TenPayUtils.httpsRequest(tenpayConfig.getPayUrl(), "POST", requestXml);//获取返回Map<String, String> tenPayMap = (Map<String, String>) TenPayUtils.readXml(tenPayPost, "xml", "");//微信返回状态码if (!tenPayMap.get("return_code").equals("SUCCESS")) {logger.error("微信支付请求连接失败: " + tenPayMap.get("return_msg"));throw new RRException(AppWSConstant.RS_MSG_TENPAY_FALL);}//业务结果if (!tenPayMap.get("result_code").equals("SUCCESS")) {logger.error("err_code: " + tenPayMap.get("err_code"), "err_code_des: " + tenPayMap.get("err_code_des"));throw new RRException(AppWSConstant.RS_MSG_TENPAY_FALL);}//APPIDmap.put("appid", tenPayMap.get("appid"));//商户号map.put("partnerid", tenPayMap.get("mch_id"));//预支付交易会话IDmap.put("prepayid", tenPayMap.get("prepay_id"));//扩展字段map.put("package", tenpayConfig.getPackageValue());//随机字符串map.put("noncestr", tenPayMap.get("nonce_str"));//时间戳map.put("timestamp", String.valueOf(new Date().getTime()).substring(0, 10));SortedMap<String, Object> signMap = new TreeMap<>(map);String newSign = tenPayUtils.createSign(signMap, "UTF-8");//签名map.put("sign", newSign);break;default:break;}return map;}

4.1.1ConstantInfo中的内容为

/*** 常量*/
public class ConstantInfo {//订单支付财付通回调地址public static String TENPAY_ORDER_CALLBACK = "http://mall.gzmhyj.com:8085/huakuEComBuyer/pay/tenPayOrderCallBack";
}

4.2订单微信支付回调
该接口为为微信异步回调提供的接口

   @RequestMapping(value = "/tenPayOrderCallBack", method = RequestMethod.POST)@ResponseBodypublic Map<String, String> tenPayOrderCallBack(HttpServletRequest request){Map<String, String> map = new HashMap<String, String>();try {TenPayVO tenPayVO = payService.tenPayCallBack(request);payService.tenPayOrderCallBack(tenPayVO);map.put("return_code", "SUCCESS");map.put("return_msg", "OK");} catch (Exception e) {e.printStackTrace();}return map;}

4.2.1payService的tenPayCallBack,用于解析回调的信息,拼接TenPayVO

    @Overridepublic TenPayVO tenPayCallBack(HttpServletRequest request) throws Exception {InputStream inputStream = request.getInputStream();StringBuffer resXml = new StringBuffer();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));String str;while ((str = bufferedReader.readLine()) != null) {resXml.append(str);}bufferedReader.close();inputStream.close();//logger.info("微信回调报文: " + resXml);TenPayVO tenPayVO = this.tenPayCallBackInfo(resXml.toString(), "xml", "");return tenPayVO;}

4.2.2tenPayCallBackInfo,用于解析微信支付回调返回结果,拼接TenPayVO

   private TenPayVO tenPayCallBackInfo(String xml, String rootName, String rowName) throws Exception {Map<String, Object> resHashMap = (Map<String, Object>) TenPayUtils.readXml(xml, "xml", "");SortedMap<String, Object> resMap = new TreeMap<String, Object>(resHashMap);//微信返回状态码if (!resMap.get("return_code").equals("SUCCESS")) {logger.error("微信支付回调连接失败: " + resMap.get("return_msg"));throw new RRException(AppWSConstant.RS_MSG_TENPAY_FALL);}//业务结果if (!resMap.get("result_code").equals("SUCCESS")) {logger.error("err_code: " + resMap.get("err_code"), "err_code_des: " + resMap.get("err_code_des"));throw new RRException(AppWSConstant.RS_MSG_TENPAY_FALL);}TenPayUtils tenPayUtils = new TenPayUtils();//校验签名String sign = tenPayUtils.createSign(resMap, "UTF-8");if (!sign.equals(resMap.get("sign"))) {logger.error("微信支付回调签名不正确");throw new RRException(AppWSConstant.RS_MSG_TENPAY_FALL);}TenPayVO tenPayVO = new TenPayVO();//商户订单号tenPayVO.setOutTradeNo((String) resMap.get("out_trade_no"));//业务结果tenPayVO.setResultCode((String) resMap.get("result_code"));//签名方式tenPayVO.setSignType("ASCII");//签名tenPayVO.setSign((String) resMap.get("sign"));//交易类型tenPayVO.setTradeType("APP");//交易状态tenPayVO.setTradeState((String) resMap.get("trade_state"));//商户号tenPayVO.setMchId((String) resMap.get("mch_id"));//付款银行tenPayVO.setBankType((String) resMap.get("bank_type"));//交易金额BigDecimal totalFee = new BigDecimal((String) resMap.get("total_fee"));totalFee = totalFee.divide(new BigDecimal(100));tenPayVO.setTotalFee(totalFee);//币种if (resMap.containsKey("fee_type")) {tenPayVO.setFeeType((String) resMap.get("fee_type"));}//微信支付订单号tenPayVO.setTransactionId((String) resMap.get("transaction_id"));//支付完成时间tenPayVO.setTimeEnd((String) resMap.get("time_end"));return tenPayVO;}

4.2.3payService的tenPayOrderCallBack,用于自己的回调完成的业务逻辑,如修改订单状态,存微信支付交易表等操作

 @Overridepublic void tenPayOrderCallBack(TenPayVO tenPayVO) throws Exception {if (tenPayVO != null && tenPayVO.getResultCode().equals("SUCCESS") && tenPayVO.getTradeState().equals("SUCCESS")) {//根据交易编号加锁,处理高并发synchronized (tenPayVO.getOutTradeNo()) {TOrder order = orderMapper.getOneOrderByPayNo(tenPayVO.getOutTradeNo());if (order.getOrderStatus().equals(OrderStatusEnum.PENDING_PAYMENT.toString())) {//订单需支付金额总和BigDecimal payNumSum = this.getPayNumSumByPayNo(tenPayVO.getOutTradeNo());String orderStatus = "";//以防万一,再次校验金额if (payNumSum.compareTo(tenPayVO.getTotalFee()) != 0) {logger.error("***订单号: " + tenPayVO.getOutTradeNo() + "***微信支付支付金额与订单需支付金额总和不一致***微信支付金额为:" + tenPayVO.getTotalFee() + " ***订单需支付金额总为:" + payNumSum + "***日期:" + new Date());//金额异常,订单状态为支付金额异常orderStatus = OrderStatusEnum.ABNORMAL_PAYMENT_AMOUNT.toString();} else {//金额正常,订单状态为已付款(待发货)orderStatus = OrderStatusEnum.WAIT_FOR_DELIVERY.toString();}//修改订单状态int orderFlag = orderMapper.updatePayOrderStatusByPayNo(orderStatus, tenPayVO.getOutTradeNo());//微信支付交易记录表TTenpayTradeLog tenpayTradeLog = new TTenpayTradeLog();tenpayTradeLog.setTradeLogId(Convert.createUniqueId(idWorker));//签名方式tenpayTradeLog.setSignType(tenPayVO.getSignType());//交易方式tenpayTradeLog.setTradeMode(tenPayVO.getTradeType());//交易状态tenpayTradeLog.setTradeStatus(tenPayVO.getResultCode());//商户号tenpayTradeLog.setPartner(tenPayVO.getMchId());//银行类型tenpayTradeLog.setBankType(tenPayVO.getBankType());//交易金额tenpayTradeLog.setTotalFee(tenPayVO.getTotalFee());//币种tenpayTradeLog.setFeeType(tenPayVO.getFeeType());//微信支付订单号tenpayTradeLog.setTransactionId(tenPayVO.getTransactionId());//商户订单号tenpayTradeLog.setOutTradeNo(tenPayVO.getOutTradeNo());//支付完成时间tenpayTradeLog.setTimeEnd(tenPayVO.getTimeEnd());int payFlag = tenpayTradeLogMapper.insertSelective(tenpayTradeLog);//若有一个操作出错,抛错回滚if (!(orderFlag > 0 && payFlag == 1)) {logger.error("微信支付订单回调失败");throw new RRException(AppWSConstant.RS_MSG_TENPAY_FALL);}} else {logger.info("该订单已支付处理,交易编号为: " + tenPayVO.getOutTradeNo());throw new RRException(AppWSConstant.RS_MSG_ORDER_PAY_ERROR);}}}}

4.3定时任务主动查询微信支付回调,一般微信发起的异步回调都是无序不定时的,所以一般保险起见都会写一个自己的定时任务主动查询微信支付回调

    /*** 定时任务:每十五分钟触发一次主动调用订单支付回调*/@Scheduled(cron = "0 */15 * * * ?")public void initiativeOrderPayCallBack(){//主动调用订单支付回调try {payService.initiativeOrderPayCallBack();} catch (Exception e) {logger.error("timer initiativeOrderPayCallBack Error.", e);e.printStackTrace();}}

4.3.1payService的initiativeOrderPayCallBack,用于主动查询微信支付回调与回调业务逻辑处理

    /*** 主动调用订单支付回调** @throws Exception*/@Overridepublic void initiativeOrderPayCallBack() throws Exception {//查询订单状态为orderStatus的支付编号List<Map<String, String>> payNoList = orderMapper.getPayNoByStatus(OrderStatusEnum.PENDING_PAYMENT.toString());for (Map<String, String> map : payNoList) {try {switch (PayTypeEnum.valueOf(map.get("payType"))) {case TENPAY://财付通TenPayVO tenPayVO = this.tenPayQueryCallBack(map.get("payNo"));//订单回调处理this.tenPayOrderCallBack(tenPayVO);break;default:break;}} catch (Exception e) {logger.error(e.getMessage());e.printStackTrace();}}}

4.3.2payService的tenPayQueryCallBack,用于主动查询微信支付回调,拼接TenPayVO

 @Overridepublic TenPayVO tenPayQueryCallBack(String payNo) throws Exception {SortedMap<String, Object> paramsMap = new TreeMap<String, Object>();//应用APPIDparamsMap.put("appid", tenpayConfig.getAppId());//商户号paramsMap.put("mch_id", tenpayConfig.getMchId());//商户订单号paramsMap.put("out_trade_no", payNo);//随机字符串paramsMap.put("nonce_str", Convert.getUUID());TenPayUtils tenPayUtils = new TenPayUtils();//签名String sign = tenPayUtils.createSign(paramsMap, "UTF-8");paramsMap.put("sign", sign);//请求报文String requestXml = TenPayUtils.tenPayXmlInfo(paramsMap);//发送微信查询post请求String tenQueryPost = TenPayUtils.httpsRequest(tenpayConfig.getQueryUrl(), "POST", requestXml);TenPayVO tenPayVO = this.tenPayCallBackInfo(tenQueryPost, "xml", "");return tenPayVO;}

实现微信app支付的springboot项目相关推荐

  1. JAVA微信扫码支付及微信App支付开发(模式二)完整功能实现

    一,准备工作 事前申请一个商家版的微信公众号(目前微信支付只有商家版公众号可开通),然后开通微信支付功能,并做相应的配置. 申请开通微信公众号和开通微信支付需要等待审核,一般都5个工作日左右.开通成功 ...

  2. 第三方支付——微信app支付

    微信App支付 前言 本篇文章将结合自己实际开发经验,从一下几个方面介绍微信app支付,什么是微信app支付?支付流程是什么样的? 前期需要准备些什么?结合官方文档和实际代码带大家走流程. 正文 微信 ...

  3. 微信APP支付之IJpay的使用

    写在开始:一个搬砖程序员的随缘记录 微信支付相对其他支付,比如支付宝支付坑比较多.一直报签名失败.签名参数顺序.数据类型,加密类型这些都需要注意,用第三方的比较省心. IJpay介绍: 聚合支付,IJ ...

  4. 微信APP支付申请方法

    2019独角兽企业重金招聘Python工程师标准>>> 目前,全国各大商场.超市.便利店.餐饮业.旅游业.医疗业等等都接入了微信支付,并开通微信公众号线上商城做起了线上推广和销售.微 ...

  5. Unity和AndroidStudio交互制作SDK并和其他的SDK合并(微信APP支付)

    本案例使用的AndroidStudio版本为 171.4408382 Unity版本为 5.2.4f1 如果跟我一样是新手,就请先看我下面这篇文章 https://blog.csdn.net/weix ...

  6. java后台 apiV3 对接微信app支付

    因为项目中需要用到微信支付,这里对自己对接的流程做一个记录 一.接入前准备 1.申请应用appId与商户号,配置apiV3秘钥 2.生成商户证书 首先登录微信商家平台,进入"账户中心–> ...

  7. 微信APP支付的踩坑记录(一):prepay_id 与 prepayid

    最近在做微信APP支付时,发现报下面这个错误: -1 错误 可能的原因:签名错误.未注册APPID.项目设置APPID不正确.注册的APPID与设置的不匹配.其他异常等. 用微信签名校验工具校验签名又 ...

  8. Java对接微信支付实现微信APP支付

    Java对接微信实现微信APP支付 之前对接过第三方的支付方式,也有接入微信jsapi的支付方式,这次项目需求要求对接微信APP支付,找了很多,几乎都没有最新版的微信支付v3的对接相关的详细博客,真的 ...

  9. android微信支付都需要什么意思,Android开发微信APP支付功能的要点小结

    基本概念 包名值得是你APP的包,在创建工程时候设置的,需要在微信支付平台上面设置. 签名指的是你生成APK时候所用的签名文件的md5,去掉:全部小写,需要在微信支付平台上面设置. 调试阶段,签名文件 ...

最新文章

  1. 如何在JavaScript中比较数组?
  2. Maven最全教程,还有哪里对maven不解的地方看过来!
  3. 利用openpyxl,Python对excel读写文件
  4. 数仓中长跳转问题复现及解决方案
  5. 敏捷开发一千零一问系列之三:序言及解决问题的心法(共振)
  6. DeepMind智能体自学跑酷:略显智障,结果尚好
  7. springboot 多环境配置文件
  8. Java游戏开发 —— 扫雷
  9. Eclipse组合KEmulator
  10. 光纤猫可做无线打印服务器吗,光猫自带的天线,这些天线都有什么用呢?是无线功能吗?...
  11. GetWindowRect,GetClientRect,ScreenToClient MoveWindow SetWindowPos 用法说明
  12. 点到线的距离计算公式
  13. fidder无法抓取浏览器Https,提示“证书错误”
  14. [交互问题]XML 解析错误:格式不佳
  15. 知乎网的CSS命名规律研究
  16. 达观数据爱心公益再出发,走进广西桥业小学开展捐书助学活动
  17. Android开发和安全系列工具
  18. 6.1 Python 单分支结构 if语句
  19. 实现一个CAN通讯上位机
  20. SVD奇异值分解 中特征值与奇异值的数学理解与意义

热门文章

  1. 【H.264/AVC视频编解码技术详解】二. 主流视频编码标准的发展
  2. iPad 使用技巧:备忘录
  3. spring boot注解@PostConstruct
  4. 总结 nginx access.log 太大如何清理
  5. shell编程(二)
  6. 基于Axure的跑步软件的界面原型化系统
  7. lg空调代码大全解决_lg空调故障代码是什么意思 lg空调故障代码大全【详解】...
  8. 【前端22_混合开发】介绍、初步认识MUI、UI组件、窗口管理
  9. E4A - 蓝牙串口连接失败的问题
  10. 仿微信、微博发朋友圈,文字+图片+视频