一、先去微信申请相应的appid等,然后在yml文件增加相应配置

pay:
  wxpay:
    appID: ******
    mchID: *****
    key: *****
    notifyUrl: *****
    appSecret: *****

建立配置类:

@ConfigurationProperties(prefix = "pay.wxpay")
public class MyWXPayConfig implements WXPayConfig {private String appSecret;/** 公众账号ID */private String appID;/** 商户号 */private String mchID;/** API 密钥 */private String key;/** API 沙箱环境密钥 */private String sandboxKey;/** API证书绝对路径 */private String certPath;/** 退款异步通知地址 */private String notifyUrl;private Boolean useSandbox;/** HTTP(S) 连接超时时间,单位毫秒 */private int httpConnectTimeoutMs = 80000;/** HTTP(S) 读数据超时时间,单位毫秒 */private int httpReadTimeoutMs = 100000;/*** 获取商户证书内容** @return 商户证书内容*/@Overridepublic InputStream getCertStream() {File certFile = new File(certPath);InputStream inputStream = null;try {inputStream = new FileInputStream(certFile);} catch (FileNotFoundException e) {e.printStackTrace();}return inputStream;}@Overridepublic String getKey() {if (useSandbox) {return sandboxKey;}return key;}public String getAppSecret() {return appSecret;}public void setAppSecret(String appSecret) {this.appSecret = appSecret;}public String getAppID() {return appID;}public void setAppID(String appID) {this.appID = appID;}public String getMchID() {return mchID;}public void setMchID(String mchID) {this.mchID = mchID;}public String getSandboxKey() {return sandboxKey;}public void setSandboxKey(String sandboxKey) {this.sandboxKey = sandboxKey;}public String getCertPath() {return certPath;}public void setCertPath(String certPath) {this.certPath = certPath;}public String getNotifyUrl() {return notifyUrl;}public void setNotifyUrl(String notifyUrl) {this.notifyUrl = notifyUrl;}public Boolean getUseSandbox() {return useSandbox;}public void setUseSandbox(Boolean useSandbox) {this.useSandbox = useSandbox;}public int getHttpConnectTimeoutMs() {return httpConnectTimeoutMs;}public void setHttpConnectTimeoutMs(int httpConnectTimeoutMs) {this.httpConnectTimeoutMs = httpConnectTimeoutMs;}public int getHttpReadTimeoutMs() {return httpReadTimeoutMs;}public void setHttpReadTimeoutMs(int httpReadTimeoutMs) {this.httpReadTimeoutMs = httpReadTimeoutMs;}public void setKey(String key) {this.key = key;}}

二、建立生成支付二维码的类:

public class PayUtil {/*** 根据url生成二位图片对象** @param codeUrl* @return* @throws WriterException*/public static BufferedImage getQRCodeImge(String codeUrl) throws WriterException {Map<EncodeHintType, Object> hints = new Hashtable();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);hints.put(EncodeHintType.CHARACTER_SET, "UTF8");int width = 256;BitMatrix bitMatrix = (new MultiFormatWriter()).encode(codeUrl, BarcodeFormat.QR_CODE, width, width, hints);BufferedImage image = new BufferedImage(width, width, 1);for(int x = 0; x < width; ++x) {for(int y = 0; y < width; ++y) {image.setRGB(x, y, bitMatrix.get(x, y) ? -16777216 : -1);}}return image;}
}

三、建立服务类

