废话不多说直接上代码 不熟悉的直接私信我
依赖
<dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>0.4.2</version> </dependency>
配置类(填写自己的配置)
/** * 微信支付配置信息 */ @PropertySource(value = {"classpath:wxpayConfig.properties"}) @Component public class WxPayConfigure { private static final Logger log = LoggerFactory.getLogger(WxPayConfigure.class); @Value("${NOTIFY_URL}") private String NOTIFY_URL; @Value("${MCH_ID}") private String MCH_ID; // 商户号 @Value("${MCH_SERIAL_NO}") private String MCH_SERIAL_NO; // 商户证书序列号 // 你的商户私钥 @Value("${API_V3_KEY}") private String API_V3_KEY; @Value("${APP_ID}") private String APP_ID; @Value("${PACKAGE}") private String PACKAGE; //签名固定字符串(必须) // 商户私钥 @Value("${PRIVATE_KEY}") private String PRIVATE_KEY; //你的微信支付平台证书 @Value("${CERTIFICATE}") private String certificate; @Value("${wxDomainUrl}") private String wxDomainUrl; public String getWxDomainUrl() { return wxDomainUrl; } public void setWxDomainUrl(String wxDomainUrl) { this.wxDomainUrl = wxDomainUrl; } public String getNOTIFY_URL() { return NOTIFY_URL; } public void setNOTIFY_URL(String NOTIFY_URL) { this.NOTIFY_URL = NOTIFY_URL; } public String getMCH_ID() { return MCH_ID; } public void setMCH_ID(String MCH_ID) { this.MCH_ID = MCH_ID; } public String getMCH_SERIAL_NO() { return MCH_SERIAL_NO; } public void setMCH_SERIAL_NO(String MCH_SERIAL_NO) { this.MCH_SERIAL_NO = MCH_SERIAL_NO; } public String getAPI_V3_KEY() { return API_V3_KEY; } public void setAPI_V3_KEY(String API_V3_KEY) { this.API_V3_KEY = API_V3_KEY; } public String getAPP_ID() { return APP_ID; } public void setAPP_ID(String APP_ID) { this.APP_ID = APP_ID; } public String getPACKAGE() { return PACKAGE; } public void setPACKAGE(String PACKAGE) { this.PACKAGE = PACKAGE; } public String getPRIVATE_KEY() { return PRIVATE_KEY; } public void setPRIVATE_KEY(String PRIVATE_KEY) { this.PRIVATE_KEY = PRIVATE_KEY; } public String getCertificate() { return certificate; } public void setCertificate(String certificate) { this.certificate = certificate; } public WxPayConfigure() { } /** * 获取商户秘钥 * @return */ private PrivateKey getPrivateKey(){ PrivateKey privateKey = PemUtil.loadPrivateKey(PRIVATE_KEY); return privateKey; } /** * 获取签名验证器 启动加载一次 * @return * @throws NotFoundException */ @Bean public Verifier getVerifier() throws NotFoundException { //获取私钥 PrivateKey privateKey = getPrivateKey(); // 获取证书管理器实例 CertificatesManager certificatesManager = CertificatesManager.getInstance(); // 向证书管理器增加需要自动更新平台证书的商户信息 try { certificatesManager.putMerchant(MCH_ID, new WechatPay2Credentials(MCH_ID, new PrivateKeySigner(MCH_SERIAL_NO, privateKey)), API_V3_KEY.getBytes(StandardCharsets.UTF_8)); //... 若有多个商户号,可继续调用putMerchant添加商户信息 } catch (IOException | HttpCodeException | GeneralSecurityException e) { log.error("微信商户私钥加载失败={}",e.getMessage()); } // 从证书管理器中获取verifier return certificatesManager.getVerifier(MCH_ID); } /** * 获取微信支付http请求对象并且只加载一次 * @param verifier * @return */ @Bean public CloseableHttpClient getWxPayClient(Verifier verifier){ //获取商户私钥 PrivateKey privateKey = getPrivateKey(); // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新 WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() .withMerchant(MCH_ID, MCH_SERIAL_NO, privateKey) .withValidator(new WechatPay2Validator(verifier)); CloseableHttpClient httpClient = builder.build(); /** * 使用WechatPayHttpClientBuilder需要调用withWechatPay设置微信支付平台证书, * 而平台证书又只能通过调用获取平台证书接口下载。为了解开"死循环", * 你可以在第一次下载平台证书时,按照下述方法临时"跳过”应答签名的验证。 */ // CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create() // .withMerchant(MCH_ID, MCH_SERIAL_NO, privateKey) // .withValidator(response -> true) // NOTE: 设置一个空的应答签名验证器,**不要**用在业务请求 // .build(); return httpClient; } }
二维码工具类:
public class QrUtil { public static String qrBase64Str(String url) throws Exception{ String base64Str = null; ByteArrayOutputStream out = null; try { out = QRCode.from(url).to(ImageType.JPG).withSize(250, 250).stream(); BASE64Encoder encoder = new BASE64Encoder(); // 返回Base64编码过的字节数组字符串 base64Str = encoder.encode(out.toByteArray()); } finally { if (null != out) { out.close(); } } return base64Str; }
@Service public class WxPayUtil { private static Log log = LogFactory.getLog(WxPayUtil.class); @Autowired private WxPayConfigure wxPayConfigure; @Autowired private MyConfiguration myConfiguration; /** * 商户Native支付下单接口,微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。 */ public String createOrder(PayParams payParams, HttpServletResponse response){ // HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native"); HttpPost httpPost = new HttpPost(WxApiType.NATIVE_PAY.getValue()); 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(); //元化为分 BigDecimal bigDecimal = new BigDecimal(payParams.getTotalAmount()); BigDecimal str = new BigDecimal("100"); BigDecimal moneyResult = bigDecimal.multiply(str); //appid 微信生成的应用ID,全局唯一。 必填 //mchid 直连商户号 必填 //description 商品描述 必填 //out_trade_no 商户订单号 商户系统内部订单号 必填 // time_expire 交易结束时间 非必填 订单失效时间 //attach 附加数据 //notify_url 必填 回调url 必填 //amount + 订单金额 total int类型(微信要求的) 必填 currency 货币类型 CNY(人民币) 非必填 rootNode.put("mchid", wxPayConfigure.getMCH_ID()) .put("appid",wxPayConfigure.getAPP_ID() ) .put("description", "日照市中心医院自助缴费") .put("notify_url", wxPayConfigure.getNOTIFY_URL()) //商户订单号 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一 // .put("out_trade_no", payParams.getOutTradeNo()); .put("out_trade_no", payParams.getOutTradeNo()); rootNode.putObject("amount") .put("total", moneyResult.intValue()); // .put("total", 1); // rootNode.putObject("payer") // .put("openid", "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"); String codeUrl=""; try { objectMapper.writeValue(bos, rootNode); httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8")); CloseableHttpResponse closeableHttpResponse = null; CloseableHttpClient wxPayClient = wxPayConfigure.getWxPayClient(wxPayConfigure.getVerifier()); closeableHttpResponse = wxPayClient.execute(httpPost); String bodyAsString = EntityUtils.toString(closeableHttpResponse.getEntity()); ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(bodyAsString); //二维码url codeUrl = jsonNode.get("code_url").asText(); } catch (IOException | NotFoundException e) { e.printStackTrace(); } String qrCodePath = myConfiguration.getQrCode(); String filePath = String.format(qrCodePath+"/qr-%s.jpg", payParams.getOutTradeNo()); // log.info("filePath:" + filePath); ZxingUtils.getQRCodeImge(codeUrl, 256, filePath); //用流读取显示二维码 File file = new File(filePath); ServletOutputStream outputStream = null; try { outputStream = response.getOutputStream(); ImageIO.write(ImageIO.read(file),"jpg",outputStream); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } //最后删除生成的图片 FileUtil.deleteFile(filePath); return null; } /** * 微信查询订单 查询订单可通过微信支付订单号和商户订单号两种方式查询,两种查询方式返回结果相同 */ // 微信支付订单号查询 1217752501201407033233368018 微信支付订单号 1230000109 商户号 // get 请求URL: https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id} // https://api.mch.weixin.qq.com/v3/pay/transactions/id/1217752501201407033233368018?mchid=1230000109 //商户订单号查询 1217752501201407033233368018 商户订单号 1230000109商户号 // 商户订单号查询 get 请求URL: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no} // https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/1217752501201407033233368018?mchid=1230000109 public String queryWxOrder( PayParams payParams){ URIBuilder uriBuilder = null; try { // uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/"+payParams.getOutTradeNo()+"?mchid="+wxPayConfigure.getMCH_ID()); uriBuilder = new URIBuilder(WxApiType.ORDER_QUERY_BY_NO.getValue()+payParams.getOutTradeNo()+"?mchid="+wxPayConfigure.getMCH_ID()); } catch (URISyntaxException e) { e.printStackTrace(); } HttpGet httpGet = null; try { assert uriBuilder != null; httpGet = new HttpGet(uriBuilder.build()); } catch (URISyntaxException e) { e.printStackTrace(); } assert httpGet != null; httpGet.addHeader("Accept", "application/json"); CloseableHttpResponse response = null; CloseableHttpClient wxPayClient = null; try { wxPayClient = wxPayConfigure.getWxPayClient(wxPayConfigure.getVerifier()); } catch (NotFoundException e) { e.printStackTrace(); } try { assert wxPayClient != null; response = wxPayClient.execute(httpGet); } catch (IOException e) { e.printStackTrace(); } String bodyAsString = null; try { assert response != null; bodyAsString = EntityUtils.toString(response.getEntity()); } catch (IOException e) { e.printStackTrace(); } // System.out.println(bodyAsString); ObjectMapper mapper = new ObjectMapper(); String tradeStateDesc =""; try { JsonNode jsonNode = mapper.readTree(bodyAsString); // Map<String,String> map = mapper.convertValue(bodyAsString, Map.class); tradeStateDesc = jsonNode.get("trade_state_desc").asText(); } catch (IOException e) { e.printStackTrace(); } return tradeStateDesc; } /** * 关闭订单 待测试 * @param payParams */ public void closeWxOrder(PayParams payParams){ HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/"+payParams.getOutTradeNo()+"/close"); 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",wxPayConfigure.getMCH_ID()); CloseableHttpResponse response = null; String bodyAsString = null; try { objectMapper.writeValue(bos, rootNode); httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8")); CloseableHttpClient wxPayClient = wxPayConfigure.getWxPayClient(wxPayConfigure.getVerifier()); response = wxPayClient.execute(httpPost); bodyAsString = EntityUtils.toString(response.getEntity()); } catch (IOException | NotFoundException e) { e.printStackTrace(); } int statusCode = response.getStatusLine().getStatusCode();//204 正常 System.out.println(bodyAsString); } /** * 申请退款 * @param payParams * @return */ public String refundOrder(PayParams payParams){ HttpPost httpPost = new HttpPost(WxApiType.REFUND_ORDER_BY_NO.getValue()); 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(); //元化为分 BigDecimal str = new BigDecimal("100"); BigDecimal totalBigDecimal = new BigDecimal(payParams.getTotalAmount()); BigDecimal totalMoneyResult = totalBigDecimal.multiply(str); BigDecimal refundBigDecimal = new BigDecimal(payParams.getRefundAmount()); BigDecimal refundMoneyResult = refundBigDecimal.multiply(str); //appid 微信生成的应用ID,全局唯一。 必填 //mchid 直连商户号 必填 //description 商品描述 必填 //out_trade_no 商户订单号 商户系统内部订单号 必填 // time_expire 交易结束时间 非必填 订单失效时间 //attach 附加数据 //notify_url 必填 回调url 必填 //amount + 订单金额 total int类型(微信要求的) 必填 currency 货币类型 CNY(人民币) 非必填 //商户订单号 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一 rootNode.put("out_trade_no", payParams.getOutTradeNo()) .put("out_refund_no",payParams.getRefundTradeNo()) .put("reason", "正常退款"); rootNode.putObject("amount") .put("total", totalMoneyResult.intValue()) .put("refund", refundMoneyResult.intValue()) .put("currency","CNY"); String status=""; // String reason=""; try { objectMapper.writeValue(bos, rootNode); httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8")); CloseableHttpResponse response = null; CloseableHttpClient wxPayClient = wxPayConfigure.getWxPayClient(wxPayConfigure.getVerifier()); response = wxPayClient.execute(httpPost); String bodyAsString = EntityUtils.toString(response.getEntity()); ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(bodyAsString); //SUCCESS:退款成功 //CLOSED:退款关闭 //PROCESSING:退款处理中 //ABNORMAL:退款异常 status = jsonNode.get("status").asText(); // reason = jsonNode.get("reason").asText(); } catch (IOException | NotFoundException e) { e.printStackTrace(); } // return status; } }