diff --git a/fastbee-common/src/main/java/com/fastbee/common/utils/pay/AesUtil.java b/fastbee-common/src/main/java/com/fastbee/common/utils/pay/AesUtil.java index 0ea21af..15b1d5d 100644 --- a/fastbee-common/src/main/java/com/fastbee/common/utils/pay/AesUtil.java +++ b/fastbee-common/src/main/java/com/fastbee/common/utils/pay/AesUtil.java @@ -1,6 +1,6 @@ package com.fastbee.common.utils.pay; -import java.nio.charset.StandardCharsets; +import java.io.IOException; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -10,37 +10,26 @@ import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; - -/** - * @author xy-peng - */ public class AesUtil { - - private static final String TRANSFORMATION = "AES/GCM/NoPadding"; - - private static final int KEY_LENGTH_BYTE = 32; - private static final int TAG_LENGTH_BIT = 128; - + static final int KEY_LENGTH_BYTE = 32; + static final int TAG_LENGTH_BIT = 128; private final byte[] aesKey; - public AesUtil(byte[] key) { if (key.length != KEY_LENGTH_BYTE) { throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节"); } this.aesKey = key; } - public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) - throws GeneralSecurityException { + throws GeneralSecurityException, IOException { try { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); SecretKeySpec key = new SecretKeySpec(aesKey, "AES"); GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce); - - Cipher cipher = Cipher.getInstance(TRANSFORMATION); cipher.init(Cipher.DECRYPT_MODE, key, spec); cipher.updateAAD(associatedData); - return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8); - + String result=new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8"); + return result; } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new IllegalStateException(e); } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { diff --git a/fastbee-common/src/main/java/com/fastbee/common/utils/pay/RSAUtil.java b/fastbee-common/src/main/java/com/fastbee/common/utils/pay/RSAUtil.java new file mode 100644 index 0000000..d227cc9 --- /dev/null +++ b/fastbee-common/src/main/java/com/fastbee/common/utils/pay/RSAUtil.java @@ -0,0 +1,51 @@ +package com.fastbee.common.utils.pay; + +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +public class RSAUtil { + + /** + * 验签方法 + * @param wechatpaySignature Wechatpay-Signature 响应头中的签名 + * @param wechatpayTimestamp Wechatpay-Timestamp 响应头中的时间戳 + * @param wechatpayNonce Wechatpay-Nonce 响应头中的随机串 + * @param responseBody 应答报文主体 + * @param publicKey 微信支付公钥(PEM 格式,去掉头尾并解码为二进制) + * @return 是否验签成功 + * @throws Exception + */ + public static boolean verifySignature(String wechatpaySignature, + String wechatpayTimestamp, + String wechatpayNonce, + String responseBody, + String publicKey) throws Exception { + // 构造验签名串:应答时间戳\n应答随机串\n应答报文主体\n + String message = wechatpayTimestamp + "\n" + + wechatpayNonce + "\n" + + responseBody + "\n"; + + // 解码微信支付公钥(Base64 格式) + byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey rsaPublicKey = keyFactory.generatePublic(keySpec); + + // 初始化 Signature 对象,指定算法为 SHA256withRSA + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initVerify(rsaPublicKey); + + // 更新验签名串 + signature.update(message.getBytes(StandardCharsets.UTF_8)); + + // 验证签名 + byte[] signatureBytes = Base64.getDecoder().decode(wechatpaySignature); + return signature.verify(signatureBytes); + } + + +} diff --git a/fastbee-common/src/main/java/com/fastbee/common/utils/pay/wechat_public_key.pem b/fastbee-common/src/main/java/com/fastbee/common/utils/pay/wechat_public_key.pem new file mode 100644 index 0000000..5b5f421 --- /dev/null +++ b/fastbee-common/src/main/java/com/fastbee/common/utils/pay/wechat_public_key.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4zej1cqugGQtVSY2Ah8RMCKcr2UpZ8Npo+5Ja9xpFPYkWHaF1Gjrn3d5kcwAFuHHcfdc3yxDYx6+9grvJnCA2zQzWjzVRa3BJ5LTMj6yqvhEmtvjO9D1xbFTA2m3kyjxlaIar/RYHZSslT4VmjIatW9KJCDKkwpM6x/RIWL8wwfFwgz2q3Zcrff1y72nB8p8P12ndH7GSLoY6d2Tv0OB2+We2Kyy2+QzfGXOmLp7UK/pFQjJjzhSf9jxaWJXYKIBxpGlddbRZj9PqvFPTiep8rvfKGNZF9Q6QaMYTpTp/uKQ3YvpDlyeQlYe4rRFauH3mOE6j56QlYQWivknDX9VrwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/fastbee-common/src/main/java/com/fastbee/common/utils/pay/wxPayConfig.java b/fastbee-common/src/main/java/com/fastbee/common/utils/pay/wxPayConfig.java index 7710a3d..4a31e34 100644 --- a/fastbee-common/src/main/java/com/fastbee/common/utils/pay/wxPayConfig.java +++ b/fastbee-common/src/main/java/com/fastbee/common/utils/pay/wxPayConfig.java @@ -3,12 +3,28 @@ package com.fastbee.common.utils.pay; import java.io.*; import java.security.KeyFactory; import java.security.PrivateKey; +import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64; public class wxPayConfig { + // 获取微信支付公钥 + public static String getPublicKey(String publicKeyPath) { + try { + // 读取私钥文件内容 + String publicKeyContent = readFile(publicKeyPath); + // 去除私钥文件中的头尾信息 + publicKeyContent = publicKeyContent.replace("-----BEGIN PUBLIC KEY-----", "") + .replace("-----END PUBLIC KEY-----", "") + .replaceAll("\\s+", ""); + return publicKeyContent; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } // 获取商户私钥 public static PrivateKey getPrivateKey(String privateKeyPath) { diff --git a/fastbee-framework/src/main/java/com/fastbee/framework/config/SecurityConfig.java b/fastbee-framework/src/main/java/com/fastbee/framework/config/SecurityConfig.java index 0acaf6e..95b4331 100644 --- a/fastbee-framework/src/main/java/com/fastbee/framework/config/SecurityConfig.java +++ b/fastbee-framework/src/main/java/com/fastbee/framework/config/SecurityConfig.java @@ -135,6 +135,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .antMatchers("/system/district/tree").permitAll() .antMatchers("/sse/**").permitAll() .antMatchers("/common/upload").permitAll() + .antMatchers("/pay/getresult").permitAll() // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated() diff --git a/fastbee-open-api/src/main/java/com/fastbee/data/controller/pay/WeChatPayController.java b/fastbee-open-api/src/main/java/com/fastbee/data/controller/pay/WeChatPayController.java index 6442a29..16d3c26 100644 --- a/fastbee-open-api/src/main/java/com/fastbee/data/controller/pay/WeChatPayController.java +++ b/fastbee-open-api/src/main/java/com/fastbee/data/controller/pay/WeChatPayController.java @@ -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 result=CreateOrder(recharge);//生成订单 + Map result = userWechatPayService.CreateOrder(recharge); // 生成订单 + + //打印出返回前端的所有参数 + // 获取键的集合 + Set 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 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 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 result=new HashMap<>(); - - Map reqdata=new HashMap(); - Map amount=new HashMap<>(); - Map 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 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()); - } + + + } diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/domain/dto/WeChatRechargeBacktracking.java b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/domain/dto/WeChatRechargeBacktracking.java index 9b4122f..50875d0 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/domain/dto/WeChatRechargeBacktracking.java +++ b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/domain/dto/WeChatRechargeBacktracking.java @@ -4,10 +4,10 @@ import lombok.Data; @Data public class WeChatRechargeBacktracking { - private String id; - private String create_time; - private String resource_type; - private String event_type; - private String summary; - private WeChatRechargeBacktrackingResource resource; + private String id;//回调通知唯一编号 + private String create_time;//通知创建时间 + private String resource_type;//资源数据类型 + private String event_type;//回调通知类型:TRANSACTION.SUCCESS + private String summary;//备注 + private WeChatRechargeBacktrackingResource resource;//通知资源数据 } diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/domain/dto/WeChatRechargeBacktrackingResource.java b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/domain/dto/WeChatRechargeBacktrackingResource.java index 2d5c4bb..e3d957e 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/domain/dto/WeChatRechargeBacktrackingResource.java +++ b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/domain/dto/WeChatRechargeBacktrackingResource.java @@ -4,10 +4,10 @@ import lombok.Data; @Data public class WeChatRechargeBacktrackingResource{ - private String original_type; - private String algorithm; - private String cliphertext; - private String associated_data; - private String nonce; + private String original_type;//加密前的对象类型,transaction + private String algorithm;//加密算法类型 + private String ciphertext;//回调数据密文ciphertext + private String associated_data;//附加数据 + private String nonce;//随机串 } diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/mapper/NgUserRechargeRecordsMapper.java b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/mapper/NgUserRechargeRecordsMapper.java index a54642a..c16672f 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/mapper/NgUserRechargeRecordsMapper.java +++ b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/mapper/NgUserRechargeRecordsMapper.java @@ -34,6 +34,7 @@ public interface NgUserRechargeRecordsMapper * @param rechargeCode * @return */ + @Select("select * from ng_user_recharge_records where recharge_code=#{rechargeCode}") public NgUserRechargeRecords selectNgUserRechargeRecordsByRechargeCode(String rechargeCode); /** diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/mapper/UserRechargeCardsMapper.java b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/mapper/UserRechargeCardsMapper.java index c3db9ed..d0c3103 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/mapper/UserRechargeCardsMapper.java +++ b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/mapper/UserRechargeCardsMapper.java @@ -4,6 +4,7 @@ import java.util.List; import com.fastbee.rechargecard.domain.UserRechargeCards; import com.github.yulichang.base.MPJBaseMapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Repository; /** @@ -34,6 +35,7 @@ public interface UserRechargeCardsMapper extends MPJBaseMapper CreateOrder(WeChatRecharge recharge) throws Exception; +} diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/NgUserRechargeRecordsServiceImpl.java b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/NgUserRechargeRecordsServiceImpl.java index 9736e82..eb7b74d 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/NgUserRechargeRecordsServiceImpl.java +++ b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/NgUserRechargeRecordsServiceImpl.java @@ -32,11 +32,13 @@ public class NgUserRechargeRecordsServiceImpl implements INgUserRechargeRecordsS NgUserRechargeRecords ngUserRechargeRecords=new NgUserRechargeRecords(); ngUserRechargeRecords.setRechargeTime(DateUtils.getNowDate()); ngUserRechargeRecords.setBalance(rechargecardUser.getAmount()); + ngUserRechargeRecords.setAmount(rechargecardUser.getAmount()); ngUserRechargeRecords.setType(1);//微信 ngUserRechargeRecords.setStatus(0);//生成订单 ngUserRechargeRecords.setAreaCode(String.valueOf(rechargecardUser.getAreacode())); ngUserRechargeRecords.setCardNumber(String.valueOf(rechargecardUser.getCardnumber())); ngUserRechargeRecords.setRechargeCode(rechargecardUser.getRechargeCode()); + ngUserRechargeRecords.setSerialNumber(rechargecardUser.getDeviceNumber()); return ngUserRechargeRecordsMapper.insertNgUserRechargeRecords(ngUserRechargeRecords); } diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserConsumptionDetailsServiceImpl.java b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserConsumptionDetailsServiceImpl.java index 3edd5e8..8149c9e 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserConsumptionDetailsServiceImpl.java +++ b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserConsumptionDetailsServiceImpl.java @@ -214,8 +214,9 @@ public class UserConsumptionDetailsServiceImpl implements IUserConsumptionDetail userConsumptionDetails.setPaymentStatus(0); userConsumptionDetails.setPaymentMethod(recharge.getType()); userConsumptionDetails.setPaymentTime(DateUtils.getNowDate()); - userConsumptionDetails.setStatus(0); + userConsumptionDetails.setStatus(2); userConsumptionDetails.setCreateTime(DateUtils.getNowDate()); + userConsumptionDetails.setDeviceNumber(recharge.getDeviceNumber()); return userConsumptionDetailsMapper.insertUserConsumptionDetails(userConsumptionDetails); } diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserRechargeCardsServiceImpl.java b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserRechargeCardsServiceImpl.java index de67f48..160d0d5 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserRechargeCardsServiceImpl.java +++ b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserRechargeCardsServiceImpl.java @@ -106,48 +106,73 @@ public class UserRechargeCardsServiceImpl implements IUserRechargeCardsService * @return */ @Override - public int updateUserRechargeWechat(String rechargeCode) { + public int updateUserRechargeWechat(String rechargeCode,BigDecimal payer_total) throws Exception { + + //用户充值记录中订单信息状态更改为已支付 NgUserRechargeRecords ngUserRechargeRecords=new NgUserRechargeRecords(); + if(rechargeCode==null) + { + throw new Exception("订单编号为空"); + } + + if(userRechargeRecordsMapper.selectNgUserRechargeRecordsByRechargeCode(rechargeCode)==null) + { + throw new Exception("订单信息不存在"); + } ngUserRechargeRecords=userRechargeRecordsMapper.selectNgUserRechargeRecordsByRechargeCode(rechargeCode);//查询订单信息 ngUserRechargeRecords.setStatus(1);//状态更改为已支付 - ngUserRechargeRecords.setRechargeCode(rechargeCode); + userRechargeRecordsMapper.updateNgUserRechargeRecords(ngUserRechargeRecords); - /* userConsumptionDetails.setCreateTime(DateUtils.getNowDate()); - NgUserRechargeRecords ngUserRechargeRecords = NgUserRechargeRecords.builder() - .userId(info.getUserId()).userName(info.getUserName()) - .cardNumber(info.getCardNumber()).areaCode(rechargecardUser.getAreacode()) - .type(rechargecardUser.getStatus()).amount(rechargecardUser.getNumber()) - .balance(info.getBalance()).rechargeTime(DateUtils.getNowDate()) - .rechargeCode(null).status(0).serialNumber(null).deviceNumber(null).projectId(null) - .deptId(null) - .areaCode(rechargecardUser.getAreacode()) - .build();*/ - userRechargeRecordsMapper.updateNgUserRechargeRecordsWechat(ngUserRechargeRecords); - /*RechargecardUser rechargecardUser=new RechargecardUser(); - // 计算新的余额 - BigDecimal newBalance = rechargecardUser.getAmount().add(info.getBalance());*/ - // 更新用户充值卡信息,包括新的余额 -// info.setBalance(newBalance); -// info.setUpdateTime(DateUtils.getNowDate()); -// info.setAreaCode(String.valueOf(rechargecardUser.getAreaCode())); + //用户充值卡中的余额更改 + String cardNumber=ngUserRechargeRecords.getCardNumber();//卡号 + BigDecimal balance=ngUserRechargeRecords.getAmount();//充值金额 + if(!cardNumber.isEmpty()) + { + if(userRechargeCardsMapper.selectUserRechargeCardsByCardNumber(cardNumber)==null) + { + throw new Exception("用户信息不存在"); + } + UserRechargeCards rechargeCards=userRechargeCardsMapper.selectUserRechargeCardsByCardNumber(ngUserRechargeRecords.getCardNumber()); + BigDecimal newBalance = rechargeCards.getBalance().add(balance); + System.out.println(cardNumber+"的余额从"+rechargeCards.getBalance()+"变成了"+newBalance); + rechargeCards.setBalance(newBalance); + userRechargeCardsMapper.updateUserRechargeCards(rechargeCards); + }else{ + throw new Exception("卡号为空"); + } - /*//构建主题 - String topic ="hzlink/147/"+rechargecardUser.getDeviceNumber()+"/cmd/down"; + + + //用户消费明细记录中状态更改为已支付 + /*UserConsumptionDetails userConsumptionDetails=userConsumptionDetailsMapper.selectUserConsumptionDetailsBy(); + userConsumptionDetails.setStatus(0);//更改为已支付 + userConsumptionDetails.setPaymentStatus(2);//账单状态更改为已支付*/ + + String areaCode=ngUserRechargeRecords.getAreaCode(); + + //构建主题 + String topic ="hzlink/147/"+ngUserRechargeRecords.getSerialNumber()+"/cmd/down"; //构建消息 Map param = new HashMap<>(); //远程阀控 param.put("cmd",1000); Map data = new HashMap<>(); - data.put("orderNum", ngUserRechargeRecords.getId()); - data.put("cardNum",rechargecardUser.getCardnumber()); - data.put("areaCode",rechargecardUser.getAreacode()); - data.put("investBalance",rechargecardUser.getAmount().doubleValue()); - data.put("investWater",rechargecardUser.getWater()); + data.put("orderNum", rechargeCode);//订单号 + data.put("cardNum",cardNumber);//卡号 + data.put("areaCode",areaCode);//区域号 + data.put("investBalance",balance);//充值的金额 + data.put("investWater",100);//充值的水量 param.put("data",data); - pubMqttClient.publish(1,true,topic, JSONUtil.toJsonStr(param));*/ + try{ + //pubMqttClient.publish(1,true,topic, JSONUtil.toJsonStr(param)); + }catch (Exception e) + { + throw new Exception("消息发布失败"); + } + // int i = userRechargeCardsMapper.updateUserRechargeCards(info); return 1; } diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserWechatPayServiceImpl.java b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserWechatPayServiceImpl.java new file mode 100644 index 0000000..1a98513 --- /dev/null +++ b/fastbee-service/fastbee-rechargecard-service/src/main/java/com/fastbee/rechargecard/service/impl/UserWechatPayServiceImpl.java @@ -0,0 +1,195 @@ +package com.fastbee.rechargecard.service.impl; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.fastbee.common.utils.pay.wxPayConfig; +import com.fastbee.rechargecard.domain.dto.WeChatRecharge; +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 org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +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.stereotype.Service; + +import java.io.IOException; +import java.security.PrivateKey; +import java.security.Signature; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +@Service +public class UserWechatPayServiceImpl implements IUserWechatPayService { + + + /** 商户号 */ + 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 publicKeyPath="fastbee-common/src/main/java/com/fastbee/common/utils/pay/wechat_public_key.pem"; + @Override + /** + * 创建订单,获取prepay_id和paySign + * @param recharge + * @return + * @throws Exception + */ + public Map 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 result=new HashMap<>(); + + Map reqdata=new HashMap(); + Map amount=new HashMap<>(); + Map payer=new HashMap<>(); + amount.put("total",recharge.getTotal()); + System.out.print(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://46b411f6.r3.cpolar.cn/pay/getresult");//"\t\n" + + reqdata.put("payer",payer); + //String Signature=getSign(reqdata); + Map info=getSign(reqdata); + String timeStamp=info.get("timeStamp"); + String nonce_str=info.get("nonce_str"); + + result.put("timeStamp",timeStamp); + result.put("mchid",mchId); + result.put("signType","RSA"); + result.put("nonceStr",nonce_str); + result.put("partnerid",mchId); + String Signature=info.get("sign"); + + 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); + + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + //完成签名并执行请求 + 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); + result.put("paySign",getPaySign(prepayId,timeStamp,nonce_str)); + 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) { + response.close(); + httpClient.close(); + throw new RuntimeException(e); + } finally { + response.close(); + httpClient.close(); + } + } + /** + * 生成签名 + */ + private Map getSign(Map reqBody) throws Exception { + //获取时间戳 + + String reqMethod="POST"; + String url="/v3/pay/transactions/jsapi"; + /*String reqMethod="GET"; + String url="/v3/refund/domestic/refunds/123123123123";*/ + String timeStamp = String.valueOf(System.currentTimeMillis() / 1000); + //timeStamp="1554208460"; + String nonce_str= UUID.randomUUID().toString(); + //nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242"; + String reqParam= JSONUtil.toJsonStr(reqBody); + + /*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")); + Map info=new HashMap<>(); + info.put("timeStamp",timeStamp); + info.put("nonce_str",nonce_str); + info.put("sign",sign); + + /*//进行sha256 + String sha256HexSignStr = DigestUtil.sha256Hex(signStr); + //在进行base64 + String base64SignStr = Base64.getEncoder().encodeToString(sha256HexSignStr.getBytes()); +*/ + return info; + } + /** + * 生成前端所需签名 + */ + private String getPaySign(String prepayId,String timeStamp,String nonce_str) throws Exception { + + /** + * 使用字段appId、timeStamp、nonceStr、package + */ + String signStr=appId+"\n"+timeStamp+"\n"+nonce_str+"\n"+"prepay_id="+prepayId+"\n"; + String sign=sign(signStr.getBytes("utf-8")); + + return sign; + } + + /** + * 生成签名方法 + * @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()); + } +} diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/resources/mapper/rechargecard/NgUserRechargeRecordsMapper.xml b/fastbee-service/fastbee-rechargecard-service/src/main/resources/mapper/rechargecard/NgUserRechargeRecordsMapper.xml index fcc419a..e37e9c2 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/resources/mapper/rechargecard/NgUserRechargeRecordsMapper.xml +++ b/fastbee-service/fastbee-rechargecard-service/src/main/resources/mapper/rechargecard/NgUserRechargeRecordsMapper.xml @@ -76,10 +76,10 @@ - diff --git a/fastbee-service/fastbee-rechargecard-service/src/main/resources/mapper/rechargecard/UserRechargeCardsMapper.xml b/fastbee-service/fastbee-rechargecard-service/src/main/resources/mapper/rechargecard/UserRechargeCardsMapper.xml index c59b6ff..3c402b9 100644 --- a/fastbee-service/fastbee-rechargecard-service/src/main/resources/mapper/rechargecard/UserRechargeCardsMapper.xml +++ b/fastbee-service/fastbee-rechargecard-service/src/main/resources/mapper/rechargecard/UserRechargeCardsMapper.xml @@ -58,10 +58,10 @@ where card_number= #{cardnumber} -