申请测试号链接
申请后得到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("【微信模版消息】发送失败");
}
}
}