/*** 对WXPay的简单封装,处理支付密切相关的逻辑.* @author wangCJ**/
public class WXPayClient extends WXPay {/** 密钥算法 */private static final String ALGORITHM = "AES";/** 加解密算法/工作模式/填充方式 */private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS5Padding";/** 用户支付中,需要输入密码 */private static final String ERR_CODE_USERPAYING = "USERPAYING";private static final String ERR_CODE_AUTHCODEEXPIRE = "AUTHCODEEXPIRE";/** 交易状态: 未支付 */private static final String TRADE_STATE_NOTPAY = "NOTPAY";/** 用户输入密码,尝试30秒内去查询支付结果 */private static Integer remainingTimeMs = 10000;private WXPayConfig config;public WXPayClient(WXPayConfig config, WXPayConstants.SignType signType, boolean useSandbox) {super(config, signType, useSandbox);this.config = config;}/**** 刷卡支付** 对WXPay#microPay(Map)增加了当支付结果为USERPAYING时去轮询查询支付结果的逻辑处理** 注意:该方法没有处理return_code=FAIL的情况,暂时不考虑网络问题,这种情况直接返回错误** @param reqData* @return* @throws Exception*/public Map<String, String> microPayWithPOS(Map<String, String> reqData) throws Exception {// 开始时间(毫秒)long startTimestampMs = System.currentTimeMillis();Map<String, String> responseMapForPay = super.microPay(reqData);// // 先判断 协议字段返回(return_code),再判断 业务返回,最后判断 交易状态(trade_state)// 通信标识,非交易标识String returnCode = responseMapForPay.get("return_code");if (WXPayConstants.SUCCESS.equals(returnCode)) {String errCode = responseMapForPay.get("err_code");// 余额不足,信用卡失效if (ERR_CODE_USERPAYING.equals(errCode) || "SYSTEMERROR".equals(errCode) || "BANKERROR".equals(errCode)) {Map<String, String> orderQueryMap = null;Map<String, String> requestData = new HashMap<>();requestData.put("out_trade_no", reqData.get("out_trade_no"));// 用户支付中,需要输入密码或系统错误则去重新查询订单API err_code, result_code, err_code_des// 每次循环时的当前系统时间 - 开始时记录的时间 > 设定的30秒时间就退出while (System.currentTimeMillis() - startTimestampMs < remainingTimeMs) {// 商户收银台得到USERPAYING状态后,经过商户后台系统调用【查询订单API】查询实际支付结果。orderQueryMap = super.orderQuery(requestData);String returnCodeForQuery = orderQueryMap.get("return_code");if (WXPayConstants.SUCCESS.equals(returnCodeForQuery)) {// 通讯成功String tradeState = orderQueryMap.get("trade_state");if (WXPayConstants.SUCCESS.equals(tradeState)) {// 如果成功了直接将查询结果返回return orderQueryMap;}// 如果支付结果仍为USERPAYING,则每隔5秒循环调用【查询订单API】判断实际支付结果Thread.sleep(1000);}}// 如果用户取消支付或累计30秒用户都未支付,商户收银台退出查询流程后继续调用【撤销订单API】撤销支付交易。String tradeState = orderQueryMap.get("trade_state");if (TRADE_STATE_NOTPAY.equals(tradeState) || ERR_CODE_USERPAYING.equals(tradeState) || ERR_CODE_AUTHCODEEXPIRE.equals(tradeState)) {Map<String, String> reverseMap = this.reverse(requestData);String returnCodeForReverse = reverseMap.get("return_code");String resultCode = reverseMap.get("result_code");if (WXPayConstants.SUCCESS.equals(returnCodeForReverse) && WXPayConstants.SUCCESS.equals(resultCode)) {// 如果撤销成功,需要告诉客户端已经撤销订单了responseMapForPay.put("err_code_des", "用户取消支付或尚未支付,后台已经撤销该订单,请重新支付!");}}}}return responseMapForPay;}/*** 从request的inputStream中获取参数* @param request* @return* @throws Exception*/public Map<String, String> getNotifyParameter(HttpServletRequest request) throws Exception {InputStream inputStream = request.getInputStream();ByteArrayOutputStream outSteam = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length = 0;while ((length = inputStream.read(buffer)) != -1) {outSteam.write(buffer, 0, length);}outSteam.close();inputStream.close();// 获取微信调用我们notify_url的返回信息String resultXml = new String(outSteam.toByteArray(), "utf-8");Map<String, String> notifyMap = WXPayUtil.xmlToMap(resultXml);return notifyMap;}/*** 解密退款通知** <a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_16&index=11>退款结果通知文档</a>* @return* @throws Exception*/public Map<String, String> decodeRefundNotify(HttpServletRequest request) throws Exception {// 从request的流中获取参数Map<String, String> notifyMap = this.getNotifyParameter(request);String reqInfo = notifyMap.get("req_info");//(1)对加密串A做base64解码,得到加密串Bbyte[] bytes = new BASE64Decoder().decodeBuffer(reqInfo);//(2)对商户key做md5,得到32位小写key* ( key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);SecretKeySpec key = new SecretKeySpec(WXPayUtil.MD5(config.getKey()).toLowerCase().getBytes(), ALGORITHM);cipher.init(Cipher.DECRYPT_MODE, key);//(3)用key*对加密串B做AES-256-ECB解密(PKCS7Padding)// java.security.InvalidKeyException: Illegal key size or default parameters// https://www.cnblogs.com/yaks/p/5608358.htmlString responseXml = new String(cipher.doFinal(bytes),"UTF-8");Map<String, String> responseMap = WXPayUtil.xmlToMap(responseXml);return responseMap;}/*** 获取沙箱环境验签秘钥API* <a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=23_1">获取验签秘钥API文档</a>* @return* @throws Exception*/public Map<String, String> getSignKey() throws Exception {Map<String, String> reqData = new HashMap<>();reqData.put("mch_id", config.getMchID());reqData.put("nonce_str", WXPayUtil.generateNonceStr());String sign = WXPayUtil.generateSignature(reqData, config.getKey(), WXPayConstants.SignType.MD5);reqData.put("sign", sign);String responseXml = this.requestWithoutCert("https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey", reqData,config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs());Map<String, String> responseMap = WXPayUtil.xmlToMap(responseXml);return responseMap;}}

