微信App支付 Java服务端 V3版

统一下单

Controller层

    /**
     * 微信下单
     *
     * @param reqDto
     * @return
     */
    @ApiOperation("微信下单")
    @PostMapping("/pay")
    public Result<WxPayResDto> wxpay(@RequestBody WxPayReqDto reqDto) {
        ValidatorUtils.validateEntity(reqDto);
        return iWxService.wxToPay(reqDto.getOrderId());
    }

controller 仅提供app端访问

Service层

/**
     * 微信下单
     *
     * @param orderId
     * @return
     */
    @Override
    public Result wxToPay(Long orderId) {
        //查询订单
        FwServiceOrder order = fwServiceOrderMapper.selectFwServiceOrderById(orderId);
        if (StringUtils.isNull(order)) {
            return Result.error("订单不存在");
        }
        if (!"0".equals(order.getStatus())) {
            return Result.error("订单状态有误");
        }
        //订单实际价格
        BigDecimal amount = null;
        if (StringUtils.isNull(order.getCouponsPrice())) {
            amount = order.getPrice();
        } else {
            amount = order.getPrice().subtract(order.getCouponsPrice());
        }
        if (amount.intValue() < 0) {
            return Result.error("非法操作");
        }
        //建造者模式构建参数
        WxPrePayMainDTO wxPrePayMainDTO = WxPrePayMainDTO.builder()
                .appid(WxConfigConstant.APP_ID)
                .mchid(WxConfigConstant.MCH_ID)
                .description(StringUtils.isEmpty(order.getRemak()) ? "服务下单" : order.getRemak())
                .out_trade_no(order.getNumber())
                .attach(order.getOrderId() + "")
                .notify_url(WxConfigConstant.NOTIFY_URL)
                .amount(new WxPrePayAmountDTO(amount.multiply(new BigDecimal(100)).intValue(), "CNY"))
                .build();
        //获取token
        String token = this.getToken(JSON.toJSONString(wxPrePayMainDTO), "POST", "/v3/pay/transactions/app");
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");
        headers.set("Authorization", token);
        logger.info("微信统一下单请求参数======" + JSON.toJSONString(wxPrePayMainDTO));
        logger.info("微信统一下单请求token======" + token);
         HttpEntity<String> request = new HttpEntity<String>(
                JSON.toJSONString(wxPrePayMainDTO), headers);
        JSONObject response = null;
        try {
            response = restTemplate.postForObject("https://api.mch.weixin.qq.com/v3/pay/transactions/app",
                    request, JSONObject.class);
        } catch (HttpClientErrorException e) {
            response = JSONObject.parseObject(e.getResponseBodyAsString());
            this.closeOrder(order.getNumber());
            return Result.error(response.getString("message"));
        }
        String prepay_id = response.getString("prepay_id");
        if (StringUtils.isEmpty(prepay_id)) {
            return Result.error("支付失败");
        }
        //需要再次签名,返给前端用来唤起支付
        logger.info("微信统一下单请求返回参数======" + response);
        AwakenPayDTO awakenPayDTO = this.getAwakenPaySign("prepay_id=" + prepay_id);
        awakenPayDTO.setOrderCode(order.getNumber());
        awakenPayDTO.setPrepayid(prepay_id);
        return Result.success(awakenPayDTO);
    }
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WxPrePayMainDTO {

    //应用ID
    private String appid;
    //直连商户号
    private String mchid;
    //商品描述
    private String description;
    //商户订单号
    private String out_trade_no;
    //附加数据
    private String attach;
    //通知地址
    private String notify_url;
    //订单金额
    private WxPrePayAmountDTO amount;

}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WxPrePayAmountDTO {
    //总金额 单位是分
    private Integer total;
    //货币类型
    private String currency = "CNY";

}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "微信支付返回参数", description = "微信支付返回参数")
public class AwakenPayDTO {

