背景
PC端项目需要实现微信扫码支付功能,申请微信商户号,获取如下参数appId,merchId,key和证书等信息
1. 引入sdk
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
2. Yaml配置
wx-pay:
appId: xxxxxxxxxxxxxxxxx
#证书的位置
certPath: classpath:apiclient_cert.p12
key: xxxxxxxxxxxxxxxx
mchId: xxxxxxxxxxxxxxxx
3. 将证书放在resource目录下,并yaml配置
4. 微信配置文件WxConfig,创建bean对象注入
@Configuration
public class WxPayConfig {
@Value("${wx-pay.appId}")
private String appId;
@Value("${wx-pay.mchId}")
private String mchId;
@Value("${wx-pay.key}")
private String key;
@Value("${wx-pay.certPath}")
private String certPath;
@Bean
public WXPay wxPay() throws Exception {
WXPayConfig payConfig = new WXPayConfig() {
@Override
public String getAppID() {
return appId;
}
@Override
public String getMchID() {
return mchId;
}
@Override
public String getKey() {
return key;
}
@Override
public InputStream getCertStream() {
try {
return resource.getInputStream();
} catch (Exception e) {
throw new RuntimeException("Failed to load certificate", e);
}
}
@Override
public int getHttpConnectTimeoutMs() {
return 0;
}
@Override
public int getHttpReadTimeoutMs() {
return 0;
}
// 根据需要实现其他方法,如设置超时等
};
// 创建WXPay实例,这里假设使用MD5签名
return new WXPay(payConfig, WXPayConstants.SignType.MD5);
}
}
5. 微信支付工具类
public String pay(String title,String orderNo,BigDecimal amount,String notifyUrl) {
try {
//String orderNo= TouUtil.getOrderNo();
Map<String, String> data = new HashMap<String, String>();
data.put("body", title);
data.put("out_trade_no", orderNo);
data.put("fee_type", "CNY");
data.put("total_fee", String.valueOf(NumberUtil.mul(amount,100)));
data.put("spbill_create_ip", "127.0.0.1");
data.put("notify_url", notifyUrl);
data.put("trade_type", "NATIVE");
data.put("product_id", UUID.randomUUID().toString());
// 发起支付请求
Map<String, String> resp = wxPay.unifiedOrder(data);
if ("SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"))) {
//插入记录
return resp.get("code_url");
} else {
logger.info("微信支付错误{}",resp.toString());
throw new RuntimeException("wxpay error");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
6. 支付回调
@RequestMapping("chargeBuyWx")
public String chargeBuyWx(HttpServletRequest request) {
try {
// 解析微信支付回调请求参数
Map<String, String> params = parseXml(request.getInputStream());
boolean verifyResult = wxPay.isPayResultNotifySignatureValid(params);
if (verifyResult) {
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String totalAmount = params.get("total_fee");
logger.info("会员充值回调 {}",outTradeNo);
LambdaQueryWrapper<TnlMoneyDto>wrapper=new LambdaQueryWrapper<>();
wrapper.eq(TnlMoneyDto::getOrderNo,outTradeNo);
wrapper.eq(TnlMoneyDto::getStatus,0);
TnlMoneyDto moneyDto=moneyMapper.selectOne(wrapper);
if(ObjectUtil.isNotEmpty(moneyDto)){
moneyDto.setStatus(1);
moneyMapper.update(moneyDto,wrapper);
//等级处理
LambdaQueryWrapper<UserDto>queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(UserDto::getId,moneyDto.getUId());
UserDto userDto=userMapper.selectOne(queryWrapper);
BigDecimal money= NumberUtil.add(userDto.getScore(), Convert.toBigDecimal(totalAmount).divide(new BigDecimal(100)));
userDto.setScore(money);
logger.info("会员充值回调 {}",money);
userMapper.update(userDto,queryWrapper);
}
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
}else {
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名验证失败]]></return_msg></xml>";
}
}catch (Exception e) {
throw new RuntimeException(e);
}
}
7. 解析微信回调工具
private Map<String, String> parseXml(InputStream inputStream) throws Exception {
// 使用try-with-resources确保inputStream被关闭
try (InputStream is = inputStream;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
String xml = outputStream.toString("utf-8");
return WXPayUtil.xmlToMap(xml);
}
}