支付模块-下单接口修改以及支付结果回溯接口修改
This commit is contained in:
@ -5,69 +5,53 @@ import cn.hutool.json.JSONException;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.json.ObjectMapper;
|
||||
import com.dtflys.forest.annotation.Success;
|
||||
import com.fastbee.common.core.controller.BaseController;
|
||||
import com.fastbee.common.core.domain.AjaxResult;
|
||||
import com.fastbee.common.utils.pay.AesUtil;
|
||||
import com.fastbee.common.wechat.WeChatLoginBody;
|
||||
import com.fastbee.rechargecard.domain.NgUserRechargeRecords;
|
||||
import com.fastbee.rechargecard.domain.dto.RechargecardUser;
|
||||
import com.fastbee.common.utils.pay.RSAUtil;
|
||||
import com.fastbee.rechargecard.domain.dto.WeChatRecharge;
|
||||
import com.fastbee.rechargecard.domain.dto.WeChatRechargeBacktracking;
|
||||
import com.fastbee.rechargecard.service.INgUserRechargeRecordsService;
|
||||
import com.fastbee.rechargecard.service.IUserConsumptionDetailsService;
|
||||
import com.fastbee.rechargecard.service.IUserRechargeCardsService;
|
||||
import com.fastbee.rechargecard.service.IUserWechatPayService;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.HttpEntity;
|
||||
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.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Signature;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
import com.fastbee.common.utils.pay.wxPayConfig;
|
||||
|
||||
import static cn.hutool.core.util.XmlUtil.xmlToMap;
|
||||
import static com.fastbee.common.constant.Constants.LANGUAGE;
|
||||
import static com.fastbee.common.utils.pay.RSAUtil.verifySignature;
|
||||
import static com.fastbee.rechargecard.service.impl.UserWechatPayServiceImpl.apiV3Key;
|
||||
|
||||
@Api(tags = "支付模块")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/pay")
|
||||
public class WeChatPayController extends BaseController {
|
||||
/** 商户号 */
|
||||
public static String mchId = "1531795301";
|
||||
/** 商户API私钥文件路径 */
|
||||
public static String privateKeyPath = "fastbee-common/src/main/java/com/fastbee/common/utils/pay/apiclient_key.pem";
|
||||
/** 商户API证书序列号 */
|
||||
public static String serial_no = "3075B63EF52666EDC3EAFC5D4FB35C02CE123A9C";
|
||||
/** 商户APIV3密钥 */
|
||||
public static String apiV3Key = "e85a203e8ca146102f5cd7ecff912580";
|
||||
//微信小程序appid
|
||||
public static String appId="wx308612d2a8423311";
|
||||
//请求随机串
|
||||
public static String nonce_str="";
|
||||
//时间戳
|
||||
public static String timeStamp="";
|
||||
// 使用HttpClientBuilder创建CloseableHttpClient实例,采用默认配置
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||
|
||||
@Autowired
|
||||
private INgUserRechargeRecordsService ngUserRechargeRecordsService;
|
||||
@ -75,6 +59,8 @@ public class WeChatPayController extends BaseController {
|
||||
private IUserRechargeCardsService userRechargeCardsService;
|
||||
@Autowired
|
||||
private IUserConsumptionDetailsService userConsumptionDetailsService;
|
||||
@Autowired
|
||||
private IUserWechatPayService userWechatPayService;
|
||||
|
||||
/**
|
||||
* 微信支付生成订单
|
||||
@ -83,164 +69,150 @@ public class WeChatPayController extends BaseController {
|
||||
@ApiOperation("生成订单")
|
||||
@PostMapping("/order")
|
||||
public AjaxResult BuildOrder(@RequestBody WeChatRecharge recharge) throws Exception {
|
||||
System.out.println("生成订单");
|
||||
String out_trade_no=UUID.randomUUID().toString().replace("-", "");
|
||||
while(ngUserRechargeRecordsService.SelectRechargeRecodeByRechargeCode(out_trade_no) !=null)
|
||||
{
|
||||
out_trade_no=UUID.randomUUID().toString().replace("-", "");;
|
||||
}
|
||||
//System.out.println(out_trade_no);
|
||||
recharge.setRechargeCode(out_trade_no);
|
||||
Map<String,String> result=CreateOrder(recharge);//生成订单
|
||||
Map<String, String> result = userWechatPayService.CreateOrder(recharge); // 生成订单
|
||||
|
||||
//打印出返回前端的所有参数
|
||||
// 获取键的集合
|
||||
Set<String> keySet = result.keySet();
|
||||
// 遍历键集合
|
||||
for (String key : keySet) {
|
||||
System.out.println(key + ": " + result.get(key));
|
||||
}
|
||||
|
||||
if(result.isEmpty())
|
||||
{
|
||||
return toAjax("微信支付订单生成失败");
|
||||
System.out.println("微信支付订单生成失败");
|
||||
return error("微信支付订单生成失败");
|
||||
}
|
||||
System.out.println("微信支付订单生成成功");
|
||||
|
||||
//订单生成成功
|
||||
int flag=ngUserRechargeRecordsService.insertNgUserRechargeRecordsWeChat(recharge);//插入用户充值记录表
|
||||
flag=userConsumptionDetailsService.insertUserConsumptionDetailsWechat(recharge);//插入用户消费明细表
|
||||
//flag=userConsumptionDetailsService.insertUserConsumptionDetailsWechat(recharge);//插入用户消费明细表
|
||||
if(flag==1)
|
||||
{
|
||||
return success(result);
|
||||
}
|
||||
return toAjax("系统内部订单生成失败");
|
||||
return error("系统内部订单生成失败");
|
||||
}
|
||||
|
||||
@PostMapping("/getresult")
|
||||
@ApiOperation("支付通知结果回溯")
|
||||
@ResponseBody
|
||||
public String getResult(@RequestBody WeChatRechargeBacktracking backtracking) throws Exception {
|
||||
String algorithm=backtracking.getResource().getAlgorithm();
|
||||
String nonce=backtracking.getResource().getNonce();
|
||||
String associated_data=backtracking.getResource().getAssociated_data();
|
||||
String cliphertext=backtracking.getResource().getCliphertext();
|
||||
AesUtil aesUtil=new AesUtil(apiV3Key.getBytes("utf-8"));
|
||||
//解密后的值
|
||||
String decryptKey=aesUtil.decryptToString(associated_data.getBytes("utf-8"),nonce.getBytes("utf-8"),cliphertext);
|
||||
System.out.println("解密后的:"+decryptKey);
|
||||
public ResponseEntity<?> getResult(@RequestBody JSONObject jsonObject, HttpServletRequest request) throws Exception {//WeChatRechargeBacktracking backtracking
|
||||
// 从HTTP请求头中获取微信签名和时间戳等值
|
||||
System.out.println("微信回调开始---------");
|
||||
String wechatpaySignature = request.getHeader("Wechatpay-Signature");//验签的签名值
|
||||
String wechatpaySerial = request.getHeader("Wechatpay-Serial");//序列号
|
||||
String wechatpayTimestamp = request.getHeader("Wechatpay-Timestamp");//时间戳
|
||||
String wechatpayNonce = request.getHeader("Wechatpay-Nonce");//随机字符串
|
||||
String json=jsonObject.toString();
|
||||
System.out.println("微信回调报文:{"+json+"}");
|
||||
// 构建应答报文
|
||||
Map<String, String> responseBody = new HashMap<>();
|
||||
//解密jsonObject对象
|
||||
String associated_data= (String) JSONUtil.getByPath(JSONUtil.parse(json),"resource.associated_data");//加密数据
|
||||
String ciphertext=(String) JSONUtil.getByPath(JSONUtil.parse(json),"resource.ciphertext");//数据密文
|
||||
System.out.println("ciphertext:"+ciphertext);
|
||||
String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");
|
||||
|
||||
/**
|
||||
* 验签字符串
|
||||
* 应答时间戳\n
|
||||
* 应答随机串\n
|
||||
* 应答报文主体\n
|
||||
*/
|
||||
//String signStr=wechatpayTimestamp+"\n"+wechatpayNonce+"\n"+json+"\n";//验签字符串
|
||||
// 使用微信支付公钥验签
|
||||
/**
|
||||
* 验签方法
|
||||
* wechatpaySignature Wechatpay-Signature 响应头中的签名
|
||||
* wechatpayTimestamp Wechatpay-Timestamp 响应头中的时间戳
|
||||
* wechatpayNonce Wechatpay-Nonce 响应头中的随机串
|
||||
* responseBody 应答报文主体
|
||||
* publicKey 微信支付公钥(PEM 格式,去掉头尾并解码为二进制)
|
||||
*/
|
||||
/*String publicKey=wxPayConfig.getPublicKey(publicKeyPath);//读取并预处理后的微信支付公钥
|
||||
boolean isVerified = verifySignature(wechatpaySignature, wechatpayTimestamp, wechatpayNonce, json, publicKey);
|
||||
if (isVerified) {
|
||||
System.out.println("签名验证成功");
|
||||
} else {
|
||||
System.out.println("签名验证失败");
|
||||
return error("签名验证失败");
|
||||
}*/
|
||||
//使用apiv3key解密
|
||||
String decryptData="";
|
||||
try{
|
||||
decryptData= new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8)).decryptToString
|
||||
(associated_data.getBytes(StandardCharsets.UTF_8),
|
||||
nonce.getBytes(StandardCharsets.UTF_8),
|
||||
ciphertext);
|
||||
}catch (Exception e)
|
||||
{
|
||||
System.out.println("解密失败");
|
||||
responseBody.put("code", "FAIL");
|
||||
responseBody.put("message", "解密失败");
|
||||
|
||||
return decryptKey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建订单,获取prepay_id和paySign
|
||||
* @param recharge
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public Map<String, String> CreateOrder(WeChatRecharge recharge) throws Exception{
|
||||
System.out.println("CreateOrder");
|
||||
//请求URL
|
||||
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
|
||||
Map<String,String> result=new HashMap<>();
|
||||
|
||||
Map<String,Object> reqdata=new HashMap<String,Object>();
|
||||
Map<String,Object> amount=new HashMap<>();
|
||||
Map<String,Object> payer=new HashMap<>();
|
||||
amount.put("total",recharge.getTotal());
|
||||
amount.put("currency",recharge.getCurrency());
|
||||
payer.put("openid",recharge.getOpenId());
|
||||
|
||||
reqdata.put("amount",amount);
|
||||
reqdata.put("appid",appId);
|
||||
reqdata.put("mchid",mchId);
|
||||
reqdata.put("description",recharge.getCardnumber()+recharge.getAmount().toString());
|
||||
reqdata.put("out_trade_no",recharge.getRechargeCode());
|
||||
reqdata.put("notify_url","https://1481109f.r3.cpolar.cn/pay/getresult");
|
||||
reqdata.put("payer",payer);
|
||||
String Signature=getSign(reqdata);
|
||||
result.put("paySign",Signature);
|
||||
String Authorization="WECHATPAY2-SHA256-RSA2048 mchid=\""+mchId+"\",nonce_str=\""+nonce_str+"\",signature=\""+Signature+"\",timestamp=\""+timeStamp+"\",serial_no=\""+serial_no+"\"";
|
||||
|
||||
StringEntity entity = new StringEntity(JSONUtil.toJsonStr(reqdata), "utf-8");
|
||||
entity.setContentType("application/json");
|
||||
httpPost.setEntity(entity);
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
httpPost.setHeader("Authorization",Authorization);
|
||||
|
||||
|
||||
//完成签名并执行请求
|
||||
CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||
try {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == 200) {
|
||||
// 假设responseEntity是包含JSON响应的字符串
|
||||
String responseEntity = EntityUtils.toString(response.getEntity());
|
||||
|
||||
// 使用Hutool的JSONUtil解析JSON字符串
|
||||
JSONObject jsonObject = JSONUtil.parseObj(responseEntity);
|
||||
|
||||
// 安全地获取prepay_id的值
|
||||
String prepayId = jsonObject.getStr("prepay_id");
|
||||
|
||||
System.out.println("Prepay ID: " + prepayId);
|
||||
result.put("prepay_id",prepayId);
|
||||
System.out.println("success,return body = " + prepayId);
|
||||
|
||||
return result;
|
||||
|
||||
} else if (statusCode == 204) {
|
||||
return null;
|
||||
} else {
|
||||
System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
|
||||
throw new IOException("request failed");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
response.close();
|
||||
httpClient.close();
|
||||
// 返回500状态码以及符合要求的应答报文
|
||||
return new ResponseEntity<>(responseBody, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
//return error("解密失败");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 生成签名
|
||||
*/
|
||||
public String getSign(Map<String,Object> reqBody) throws Exception {
|
||||
//获取时间戳
|
||||
|
||||
String reqMethod="POST";
|
||||
String url="/v3/pay/transactions/jsapi";
|
||||
/*String reqMethod="GET";
|
||||
String url="/v3/refund/domestic/refunds/123123123123";*/
|
||||
timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
//timeStamp="1554208460";
|
||||
nonce_str= UUID.randomUUID().toString();
|
||||
//nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242";
|
||||
String reqParam= JSONUtil.toJsonStr(reqBody);
|
||||
System.out.println("解密后的:"+decryptData);
|
||||
if(decryptData==null)
|
||||
{
|
||||
System.out.println("解密后值为空");
|
||||
responseBody.put("code", "FAIL");
|
||||
responseBody.put("message", "解密后值为空");
|
||||
|
||||
/*HTTP请求方法\n
|
||||
URL\n
|
||||
请求时间戳\n
|
||||
请求随机串\n
|
||||
请求报文主体\n
|
||||
*/
|
||||
String signStr=reqMethod+"\n"+url+"\n"+timeStamp+"\n"+nonce_str+"\n"+reqParam +"\n";
|
||||
//String signStr=reqMethod+"\n"+url+"\n"+timeStamp+"\n"+nonce_str+"\n\n";
|
||||
String sign=sign(signStr.getBytes("utf-8"));
|
||||
// 返回500状态码以及符合要求的应答报文
|
||||
return new ResponseEntity<>(responseBody, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
//return error("解密后值为空");
|
||||
}
|
||||
// 使用Hutool的JSONUtil解析JSON字符串
|
||||
JSONObject decryptJsonObject = JSONUtil.parseObj(decryptData);
|
||||
|
||||
/*//进行sha256
|
||||
String sha256HexSignStr = DigestUtil.sha256Hex(signStr);
|
||||
//在进行base64
|
||||
String base64SignStr = Base64.getEncoder().encodeToString(sha256HexSignStr.getBytes());
|
||||
*/
|
||||
return sign;
|
||||
String result = decryptJsonObject.getStr("trade_state_desc");
|
||||
String trade_state=decryptJsonObject.getStr("trade_state");
|
||||
if(result.isEmpty() || ! result.equals("支付成功") || !trade_state.equals("SUCCESS") )
|
||||
{
|
||||
System.out.println("支付失败");
|
||||
responseBody.put("code", "FAIL");
|
||||
responseBody.put("message", "支付失败");
|
||||
|
||||
// 返回500状态码以及符合要求的应答报文
|
||||
return new ResponseEntity<>(responseBody, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
//return error("支付失败");
|
||||
}
|
||||
//支付成功后
|
||||
JSONObject amount=decryptJsonObject.getJSONObject("amount");
|
||||
BigDecimal payer_total=amount.getBigDecimal("payer_total");//支付金额
|
||||
String rechargeCode=decryptJsonObject.getStr("out_trade_no");//订单号
|
||||
int flag=userRechargeCardsService.updateUserRechargeWechat(rechargeCode,payer_total);
|
||||
if(flag==1)
|
||||
{
|
||||
System.out.println("支付成功");
|
||||
//return success("支付成功");
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
System.out.println("修改数据库失败");
|
||||
responseBody.put("code", "FAIL");
|
||||
responseBody.put("message", "修改数据库失败");
|
||||
|
||||
// 返回500状态码以及符合要求的应答报文
|
||||
return new ResponseEntity<>(responseBody, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
//return error("修改数据库失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名方法
|
||||
* @param message
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private String sign(byte[] message) throws Exception{
|
||||
Signature sign;
|
||||
sign = Signature.getInstance("SHA256withRSA");
|
||||
//这里需要一个PrivateKey类型的参数,就是商户的私钥。
|
||||
//获取商户私钥——传商户私钥位置
|
||||
PrivateKey privateKey = wxPayConfig.getPrivateKey(privateKeyPath);
|
||||
sign.initSign(privateKey);
|
||||
sign.update(message);
|
||||
return Base64.getEncoder().encodeToString(sign.sign());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user