    @ApiModelProperty(value = "时间戳", name = "timeStamp", example = "20091225091010")
    private long timeStamp;
    @ApiModelProperty(value = "随机字符串", name = "nonceStr", example = "5K8264ILTKCH16CQ2502SI8ZNMTM67VS")
    private String nonceStr;
    @ApiModelProperty(value = "订单详情扩展字符串", name = "packageInfo", example = "Sign=WXPay")
    private String packageInfo;
    @ApiModelProperty(value = "签名类型", name = "signType", example = "RSA")
    private String signType;
    @ApiModelProperty(value = "签名", name = "paySign", example = "C380BEC2BFD727A4B6845133519F3AD6")
    private String paySign;
    @ApiModelProperty(value = "订单编号", name = "orderCode", example = "fw1515125221515")
    private String orderCode;
    @ApiModelProperty(value = "预支付交易会话ID", name = "prepayid", example = "K8264ILTKCH16CQ2502SI8ZNMTM67VS")
    private String prepayid;
}

支付成功后的回调

/**
     * 微信支付回调
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @Override
    public FwServiceOrder notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        FwServiceOrder order = null;
        Map<String, String> map = new HashMap<>(12);
        String result = readData(request);
        // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
        String plainText = verifyNotify(result, WxConfigConstant.KEY);
        if (StringUtils.isNotEmpty(plainText)) {
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "支付成功");
            //获取返回参数
            String orderId = JSON.parseObject(plainText).getString("attach");
            //用户支付金额,单位为分   total -总金额  payer_total-用户支付金额
            int payer_total = JSON.parseObject(plainText).getJSONObject("amount").getIntValue("total");
            order = fwServiceOrderMapper.selectFwServiceOrderById(Long.parseLong(orderId));
            if (StringUtils.isNotNull(order)) {
                if (!"0".equals(order.getStatus())) {
                    response.setStatus(500);
                    map.put("code", "ERROR");
                    map.put("message", "订单状态不满足付款条件");
                    order = null;
                } else {
                    //支付成功 修改订单信息
                    order.setStatus("1");
                    order.setPayType("0");
                    order.setPayTime(DateUtils.getNowDate());
                    //分转元
                    order.setActualPrice(new BigDecimal(payer_total).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
                    if (fwServiceOrderMapper.updateFwServiceOrder(order) <= 0) {
                        response.setStatus(500);
                        map.put("code", "ERROR");
                        map.put("message", "支付失败,请重试");
                        order = null;
                    }
                }
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "订单不存在");
                order = null;
            }
        } else {
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "签名错误");
        }
        response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
        response.getOutputStream().write(JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8));
        response.flushBuffer();
        return order;
    }

申请退款

/**
     * 微信申请退款
     *
     * @param reqDto
     * @return
     */
    @Override
    public Result wxRefunds(WxRefundsReqDto reqDto) {
        //参数判断
        if (StringUtils.isEmpty(reqDto.getOut_refund_no())) {
            return Result.error("退款单号不可为空");
        }
        if (StringUtils.isEmpty(reqDto.getOut_trade_no())) {
            return Result.error("订单号不可为空");
        }
        if (StringUtils.isNull(reqDto.getTotal())) {
            return Result.error("原订单金额不可为空");
        }
        if (StringUtils.isNull(reqDto.getRefund())) {
            return Result.error("退款金额不可为空");
        }
        //创建微信退款请求参数
        WxPreRefundsMainDTO mainDTO = WxPreRefundsMainDTO.builder()
                .out_refund_no(reqDto.getOut_refund_no())
                .out_trade_no(reqDto.getOut_trade_no())
                .amount(new WxPreRefundsAmountDTO(reqDto.getRefund(), reqDto.getTotal(), "CNY"))
                .notify_url(WxConfigConstant.REFUND_NOTIFY_URL)
                .reason(StringUtils.isEmpty(reqDto.getReason()) ? "默认退款原因" : reqDto.getReason())
                .build();
        //获取token
        String token = this.getToken(JSON.toJSONString(mainDTO), "POST", "/v3/refund/domestic/refunds");
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");
        headers.set("Authorization", token);
        logger.info("微信申请退款请求参数======" + JSON.toJSONString(mainDTO));
        logger.info("微信申请退款请求token======" + token);
        HttpEntity<String> request = new HttpEntity<String>(
                JSON.toJSONString(mainDTO), headers);
        JSONObject response = null;
        try {
            response = restTemplate.postForObject("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds",
                    request, JSONObject.class);
        } catch (HttpClientErrorException e) {
            response = JSONObject.parseObject(e.getResponseBodyAsString());
            return Result.error(response.getString("message"));
        }
        if (StringUtils.isNull(response)) {
            return Result.error("退款申请失败,请重试");
        }
        String status = response.getString("status");
        if ("SUCCESS".equals(status)) {
            return Result.success("退款申请成功");
        } else {
            return Result.error("退款申请失败,请重试");
        }
    }

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WxPreRefundsMainDTO {

    //原支付交易对应的商户订单号
    private String out_trade_no;
    //商户退款单号
    private String out_refund_no;
    //退款原因
    private String reason;
    //退款结果回调url
    private String notify_url;
    //金额信息
    private WxPreRefundsAmountDTO amount;
}

