首先,参考文档:
【微信支付】H5支付开发文档
Java 后端微信支付demo
- 引入jar包
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
- 配置申请好的AppId,MchId, Key
这里只需要统一下单、支付回调以及查询订单,所以不需要加载证书
import com.github.wxpay.sdk.WXPayConfig;
import java.io.InputStream;
/** 配置我们自己的信息 */
public class WxPayConfig implements WXPayConfig {
// /** 加载证书 这里证书需要到微信商户平台进行下载*/
// private byte [] certData;
//
// public WxPayConfig() throws Exception{
// InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("../cert/pay/apiclient_cert.p12");
// this.certData = IOUtils.toByteArray(certStream);
// certStream.close();
// }
/** 设置我们自己的appid
* 商户号
* 秘钥
* */
@Override
public String getAppID() {
return "###AppId";
}
@Override
public String getMchID() {
return "###MchId";
}
@Override
public String getKey() {
return "###Key";
}
@Override
public InputStream getCertStream() {
return null;
}
@Override
public int getHttpConnectTimeoutMs() {
return 0;
}
@Override
public int getHttpReadTimeoutMs() {
return 0;
}
}
- 统一下单接口示例:
// 微信支付下单
@PreAuthorize("@el.check('anonymous')") // 匿名访问
@PostMapping("/prePay")
public ResponseEntity placeOrder(HttpServletRequest request, @RequestBody Map params) throws Exception {
// 保存订单并返回订单号 shopOrderDTO.getId()
// 处理请求参数
WxPayConfig wxPayConfig = new WxPayConfig();
WXPay wxPay = new WXPay(wxPayConfig);
String url = "###公网地址";
String notifyUrl = url + "/payReturn"; // 微信支付回调地址,详情参考微信官方文档要求
Map<String,String> data = new HashMap<>();
data.put("out_trade_no", shopOrderDTO.getId()+""); //订单编号
data.put("total_fee",params.get("total_free").toString()); //金额(单位为分) int
data.put("attach", new JSONObject().toJSONString(attach)); //附加数据:{nums:1, device_id:"0x234143", store_id:10000000}
data.put("appid",wxPayConfig.getAppID());
data.put("mch_id",wxPayConfig.getMchID());
data.put("trade_type","MWEB"); // h5支付固定写法
data.put("device_info","WEB"); // h5支付固定写法
data.put("notify_url",notifyUrl);
data.put("spbill_create_ip", IPUtil.getIPAddress(request));
data.put("fee_type","CNY");
data.put("body","###支付信息描述");
data.put("nonce_str", WXPayUtil.generateNonceStr());
data.put("scene_info", "###参考官方文档");
// 生成签名
String s = WXPayUtil.generateSignature(data, wxPayConfig.getKey());
data.put("sign",s);
// 发起下单请求
Map<String, String> respData = wxPay.unifiedOrder(data);
// 处理下单结果
if (respData.get("return_code").equals("SUCCESS")){
if (respData.get("result_code").equals("SUCCESS")) {
respData.put("out_trade_no", shopOrderDTO.getId()+"");
return new ResponseEntity<>(respData, HttpStatus.OK);
} else {
// 下单失败的处理 如保存日志
throw new Exception(respData.get("err_code_des"));
}
} else {
// 下单失败的处理 如保存日志
throw new Exception(respData.get("return_msg"));
}
}
- 支付回调接口
// 微信支付回调
@PreAuthorize("@el.check('anonymous')")
@RequestMapping("/payReturn")
public String payReturn(HttpServletRequest request, HttpServletResponse response) throws Exception {
// logger.info("微信支付回调:");
WxPayConfig wxPayConfig = new WxPayConfig();
WXPay wxPay = new WXPay(wxPayConfig);
// 接收请求参数
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
String xml = new String(outSteam.toByteArray(), "utf-8");
// 转为Map
Map<String, String> params = WXPayUtil.xmlToMap(xml);
outSteam.close();
inStream.close();
// 验证签名
if (wxPay.isResponseSignatureValid(params)) {
if (params.get("return_code").equals("FAIL")) {
shopLogService.anonymousCreate(shopLogService.getShopLog(null, null, "支付发起失败",params.get("return_msg") + "" ));
} else if (params.get("return_code").equals("SUCCESS")){
if (params.get("result_code").equals("FAIL")) {
// 支付失败
} else if (params.get("result_code").equals("SUCCESS")) {
// 查询订单,将支付返回结果与订单保存信息对比
ShopOrderDTO orderDTO = shopOrderService.findById(Long.valueOf(params.get("out_trade_no")));
// 判断金额、订单支付状态、支付结果
if (orderDTO.getAmount() == Integer.valueOf(params.get("total_fee")) && orderDTO.getState() == 1
&& !StringUtils.isBlank(params.get("transaction_id"))) {
// 修改订单状态为已支付 省略
return "<xml>\n" +
" <return_code><![CDATA[SUCCESS]]></return_code>\n" +
" <return_msg><![CDATA[OK]]></return_msg>\n" +
"</xml>";
} else if (StringUtils.isBlank(params.get("transaction_id"))){
// 支付ID为空
} else if (orderDTO.getState() == 0){
// 订单状态为已支付
} else if (orderDTO.getAmount() != Integer.valueOf(params.get("total_fee"))){
// 支付金额与订单金额不相等
}
}
}
}
return "";
}
- 查询订单接口
// 微信支付查询 参数是订单id
@PreAuthorize("@el.check('anonymous')")
@RequestMapping("/paySearch")
public Map paySearch(String id) throws Exception {
// 查询订单
ShopOrderDTO orderDTO = shopOrderService.findById(Long.valueOf(id));
// 如果订单已支付且支付id不为空,可以直接返回结果
if (orderDTO.getState() == 0 && !StringUtils.isBlank(orderDTO.getPayId())) {
Map<String, String> result = new HashMap<>();
result.put("return_code", "SUCCESS");
result.put("result_code", "SUCCESS");
result.put("trade_state", "SUCCESS");
return result;
} else {
// 处理参数
WxPayConfig wxPayConfig = new WxPayConfig();
WXPay wxPay = new WXPay(wxPayConfig);
Map<String,String> data = new HashMap<>();
data.put("out_trade_no", id); //订单编号
data.put("appid",wxPayConfig.getAppID());
data.put("mch_id",wxPayConfig.getMchID());
data.put("nonce_str", WXPayUtil.generateNonceStr());
// 签名
String s = WXPayUtil.generateSignature(data, wxPayConfig.getKey());
data.put("sign",s);
// 发起查询
Map<String, String> result = wxPay.orderQuery(data);
// 如果用户已支付
if (result.get("return_code").equals("SUCCESS") && result.get("result_code").equals("SUCCESS") && result.get("trade_state").equals("SUCCESS")) {
// 修改订单支付状态和支付id
}
return result;
}
}