网页授权登陆
申请公众号(测试号也行)
申请测试号链接
申请后得到 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("【微信模版消息】发送失败");
}
}
}