退款成功回调

@Override
    public Result<String> refundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, String> map = new HashMap<>(12);
        Result resultData = null;
        String result = readData(request);
        // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
        String plainText = verifyNotify(result, WxConfigConstant.KEY);
        if (StringUtils.isNotEmpty(plainText)) {
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "退款成功");
            JSONObject jsonObject = JSON.parseObject(plainText);
            resultData = new Result(200, "退款成功", jsonObject.getString("out_refund_no"));
        } else {
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "签名错误");
            resultData = new Result(500, "退款失败");
        }
        response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
        response.getOutputStream().write(JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8));
        response.flushBuffer();
        return resultData;
    }

获取统一下单请求Token

 /**
     * 获取统一下单请求Token
     *
     * @param body
     * @param method
     * @param url
     * @return
     */
    private String getToken(String body, String method, String url) {
        //1.加载证书
        KeyPair keyPair = wxPayUtil.createPKCS12("wx/apiclient_cert.p12",
                "Tenpay Certificate", WxConfigConstant.MCH_ID);
        String nonceStr = wxPayUtil.generateNonceStr();
        long timestamp = System.currentTimeMillis() / 1000;
        //2.获取签名
        String sign = wxPayUtil.requestSign(method, url, timestamp, nonceStr,
                body, keyPair);
        //3.封装token
        String token = wxPayUtil.token(WxConfigConstant.MCH_ID, nonceStr, timestamp, WxConfigConstant.CERTNO, sign);
        return token;
    }

处理返回对象

/**
     * 处理返回对象
     *
     * @param request
     * @return
     */
    static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

支付异步通知验证签名

   /**
     * v3 支付异步通知验证签名
     *
     * @param body 异步通知密文
     * @param key  api 密钥
     * @return 异步通知明文
     * @throws Exception 异常信息
     */
   private String verifyNotify(String body, String key) throws Exception {
        // 获取平台证书序列号
        JSONObject resultObject = JSON.parseObject(body);
        JSONObject resource = resultObject.getJSONObject("resource");
        String cipherText = resource.getString("ciphertext");
        String nonceStr = resource.getString("nonce");
        String associatedData = resource.getString("associated_data");
        // 你的Apiv3秘钥转换成Utf8的Byte
        byte[] aesKey = key.trim().toLowerCase().getBytes("UTF-8");
        // 以下微信传来的附加值(很重要)
        byte[] associatedDataBytes = associatedData.getBytes("UTF-8");
        byte[] nonceBytes = nonceStr.getBytes("UTF-8");
        byte[] cipherTextBytes =  Base64.decodeBase64(cipherText);

        AesUtil aesUtil = new AesUtil(aesKey);
        // 密文解密
        return aesUtil.decryptToString(
                associatedDataBytes,
                nonceBytes,
                cipherTextBytes
        );
    }

需要再次签名,返给前端用来唤起支付

    /**
     * 需要再次签名,返给前端用来唤起支付
     *
     * @param body
     * @return
     */
    private AwakenPayDTO getAwakenPaySign(String body) {
        //1.加载证书
        KeyPair keyPair = wxPayUtil.createPKCS12("wx/apiclient_cert.p12",
                "Tenpay Certificate", WxConfigConstant.MCH_ID);
        AwakenPayDTO awakenPayDTO = new AwakenPayDTO();
        String nonceStr = wxPayUtil.generateNonceStr();
        long timestamp = System.currentTimeMillis() / 1000;
        //2.获取签名
        String sign = wxPayUtil.awakenPaySign(WxConfigConstant.APP_ID, timestamp, nonceStr, body, keyPair);
        //3.封装token
        awakenPayDTO.setNonceStr(nonceStr);
        awakenPayDTO.setPackageInfo(body);
        awakenPayDTO.setSignType("RSA");
        awakenPayDTO.setTimeStamp(timestamp);
        awakenPayDTO.setPaySign(sign);
        return awakenPayDTO;
    }