四、建立controller

@RestController
@RequestMapping("/web/wxpay")
public class WXPayPrecreateController {@Autowiredprivate WXPay wxPay;@Autowiredprivate WXPayClient wxPayClient;@Autowiredprivate MyWXPayConfig myWXPayConfig;@Autowiredprivate OrderService orderService;@Autowiredprivate PayWebSocket payWebSocket;/*** 扫码支付 - 统一下单** <a href="https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1">* 扫码支付API</a>*/// @PostMapping("/order")@ApiOperation(value = "createCode", notes = "返回支付二维码")@GetMapping("/common/createCode")public void precreate(Order order, HttpServletResponse response)throws Exception {order = orderService.selectListSelective(order).get(0);Map<String, String> reqData = new HashMap<>();reqData.put("appid", myWXPayConfig.getAppID());reqData.put("mch_id", myWXPayConfig.getMchID());// 订单号reqData.put("out_trade_no", order.getOrderCode());reqData.put("trade_type", "NATIVE");reqData.put("product_id", order.getFilmId() + "");reqData.put("body", "商户下单");// 交易结束时间// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");// reqData.put("time_expire", dateFormat.format(new// Date().getTime()+20*60*1000L));// 订单总金额,单位为分reqData.put("total_fee", order.getOrderPrice().longValue() + "");// APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。reqData.put("spbill_create_ip", "129.226.53.55");// 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。reqData.put("notify_url", myWXPayConfig.getNotifyUrl());// 自定义参数, 可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB"reqData.put("device_info", "WEB");// 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。reqData.put("attach", "");// sign签名reqData.put("sign", myWXPayConfig.getKey());// 随机字符串reqData.put("nonce_str", RandomStringUtils.randomAlphanumeric(10));/*** { code_url=weixin://wxpay/bizpayurl?pr=vvz4xwC, trade_type=NATIVE,* return_msg=OK, result_code=SUCCESS, return_code=SUCCESS,* prepay_id=wx18111952823301d9fa53ab8e1414642725 }*/Map<String, String> responseMap = wxPay.unifiedOrder(reqData);System.out.println(responseMap);String returnCode = responseMap.get("return_code");String resultCode = responseMap.get("result_code");if (WXPayConstants.SUCCESS.equals(returnCode)&& WXPayConstants.SUCCESS.equals(resultCode)) {String prepayId = responseMap.get("prepay_id");String codeUrl = responseMap.get("code_url");BufferedImage image = PayUtil.getQRCodeImge(codeUrl);response.setContentType("image/jpeg");response.setHeader("Pragma", "no-cache");response.setHeader("Cache-Control", "no-cache");// response.setIntHeader("Expires",-1);ImageIO.write(image, "JPEG", response.getOutputStream());}}/**** @param request* @return* @throws Exception*/@RequestMapping("/common/notify")public void precreateNotify(HttpServletRequest request,HttpServletResponse response) throws Exception {Map<String, String> reqData = wxPayClient.getNotifyParameter(request);/*** { transaction_id=4200000138201806180751222945,* nonce_str=aaaf3fe4d3aa44d8b245bc6c97bda7a8, bank_type=CFT,* openid=xxx, sign=821A5F42F5E180ED9EF3743499FBCF13, fee_type=CNY,* mch_id=xxx, cash_fee=1, out_trade_no=186873223426017, appid=xxx,* total_fee=1, trade_type=NATIVE, result_code=SUCCESS,* time_end=20180618131247, is_subscribe=N, return_code=SUCCESS }*/// 特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。boolean signatureValid = wxPay.isPayResultNotifySignatureValid(reqData);if (signatureValid) {/*** 注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。* 推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,* 判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。* 在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。*/String orderCode = reqData.get("out_trade_no");Order order = new Order();order.setOrderCode(orderCode);order = orderService.selectListSelective(order).get(0);if(order.getOrderState()==1){if ("SUCCESS".equals(reqData.get("result_code"))) {order.setOrderState(3);} else {order.setOrderState(2);}orderService.updateByPrimaryKeySelective(order);// 通知浏览器结果payWebSocket.sendMessageTo(JSON.toJSONString(order), orderCode);}}}
}

其中precreate方法就是创建支付二维码的方法,precreateNotify方法为支付过后的回调地址

