流程
https://www.cnblogs.com/xyt-0412/p/4953748.html
集成工具包
https://github.com/Wechat-Group/weixin-java-tools
https://github.com/Wechat-Group/weixin-java-tools/wiki/%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98
微信支付接口调试工具(调试sign是否正确即可)
https://pay.weixin.qq.com/wiki/tools/signverify/
第一步 , 添加依赖
com.github.binarywang
weixin-java-pay
3.2.0
第二步, 在application.yml中配置参数
wx:
pay:
appId: wxd7b0c5e79c63c714 #微信公众号或者小程序等的appid
mchId: 1513914421 #微信支付商户号
mchKey: 1wRzyIaYNlFZRiu307Ih4Nc1QJU5ac7u #微信支付商户密钥
keyPath: /usr/dev/tomcat8/webapps/cert/apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
第三步 , config目录
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* wxpay pay properties
*
* @author Binary Wang
*/
@Data
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties {
/**
* 设置微信公众号或者小程序等的appid
*/
private String appId;
/**
* 微信支付商户号
*/
private String mchId;
/**
* 微信支付商户密钥
*/
private String mchKey;
/**
* apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
*/
private String keyPath;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,
ToStringStyle.MULTI_LINE_STYLE);
}
}
第四步,添加注入
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
/**
* @author Binary Wang
*/
@Configuration
@ConditionalOnClass(WxPayService.class)
@EnableConfigurationProperties(WxPayProperties.class)
public class WxPayConfiguration {
private WxPayProperties properties;
@Autowired
public WxPayConfiguration(WxPayProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public WxPayService wxService() {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
// payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));
// payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}
第五步 , 统一下单
@Override
@Transactional
public WxPayAppOrderResult wechatpay(CreatePayOrderRequest orderRequest) {
PayOrder order = getPayOrder(orderRequest);
logger.info("调用微信支付.订单详情:"+order.toString());
try {
WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
request.setBody("安保费用支付");
request.setOutTradeNo(order.getUuid());
request.setFeeType("CNY");
request.setTotalFee(BaseWxPayRequest.yuanToFen("1"));//元转成分
request.setSpbillCreateIp("47.99.172.109");
request.setNotifyUrl("http://47.99.172.109:8080/anbao/order/wechatpaySuccessCallBack");
request.setSignType(WxPayConstants.SignType.MD5);
request.setTradeType(WxPayConstants.TradeType.APP);
WxPayAppOrderResult wxPayAppOrderResult = wxPayService.createOrder(request);
logger.info("封装返回参数:"+wxPayAppOrderResult.toString());
return wxPayAppOrderResult;
} catch (Exception e) {
logger.error("微信支付失败!订单号:"+ order.getUuid()+",原因:"+ e.getMessage());
throw new BusinessException(CommonErrorResult.BUSINESS_ERROR, "支付失败");
}
}
第六步, 成功回调
@Override
@Transactional
public String wechatPaySuccess(HttpServletRequest request, HttpServletResponse response) {
logger.info("微信订单支付成功回调");
// 解析结果存储在HashMap
try {
String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);
// 结果正确
String orderId = result.getOutTradeNo();
//String tradeNo = result.getTransactionId();
//String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
//自己处理订单的业务逻辑,需要判断订单是否已经支付过,否则可能会重复调用
PayOrder payOrder = baseRepository.getObjById(PayOrder.class,orderId);
//更新订单支付状态
...
return WxPayNotifyResponse.success("处理成功!");
} catch (Exception e) {
e.printStackTrace();
logger.error("微信回调结果异常,异常原因:"+e.getMessage());
return WxPayNotifyResponse.fail(e.getMessage());
}
}
/**
* 生成医生二维码
* @param doctorId
* @return
*/
public static String createQRPic(String doctorId) {
String barCodeUrl = "";
String tokenRequest = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APP_ID&secret=APP_SECRET"
.replace("APP_ID", AppConstants.WX_CONFIG.APP_ID)
.replace("APP_SECRET", AppConstants.WX_CONFIG.APP_SECRET);
String tokenResponse = HttpUtil.get(tokenRequest);
JSONObject tokenJson = JSON.parseObject(tokenResponse);
if (tokenJson != null) {
String accessToken = tokenJson.getString("access_token");
if (StringUtil.isNotEmpty(accessToken)) {
String ticketUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;
String data = "{\"action_name\": \"QR_LIMIT_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": " + doctorId + "}}}";
String ticketResponse = null;
try {
ticketResponse = HttpUtil.post(ticketUrl, data);
JSONObject ticketJson = JSON.parseObject(ticketResponse);
if(null != ticketJson) {
String ticket = ticketJson.getString("ticket");
barCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return barCodeUrl;
}
方案
在服务端配置接口,在微信公众平台(基本配置->服务器配置)配置扫码回调接口即可
代码
/**
* 生成医生二维码
* @param doctorId
* @return
*/
public static String createQRPic(String doctorId) {
String barCodeUrl = "";
String tokenRequest = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APP_ID&secret=APP_SECRET"
.replace("APP_ID", AppConstants.WX_CONFIG.APP_ID)
.replace("APP_SECRET", AppConstants.WX_CONFIG.APP_SECRET);
String tokenResponse = HttpUtil.get(tokenRequest);
JSONObject tokenJson = JSON.parseObject(tokenResponse);
if (tokenJson != null) {
String accessToken = tokenJson.getString("access_token");
if (StringUtil.isNotEmpty(accessToken)) {
String ticketUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;
String data = "{\"action_name\": \"QR_LIMIT_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": " + doctorId + "}}}";
String ticketResponse = null;
try {
ticketResponse = HttpUtil.post(ticketUrl, data);
JSONObject ticketJson = JSON.parseObject(ticketResponse);
if(null != ticketJson) {
String ticket = ticketJson.getString("ticket");
barCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return barCodeUrl;
}
二者不可兼容,如果想兼容,则
1.保持开发者模式开启(用于扫码关注回调,此时微信自定义菜单会失效)
2.用第三方托管自定义菜单,在第三方里设置菜单url
需要再商户平台API安全中下载证书,放在服务器根目录下
https://www.sohu.com/a/234912109_100142931