一:java配置
二:工具类:获取本地IP与Enum类 与订单支付返回数据
1: 获取本地IP工具类
2:订单 Enum类
package com.io.common.enums;
public enum OrderStatusEnum {
CANCEL(0,"已取消"),
NOT_YET_SHIPPED(1,"待支付"),
PART_OF_THE_SHIPMENT(2,"待发货"),
WAIT_RECEIVING(3,"待收货"),
ACHIEVE(4,"已完成"),
;
private Integer key;
private String desc;
OrderStatusEnum(Integer key, String desc){
this.key = key;
this.desc = desc;
}
public Integer getKey() {
return key;
}
public String getDesc() {
return desc;
}
}
3:支付方式Enum类
package com.io.common.enums;
public enum PayTypeEnum {
WX_PAY(1, "微信支付"),
;
private Integer key;
private String desc;
PayTypeEnum(Integer key, String desc) {
this.key = key;
this.desc = desc;
}
public Integer getKey() {
return key;
}
public String getDesc() {
return desc;
}
public static String getDesc(Integer key) {
for (PayTypeEnum c : PayTypeEnum.values()) {
if (c.key.equals(key)) {
return c.getDesc();
}
}
return null;
}
}
4:微信支付form提交数据
package com.io.order.form;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author ts
* @version 1.0
* @date 2022/08/05
*/
@Data
public class WxPayForm {
private Integer orderId;
@ApiModelProperty("订单号")
private String orderNo;
@ApiModelProperty("支付订单号")
private String orderPayNo;
@ApiModelProperty("实际支付金额")
private BigDecimal payAmount;
}
5:微信支付订单返回数据
package com.io.order.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class AfterPayVO {
@ApiModelProperty("timeStamp")
private String timeStamp;
@ApiModelProperty("nonceStr")
private String nonceStr;
@ApiModelProperty("packageValue")
private String packageValue;
@ApiModelProperty("signType")
private String signType;
@ApiModelProperty("paySign")
private String paySign;
}
三:service与controller
1:支付 service类
package com.io.order.service;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.io.order.form.WxPayForm;
import com.io.order.vo.AfterPayVO;
import javax.servlet.http.HttpServletResponse;
public interface PayService {
/**
* 微信支付
* @param form 订单数据
* @param userId // 用户id
* @param wxId // 微信用户id
* @return
* @throws
*/
AfterPayVO pay(WxPayForm form, String userId,Integer wxId) throws WxPayException;
/**
* 微信支付回调
* @param appid
* @param xmlData
* @param response
* @throws Exception
*/
void payNotify(String appid, String xmlData, HttpServletResponse response) throws Exception;
}
2:支付 service类实现
package com.io.order.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.io.common.enums.OrderStatusEnum;
import com.io.common.enums.PayTypeEnum;
import com.io.entity.WxUserEntity;
import com.io.exception.RRException;
import com.io.order.config.WxPayProperties;
import com.io.order.dao.OrderDao;
import com.io.order.entity.OrderEntity;
import com.io.order.form.WxPayForm;
import com.io.order.service.PayService;
import com.io.order.vo.AfterPayVO;
import com.io.order.vo.RefundVO;
import com.io.service.WxUserService;
import com.io.util.ConvertUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.time.LocalDateTime;
import java.util.Objects;
@Service
@Slf4j
public class PayServiceImpl implements PayService {
@Autowired
private WxUserService wxUserService;
@Value("${he.wx.appid}")
private String wxAppid;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public AfterPayVO pay(WxPayForm form, String userId, Integer wxId) throws WxPayException {
// 查询根据微信id(存微信用户表的id)查询MySQL数据库获取当前用户的微信数据
WxUserEntity byId = wxUserService.getById(wxId);
if (Objects.isNull(byId)){
log.info("微信支付用户wxId:" + wxId);
throw new RRException("无该微信用户");
}
WxPayService wxPayService = this.getWxPayService(wxAppid);
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
orderRequest.setBody("商品付款");
orderRequest.setOutTradeNo(form.getOrderPayNo());
orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(form.getPayAmount().toString()));//元转成分
orderRequest.setOpenid(byId.getXwOpenId()); // 支付微信用户 微信openId
orderRequest.setSpbillCreateIp(IpUtils.getAddrIp()); // 本地ip设置
orderRequest.setSpbillCreateIp("114.55.114.66");
orderRequest.setNotifyUrl(String.format(properties.getNotifyUrl(), "payNotify", byId.getXwOpenId())); // 支付回调路径与参数拼接设置
// 支付方式
orderRequest.setTradeType("JSAPI");
orderRequest.setAppid(wxAppid);
Object result = wxPayService.createOrder(orderRequest);
AfterPayVO afterPayVO = ConvertUtils.sourceToTarget(result, AfterPayVO.class);
return afterPayVO;
}
@Override
public void payNotify(String appid, String xmlData, HttpServletResponse response) throws Exception {
WxPayService wxPayService = this.getWxPayService(appid);
final WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
log.info("支付订单号:" + notifyResult.getOutTradeNo());
// 小程序支付成功后回调这个接口 后的订单业务逻辑 (请根据项目来编写)
LambdaQueryWrapper<OrderEntity> lambdaQueryWrapper =new LambdaQueryWrapper<OrderEntity>();
lambdaQueryWrapper.eq(OrderEntity::getOrderPayNo,notifyResult.getOutTradeNo());
OrderEntity orderEntity = orderDao.selectOne(lambdaQueryWrapper);
//订单状态
if (OrderStatusEnum.NOT_YET_SHIPPED.getKey().equals(orderEntity.getOrderStatus())){
orderEntity.setOrderStatus(OrderStatusEnum.PART_OF_THE_SHIPMENT.getKey());
orderEntity.setPaymentType(PayTypeEnum.WX_PAY.getKey());
orderEntity.setPaymentTime(LocalDateTime.now());
orderDao.updateById(orderEntity);
}
//回复微信防止重复回调
StringBuilder resXml = new StringBuilder();
resXml.append("<xml>");
resXml.append("<return_code><![CDATA[SUCCESS]]></return_code>");
resXml.append("<return_msg><![CDATA[OK]]></return_msg>");
resXml.append("</xml>");
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.toString().getBytes());
out.flush();
out.close();
}
/** 获取商户号配置并生成 WxPayService
* getWxPayService
* @param appid
* @return
*/
private WxPayService getWxPayService(String appid){
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(appid);
payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}
3: Controller类
package com.io.order.controller;
import com.io.base.BaseController;
import com.io.order.service.PayService;
import com.io.util.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/pay")
@Api(tags = "支付接口")
@Slf4j
public class PayController{
@Autowired
private PayService payService;
@PostMapping("/payNotify/{appid}")
@ApiOperation("支付回调")
public R payNotify(@PathVariable String appid, @RequestBody String xmlData, HttpServletResponse response) throws Exception {
payService.payNotify(appid, xmlData, response);
return R.ok();
}
三:小程序调用 支付接口
注:res.data.purchase 是先走下单逻辑(去后台下单并且调用了 支付接口)
返回参数: AfterPayVO类;
小程序前端所用到的参数是 订单支付返回的参数
wx.requestPayment({
timeStamp: res.data.purchase.timeStamp,
nonceStr: res.data.purchase.nonceStr,
package: res.data.purchase.packageValue,
signType: 'MD5',
paySign: res.data.purchase.paySign,
success (res) {
支付成功
},
fail (res) {
支付取消或失败
}
})
2: 开发工具中测试支付接口 所展示的样子
3:正式环境样式