您的位置 首页 java

实现APP微信支付之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.get byte s(Standard charset s.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("#34;);
            httpPost.add Header ("Accept", "application/json");
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();

            ObjectNode  root Node = 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"));
            CloseableHtt pre sponse response = httpClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());

            JSONObject  json Object = JSON.parseObject(bodyAsString);

            return (String) jsonObject.get("prepay_id");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }  

生成签名部分

     /**
     * APP支付 V3  SHA256with RSA  签名.
     *
     * @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(HttpServlet request  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 {
         Servlet InputStream 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. decode FromString(ciphertext));
            } catch (GeneralSecurityException e) {
                throw new IllegalArgumentException(e);
            }
            return new String(bytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }  

文章来源:智云一二三科技

文章标题:实现APP微信支付之Java服务端开发

文章地址:https://www.zhihuclub.com/186988.shtml

关于作者: 智云科技

热门文章

网站地图