package com.yeshi.location.app.controller;
|
|
import com.yeshi.location.app.service.inter.vip.OrderService;
|
import com.yeshi.location.app.utils.vip.VIPOrderUtil;
|
import com.yeshi.location.app.utils.vip.VipUtil;
|
import net.sf.json.JSONObject;
|
import org.apache.commons.io.IOUtils;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.stereotype.Controller;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.yeshi.utils.StringUtil;
|
import org.yeshi.utils.entity.wx.WXAPPInfo;
|
|
import javax.annotation.Resource;
|
import javax.crypto.Cipher;
|
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.spec.GCMParameterSpec;
|
import javax.crypto.spec.SecretKeySpec;
|
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.IOException;
|
import java.security.GeneralSecurityException;
|
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidKeyException;
|
import java.security.NoSuchAlgorithmException;
|
import java.util.Base64;
|
|
@Controller
|
@RequestMapping("wx")
|
public class WXController {
|
Logger logger = LoggerFactory.getLogger(WXController.class);
|
|
@Resource
|
private OrderService orderService;
|
|
private static String decryptToString(String apiV3Key, String associatedData, String nonce, String ciphertext)
|
throws GeneralSecurityException, IOException {
|
try {
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes("UTF-8"), "AES");
|
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes("UTF-8"));
|
|
cipher.init(Cipher.DECRYPT_MODE, key, spec);
|
cipher.updateAAD(associatedData.getBytes("UTF-8"));
|
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
throw new IllegalStateException(e);
|
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
throw new IllegalArgumentException(e);
|
}
|
}
|
|
/**
|
* 处理通知结果
|
*
|
* @param request
|
* @throws Exception
|
*/
|
private void process(HttpServletRequest request) throws Exception {
|
WXAPPInfo wxappInfo = VipUtil.getWXAPP();
|
//验证证书序列号
|
String mchSerialNo = request.getHeader("Wechatpay-Serial");
|
logger.debug("微信支付mchSerialNo:{}", mchSerialNo);
|
// if (!mchSerialNo.equalsIgnoreCase(wxappInfo.getMchSerialNo())) {
|
// throw new Exception("证书序列号不一致");
|
// }
|
|
String timeStamp = request.getHeader("Wechatpay-Timestamp");
|
String nonce = request.getHeader("Wechatpay-Nonce");
|
String signature = request.getHeader("Wechatpay-Signature");
|
String data = null;
|
|
try {
|
if (request.getInputStream() != null) {
|
String entity = IOUtils.toString(request.getInputStream(), "UTF-8");
|
data = entity;
|
logger.debug("微信支付回调entity:{}", entity);
|
}
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
|
|
if (StringUtil.isNullOrEmpty(data)) {
|
throw new Exception("通知的内容为空");
|
}
|
|
JSONObject resultJson = JSONObject.fromObject(data);
|
String eventType = resultJson.optString("event_type");
|
switch (eventType) {
|
//支付成功
|
case "TRANSACTION.SUCCESS":
|
JSONObject resource = resultJson.optJSONObject("resource");
|
String ciphertext = resource.optString("ciphertext");
|
String r = decryptToString(wxappInfo.getApiV3Key(), resource.optString("associated_data"), resource.optString("nonce"), ciphertext);
|
//解密格式如下 {"mchid":"1520950211","appid":"wxa99686bb65a9f466","out_trade_no":"buwan-vip-8","transaction_id":"4200000796202101259681241680","trade_type":"MWEB","trade_state":"SUCCESS","trade_state_desc":"支付成功","bank_type":"OTHERS","attach":"","success_time":"2021-01-25T16:18:33+08:00","payer":{"openid":"oq7R20lxhKF8qSnkszxFJHViyKEY"},"amount":{"total":10,"payer_total":10,"currency":"CNY","payer_currency":"CNY"}}
|
logger.debug("数据解码:{}", r);
|
JSONObject decript = JSONObject.fromObject(r);
|
String outTradeNo = decript.optString("out_trade_no");
|
String appId = decript.optString("appid");
|
String mchId = decript.optString("mchid");
|
String tradeState = decript.optString("trade_state");
|
//支付成功
|
if (tradeState.equalsIgnoreCase("SUCCESS")) {
|
Long id = VIPOrderUtil.getIdFromOutOrderNo(outTradeNo);
|
orderService.checkOrderPayState(id);
|
}
|
break;
|
}
|
}
|
|
|
/**
|
* 微信支付结果通知
|
*
|
* @param request
|
* @param response
|
*/
|
@RequestMapping("pay/vip")
|
public void vipPay(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
try {
|
process(request);
|
JSONObject data = new JSONObject();
|
data.put("code", "SUCCESS");
|
data.put("message", "处理成功");
|
response.sendError(200, data.toString());
|
} catch (Exception e) {
|
logger.error("微信支付回调处理出错:", e);
|
e.printStackTrace();
|
JSONObject data = new JSONObject();
|
data.put("code", "FAIL");
|
data.put("message", e.getMessage());
|
response.sendError(500, data.toString());
|
}
|
|
}
|
|
public static void main(String[] args) {
|
|
String result = "{\n" +
|
" \"id\":\"c86a0485-0b56-5c6a-b449-d2a17fbb98ea\",\n" +
|
" \"create_time\":\"2021-01-25T16:18:33+08:00\",\n" +
|
" \"resource_type\":\"encrypt-resource\",\n" +
|
" \"event_type\":\"TRANSACTION.SUCCESS\",\n" +
|
" \"summary\":\"支付成功\",\n" +
|
" \"resource\":{\n" +
|
" \"original_type\":\"transaction\",\n" +
|
" \"algorithm\":\"AEAD_AES_256_GCM\",\n" +
|
" \"ciphertext\":\"UG6kFmJ4z+zCyOldYZLa/y+jzWwyLLMjc8usFqum0Yh08qR0nGPhLYyXCyIGi6DvnG33Ju7t1grKBA5VP0nLqw8NrITwajCK+Ph6avkxSz6lv7ObenIGp6tg+SJe/UxS9rToLH0sDVUB4L6XvawHw5ite/40G0lrdVCbZlJZCm4NxfnH3iRMnBZBw3QaUlySRoKugMIc2WzloHueq7K4bc7tCln4uro3eNDEHe++p2QWuiHmDm6s+aMLHKdQj723aVPhmZLc1kWqUAua6QJx77Jn3eYy8I0PksTKh1EdK3DV4+Fl4+UBZ86aqHdIHy+7gj0vRyDXXIUdfHYHQPMkYr46KfjoVSbA/Jop+2uH610a8jBRP4aP/3YJ2XBJbvw/DSupTJ7z8k1e9xCNJUfN3SeycvFIyaQI/mYi8jpe2F6ek2wexGUAXB5bDmoNGMGkIbbLE9NjJazF8O1WtQilqMIeJ/CiW6Pnrn0N/BibK1EuJxyr2dXmHt+aA+jpvwI8pTWBXn8ZeYG9CeMM0Ml+mBQcPzYdPx1ZsrKylJoIlvwSZTy4cRGSQlC/0w==\",\n" +
|
" \"associated_data\":\"transaction\",\n" +
|
" \"nonce\":\"2pIZSvqoRYYu\"\n" +
|
" }\n" +
|
"}";
|
WXAPPInfo wxappInfo = new WXAPPInfo("wxa99686bb65a9f466", "1520950211", "454328C324C6CC21355D064B44D6524CD7506DD0", "", "XYJkJ2018FAfaodCCx899mLl138rfGVd");
|
|
JSONObject resultJson = JSONObject.fromObject(result);
|
JSONObject resource = resultJson.optJSONObject("resource");
|
String ciphertext = resource.optString("ciphertext");
|
try {
|
String r = decryptToString(wxappInfo.getApiV3Key(), resource.optString("associated_data"), resource.optString("nonce"), ciphertext);
|
System.out.println(r);
|
} catch (GeneralSecurityException e) {
|
e.printStackTrace();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
|
}
|
|
|
}
|