微信支付服务端工具类

@Service
public class CcbUtil {

    /**
     * 日志管理器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(CcbUtil.class);

    /**
     * 线上支付
     *
     * @param orderNo 订单号
     * @param openId  微信openId
     * @param proinfo 商品类型信息
     * @param payment 付款金额 单位:元,精确到两位小数
     * @return 支付参数
     */
    public static Map<String, String> pay(String orderNo, String openId, String proinfo, BigDecimal payment) {
        // 按指定顺序处理参数,进行签名
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("appid", WeChatApiUtil.APP_ID);//应用ID
        map.put("mchid", WeChatApiUtil.MCH_ID);//直连商户号
        map.put("time_expire", TimeUtil.timeStampToRfc3339(System.currentTimeMillis() + 300000)); // 订单超时时间,yyyyMMddhhmmss
        map.put("description", proinfo);//商品描述
        map.put("out_trade_no", orderNo);//商户订单号
        map.put("notify_url", WeChatApiUtil.NOTIFY_URL);//通知地址
        Map<String, Object> payMap = new HashMap<>();
        payMap.put("total", payment.multiply(BigDecimal.valueOf(100)).intValue());
        payMap.put("currency", "CNY");
        map.put("amount", payMap); // 总金额 单位为分
        Map<String, Object> payerMap = new HashMap<>();
        payerMap.put("openid", openId);
        map.put("payer", payerMap);//用户标识

        // 处理签名
        String token = getToken("POST", HttpUrl.parse(WeChatApiUtil.URL), JsonUtil.toJsonStr(map), orderNo);
        // 请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "WECHATPAY2-SHA256-RSA2048 " + token);
        headers.put("Accept", "application/json");
        LOGGER.info("微信支付发起请求:\n报文={}\n请求头={}", JsonUtil.toJsonStr(map), JsonUtil.toJsonStr(headers));
        // 请求
        String res = OkHttpUtil.postForString(MediaType.APPLICATION_JSON_VALUE, WeChatApiUtil.URL, JsonUtil.toJsonStr(map), headers);
        LOGGER.info("微信支付响应信息:\n报文={}", res);
        if (!CommonUtil.isEmpty(res)) {
            // 解析
            Map<String, String> resMap = JsonUtil.toMap(res);
            // 判断是否包含支付要素
            if (resMap.containsKey("prepay_id")) {
                String prepayId = resMap.get("prepay_id");
                // 组装支付要素
                Map<String, String> payInfo = new HashMap<>();
                payInfo.put("appId", WeChatApiUtil.APP_ID);
                payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                payInfo.put("nonceStr", RandomStringUtils.randomAlphanumeric(32));
                payInfo.put("package", "prepay_id=" + prepayId);
                payInfo.put("signType", "RSA");
                // 生成签名
                String content = String.format("%s\n%s\n%s\n%s\n", WeChatApiUtil.APP_ID, payInfo.get("timeStamp"), payInfo.get("nonceStr"), payInfo.get("package"));
                payInfo.put("paySign", sign(content));
                return payInfo;
            }
            throw new QualityException(ErrorMsg.PAYMENT_FAILED);
        }
        throw new QualityException(ErrorMsg.PAYMENT_FAILED);
    }

    private static String getToken(String method, HttpUrl url, String body, String orderNo) {
        String nonceStr = RandomStringUtils.randomAlphanumeric(32);
        long timestamp = System.currentTimeMillis() / 1000;
        String signature = sign(buildMessage(method, url, timestamp, nonceStr, body));
        return "mchid=\"" + WeChatApiUtil.MCH_ID + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + WeChatApiUtil.SERIAL_NO + "\","
                + "signature=\"" + signature + "\"";
    }

    private static String sign(String message) {
        String sign = "";
        try {
            String content = new String(Files.readAllBytes(Paths.get(WeChatApiUtil.MCH_PRIVATE_KEY_PATH)), "utf-8");
//            byte[] keyBytes = IOUtils.toByteArray(new FileInputStream());
//            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
//            KeyFactory kf = KeyFactory.getInstance("RSA");
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            PrivateKey newPrivateKey = kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
            Signature signature;
            signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(newPrivateKey);
            signature.update(message.getBytes("utf-8"));
            sign = Base64.getEncoder().encodeToString(signature.sign());
        } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IOException | InvalidKeySpecException e) {
            LOGGER.error("签名错误:{}", e);
            e.printStackTrace();
        }
        return sign;
    }

    private static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
        String canonicalUrl = url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
        }
        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }

    /**
     * 取消订单
     */
    public static void cancel(String outTradeNo) {
        // 按指定顺序处理参数,进行签名
        Map<String, String> map = new LinkedHashMap<>();
        map.put("mchid", WeChatApiUtil.MCH_ID);//直连商户号
        // 处理签名
        String token = getToken("POST", HttpUrl.parse(WeChatApiUtil.CANCEL(outTradeNo)), JsonUtil.toJsonStr(map), outTradeNo);
        // 请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "WECHATPAY2-SHA256-RSA2048 " + token);
        headers.put("Accept", "application/json");
        LOGGER.info("微信支付发起请求:\n报文={}\n请求头={}", JsonUtil.toJsonStr(map), JsonUtil.toJsonStr(headers));
        OkHttpUtil.postForString(MediaType.APPLICATION_JSON_VALUE, WeChatApiUtil.CANCEL(outTradeNo), JsonUtil.toJsonStr(map), headers);
    }

}
public class WeChatApiUtil {

    public static final String APP_ID = "wx1f1a699111111111122";

    public static final String APP_SECRET = "fb411117809111111df49c18691940";

    public static final String WX_OPENID_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";

    public static final String WX_USERINFO_URL = "https://api.weixin.qq.com/wxa/getpaidunionid?access_token=%s&openid=%s";

    public static final String WX_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    public static final String MCH_ID = "1500000001";

    public static final String API_V3_KEY = "test201900000n0712";

    public static final String SERIAL_NO = "12021555CDD4BC54045151245A3A8CE";

    public static final String URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";

    public static final String NOTIFY_URL = "https://www.test.com/test/api/pay-notify/wx";

    public static final String MCH_PRIVATE_KEY_PATH = "/data/test/apiclient_key.pem";

    //public static final String MCH_PRIVATE_KEY_PATH = "F:\\项目代码\\test\\apiclient_key.pem";
    public static final String CANCEL(String out_trade_no) {
        return "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + out_trade_no + "/close";
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值