目录
废话不多说,先上代码
- application-dev.yml
#支付
pay:
# 支付回调通知地址
notifyUrl: 别想C 填自己的
# 微信App支付
weChat: 别想C 填自己的
# 微信支付AppID
applyAppId: 别想C 填自己的
# 微信支付商户号
mchId: 别想C 填自己的
# 微信支付API密钥
apiV3Key: 别想C 填自己的
# 微信支付证书序列号
mchSerialNo: 别想C 填自己的
# 微信支付证书私钥路径 ssl
privateKeyPath: C:\Users\dzx\Desktop\yiNong\ssl\apiclient_key.pem
# 微信支付接口域名地址
domain: https://api.mch.weixin.qq.com
- QuickStart
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* APP 支付
*/
@Configuration
@Data
public class QuickStart {
/**
* applyAppId
*/
@Value("${pay.weChat.applyAppId}")
private String appid;
/**
* 商户号
*/
@Value("${pay.weChat.mchId}")
private String merchantId;
/**
* 商户API私钥路径
*/
@Value("${pay.weChat.privateKeyPath}")
private String privateKeyPath;
/**
* 商户证书序列号
*/
@Value("${pay.weChat.mchSerialNo}")
private String merchantSerialNumber;
/**
* 商户APIV3密钥
*/
@Value("${pay.weChat.apiV3Key}")
private String apiV3Key;
@Value("${pay.notifyUrl}")
private String notifyUrl;
}
- 接收数据的实体
Resource
import lombok.Data;
@Data
public class Resource {
private String algorithm;
private String ciphertext;
private String associated_data;
private String original_type;
private String nonce;
}
PayNotifyParams
import lombok.Data;
@Data
public class PayNotifyParams {
private String id;
private String create_time;
private String event_type;
private String resource_type;
private Resource resource;
private String summary;
}
上业务代码
- WeChatService
import com.ynjs.common.pay.weChat.app.PayNotifyParams;
import java.util.Map;
public interface WeChatService {
/**
* 调用统一下单API
*
* @param orderId
* @return
* @throws Exception
*/
String appPay(String orderId) throws Exception;
/**
* 支付成功通知
*
* @param payNotifyParams
* @return
*/
Map<String, String> payNotify(PayNotifyParams payNotifyParams);
}
- WeChatServiceImpl
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.app.model.Amount;
import com.wechat.pay.java.service.payments.app.model.PrepayRequest;
import com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse;
import com.ynjs.common.exception.CustomException;
import com.ynjs.common.pay.weChat.app.PayNotifyParams;
import com.ynjs.common.pay.weChat.app.QuickStart;
import com.ynjs.mapper.CrmUserOrderMapper;
import com.ynjs.mapper.DevIotClusterMapper;
import com.ynjs.pojo.CrmUserOrder;
import com.ynjs.pojo.DevIotCluster;
import com.ynjs.service.WeChatService;
import lombok.extern.log4j.Log4j2;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.GeneralSecurityException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Log4j2
@Service
public class WeChatServiceImpl implements WeChatService {
@Resource
private CrmUserOrderMapper crmUserOrderMapper;
@Resource
private QuickStart quickStart;
@Resource
private CloseableHttpClient httpClient;
@Resource
private DevIotClusterMapper devIotClusterMapper;
/**
* 支付成功通知
*
* @param orderId
* @return
*/
public String appPay(String orderId) {
if (StrUtil.isBlank(orderId)) {
throw new CustomException("订单不能为空");
}
CrmUserOrder cuo = crmUserOrderMapper.getUsOrderInfo(orderId);
if (Objects.isNull(cuo)) {
throw new CustomException("找不到该订单!");
}
CrmUserOrder crmUserOrder = crmUserOrderMapper.finishOrder(orderId);
Integer payState = crmUserOrder.getPAY_STATE();
if (payState == 1) {
throw new CustomException("该订单已支付,请勿重复支付");
}
// 使用自动更新平台证书的RSA配置
// 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(quickStart.getMerchantId())
.privateKeyFromPath(quickStart.getPrivateKeyPath())
.merchantSerialNumber(quickStart.getMerchantSerialNumber())
.apiV3Key(quickStart.getApiV3Key())
.build();
// 构建service
AppServiceExtension service = new AppServiceExtension.Builder().config(config).build();
// request.setXxx(val)设置所需参数,具体参数可见Request定义
PrepayRequest request = new PrepayRequest();
BigDecimal payAmount = cuo.getPAY_AMOUNT();
BigDecimal multiply = payAmount.multiply(new BigDecimal("100")); //乘
Amount amount = new Amount();
amount.setTotal(multiply.intValue()); // 金额(以分为单位)
amount.setCurrency("CNY");
request.setAmount(amount);
request.setAppid(quickStart.getAppid());
request.setMchid(quickStart.getMerchantId());
request.setDescription("渔浪浪平台充值");
request.setAttach(crmUserOrder.getIOT_CODE() + "-" + cuo.getRECHARGE());
request.setNotifyUrl(quickStart.getNotifyUrl() + "/api/appapi/WeChatAppNotify");
request.setOutTradeNo(orderId);
// 调用下单方法,得到应答
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
response.getNonceStr();
Gson gson = new Gson();
return gson.toJson(response);
}
/**
* 支付成功后回调通知
*
* @return
*/
public Map<String, String> payNotify(PayNotifyParams payNotifyParams) {
Map<String, String> res = new HashMap<>();
try {
String json = new AesUtil(quickStart.getApiV3Key().getBytes()).decryptToString(
payNotifyParams.getResource().getAssociated_data().getBytes(),
payNotifyParams.getResource().getNonce().getBytes(),
payNotifyParams.getResource().getCiphertext());
String outTradeNo = JSON.parseObject(json, Map.class).get("out_trade_no").toString();
String attach = JSON.parseObject(json, Map.class).get("attach").toString();
String amount = JSON.parseObject(json, Map.class).get("amount").toString();
String total = JSON.parseObject(amount, Map.class).get("total").toString();
// 金额单位为分
BigDecimal totalBig = new BigDecimal(total);
LocalDateTime now = LocalDateTime.now();
CrmUserOrder cuo = new CrmUserOrder();
cuo.setOutTradeNo(outTradeNo);
cuo.setTransactionId(JSON.parseObject(json, Map.class).get("transaction_id").toString());
cuo.setCashFee(totalBig.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP));
cuo.setPAY_STATE(1);
cuo.setORDER_ID(outTradeNo);
cuo.setMEAL_EX(attach);
cuo.setROW_DATE_UPDATE(now);
int update = crmUserOrderMapper.UpdateOrder(cuo);
if (update > 0) {
CrmUserOrder order = crmUserOrderMapper.finishOrder(outTradeNo);
Integer recharge = order.getRECHARGE();// 充值天数
String iotCode = order.getIOT_CODE(); // 充值的SN设备
DevIotCluster cluster = devIotClusterMapper.getCluster(iotCode);
Duration duration = Duration.between(now, cluster.getDUE_DATE());
long days = duration.toDays();
if (days < 0) {
days = 0;
}
LocalDateTime timestamp = now.plusDays(recharge + days + 1);
DevIotCluster dic = new DevIotCluster();
dic.setDUE_DATE(timestamp);
dic.setIOT_CODE(iotCode);
dic.setROW_DATE_UPDATE(now);
int 充值结果 = devIotClusterMapper.upByIotCode(dic);
if (充值结果 > 0) {
res.put("code", JSON.parseObject(json, Map.class).get("trade_state").toString());
res.put("message", JSON.parseObject(json, Map.class).get("trade_state_desc").toString());
}
}
} catch (GeneralSecurityException e) {
e.printStackTrace();
res.put("code", "FAIL");
res.put("message", "失败");
}
return res;
}
/**
* 商户订单号查询订单
*
* @throws Exception
*/
public void queryOrder(String orderId) throws Exception {
//请求URL
URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + orderId);
uriBuilder.setParameter("mchid", quickStart.getMerchantId());
//完成签名并执行请求
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) {
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
/**
* 关闭订单
*
* @throws Exception
*/
public void closeOrder(String orderId) throws Exception {
//请求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + orderId + "/close");
//请求body参数
String reqdata = "{\"mchid\": \"" + quickStart.getMerchantId() + "\"}";
StringEntity entity = new StringEntity(reqdata, "utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) {
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
}
import com.ynjs.common.pay.weChat.app.PayNotifyParams;
import com.ynjs.common.result.Result;
import com.ynjs.service.WeChatService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Log4j2
@RestController
@RequestMapping("/appapi")
@Api(tags = "WX APP支付")
public class WeChatPayController {
@Resource
private WeChatService weChatService;
/**
* 微信APP支付 /api/wechat_pay/app/GetAppParams
*
* @param orderId
* @return
* @throws Exception
*/
@PostMapping("/GetAppParams")
@ApiOperation("调用统一下单API")
public Result AppPay(String orderId) throws Exception {
//调用微信服务获取App支付参数
return Result.success(weChatService.appPay(orderId));
}
@PostMapping("/WeChatAppNotify")
@ApiOperation("支付成功通知")
public Result weChatAppNotify(@RequestBody PayNotifyParams payNotifyParams) {
return Result.success(weChatService.payNotify(payNotifyParams));
}
}