admin
2021-01-25 cbc9ffb792e29beddf15dbfa70437bfc40de5baa
完善微信H5支付功能
2个文件已修改
1个文件已添加
175 ■■■■■ 已修改文件
src/main/java/com/yeshi/buwan/controller/WXController.java 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/yeshi/buwan/pptv/entity/VideoPPTVMap.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/domain/LoginUser.hbm.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/yeshi/buwan/controller/WXController.java
New file
@@ -0,0 +1,168 @@
package com.yeshi.buwan.controller;
import com.yeshi.buwan.util.StringUtil;
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.entity.wx.WXAPPInfo;
import org.yeshi.utils.wx.WXPayV3Util;
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);
    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 = new WXAPPInfo();
        //验证证书序列号
        String mchSerialNo = request.getHeader("Wechatpay-Serial");
        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.error("微信支付回调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"}}
                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")) {
                    boolean isPaySuccess = WXPayV3Util.isPaySuccess(outTradeNo, wxappInfo);
                    if (isPaySuccess) {
                        //TODO 支付成功
                    }
                }
                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) {
            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();
        }
    }
}
src/main/java/com/yeshi/buwan/pptv/entity/VideoPPTVMap.java
@@ -8,6 +8,9 @@
@Document(collection = "videoPPTVMap")
public class VideoPPTVMap {
    public VideoPPTVMap() {
    }
    @Id
    private Long videoId;
    private String infoId;
src/main/resources/domain/LoginUser.hbm.xml
@@ -19,12 +19,8 @@
        <property name="systemId" type="string" column="`system_id`"></property>
        <property name="qqOpenId" type="string" column="`qq_open_id`"></property>
        <property name="qqNickName" type="string" column="`qq_nick_name`"></property>
        <property name="qqPortrait" type="string" column="`qq_portrait`"></property>
        <property name="wxOpenId" type="string" column="`wx_open_id`"></property>
        <property name="wxUnionId" type="string" column="`wx_union_id`"></property>
        <property name="wxNickName" type="string" column="`wx_nick_name`"></property>
        <property name="wxPortrait" type="string" column="`wx_portrait`"></property>
        <property name="email" type="string" column="`email`"></property>
        <property name="phone" type="string" column="`phone`"></property>