在pom.xml文件添加:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.47</version>
</dependency>
直接撸代码:
第一个文件代码:
public class GatewayNotifyController {
@Autowired
private MerchantTransCommonClient merchantTransCommonClient;
@Autowired
private MerchantWebChatClient MerchantWebChatClient;
@Autowired
private MerchantAlipayClient merchantAlipayClient;
@Autowired
private AESUtil aESUtil;
@ApiOperation("微信退款结果回调")
@RequestMapping(value = "/wxRefund/notifRefundyUrl", produces = MediaType.APPLICATION_JSON_VALUE)
public void notifRefundyUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info("微信退款结果回调开始回调-------");
SortedMap<String, Object> return_data = new TreeMap<String, Object>();
try {
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
String resultxml = new String(outSteam.toByteArray(), "utf-8");
log.info("微信退款结果回调内容:{}",resultxml);
Map<String, String> notifyMap = WXPayUtil.xmlToMap(resultxml); // 转换成map
outSteam.close();
inStream.close();
//判断返回状态码
if(notifyMap.get("return_code")!=null&¬ifyMap.get("return_code").equals("SUCCESS")){
//表示通讯成功
String appId=notifyMap.get("appid");//微信分配的公众账号ID
String mchId=notifyMap.get("mch_id");//微信支付分配的商户号
//应用渠道参数 查询这个微信分配的商户号和公众账号id在数据库中的商户秘钥,注意:同一个分配的商户号和公众账号ID 无论支付方式是什么秘钥都是一样的 SUCCESS
//这里面的代码是我自己的别用 主要是获取商户的秘钥开始 ---------begin
HsyAppChannelParamsDto appChannelParamsDto=null;
BaseResMessage<HsyAppChannelParamsDto> queryChannelByTransFlow = merchantTransCommonClient.queryChannelByChannelMerNoAndAppId(mchId,appId,PayChannelEnum.PAY_CHANNEL_WX.getIndex());
log.info("queryChannelByTransFlow:{}",queryChannelByTransFlow);
if(!ServiceConstants.RES_SUCCESS_CODE.equals(queryChannelByTransFlow.getCode())) {
if(BaseTransExceptionEnum.MER_APP_PAY_CHANNEL_PARAMS_ERROR.getKey().equals(queryChannelByTransFlow.getCode())) {
log.info("appId:{},mch_id:{},channelCode:{},未查询到应用渠道参数",mchId,appId,PayChannelEnum.PAY_CHANNEL_WX.getIndex());
return_data.put("return_code", "FAIL");
return_data.put("return_msg", "OK");
}else {
appChannelParamsDto= queryChannelByTransFlow.getData();
if(appChannelParamsDto==null||StringUtils.isEmpty(appChannelParamsDto.getSecretKey())){
log.info("appId:{},mch_id:{},channelCode:{},,查询到应用渠道参数秘钥为空",appId,mchId,PayChannelEnum.PAY_CHANNEL_WX.getIndex());
return_data.put("return_code", "FAIL");
return_data.put("return_msg", queryChannelByTransFlow.getMessage());
}
}
String respMsg= PayCommonUtil.getRequestXml(return_data);
log.info("微信退款结果回调内容respMsg:{}",respMsg);
sendResponse(response, respMsg);
return;
}
appChannelParamsDto= queryChannelByTransFlow.getData();
//返回成功商户秘钥为空的时候
if(appChannelParamsDto==null||StringUtils.isEmpty(appChannelParamsDto.getSecretKey())){
return_data.put("return_code", "FAIL");
return_data.put("return_msg", "商户秘钥为空");
String respMsg= PayCommonUtil.getRequestXml(return_data);
log.info("微信退款结果回调内容respMsg:{}",respMsg);
sendResponse(response, respMsg);
return;
}
//获取要解析的数据
String reqInfo=notifyMap.get("req_info");
//---获取商户的秘钥结束 end 获取解密后的返回串,这个才是真正需要的数据
log.info("微信退款结果退款解析数据前 appId:{}, mch_id:{}, SecretKey{}, reqInfo:{} ",appId,mchId,appChannelParamsDto.getSecretKey(),JSON.toJSONString(reqInfo));
String decryptInfo = aESUtil.decryptData(reqInfo, appChannelParamsDto.getSecretKey());
log.info("微信退款结果退款解析数据后 SecretKey:{}, decryptInfo解密后:{},",appChannelParamsDto.getSecretKey(),decryptInfo);
//解析回来返回为空
if(StringUtils.isEmpty(decryptInfo)){
return_data.put("return_code", "FAIL");
return_data.put("return_msg", "解密以后数据为空");
String respMsg= PayCommonUtil.getRequestXml(return_data);
log.info("微信退款结果回调内容respMsg:{}",respMsg);
sendResponse(response, respMsg);
return;
}
//将返回串转换成 Map
Map<String, String> reqInfoMap = WXPayUtil.xmlToMap(decryptInfo);
reqInfoMap.put("return_code",notifyMap.get("return_code"));
reqInfoMap.put("return_msg",notifyMap.get("return_msg"));
BaseResMessage<Object> dealTransOrderResult = MerchantWebChatClient.dealRefundNotifyOrderResult(reqInfoMap);
if(!ServiceConstants.RES_SUCCESS_CODE.equals(dealTransOrderResult.getCode())) {
if(BaseTransExceptionEnum.REFUND_RECORD_ALERDAY_SUCCESS.getKey().equals(dealTransOrderResult.getCode())) {
return_data.put("return_code", "SUCCESS");
return_data.put("return_msg", "OK");
}else {
return_data.put("return_code", "FAIL");
return_data.put("return_msg", dealTransOrderResult.getMessage());
}
}else {
return_data.put("return_code", "SUCCESS");
return_data.put("return_msg", "OK");
}
String respMsg= PayCommonUtil.getRequestXml(return_data);
log.info("结果通知返回微信内容respMsg:{}",respMsg);
sendResponse(response, respMsg);
return;
}else{
//表示通讯失败
return_data.put("return_code", notifyMap.get("return_code"));
return_data.put("return_msg", notifyMap.get("return_msg"));
String respMsg= PayCommonUtil.getRequestXml(return_data);
sendResponse(response, respMsg);
return;
}
} catch (Exception e) {
log.error("微信退款结果:"+e);
return_data.put("return_code", "FAIL");
return_data.put("return_msg", "系统异常");
String respMsg= PayCommonUtil.getRequestXml(return_data);
sendResponse(response, respMsg);
return;
}
/**
* 发送服务应答报文
*
* @throws Exception
* @throws IOException
*/
public void sendResponse(HttpServletResponse response, String respMsg) {
// POST请求服务,发送报文
OutputStream outputStream = null;
try {
byte[] bys = respMsg.getBytes("UTF-8");
// 设置Http-headers信息
response.setContentType("application/xml;charset=UTF-8");
outputStream = response.getOutputStream();
outputStream.write(bys);
outputStream.flush();
} catch (Exception e) {
log.error("微信通知返回失败",e);
} finally {
if (null != outputStream) {
try {
outputStream.close();
} catch (Exception e) {
log.error("微信通知返回失败",e);
}
}
}
}
}
}
第二个文件:
package com.haoshouyin.cloud.api.utils;
import com.github.wxpay.sdk.WXPayUtil;
import com.haoshouyin.cloud.common.utils.Base64Util;
import com.haoshouyin.cloud.common.utils.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.stereotype.Component;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.util.Map;
@Slf4j
@Component
public class AESUtil {
/**
* 密钥算法
*/
private static final String ALGORITHM = "AES";
/**
* 加解密算法/工作模式/填充方式
*/
private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";
/**
* 生成key
*/
//微信支付API密钥设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
/* private static String paySign = "d773533ef81d3b01f8933a5c0dcc8c71";
//对商户key做md5,得到32位小写key*
private static SecretKeySpec key = new SecretKeySpec(MD5Util.MD5Encode(paySign, "UTF-8").toLowerCase().getBytes(), ALGORITHM);
static {
}*/
/**
* AES加密
*
* @param data
* @return
* @throws Exception
*/
public static String encryptData(String data, String merchKey) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// 创建密码器
Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING, "BC");
// 初始化
SecretKeySpec key = new SecretKeySpec(MD5Util.MD5Encode(merchKey, "UTF-8").toLowerCase().getBytes(), ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return Base64Util.encode(cipher.doFinal(data.getBytes()));
}
/**
* AES解密
* <p>
* (1)对加密串A做base64解码,得到加密串B
* (2)用key*对加密串B做AES-256-ECB解密(PKCS7Padding)
*
* @param base64Data
* @return
* @throws Exception
*/
public static String decryptData(String base64Data, String merchKey) throws Exception {
try {
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING, "BC");
SecretKeySpec key = new SecretKeySpec(MD5Util.MD5Encode(merchKey, "UTF-8").toLowerCase().getBytes(), ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(Base64Util.decode(base64Data)));
} catch (Exception e) {
log.error("AES解密出错:{}",e);
e.printStackTrace();
}
return "";
}
public static void main(String[] args) throws Exception {
// String reqInfo="XpYWVVDwnqZctk5n1u66B0a+fQQ2bDlISsgOLog67a4RuSRXAomNUjumCFeXMbo4u1Li2ZZTx8cLRZSM63PC5k3gmgxzlMFympZ/wVVnvqiypkWSAJwBZ4uoFe4ax7eHFksI5GKNeV/qe1Ev0mS0RqzBL+f7elTu61vWXAu7489A24UwGwFHHJFHRnjb7w/uSiaj+efpVqnJXjcqvGmPajWc6M8eYnT45FFAPZru2CBvoQYS1DSeb84w74uvYBOdX7mdQs3mdISPg7gANxPMfbLwZvlaAaP4B0V4MkisskgUuiJMlVqbIgMIxJn1vsvzBgzZ3HPcuCsP3EHIK4AKzCfb8uIrX3bmMo/YszJbTzMsfbd+PFZh1Uqzh3Y1aG3lm+oBqZciTAZVZjIRHf5EpavkUhGGWY2eqPoi2tbpuCHT1cFa6kTCDMSYgpd3IVChFiSOyYmKE61wtNwFLaCdNBbpcKTnQyWCl1YOUx7N62A57ahuk6ngYTxGfCJOHFL+HUrPwviaIPz1wolrnzasEroXzBRA7xPnKfiyvGsz1plaGX8XBLZVisiKzP87Yfq2DfJ85PLXuEOd5nXXMlRPqCgLslsoCEvb9QCPCNp7b3TtZc4u4fxuPU5+MWamnicpkdU5lYt9ZSBL/0wuCNN6lklEvZry3RAi1BY4TchIsIXKI5qY3pvsdnRBm/XNAxI9HleX2eE7z+HjwdMRZHjjn2GzlJ5gpSXag8fxJ8QrABiZpN6B7u/bcwr/J7Xh1r4sJHJqlBaJ1XDQAqibFbjbNfs+hxrdny3bvsq8fGaLj44xPfDtUUzlFGNACKZO/4u93oFyGI3RnTbW/hsEUqKHgoDcxRpkyeS0poH/7beNa2ZyMrU3Mxm2EY/Wm4iy3tx5Xxss5FuQ9/Qf/YLTY8HG0B1lJ/nCZaklRgBEywAjg3AFl/UpZWnvu2fEm3GdtuQ5hqG5D6miGtDUb936BpSFXfPcGPtTJ3YW8VMaod3Hv0o=";
String xml = "<xml><return_code>SUCCESS</return_code><appid><![CDATA[wx7069606234e55acd]]></appid><mch_id><![CDATA[1504258471]]></mch_id><nonce_str><![CDATA[39874f40c95ac398ed839e07bfdd3ca3]]></nonce_str><req_info><![CDATA[XpYWVVDwnqZctk5n1u66B0a+fQQ2bDlISsgOLog67a4RuSRXAomNUjumCFeXMbo4u1Li2ZZTx8cLRZSM63PC5k3gmgxzlMFympZ/wVVnvqiypkWSAJwBZ4uoFe4ax7eHFksI5GKNeV/qe1Ev0mS0RqzBL+f7elTu61vWXAu7489A24UwGwFHHJFHRnjb7w/uSiaj+efpVqnJXjcqvGmPajWc6M8eYnT45FFAPZru2CBvoQYS1DSeb84w74uvYBOdX7mdQs3mdISPg7gANxPMfbLwZvlaAaP4B0V4MkisskgUuiJMlVqbIgMIxJn1vsvzBgzZ3HPcuCsP3EHIK4AKzCfb8uIrX3bmMo/YszJbTzMsfbd+PFZh1Uqzh3Y1aG3lm+oBqZciTAZVZjIRHf5EpavkUhGGWY2eqPoi2tbpuCHT1cFa6kTCDMSYgpd3IVChFiSOyYmKE61wtNwFLaCdNBbpcKTnQyWCl1YOUx7N62A57ahuk6ngYTxGfCJOHFL+HUrPwviaIPz1wolrnzasEroXzBRA7xPnKfiyvGsz1plaGX8XBLZVisiKzP87Yfq2DfJ85PLXuEOd5nXXMlRPqCgLslsoCEvb9QCPCNp7b3TtZc4u4fxuPU5+MWamnicpkdU5lYt9ZSBL/0wuCNN6lklEvZry3RAi1BY4TchIsIXKI5qY3pvsdnRBm/XNAxI9HleX2eE7z+HjwdMRZHjjn2GzlJ5gpSXag8fxJ8QrABiZpN6B7u/bcwr/J7Xh1r4sJHJqlBaJ1XDQAqibFbjbNfs+hxrdny3bvsq8fGaLj44xPfDtUUzlFGNACKZO/4u93oFyGI3RnTbW/hsEUqKHgoDcxRpkyeS0poH/7beNa2ZyMrU3Mxm2EY/Wm4iy3tx5Xxss5FuQ9/Qf/YLTY8HG0B1lJ/nCZaklRgBEywAjg3AFl/UpZWnvu2fEm3GdtuQ5hqG5D6miGtDUb936BpSFXfPcGPtTJ3YW8VMaod3Hv0o=]]></req_info></xml>";
Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml); // 转换成map
String reqInfo = notifyMap.get("req_info");
String key = "d773533ef81d3b01f8933a5c0dcc8c71";
System.out.println(AESUtil.decryptData(reqInfo, key));
}
}
注意:
因为解密为PKCS7Padding
所以需要先下载jar包,根据版本下载也可以在下面的百度云盘链接下载;
JDK8 jar包下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
JDK7 jar包下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK6 jar包下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
下载后替换掉本地的包,提前把本地的包备份
D:\jdk1.8\jdk1.8.0_111\jre\lib\security
D:\jdk1.8\jre1.8.0_111\lib\security
local_policy.jar
US_export_policy.jar
,因为某些国家的进口管制限制,Java发布的运行环境包中的加解密有一定的限制。比如默认不允许256位密钥的AES加解密,解决方法就是修改策略文件, 从官方网站下载JCE无限制权限策略文件,注意自己JDK的版本别下错了。将local_policy.jar和US_export_policy.jar这两个文件替换%JRE_HOME%\lib\security和%JDK_HOME%\jre\lib\security下原来的文件,注意先备份原文件。
百度云盘:
链接: https://pan.baidu.com/s/1H90qANpIgzKAX2JjGzVzpA 提取码: bp9g
里面提供了jdk6,jdk7,jdk8需要别的版本可以自己去下载
自己下载需要注册账户密码。