龙空技术网

实现APP微信支付之Java服务端开发

奋斗-生活 211

前言:

目前你们对“java微信平台”都比较重视,同学们都想要分析一些“java微信平台”的相关内容。那么小编同时在网上汇集了一些关于“java微信平台””的相关资讯,希望咱们能喜欢,大家一起来了解一下吧!

首先要申请微信的应用,在微信开放平台中建立移动应用,并在“接口信息”里面开通“微信支付”。

随后,把api证书、apiv3密钥申请好并把回调地址设置好

接下来直接上代码!

这里是用maven引用微信支付的依赖

        <!-- 微信支付 -->        <dependency>            <groupId>com.github.wechatpay-apiv3</groupId>            <artifactId>wechatpay-apache-httpclient</artifactId>            <version>0.4.4</version>        </dependency>

这里是获取预支付交易会话标识的代码部分

    private  CloseableHttpClient httpClient;    private  AutoUpdateCertificatesVerifier verifier;    @Autowired    private WxPayConfigServiceImpl wxPayConfigService;    public void setup(String mchId, String appV3Key, String serialNo, String keyPath, String keyAlias) {        try {            KeyPair keyPair = WXKeyPairFactory.createPKCS12(keyPath, keyAlias, mchId);            PrivateKey merchantPrivateKey = keyPair.getPrivate();            //使用自动更新的签名验证器,不需要传入证书            verifier = new AutoUpdateCertificatesVerifier(                    new WechatPay2Credentials(mchId, new PrivateKeySigner(serialNo, merchantPrivateKey)),                    appV3Key.getBytes(StandardCharsets.UTF_8));            httpClient = WechatPayHttpClientBuilder.create()                    .withMerchant(mchId, serialNo, merchantPrivateKey)                    .withValidator(new WechatPay2Validator(verifier))                    .build();        } catch (Exception e) {            System.out.println(e.getMessage());            e.printStackTrace();        }    }    /**     * 微信APP支付     *     * @param desc 订单描述     * @param outTradeNo 订单号     * @param total 金额(单位为分)     * @return Client     * @throws Exception     */    @Override    public String createOrder(String desc, String outTradeNo, int total) throws Exception {        // 用于判断商户平台或商家服务        String appId = "";// 应用ID        String mchId = "";// 商户号        String serialNo = "";// 商户证书序列号        String appV3Key = "";// API V3密钥        String keyPath = "";// 商家平台证书路径        String keyAlias = "Tenpay Certificate";// 证书的别名,这里是固定值        String notifyUrl = "";// 回调地址        setup(mchId, appV3Key, serialNo, keyPath, keyAlias);        try {            HttpPost httpPost = new HttpPost(";);            httpPost.addHeader("Accept", "application/json");            httpPost.addHeader("Content-type", "application/json; charset=utf-8");            ByteArrayOutputStream bos = new ByteArrayOutputStream();            ObjectMapper objectMapper = new ObjectMapper();            ObjectNode rootNode = objectMapper.createObjectNode();            rootNode.put("mchid", mchId)                    .put("appid", appId)                    .put("notify_url", notifyUrl)                    .put("description", desc)                    .put("out_trade_no", outTradeNo);            rootNode.putObject("amount")                    .put("total", total);            objectMapper.writeValue(bos, rootNode);            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));            CloseableHttpResponse response = httpClient.execute(httpPost);            String bodyAsString = EntityUtils.toString(response.getEntity());            JSONObject jsonObject = JSON.parseObject(bodyAsString);            return (String) jsonObject.get("prepay_id");        } catch (IOException e) {            e.printStackTrace();        }        return null;    }

生成签名部分

    /**     * APP支付 V3  SHA256withRSA 签名.     *     * @param AppId        应用id     * @param timestamp    当前时间戳   因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持一致     * @param nonceStr     随机字符串  要和TOKEN中的保持一致     * @param prepayId         预支付交易会话ID     * @param mchId         商户号     * @param keyPath       支付证书     * @param keyAlias      证书的别名     * @return the string     */    @SneakyThrows    public static String generateAPPSignRSA(String AppId, long timestamp, String nonceStr, String prepayId,String mchId, String keyPath, String keyAlias)  {        KeyPair keyPair = WXKeyPairFactory.createPKCS12(keyPath, keyAlias, mchId);        String signatureStr = Stream.of(AppId, String.valueOf(timestamp), nonceStr, prepayId)                .collect(Collectors.joining("\n", "", "\n"));        Signature sign = Signature.getInstance("SHA256withRSA");        sign.initSign(keyPair.getPrivate());        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));        return Base64Utils.encodeToString(sign.sign());    }

