申请测试号链接
申请后得到appID和appsecret
配置:
需要可以外网访问的域名,没有的话可以搞个内网穿透
使用第三方的SDK进行开发,避免重复造轮子,微信的开发文档如下:
第三方SDK
流程:构造链接,获取到AccessToken,拿到openId
配置WxMpServiceImpl
@Component public class WechatMpConfig { @Autowired private WechatAccountConfig wechatAccountConfig; @Bean public WxMpService wxMpService() { WxMpService wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(wxMpConfigStorage()); return wxMpService; } @Bean public WxMpConfigStorage wxMpConfigStorage() { WxMpInMemoryConfigStorage wxMpConfigStorage = new WxMpInMemoryConfigStorage(); wxMpConfigStorage.setAppId(wechatAccountConfig.getMpAppId()); wxMpConfigStorage.setSecret(wechatAccountConfig.getMpAppSecret()); return wxMpConfigStorage; } }
接口调用
//跳转到授权链接 @GetMapping("/authorize") public String authorize( @ApiParam(name = "returnUrl", value = "跳转链接")@RequestParam("returnUrl") String returnUrl) { //1. 配置 //2. 调用方法 String url = projectUrlConfig.getWechatMpAuthorize() + "/wechat/userInfo"; String redirectUrl = wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_BASE, URLEncoder.encode(returnUrl)); return "redirect:" + redirectUrl; } //确定授权后的处理方法 @GetMapping("/userInfo") public String userInfo(@ApiParam(name = "code", value = "code")@RequestParam("returnUrl") String code, @ApiParam(name = "returnUrl", value = "跳转链接")@RequestParam("returnUrl") String returnUrl ){ WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code); } catch (WxErrorException e) { log.error("[微信页面授权失败]{}",e); throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(),e.getError().getErrorMsg()); } String openId = wxMpOAuth2AccessToken.getOpenId(); return "redirect:" + returnUrl + "openId = " + openId; }
微信开放平台 ,需要自己去申请一个应用,审核通过后得到
生成二维码,拿到openId
第三方SDK配置WxMpServiceImpl
@Component public class WechatOpenConfig { @Autowired private WechatAccountConfig accountConfig; @Bean public WxMpService wxOpenService() { WxMpService wxOpenService = new WxMpServiceImpl(); wxOpenService.setWxMpConfigStorage(wxOpenConfigStorage()); return wxOpenService; } @Bean public WxMpConfigStorage wxOpenConfigStorage() { WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage(); wxMpInMemoryConfigStorage.setAppId(accountConfig.getOpenAppId()); wxMpInMemoryConfigStorage.setSecret(accountConfig.getOpenAppSecret()); return wxMpInMemoryConfigStorage; }
2. 接口调用
//跳转二维码页面,生成二维码 @GetMapping("/qrAuthorize") public String qrAuthorize(@RequestParam("returnUrl") String returnUrl) { String url = projectUrlConfig.getWechatOpenAuthorize() + "/sell/wechat/qrUserInfo"; String redirectUrl = wxOpenService.buildQrConnectUrl(url, WxConsts.QrConnectScope.SNSAPI_LOGIN, URLEncoder.encode(returnUrl)); return "redirect:" + redirectUrl; } //扫码后逻辑登陆 @GetMapping("/qrUserInfo") public String qrUserInfo(@RequestParam("code") String code, @RequestParam("state") String returnUrl) { WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { wxMpOAuth2AccessToken = wxOpenService.oauth2getAccessToken(code); } catch (WxErrorException e) { log.error("【微信网页授权】{}", e); throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg()); } log.info("wxMpOAuth2AccessToken={}", wxMpOAuth2AccessToken); String openId = wxMpOAuth2AccessToken.getOpenId(); return "redirect:" + returnUrl + "?openid=" + openId; } ```
微信支付SDK ,这个SDK是上方的SDK对支付的进一步封装
微信支付官方开发文档
需要申请一个具有商家资质的账号,等到mchId和mchKey
配置BestPayServiceImpl
@Component public class WechatPayConfig { @Autowired private WechatAccountConfig wechatAccountConfig; @Bean public BestPayServiceImpl bestPayService(){ BestPayServiceImpl bestPayService = new BestPayServiceImpl(); bestPayService.setWxPayH5Config(wxPayH5Config()); return bestPayService; } @Bean public WxPayH5Config wxPayH5Config(){ WxPayH5Config wxPayH5Config = new WxPayH5Config(); wxPayH5Config.setAppId(wechatAccountConfig.getMpAppId()); wxPayH5Config.setAppSecret(wechatAccountConfig.getMpAppSecret()); wxPayH5Config.setMchId(wechatAccountConfig.getMchId()); wxPayH5Config.setMchKey(wechatAccountConfig.getMchKey()); wxPayH5Config.setKeyPath(wechatAccountConfig.getKeyPath()); wxPayH5Config.setNotifyUrl(wechatAccountConfig.getNotifyUrl()); return wxPayH5Config; } }
编写Service
@Service @Slf4j public class PayServiceImpl implements PayService { private static final String ORDER_NAME = "微信点餐订单"; @Autowired private BestPayServiceImpl bestPayService; @Autowired private OrderService orderService; //发起支付 @Override public PayResponse create(OrderDTO orderDTO) { PayRequest payRequest = new PayRequest(); payRequest.setOpenid(orderDTO.getBuyerOpenid()); payRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue()); payRequest.setOrderId(orderDTO.getOrderId()); payRequest.setOrderName(ORDER_NAME); payRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5); log.info("【微信支付】发起支付, request={}", JsonUtil.toJson(payRequest)); PayResponse payResponse = bestPayService.pay(payRequest); log.info("【微信支付】发起支付, response={}", JsonUtil.toJson(payResponse)); return payResponse; } //支付后微信异步通知,告之微信支付结果 @Override public PayResponse notify(String notifyData) { PayResponse payResponse = bestPayService.asyncNotify(notifyData); log.info("【微信支付】异步通知, payResponse={}", JsonUtil.toJson(payResponse)); //查询订单 OrderDTO orderDTO = orderService.findOne(payResponse.getOrderId()); //判断订单是否存在 if (orderDTO == null) { log.error("【微信支付】异步通知, 订单不存在, orderId={}", payResponse.getOrderId()); throw new SellException(ResultEnum.ORDER_NOT_EXIST); } //判断金额是否一致(0.10 0.1) if (!MathUtil.equals(payResponse.getOrderAmount(), orderDTO.getOrderAmount().doubleValue())) { log.error("【微信支付】异步通知, 订单金额不一致, orderId={}, 微信通知金额={}, 系统金额={}", payResponse.getOrderId(), payResponse.getOrderAmount(), orderDTO.getOrderAmount()); throw new SellException(ResultEnum.WXPAY_NOTIFY_MONEY_VERIFY_ERROR); } //修改订单的支付状态 orderService.paid(orderDTO); return payResponse; } //退款 @Override public RefundResponse refund(OrderDTO orderDTO) { RefundRequest refundRequest = new RefundRequest(); refundRequest.setOrderId(orderDTO.getOrderId()); refundRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue()); refundRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5); log.info("【微信退款】request={}", JsonUtil.toJson(refundRequest)); RefundResponse refundResponse = bestPayService.refund(refundRequest); return refundResponse; } }
在公众号管理设置好消息模版
编写service
@Override public void orderStatus(OrderDTO orderDTO) { WxMpTemplateMessage templateMessage = new WxMpTemplateMessage(); templateMessage.setTemplateId(wechatAccountConfig.getTemplateId().get("orderStatus")); templateMessage.setToUser(orderDTO.getBuyerOpenid()); List<WxMpTemplateData> data = Arrays.asList( new WxMpTemplateData("first","111"), new WxMpTemplateData("keyword1", "微信点餐"), new WxMpTemplateData("keyword2", "18868812345"), new WxMpTemplateData("keyword3", orderDTO.getOrderId()), new WxMpTemplateData("keyword4", orderDTO.getOrderStatusEnum().getMessage()), new WxMpTemplateData("keyword5", "¥" + orderDTO.getOrderAmount()), new WxMpTemplateData("remark", "欢迎再次光临!") ); try{ wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage); }catch (WxErrorException e){ log.error("【微信模版消息】发送失败"); } } }