赞
踩
由于具体是哪个已经分不清了,有些是微信支付要用到的,有些是退款要用到的,有些是解码要用到的。
- <dependency>
- <groupId>com.github.wxpay</groupId>
- <artifactId>wxpay-sdk</artifactId>
- <version>0.0.3</version>
- </dependency>
- <dependency>
- <groupId>com.github.binarywang</groupId>
- <artifactId>weixin-java-mp</artifactId>
- </dependency>
- <dependency>
- <groupId>com.github.binarywang</groupId>
- <artifactId>weixin-java-common</artifactId>
- </dependency>
- <dependency>
- <groupId>com.github.binarywang</groupId>
- <artifactId>weixin-java-pay</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alipay.sdk</groupId>
- <artifactId>alipay-sdk-java</artifactId>
- <version>4.9.5.ALL</version>
- </dependency>
- <dependency>
- <groupId>com.github.wxpay</groupId>
- <artifactId>wxpay-sdk</artifactId>
- <version>0.0.3</version>
- </dependency>
- <dependency>
- <groupId>com.github.binarywang</groupId>
- <artifactId>weixin-java-pay</artifactId>
- <version>3.1.0</version>
- </dependency>
- <!-- 微信支付sdk -->
-
- <!-- Apache Commons Codec库 -->
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.15</version>
- </dependency>
这个类是配置微信支付的基本信息的如appId,mchId这些,建议用我的,因为后面要用到这个配置类。
注意:除了一般用到的appid这些东西外,还得去官网申请证书,如apiclient_cert.p12,pem这些。路径配置可以配置本地的地址或者服务器下的地址,按我下面那样子配置就可以。
- public class PayConfig implements WXPayConfig{
-
- private byte[] certData;
-
- public PayConfig() throws Exception {
- //服务器的路径,按照你自己的来
- File file = new File("/usr/local/cert/apiclient_cert.p12");
- // 本地测试的路径,按照你自己的来
- // File file = new File("D:\\*****\\*****\\*****\\apiclient_cert.p12");
- InputStream certStream = new FileInputStream(file);
- this.certData = new byte[(int) file.length()];
- certStream.read(this.certData);
- certStream.close();
- }
-
- public String getAppID() {
- return "****************";
- }
-
- public String getMchID() {
- return "********";
- }
-
- public String getKey() {
- return "************";
- }
-
- public InputStream getCertStream() {
- ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
- return certBis;
- }
-
- public int getHttpConnectTimeoutMs() {
- return 8000;
- }
-
- public int getHttpReadTimeoutMs() {
- return 10000;
- }
- }
拿来用就可以 ,是用于解密退款回调返回的信息req_info的。第一个decrypt方法是解密手机号的,这里用不到,只是顺便贴一下,要用可以拿去用。
- public class AesUtil {
- public static String decrypt(String encryptedData, String sessionKey, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
- // 初始化加密库
- Security.addProvider(new BouncyCastleProvider());
-
- byte[] encryptedDataBytes = Base64.getDecoder().decode(encryptedData);
- byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey);
- byte[] ivBytes = Base64.getDecoder().decode(iv);
-
-
- // 构造解密器
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
- SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES");
- AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
- params.init(new IvParameterSpec(ivBytes));
- cipher.init(Cipher.DECRYPT_MODE, keySpec, params);
-
- byte[] decryptedDataBytes = cipher.doFinal(encryptedDataBytes);
- return new String(decryptedDataBytes, StandardCharsets.UTF_8);
- }
-
- public static String aesDecrypt(String secretInfo, String rawKey) throws Exception {
- try {
- SecretKeySpec key = new SecretKeySpec(DigestUtils.md5Hex(getContentBytes(rawKey, "utf-8")).toLowerCase().getBytes(), "AES");
- Security.addProvider(new BouncyCastleProvider());
- Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
- cipher.init(Cipher.DECRYPT_MODE, key);
- return new String(cipher.doFinal(Base64.getDecoder().decode(secretInfo)),"UTF-8");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- private static byte[] getContentBytes(String content, String charset) {
- if (charset == null || "".equals(charset)) {
- return content.getBytes();
- }
- try {
- return content.getBytes(charset);
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException("MD5签名过程中出现错误" + charset);
- }
- }
-
- }
@注解按需添加
transactionId为微信支付订单号,money表示你要退款的钱,reason表示原因。
- @Data
- @Accessors(chain = true)
- public class ConfirmCancel{
- private Long transactionId;
- private String money;
- private String reason;
- }
微信退款以分为单位,不论是总额还是要退款的钱。 (有些字段和微信官方提供的不同,是因为版本不一样,用就行了)
- @Log
- @ApiOperation(value = "退款")
- @PostMapping("confirmCancel")
- public Object confirmCancel(@RequestBody ConfirmCancel confirmCancel) throws Exception {//serviceOrderId
- if (poDto != null){
- String transactionId = confirmCancel.getTransactionId();
- Double stringMonry = Double.valueOf(confirmCancel.getMoney());
-
- //退款以分为单位,且为int类型,不能有小数点。前端输入的money也得按这个来。如0.01元就得是1分
-
- //totalMoney为总额,你可以从之前支付订单存的数据库里面取,也可以直接从前端传,我这里取的是数据库里的,按你自己的来
- Double totalMoney = *****Dto.get******Vo().getTotalMoney()*100;
- Integer intToalMoney = totalMoney.intValue();
-
- Double refundMoney = stringMonry*100;
- Integer intRefundMoney = refundMoney.intValue();
-
- String url = "https://(填写域名)/(填写回调接口url)"; //如果你需要回调的话
- if (stringMonry <= totalMoney) {
- PayConfig config = new PayConfig();
- WXPay wxpay = new WXPay(config);
- String refundNo = String.valueOf(UUID.randomUUID());
- Map<String, String> map = new HashMap<>();
- map.put("appid", config.getAppID());
- map.put("mch_id", config.getMchID());
- map.put("refund_desc", confirmCancel.getReason()); //退款原因
- map.put("nonce_str", WXPayUtil.generateNonceStr());
- map.put("transaction_id", transactionId);
- map.put("out_refund_no", refundNo);
- map.put("total_fee", intToalMoney + ""); //总价格
- map.put("refund_fee", intRefundMoney + ""); //退款价格
- map.put("notify_url",url); //回调地址
- String sign = WXPayUtil.generateSignature(map, config.getKey());
- map.put("sign", sign);
-
- Map<String, String> refund = wxpay.refund(map);
- System.out.println(refund); //返回的详情,可以根据这个来看成没成功
- String return_code = refund.get("return_code");
- String return_msg = refund.get("return_msg");
-
- } else {
- return buildFailure("超出原有金额");
- }
- }
- return buildFailure("失败");
- }
实现效果
请求参数
注意:如果使用回调,得先在退款的接口中,设置你的notify_url,这个url为你的回调接口地址
再次提醒,@注解按需求添加。
- @Log
- @PostMapping("refundNotifyResult")
- public Object refundNotifyResult(@RequestBody String xmlData) throws Exception {
- System.out.println("进入回调");
- //TODO 具体业务处理
- logger.info(xmlData); //回调接收到的是xml格式的数据
-
- PayConfig config = new PayConfig();
- Map<String, String> xmlMap = WXPayUtil.xmlToMap(xmlData); //转为map格式
- System.out.println("xmlMap==>" + xmlMap);
-
- //退款成功后返回一个加密字段req_info,以下为解密
- //解密的方法在上述准备工作的AesUtil类里
- String req_info = xmlMap.get("req_info");
- String resultStr = AesUtil.aesDecrypt(req_info,config.getKey());
-
- Map<String, String> reqInfo = WXPayUtil.xmlToMap(resultStr);
- System.out.println("reqInfo===>" + reqInfo);
-
- String out_trade_no = reqInfo.get("out_trade_no");
- String return_code = xmlMap.get("return_code");
-
- Map<String,Object> parm = new HashMap<>();
- if (StringUtils.isNotBlank(return_code) && StringUtils.equals(return_code, SUCCESS)) {
-
- //你自己的业务操作
- *********************************
-
- parm.put("return_code",SUCCESS);
- parm.put("req_info",reqInfo);
- }
-
- return parm; //返回给前端的参数
- }
以下为打印的数据,因为涉及隐私,所以大部分都打码了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。