springboot集成微信支付相关推荐

  1. SpringBoot集成微信支付V3

    河南循中网络科技有限公司 - 精心创作,详细分解,按照步骤,均可成功! 文章目录 吐槽! 此文章包含实现了哪些接口? 学习资料 集成微信支付V3 什么是"商户证书"?什么是&quo ...

  2. SpringBoot集成微信支付微信退款

    微信支付 备注:本次支付接入的是微信支付v2.0版本,其中所有的请求格式均为XML. 如有需求可直接参阅官方文档 https://pay.weixin.qq.com/wiki/doc/api/inde ...

  3. springboot集成微信支付V3 SDK

    微信支付开通支付方法在这里可以参考一下:申请开通微信支付教程_个人怎么申请微信支付_郑鹏川的博客-CSDN博客 因为微信支付回调需要一个外网可访问的地址,我本地调试是采用的内网穿透的方式进行调试的. ...

  4. SpringBoot整合微信支付(Native最详细)

    一.微信支付产品介绍 1.付款码支付 用户展示微信钱包内的 " 付款码 " 给商家,商家扫描后直接完成支付,适用于线下面对面收银的场景. 2.JSAPI支付 线下场所:商户展示一个 ...

  5. springboot集成支付宝支付2.0

    springboot集成微信APP支付V3最新版 流程详解 创建应用 添加支付能力 接口加签 获取证书 集成支付到springboot项目 流程详解 相对于集成微信支付来说,支付宝相对简单些,支付宝对 ...

  6. Android集成微信支付之-天坑

    项目集成微信支付,折腾了三天左右,坑太多,做个简单记录 开通和主要原理不再讲了,参考微信支付官网 截个官网的业务流程图,下面好说明 1 支付结果回调(图中的17步) 支付结果回调,微信官方的说法是: ...

  7. SpringBoot 集成 微信绑定 微信登录

    SpringBoot 集成 微信登录 重写一个认证逻辑 实现AuthenticationProvider import com.hzjtcl.commons.security.service.Hzjt ...

  8. 微信小程序、app集成微信支付

    一.微信小程序支付 开发文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_11&index=2 申请小程序 ...

  9. android微信迁移数据,【CSDN博客迁移】Android集成微信支付之-天坑

    项目集成微信支付,折腾了三天左右,坑太多,做个简单记录 开通和主要原理不再讲了,参考微信支付官网 截个官网的业务流程图,下面好说明 微信支付业务流程.png 1 支付结果回调(图中的17步) 支付结果 ...

最新文章

  1. JavaScript学习笔记(2)——JavaScript和DOM的关系
  2. 第 15 章 Framework Design
  3. 西工大计算机专业课考什么,我的西北工业大学计算机考研之路总结
  4. 建议收藏!近期值得读的 9 篇「对抗样本」最新论文
  5. 【ArcGIS风暴】根据海拔(坡度)范围分级统计土地覆盖的类型和面积(兰州市GlobeLand30m数据为例)
  6. Mysql 中Sql控制流语句_DCL语句/控制流语句
  7. ORACLE中创建如何创建表,并设置结构和默认值
  8. html5 canvas签字,HTML5 canvas实现电子签名
  9. 大话设计模式C++版——代理模式
  10. DPDK 网卡绑定和解绑
  11. 类文件Android 代码混淆 以及 反编译 的实现类文件
  12. 跨域技术-jsonp
  13. Windows 系统中 hosts 文件无法修改的问题
  14. java word 文档合并_[原创]java合并word文件
  15. mysql安全补丁,Oracle发布了本季安全补丁,包含了mysql在内的高危漏洞补丁
  16. Neokylin7安装DM8数据库
  17. python中file是什么意思_Python中的file和open用法详解
  18. SpringData JPA联表分页查询需要使用countQuery属性
  19. idr寄存器、_STM32 GPIO寄存器 IDR ODR BSRR BRR
  20. 名字作诗,让你的名片更具有趣味性和个性化

热门文章

  1. 企信通100短信平台对各个行业短信应用需求分析
  2. 零束科技获得中国信通院“2022 XOps产业生态峰会优秀案例”奖
  3. 数据库自增id,根据当前时间更新插入数据时间
  4. 学计算机文案,对计算机专业的认识及学业规划教学文案.doc
  5. 软件测试面试桌子,软件测试面试题:如何测试电梯/伞/桌子/笔?
  6. 计算机中触发器的原理,计算机的工作原理:RAM系列-触发器
  7. (二十一)【模电】(波形的发生和信号的转换)正弦波振荡电路
  8. Python 信号分析——小波变换
  9. C51 单片机简单实例
  10. php札记,#php学习札记#基本语法