附上工具类

/**
 * @ProjectName: aila
 * @Package: com.aila.api.pay.wx.tool
 * @ClassName: AesUtil
 * @Author: dujiayu
 * @Description: aes工具
 * @Date: 2021/7/21 9:47
 * @Version: 1.0
 */
public class AesUtil {

    static final int KEY_LENGTH_BYTE = 32;
    static final int TAG_LENGTH_BIT = 128;
    private final byte[] aesKey;

    /**
     * @param key APIv3 密钥
     */
    public AesUtil(byte[] key) {
        if (key.length != KEY_LENGTH_BYTE) {
            throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
        }
        this.aesKey = key;
    }

    /**
     * 证书和回调报文解密
     *
     * @param associatedData associated_data
     * @param nonce          nonce
     * @param cipherText     ciphertext
     * @return {String} 平台证书明文
     * @throws GeneralSecurityException 异常
     */
    public String decryptToString(byte[] associatedData, byte[] nonce, byte[] cipherText) throws GeneralSecurityException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);
            return new String(cipher.doFinal(cipherText), StandardCharsets.UTF_8);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }
@Component
public class WxPayUtil {
    private KeyStore store;
    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final Random RANDOM = new SecureRandom();
    private final Object lock = new Object();

    /**
     * 获取公私钥.
     *
     * @param keyPath  the key path
     * @param keyAlias the key alias
     * @param keyPass  password
     * @return the key pair
     */
    public KeyPair createPKCS12(String keyPath, String keyAlias, String keyPass) {
        Resource resource = new ClassPathResource(keyPath);//用来读取resources下的文件
//        ClassPathResource resource = new ClassPathResource(keyPath);
        char[] pem = keyPass.toCharArray();
        try {
            synchronized (lock) {
                if (store == null) {
                    synchronized (lock) {
                        store = KeyStore.getInstance("PKCS12");
                        store.load(resource.getInputStream(), pem);
                    }
                }
            }
            X509Certificate certificate = (X509Certificate) store.getCertificate(keyAlias);
            certificate.checkValidity();
            // 证书的序列号
//	            String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
            // 证书的 公钥
            PublicKey publicKey = certificate.getPublicKey();
            // 证书的私钥
            PrivateKey storeKey = (PrivateKey) store.getKey(keyAlias, pem);

            return new KeyPair(publicKey, storeKey);

        } catch (Exception e) {
            throw new IllegalStateException("Cannot load keys from store: " + resource, e);
        }
    }