回调验证部分代码

    // 微信支付回调    @PostMapping("/notify")    public Map<String, String> wechatCallback(HttpServletRequest request, HttpServletResponse response) {        Map<String, String> map = new HashMap<>(2);        try {            //微信返回的请求体            String body = WXPayUtil.getRequestBody(request);            //如果验证签名序列号通过            if (wxAppPayService.verifiedSign(request, body)) {                //微信支付通知实体类                WxPayNotify payNotify = JSONObject.parseObject(body, WxPayNotify.class);                //如果支付成功                if ("TRANSACTION.SUCCESS".equals(payNotify.getEventType())) {                    //通知资源数据                    WxResourceVo resource = payNotify.getResource();                    //解密后资源数据                    String apiV3Key = wxPayConfigService.selectWechatMerchantApiV3Key();                    String notifyResourceStr = WXPayUtil.decryptResponseBody(resource.getAssociatedData(), resource.getNonce(), resource.getCiphertext(), apiV3Key);                    //通知资源数据对象                    WxNotifyResourceVo notifyResourceVo = JSONObject.parseObject(notifyResourceStr, WxNotifyResourceVo.class);                    String outTradeNo = notifyResourceVo.getOutTradeNo();                    String transactionId = notifyResourceVo.getTransactionId();                    //逻辑实现                    //do something                    int res = 1;                    if (res == 1){                        //通知微信正常接收到消息,否则微信会轮询该接口                        map.put("code", "SUCCESS");                        map.put("message", "成功");                    }else{                        map.put("code", "FAIL");                        map.put("message", "失败");                        response.setStatus(416);                    }                } else {                    map.put("code", "FAIL");                    map.put("message", "失败");                    response.setStatus(416);                }                //通知微信正常接收到消息,否则微信会轮询该接口                return map;            }        } catch (Exception e) {            e.printStackTrace();        }        map.put("code", "FAIL");        map.put("message", "失败");        response.setStatus(416);        return map;    }

验证部分代码

    /**     * 验签     * @param request request请求     * @param body 微信返回请求体     * @return true,false     */    @Override    public boolean verifiedSign(HttpServletRequest request,String body){        boolean result = false;        try{            String appId = "";// 应用ID            String mchId = "";// 商户号            String serialNo = "";// 商户证书序列号            String appV3Key = "";// API V3密钥            String keyPath = "";// 商家平台证书路径            String keyAlias = "Tenpay Certificate";// 证书的别名,这里是固定值            //微信返回的证书序列号            String resSerialNo = request.getHeader("Wechatpay-Serial");            //微信返回的随机字符串            String nonceStr = request.getHeader("Wechatpay-Nonce");            //微信返回的时间戳            String timestamp = request.getHeader("Wechatpay-Timestamp");            //微信返回的签名            String wechatSign = request.getHeader("Wechatpay-Signature");            KeyPair keyPair = WXKeyPairFactory.createPKCS12(keyPath, keyAlias, mchId);            PrivateKey merchantPrivateKey = keyPair.getPrivate();            //组装签名字符串            String signStr = Stream.of(timestamp, nonceStr, body)                    .collect(Collectors.joining("\n", "", "\n"));            //使用自动更新的签名验证器,不需要传入证书            verifier = new AutoUpdateCertificatesVerifier(                    new WechatPay2Credentials(mchId, new PrivateKeySigner(serialNo, merchantPrivateKey)),                    appV3Key.getBytes(StandardCharsets.UTF_8));            result = verifier.verify(resSerialNo, signStr.getBytes(StandardCharsets.UTF_8), wechatSign);        }catch (Exception e){            e.printStackTrace();            System.out.println("e:" + e);        }        return result;    }

封装的函数

    /**     * 获取请求报文     * @param request     * @return     * @throws IOException     */    public static String getRequestBody(HttpServletRequest request) throws IOException {        ServletInputStream stream = null;        BufferedReader reader = null;        StringBuffer sb = new StringBuffer();        try {            stream = request.getInputStream();            // 获取响应            reader = new BufferedReader(new InputStreamReader(stream));            String line;            while ((line = reader.readLine()) != null) {                sb.append(line);            }        } catch (IOException e) {            throw new IOException("读取返回支付接口数据流出现异常!");        } finally {            reader.close();        }        return sb.toString();    }

解码部分代码

    /**     * 解密     * @param associatedData 附加数据包     * @param nonce 加密使用的随机串     * @param ciphertext Base64编码后的密文     * @param apiV3Key       支付apiV3秘钥     * @return     */    public static String decryptResponseBody(String associatedData, String nonce, String ciphertext, String apiV3Key) {        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"));            byte[] bytes;            try {                bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext));            } catch (GeneralSecurityException e) {                throw new IllegalArgumentException(e);            }            return new String(bytes, StandardCharsets.UTF_8);        } catch (Exception e) {            e.printStackTrace();        }        return null;    }

标签: #java微信平台