WxPayController
package com.example.demo.com.example.wxPay.controller;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.com.example.task.AjaxResult;
import com.example.demo.com.example.task.IpUtils;
import com.example.demo.com.example.wxPay.entity.RechargeOrder;
import com.example.demo.com.example.wxPay.entity.WxPayBean;
import com.example.demo.com.example.wxPay.entity.WxPayMiniAppPay;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.ijpay.wxpay.model.UnifiedOrderModel;
/**
* 微信支付
*
* @author Administrator
*
*/
@RestController
@RequestMapping("wxPay")
public class WxPayController extends AbstractWxPayApiController {
// 获取微信支付配置
@Autowired
WxPayBean wxPayBean;
private final Logger log = LoggerFactory.getLogger(this.getClass());
// 回调地址
private String notifyUrl;
// 退款回调地址
// private String refundNotifyUrl;
@Override
public WxPayApiConfig getApiConfig() {
WxPayApiConfig apiConfig;
try {
apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBean.getAppId());
} catch (Exception e) {
apiConfig = WxPayApiConfig.builder().appId(wxPayBean.getAppId()).mchId(wxPayBean.getMchId())
.partnerKey(wxPayBean.getPartnerKey()).certPath(wxPayBean.getCertPath())
.domain(wxPayBean.getDomain()).build();
}
notifyUrl = apiConfig.getDomain().concat("/wxPay/payNotify");
// refundNotifyUrl = apiConfig.getDomain().concat("/wxPay/refundNotify");
return apiConfig;
}
/**
* 微信小程序支付
*
*/
@PostMapping("miniAppPay")
public AjaxResult miniAppPay(@Valid WxPayMiniAppPay wxPayMiniAppPay) {
// 获取openId一般情况下用户登录的时候openId是和用户关联的 所以openId可以通过当前的userId去查询openId
String openId = "用户的openId";
String ip = IpUtils.getHostIp();
WxPayApiConfig wxPayApiConfig = getApiConfig();
// 默认金额
BigDecimal orderPrice = new BigDecimal("1");
// 附加参数
String attach = "";
// 商品描述
String body = "";
// 商户订单号例如EE123456789
String out_trade_no = wxPayMiniAppPay.getOrderNum();
// 判断是否为充值订单类型
String orderType = out_trade_no.subSequence(0, 2).toString();
if (orderType.equals("EE")) {
// 根据订单号查询订单我这里就直接初始化实体了
// RechargeOrder rechargeOrder = rechargeOrderService.selectByOrderId(out_trade_no);
RechargeOrder rechargeOrder = new RechargeOrder();
// 订单和支付状态非初始化状态即不允许支付
if (rechargeOrder == null || rechargeOrder.getOrderStatus() != 1 || rechargeOrder.getPayStatus() != 1) {
return AjaxResult.error("订单不存在或不允许支付");
}
// 订单描述
body = "充值订单";
// 订单金额单位是元
orderPrice = rechargeOrder.getOrderPrice();
} else {
return AjaxResult.error("订单类型不存在");
}
Map<String, String> params = UnifiedOrderModel.builder().appid(wxPayApiConfig.getAppId())
.mch_id(wxPayApiConfig.getMchId()).nonce_str(WxPayKit.generateStr()).body(body).attach(attach)
.out_trade_no(out_trade_no)
// 注意 微信单位是分 我的数据库存的是元 需要转换
.total_fee(String.valueOf(orderPrice.multiply(new BigDecimal("100")).intValue())).spbill_create_ip(ip)
.notify_url(notifyUrl).trade_type(TradeType.JSAPI.getTradeType()).openid(openId).build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.pushOrder(false, params);
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
String returnCode = result.get("return_code");
String returnMsg = result.get("return_msg");
if (!WxPayKit.codeIsOk(returnCode)) {
return AjaxResult.error(returnMsg);
}
String resultCode = result.get("result_code");
if (!WxPayKit.codeIsOk(resultCode)) {
return AjaxResult.error(returnMsg);
}
// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
String prepayId = result.get("prepay_id");
Map<String, String> packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayApiConfig.getAppId(), prepayId,
wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
// String jsonStr = JSON.toJSONString(packageParams);
log.info("小程序支付统一下单返回参数:" + packageParams.toString());
return AjaxResult.success(packageParams);
}
/**
* 退款通知
*/
@RequestMapping(value = "/refundNotify")
public String refundNotify(HttpServletRequest request) {
String xmlMsg = HttpKit.readData(request);
log.info("退款通知=" + xmlMsg);
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
String returnCode = params.get("return_code");
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
if (WxPayKit.codeIsOk(returnCode)) {
String reqInfo = params.get("req_info");
String decryptData = WxPayKit.decryptData(reqInfo, getApiConfig().getPartnerKey());
log.info("退款通知解密后的数据=" + decryptData);
// 这里是处理订单信息,例如修改订单状态啥的逻辑,自己编辑
// 发送通知等
Map<String, String> xml = new HashMap<String, String>(2);
xml.put("return_code", "SUCCESS");
xml.put("return_msg", "OK");
return WxPayKit.toXml(xml);
}
return null;
}
/**
* 支付回调异步通知
*/
@RequestMapping(value = "/payNotify")
public String payNotify(HttpServletRequest request) {
String xmlMsg = HttpKit.readData(request);
log.info("支付回调通知=" + xmlMsg);
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
// 支付回调的code
String returnCode = params.get("return_code");
// 支付时间
String payTime = params.get("time_end");
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
// 注意此处签名方式需与统一下单的签名类型一致
if (WxPayKit.verifyNotify(params, getApiConfig().getPartnerKey(), SignType.HMACSHA256)) {
if (WxPayKit.codeIsOk(returnCode)) {
String resultCode = params.get("result_code");
// resultCode为SUCCESS时才代表支付成功
if (WxPayKit.codeIsOk(resultCode)) {
String orderId = params.get("out_trade_no");
// 支付流水
String transactionId = params.get("transaction_id");
// 订单金额(分):将分转化为BigDecimal 元
BigDecimal totalFee = new BigDecimal(params.get("total_fee")).divide(new BigDecimal("100"));
// 更新订单信息
// 判断是否为充值订单
String orderType = orderId.subSequence(0, 2).toString();
if (orderType.equals("EE")) {
// RechargeOrder rechargeOrder = rechargeOrderService.selectByOrderId(orderId);
RechargeOrder rechargeOrder = new RechargeOrder();
// 判断订单是否为初始化状态,支付金额一致
if (rechargeOrder != null
&& (rechargeOrder.getOrderStatus() == 1 || rechargeOrder.getOrderStatus() == 4)
&& rechargeOrder.getPayStatus() == 1
&& totalFee.compareTo(rechargeOrder.getOrderPrice()) == 0) {
// 修改支付成功状态
try {
// rechargeOrderService.paySuccess(orderId, transactionId, 1);
// 支付成功之后做的处理 我就不贴出来了 一般就是记录一下流水啊 修改订单状态的逻辑
} catch (Exception e) {
log.error("充值订单支付回调异常", e);
}
}
}
}
Map<String, String> xml = new HashMap<String, String>(2);
xml.put("return_code", "SUCCESS");
xml.put("return_msg", "OK");
return WxPayKit.toXml(xml);
}
}
return null;
}
public static void main(String[] args) {
BigDecimal totalFee = new BigDecimal("2536").divide(new BigDecimal("100"));
System.out.println(totalFee);
}
}
WxPayInterceptor 微信支付拦截器
package com.example.demo.com.example.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.example.demo.com.example.wxPay.controller.AbstractWxPayApiController;
import com.ijpay.wxpay.WxPayApiConfigKit;
/**
* @ClassName: WxPayInterceptor
* @Description: 微信支付拦截器
* @author wsj
* @date 2020年11月4日
*
*/
public class WxPayInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object handler) {
if (HandlerMethod.class.equals(handler.getClass())) {
HandlerMethod method = (HandlerMethod) handler;
Object controller = method.getBean();
if (!(controller instanceof AbstractWxPayApiController)) {
throw new RuntimeException("控制器需要继承 AbstractWxPayApiController");
}
WxPayApiConfigKit.setThreadLocalWxPayApiConfig(((AbstractWxPayApiController) controller).getApiConfig());
return true;
}
return false;
}
}
AbstractWxPayApiController
package com.example.demo.com.example.wxPay.controller;
import com.ijpay.wxpay.WxPayApiConfig;
/**
* @author Javen
*/
public abstract class AbstractWxPayApiController {
/**
* 获取微信支付配置
*
* @return {@link WxPayApiConfig} 微信支付配置
*/
public abstract WxPayApiConfig getApiConfig();
}
三个实体bean
package com.example.demo.com.example.wxPay.entity;
import java.math.BigDecimal;
import java.util.Date;
/**
* 充值订单
*
* @author Administrator
*
*/
public class RechargeOrder {
/**
* 订单号
*/
private String orderId;
/**
* 用户id
*/
private Integer userId;
/**
* 订单状态1待处理,2已完成,3处理失败,4已取消,5退款
*/
private Integer orderStatus;
/**
* 订单金额
*/
private BigDecimal orderPrice;
/**
* 能源币数量
*/
private Integer balance;
/**
* 创建时间
*/
private Date createTime;
/**
* 支付状态1待支付2支付成功
*/
private Integer payStatus;
/**
* 订单支付类型1微信2支付宝
*/
private Integer payType;
/**
* 支付时间
*/
private Date payTime;
/**
* 订单支付流水号
*/
private String outTradeNo;
/** 0未删除,1已删除 */
private Integer isDelete;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getOrderStatus() {
return orderStatus;
}
public void setOrderStatus(Integer orderStatus) {
this.orderStatus = orderStatus;
}
public BigDecimal getOrderPrice() {
return orderPrice;
}
public void setOrderPrice(BigDecimal orderPrice) {
this.orderPrice = orderPrice;
}
public Integer getBalance() {
return balance;
}
public void setBalance(Integer balance) {
this.balance = balance;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Integer getPayStatus() {
return payStatus;
}
public void setPayStatus(Integer payStatus) {
this.payStatus = payStatus;
}
public Integer getPayType() {
return payType;
}
public void setPayType(Integer payType) {
this.payType = payType;
}
public Date getPayTime() {
return payTime;
}
public void setPayTime(Date payTime) {
this.payTime = payTime;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public Integer getIsDelete() {
return isDelete;
}
public void setIsDelete(Integer isDelete) {
this.isDelete = isDelete;
}
}
package com.example.demo.com.example.wxPay.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @ClassName: WxPayBean
* @Description: 微信配置 Bean
* @author wsj
* @date 2020年11月4日
*
*/
@Component
@PropertySource("classpath:/wxpay.properties")
@ConfigurationProperties(prefix = "wxpay")
public class WxPayBean {
private String appId;
private String appSecret;
private String mchId;
private String partnerKey;
private String certPath;
private String domain;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getPartnerKey() {
return partnerKey;
}
public void setPartnerKey(String partnerKey) {
this.partnerKey = partnerKey;
}
public String getCertPath() {
return certPath;
}
public void setCertPath(String certPath) {
this.certPath = certPath;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
@Override
public String toString() {
return "WxPayBean [appId=" + appId + ", appSecret=" + appSecret + ", mchId=" + mchId + ", partnerKey="
+ partnerKey + ", certPath=" + certPath + ", domain=" + domain + "]";
}
}
package com.example.demo.com.example.wxPay.entity;
import javax.validation.constraints.NotNull;
public class WxPayMiniAppPay {
@NotNull(message = "请输入正确的订单号")
private String OrderNum;
// 支付类型1微信2支付宝
private Integer type = 1;
public String getOrderNum() {
return OrderNum;
}
public void setOrderNum(String orderNum) {
OrderNum = orderNum;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
}
wxpay.properties
#应用编号
wxpay.appId=wxc*****
#应用秘钥
wxpay.appSecret=****
#商户号
wxpay.mchId=****
#微信的商户秘钥key
wxpay.partnerKey=****
# API 证书中的 p12安装目录
wxpay.certPath=/root/payCert/wechat/apiclient_cert.p12
#应用域名,回调中会使用此参数
wxpay.domain=https://ceshi.wxPay/ceshi
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.15</version>
</dependency>
<!-- IJPay微信支付 https://gitee.com/javen205/IJPay -->
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-WxPay</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>