    /**
     * V3  SHA256withRSA 签名.
     *
     * @param method       请求方法  GET  POST PUT DELETE 等
     * @param canonicalUrl 例如  https://api.mch.weixin.qq.com/v3/pay/transactions/app?version=1 ——> /v3/pay/transactions/app?version=1
     * @param timestamp    当前时间戳   因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持一致
     * @param nonceStr     随机字符串  要和TOKEN中的保持一致
     * @param body         请求体 GET 为 "" POST 为JSON
     * @param keyPair      商户API 证书解析的密钥对  实际使用的是其中的私钥
     * @return the string
     */
    @SneakyThrows
    public String requestSign(String method, String canonicalUrl, long timestamp, String nonceStr, String body, KeyPair keyPair) {
        String signatureStr = Stream.of(method, canonicalUrl, String.valueOf(timestamp), nonceStr, body)
                .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());
    }

    @SneakyThrows
    public String awakenPaySign(String appid, long timestamp, String nonceStr, String body, KeyPair keyPair) {
        String signatureStr = Stream.of(appid, String.valueOf(timestamp), nonceStr, body)
                .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());
    }

    /**
     * 生成Token.
     *
     * @param mchId     商户号
     * @param nonceStr  随机字符串
     * @param timestamp 时间戳
     * @param serialNo  证书序列号
     * @param signature 签名
     * @return the string
     */
    public String token(String mchId, String nonceStr, long timestamp, String serialNo, String signature) {
        final String TOKEN_PATTERN = "WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\","
                + "timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\"";
        // 生成token
        return String.format(TOKEN_PATTERN,
                mchId,
                nonceStr, timestamp, serialNo, signature);
    }

    public String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

    /**
     * 解密响应体.
     *
     * @param apiV3Key       API V3 KEY  API v3密钥 商户平台设置的32位字符串
     * @param associatedData response.body.data[i].encrypt_certificate.associated_data
     * @param nonce          response.body.data[i].encrypt_certificate.nonce
     * @param ciphertext     response.body.data[i].encrypt_certificate.ciphertext
     * @return the string
     * @throws GeneralSecurityException the general security exception
     */
    public String decryptResponseBody(String apiV3Key, String associatedData, String nonce, String ciphertext) {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
            GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));

            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData.getBytes(StandardCharsets.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 (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * 请求xml组装
     *
     * @param parameters
     * @return
     */
    public static String getRequestXml(SortedMap<String, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
                sb.append("<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">");
            } else {
                sb.append("<" + key + ">" + value + "</" + key + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }


    public static void main(String[] args) {
        WxPayUtil KeyPairFactory = new WxPayUtil();
        KeyPair createPKCS12 = KeyPairFactory.createPKCS12("/apiclient_cert.p12", "Tenpay Certificate", "商户号");
        String nonceStr = KeyPairFactory.generateNonceStr();
        long timestamp = System.currentTimeMillis() / 1000;
        String sign = KeyPairFactory.requestSign("GET", "/v3/certificates",
                timestamp, nonceStr,
                ""
                , createPKCS12);
        String token = KeyPairFactory.token("商户号", nonceStr, timestamp,
                "证书号", sign);

        System.out.println(token);
    }
}
public class WxConfigConstant {

    /**
     * APP_ID
     */
    public static final String APP_ID = "wxf30c210487f84321d";

    /**
     * APP_SECRET
     */
    public static final String APP_SECRET = "bee1813225a6c0caef88ab21b222226c9";


    //===================================以下为微信支付部分================================================
    /**
     * 直连商户号,由微信支付生成并下发
     */
    public static final String MCH_ID = "15262958571";

    /**
     * 密钥key
     */
    public static final String KEY = "51a57db9e0a4f1dd2a5113dc05424066b";

    /**
     * 证书序列号
     */
    public static String CERTNO = "4EC503193104E12B14A8E25D1FCDB224C0934DFBC0";

    /**
     * 微信支付回调通知地址
     */
    public static final String NOTIFY_URL = "/api/wxPay/wxPayNotify";

    /**
     * 退款回调
     */
    public static String REFUND_NOTIFY_URL = "/api/wxPay/refundNotify";

}

特别说明

在这里插入图片描述
秘钥文件放在了资源目录下,可跟据需要放在任意位置

   @Autowired
    private RestTemplate restTemplate;

此处注解需在项目中配置注入

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(5000);//ms
        factory.setConnectTimeout(15000);//ms
        return factory;
    }
}

微信支付v3大坑
java.security.InvalidKeyException: Illegal key size错误

产生错误原因:为了数据代码在传输过程中的安全,很多时候我们都会将要传输的数据进行加密,然后等对方拿到后再解密使用。我们在使用AES加解密的时候,在遇到128位密钥加解密的时候,没有进行什么特殊处理;然而,在使用256位密钥加解密的时候,如果不进行特殊处理的话,可能会因为jdk版本的问题出现这个异常java.security.InvalidKeyException: Illegal key size。

第一种情况:如果有policy 文件夹,说明此版本为JVM启用 无限制强度管辖策略 有了一种新的更简单的方法。

请在 当前文件夹中查找文件 java.security。

现在用文本编辑器打开java.security,并找到定义java安全性属性crypto.policy的行,它可以有两个值limited或unlimited - 默认值是limited。

默认情况下,您应该能找到一条注释掉的行:

#crypto.policy=unlimited

您可以通过取消注释该行来启用无限制,删除#:

crypto.policy=unlimited

现在重新启动指向JVM的Java应用程序即可。

第二种情况:没有policy 文件夹,而是直接就有local_policy.jar,US_export_policy.jar两个jar包。

去官方下载JCE无限制权限策略文件。

jdk 5: http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html#jce_policy-1.5.0-oth-JPR

jdk6: http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

JDK7的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK8的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
将两个jar文件放到%JAVE_HOME%\jre\lib\security目录下覆盖原来文件。

代码仅供对于v3版的微信支付一知半解的小伙伴提供参考

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一名技术极客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值