赞
踩
订阅通知
JSONObject body=new JSONObject(); body.set("touser","用户openId"); body.set("template_id","订阅模板id"); JSONObject json1=new JSONObject(); json1.set("appid","小程序appid"); json1.set("pagepath","index?foo=bar"); body.set("miniprogram",json1); JSONObject json=new JSONObject(); //参数thing2 json.set("thing2",new JSONObject().set("value", "标题")); //参数thing4 json.set("thing4",new JSONObject().set("value","内容")); body.set("data",json); String accessToken = "小程序accessToken"; String post = cn.hutool.http.HttpUtil.post("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken, body.toString());
获取用户openid
//1、向微信服务器 使用登录凭证 code 获取 session_key 和 openid String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + "小程序appid" + "&secret=" + "小程序secret" + "&js_code=" + "小程序获取到的用户code" + "&grant_type=authorization_code"; System.out.println(url); RestTemplate restTemplate = restTemplateConfig.restTemplateRemote(); ResponseEntity<String> res = restTemplate.getForEntity(url, String.class); JSONObject jsonObject = JSONObject.parseObject(res.getBody()); RestTemplateConfig类 ```java package com.yhyx.mallxdfzx.config; import com.google.common.collect.Lists; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpRequest; import org.apache.http.NoHttpResponseException; import org.apache.http.client.HttpClient; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.client.RestTemplate; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.io.InterruptedIOException; import java.net.UnknownHostException; import java.nio.charset.Charset; import java.util.List; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static org.apache.commons.collections.CollectionUtils.isEmpty; /** * @Description: RestTemplate配置类 * @ClassName RestTemplateConfig */ @Configuration public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } @Bean("restTemplateRemote") public RestTemplate restTemplateRemote() { return new RestTemplate(); } /***************** 添加连接池属性支持的RestTemplate ******************/ private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateConfig.class); /** * 每个主机路由最大连接数,默认50个 */ @Value("${httpclient.defaultMaxPerRoute:50}") private int defaultMaxPerRoute; /** * 全局最大连接数,默认100个 */ @Value("${httpclient.maxTotal:100}") private int maxTotal; /** * 每个连接最大数量,默认10个 */ @Value("${httpclient.maxConnTotal:10}") private int maxConnTotal; /** * 每个路由最大连接,默认10个 */ @Value("${httpclient.maxConnPerRoute:10}") private int maxConnPerRoute; /** * 连接请求超时时间,默认60秒 */ @Value("${httpclient.connectionRequestTimeout:60000}") private int connectionRequestTimeout; /** * 连接超时时间,默认10秒 */ @Value("${httpclient.connectionTimeout:10000}") private int connectionTimeout; /** * SOCKET超时时间,默认10秒 */ @Value("${httpclient.socketTimeout:10000}") private int socketTimeout; /** * 当需要对参数进行编码的时候,使用的编码格式,默认为UTF-8 */ @Value("${httpclient.uriEncode:UTF-8}") private String uriEncode; /** * {@code HTTP}重试请求次数限制 */ @Value("${httpclient.retryCount:3}") private Integer retryCount; /** * {@code HTTP}读取响应超时时间 */ @Value("${httpclient.readTimeout:60000}") private Integer readTimeout; /** * 创建收{@code HTTP}连接池管理的{@code Spring RestTemplate}实例 * * @param clientHttpRequestFactory * @return */ @Bean("PoolingRestTemplate") public RestTemplate poolingRestTemplate( @Qualifier("PoolingClientHttpRequestFactory") ClientHttpRequestFactory clientHttpRequestFactory ) { return createRestTemplate(clientHttpRequestFactory); } /** * 创建一个{@code RestTemplate}实例,分别给内部和外部区分是否需要负载均衡的{@code RestTemplate Bean}使用 * * @param clientHttpRequestFactory * @return */ private RestTemplate createRestTemplate(ClientHttpRequestFactory clientHttpRequestFactory) { RestTemplate poolingRestTemplate = new RestTemplate(clientHttpRequestFactory); // 设置消息转换器,避免乱码 List<HttpMessageConverter<?>> messageConverterList = poolingRestTemplate.getMessageConverters(); if (!isEmpty(messageConverterList)) { messageConverterList.stream().filter(StringHttpMessageConverter.class::isInstance) .forEach(converter -> { ((StringHttpMessageConverter) converter).setDefaultCharset(Charset.forName(uriEncode)); ((StringHttpMessageConverter) converter).setWriteAcceptCharset(true); ((StringHttpMessageConverter) converter).setSupportedMediaTypes(Lists.newArrayList(MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON)); }); } return poolingRestTemplate; } /** * 创建{@code ClientHttpRequestFactory} * * @param httpClient * @return */ @Bean("PoolingClientHttpRequestFactory") public ClientHttpRequestFactory clientHttpRequestFactory(@Qualifier("PoolingHttpClient") HttpClient httpClient) { HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); httpComponentsClientHttpRequestFactory.setReadTimeout(readTimeout); return httpComponentsClientHttpRequestFactory; } /** * 创建{@code HttpClient} * * @return */ @Bean("PoolingHttpClient") public HttpClient httpClient() { // 创建注册器 Registry<ConnectionSocketFactory> protocolRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("HTTP", PlainConnectionSocketFactory.getSocketFactory()) .register("HTTPS", SSLConnectionSocketFactory.getSocketFactory()) .build(); // 创建HTTP连接池管理器 PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(protocolRegistry); poolingHttpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute); poolingHttpClientConnectionManager.setMaxTotal(maxTotal); // 创建请求配置 RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(connectionRequestTimeout) .setConnectTimeout(connectionTimeout) .setSocketTimeout(socketTimeout) .build(); // 创建ClosableHttpClient对象 HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); return httpClientBuilder .setMaxConnTotal(maxConnTotal) .setMaxConnPerRoute(maxConnPerRoute) .setDefaultRequestConfig(requestConfig) .setRetryHandler(httpRequestRetryHandler()) .build(); } /** * 重试处理器 * * @return */ @Bean("HttpRequestRetryHandler") public HttpRequestRetryHandler httpRequestRetryHandler() { LOGGER.info("创建HttpRequest连接重试管理器"); return this::handleRetryException; } private Boolean handleRetryException(IOException e, int i, HttpContext httpContext) { if (i > retryCount) { // 重试超过3次,放弃请求 LOGGER.error("retry has more than 3 time, give up request"); return FALSE; } if (e instanceof NoHttpResponseException) { // 服务器没有响应,可能是服务器断开了连接,应该重试 LOGGER.error("receive no response from server, retry"); return TRUE; } if (e instanceof SSLHandshakeException) { // SSL握手异常 LOGGER.error("SSL hand shake exception"); return FALSE; } if (e instanceof InterruptedIOException) { // 超时 LOGGER.error("InterruptedIOException"); return FALSE; } if (e instanceof UnknownHostException) { // 服务器不可达 LOGGER.error("server host unknown"); return FALSE; } if (e instanceof SSLException) { LOGGER.error("SSLException"); return FALSE; } HttpClientContext context = HttpClientContext.adapt(httpContext); HttpRequest request = context.getRequest(); if (!(request instanceof HttpEntityEnclosingRequest)) { // 如果请求不是关闭连接的请求 return TRUE; } return FALSE; } }
获取用户手机号
http://t.csdn.cn/jFJY3
使用到的两个工具类(gradle导入)
```java
implementation group: 'com.alibaba', name: 'fastjson', version: '1.2.68'
implementation group: 'cn.hutool', name: 'hutool-all', version: '5.4.0'
public String payInquiryOrder(PayVo prescriptionPayVo) { try { String selfkey =sysConfig.getPrivatekey().trim();//商户v2秘钥 String resultStr = null; String str = null; String errorString = null; String errorCode = null; String resXML = null; String resXml = null; String nonce_str = WXPayUtil.generateNonceStr(); JSONArray json = null; Map map = null; SortedMap<Object, Object> orderMap = new TreeMap<Object, Object>(); /*----- 1.生成预支付订单需要的的package数据-----*/ SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>(); packageParams.put("appid","公众号appid"); packageParams.put("mch_id", "商户号"); packageParams.put("nonce_str", nonce_str); packageParams.put("notify_url", sysConfig.getIqpaysuccesscallback()); packageParams.put("attach", prescriptionPayVo.getAttach()); packageParams.put("nonce_str", nonce_str); packageParams.put("openid", prescriptionPayVo.getOpenid()); packageParams.put("out_trade_no", prescriptionPayVo.getOut_trade_no()); packageParams.put("spbill_create_ip", WXPayUtil.localip()); packageParams.put("total_fee",com.cn.ih.java.main.utils.Utils.getFee(prescriptionPayVo.getTotal())); packageParams.put("trade_type", "JSAPI"); packageParams.put("fee_type", "CNY"); packageParams.put("body", prescriptionPayVo.getDescription()); packageParams.put("sign_type", "MD5"); /*----2.根据package生成签名sign---- */ String sign = PayForUtil.createSign("UTF-8", packageParams, selfkey); packageParams.put("sign", sign); logger.info("###signWX" + sign); String requestXML = PayForUtil.getRequestXml(packageParams); logger.info("###requestXML" + requestXML); resXml = WxHttpUtil.postData("https://api.mch.weixin.qq.com/pay/unifiedorder",requestXML); logger.info("###resXml" + resXml); if (null == resXml || "".equals(resXml)) { errorString = "接口异常!返回数据为空,请检查接口是否可用;接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder" ; resXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <xml> <return_code>" + "fail" + "</return_code><return_msg>" + errorString + "</return_msg></xml> "; logger.info("###" + errorString); orderMap.put("ResultCode", "-1"); orderMap.put("ErrorMsg", "执行失败。"); json = JSONArray.fromObject(orderMap); } else { try { map = XMLUtil.doXMLParse(resXml); String return_code = (String) map.get("return_code"); System.out.println(return_code); String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String nonceStr = String.valueOf(System.currentTimeMillis()); orderMap.put("appId", sysConfig.getWxappid()); // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 orderMap.put("timeStamp", timestamp); orderMap.put("nonceStr", nonceStr); logger.info("###nonceStr" + nonceStr); orderMap.put("package", "prepay_id=" + map.get("prepay_id")); orderMap.put("signType", "MD5"); String sign1 = PayForUtil.createSign("UTF-8", orderMap, selfkey); orderMap.put("paySign", sign1); orderMap.put("resCode", return_code); logger.info("###sign" + map.get("sign")); json = JSONArray.fromObject(orderMap); } catch (JDOMException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } logger.info("###调用JSAPI预支付下单接口需要返回的参数" + json.toString()); return json.toString(); }catch(Exception e) { e.printStackTrace(); return super.errorResult(e.getMessage()); } }
PayVo类
/** * @author qingshi * @date 2022/9/5 15:51 * info: */ public class PayVo { private String description;//商品描述 private String out_trade_no;//商户订单号 private String time_expire;// private String attach;//附加数据 private String notify_url;//回调 private String openid;//用户标识 private String total;//总金额 public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getOut_trade_no() { return out_trade_no; } public void setOut_trade_no(String out_trade_no) { this.out_trade_no = out_trade_no; } public String getTime_expire() { return time_expire; } public void setTime_expire(String time_expire) { this.time_expire = time_expire; } public String getAttach() { return attach; } public void setAttach(String attach) { this.attach = attach; } public String getNotify_url() { return notify_url; } public void setNotify_url(String notify_url) { this.notify_url = notify_url; } public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getTotal() { return total; } public void setTotal(String total) { this.total = total; } }
getFee方法
public static String getFee(String fee) { System.out.println(Float.valueOf(fee).floatValue()); // System.out.println( String.valueOf(+ Float.parseFloat(fee)) ); Float a =Float.valueOf(fee).floatValue()*100; System.out.println(a); fee = String.valueOf(a);//浮点变量a转换为字符串str // System.out.println(str); //先把小数点后的0截取掉 int idx = fee.lastIndexOf(".");//查找小数点的位置 System.out.println(idx); String strNum = fee.substring(0,idx);//截取从字符串开始到小数点位置的字符串,就是整数部分 System.out.println(strNum); //将截取后的金额转换为整数 int num = Integer.valueOf(strNum);//把整数部分通过Integer.valueof方法转换为数字 //工行金额以分为单位,将金额* 100 // num = num * 100; System.out.println(num); return num+""; }
WXPayUtil类
import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.StringWriter; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.*; import java.security.MessageDigest; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.cn.ih.java.main.utils.WXPayConstants.SignType; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class WXPayUtil { /** * XML????????????Map *@author Lyp * @param strXML XML????? * @return XML?????????Map * @throws Exception */ public static Map<String, String> xmlToMap(String strXML) throws Exception { try { Map<String, String> data = new HashMap<String, String>(); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8")); org.w3c.dom.Document doc = documentBuilder.parse(stream); doc.getDocumentElement().normalize(); NodeList nodeList = doc.getDocumentElement().getChildNodes(); for (int idx = 0; idx < nodeList.getLength(); ++idx) { Node node = nodeList.item(idx); if (node.getNodeType() == Node.ELEMENT_NODE) { org.w3c.dom.Element element = (org.w3c.dom.Element) node; data.put(element.getNodeName(),element.getTagName()); } } try { stream.close(); } catch (Exception ex) { // do nothing } return data; } catch (Exception ex) { WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML); throw ex; } } /** * ??ap?????ML????????? * * @param data Map?????? * @return XML????????? * @throws Exception */ public static String mapToXml(Map<String, String> data) throws Exception { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); org.w3c.dom.Document document = documentBuilder.newDocument(); org.w3c.dom.Element root = document.createElement("xml"); document.appendChild(root); for (String key: data.keySet()) { String value = data.get(key); if (value == null) { value = ""; } value = value.trim(); org.w3c.dom.Element filed = document.createElement(key); filed.appendChild(document.createTextNode(value)); root.appendChild(filed); } TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); DOMSource source = new DOMSource(document); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); transformer.transform(source, result); String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", ""); try { writer.close(); } catch (Exception ex) { } return output; } /** * ?????? sign ?? XML ???????? * * @param data Map?????? * @param key API??? * @return ???sign?????ML */ public static String generateSignedXml(final Map<String, String> data, String key) throws Exception { return generateSignedXml(data, key, SignType.MD5); } /** * ?????? sign ?? XML ???????? * * @param data Map?????? * @param key API??? * @param signType ?????? * @return ???sign?????ML */ public static String generateSignedXml(final Map<String, String> data, String key, SignType signType) throws Exception { String sign = generateSignature(data, key, signType); data.put(WXPayConstants.FIELD_SIGN, sign); return mapToXml(data); } /** * ???????????? * * @param xmlStr XML?????? * @param key API??? * @return ????????? * @throws Exception */ public static boolean isSignatureValid(String xmlStr, String key) throws Exception { Map<String, String> data = xmlToMap(xmlStr); if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) { return false; } String sign = data.get(WXPayConstants.FIELD_SIGN); return generateSignature(data, key).equals(sign); } /** * ????????????????????ign???????????alse?????D5????? * * @param data Map?????? * @param key API??? * @return ????????? * @throws Exception */ public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception { return isSignatureValid(data, key, SignType.MD5); } /** * ????????????????????ign???????????alse?? * * @param data Map?????? * @param key API??? * @param signType ?????? * @return ????????? * @throws Exception */ public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception { if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) { return false; } String sign = data.get(WXPayConstants.FIELD_SIGN); return generateSignature(data, key, signType).equals(sign); } /** * ?????? * * @param data ???????? * @param key API??? * @return ??? */ public static String generateSignature(final Map<String, String> data, String key) throws Exception { return generateSignature(data, key, SignType.MD5); } /** * ??????. ?????????sign_type?????????signType???????????? * * @param data ???????? * @param key API??? * @param signType ?????? * @return ??? */ public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception { Set<String> keySet = data.keySet(); String[] keyArray = keySet.toArray(new String[keySet.size()]); Arrays.sort(keyArray); StringBuilder sb = new StringBuilder(); for (String k : keyArray) { if (k.equals(WXPayConstants.FIELD_SIGN)) { continue; } if (data.get(k).trim().length() > 0) // ?????????????????? sb.append(k).append("=").append(data.get(k).trim()).append("&"); } sb.append("key=").append(key); if (SignType.MD5.equals(signType)) { return MD5(sb.toString()).toUpperCase(); } else if (SignType.HMACSHA256.equals(signType)) { return HMACSHA256(sb.toString(), key); } else { throw new Exception(String.format("Invalid sign_type: %s", signType)); } } /** * ??????????? Nonce Str * * @return String ???????? */ public static String generateNonceStr() { return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); } /** * ??? MD5 * * @param data ???????? * @return MD5??? */ public static String MD5(String data) throws Exception { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] array = md.digest(data.getBytes("UTF-8")); StringBuilder sb = new StringBuilder(); for (byte item : array) { sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); } return sb.toString().toUpperCase(); } /** * ??? HMACSHA256 * @param data ???????? * @param key ??? * @return ?????? * @throws Exception */ public static String HMACSHA256(String data, String key) throws Exception { Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256"); sha256_HMAC.init(secret_key); byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8")); StringBuilder sb = new StringBuilder(); for (byte item : array) { sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); } return sb.toString().toUpperCase(); } /** * ??? * @return */ public static Logger getLogger() { Logger logger = LoggerFactory.getLogger("wxpay java sdk"); return logger; } /** * ????????????????? * @return */ public static long getCurrentTimestamp() { return System.currentTimeMillis()/1000; } /** * ?????????????????? * @return */ public static long getCurrentTimestampMs() { return System.currentTimeMillis(); } /** * ??? uuid?? ?????????????????? nonce_str * @return */ public static String generateUUID() { return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); } /** * ??????ip??? * @return */ public static String localip(){ String ip=null; Enumeration allNetInterfaces; try { allNetInterfaces=NetworkInterface.getNetworkInterfaces(); while(allNetInterfaces.hasMoreElements()){ NetworkInterface netInterface=(NetworkInterface)allNetInterfaces.nextElement(); List<InterfaceAddress> InterfaceAddress=netInterface.getInterfaceAddresses(); for(InterfaceAddress add:InterfaceAddress){ InetAddress Ip=add.getAddress(); if(Ip!=null&&Ip instanceof Inet4Address){ ip=Ip.getHostAddress(); } } } } catch (SocketException e) { System.out.println("??????ip???????????"); e.printStackTrace(); } return ip; } }
支付成功回调接口
@RequestMapping(value="/iqPaySucessCallMethod") public void iqPaySucessCallMethod(HttpServletRequest req, HttpServletResponse response){ logger.info("========== 开始处理支付回调通知 =========="); String resultStr = null; String str = null; InputStream inputStream; StringBuffer sb = new StringBuffer(); try { inputStream = req.getInputStream(); String s; BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); while ((s = in.readLine()) != null) { sb.append(s); } in.close(); inputStream.close(); // 解析xml成map Map<String, String> m = new HashMap<String, String>(); m = XMLUtil.doXMLParse(sb.toString()); // 过滤空设置TreeMap,扫码 SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>(); Iterator<String> it = m.keySet().iterator(); while (it.hasNext()) { String parameter = it.next(); String parameterValue = m.get(parameter); String v = ""; if (null != parameterValue) { v = parameterValue.trim(); } packageParams.put(parameter, v); } // 微信支付的api密钥 String key = sysConfig.getPrivatekey(); logger.info("微信支付返回回来的参数:" + packageParams); String return_code = (String) packageParams.get("return_code"); String result_code = (String) packageParams.get("result_code"); // 判断签名是否正确 if (PayForUtil.isTenpaySign("UTF-8", packageParams, key)) { // ------------------------------- // 处理业务开始 // -------------------------- String resXml = ""; if (StrKit.notBlank(return_code) && StrKit.notBlank(result_code) && return_code.equalsIgnoreCase("SUCCESS") && result_code.equalsIgnoreCase("SUCCESS")) { // 支付成功 // 执行自己的业务逻辑 // 声明日志插入结果对象 String outTradeNo = ((String) packageParams.get("out_trade_no")); logger.info("#########################开始校验订单号:"+outTradeNo+"是否存在" ); if(!CollectionUtils.isEmpty(inquiryOrderPayList)) { //非第一次回调 // 执行自己业务逻辑结束 logger.info("给微信回调返回成功"); // 通知微信异步成功不然会一直通知后台八次之后交易失败 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; }else { //第一次回调 //执行业务 logger.info("###流水表插入开始"); //获取微信回调返回的参数 packageParams.get("appid"); packageParams.get("mch_id"); packageParams.get("trade_type"); packageParams.get("trade_state"); packageParams.get("trade_state_desc"); packageParams.get("out_trade_no"); packageParams.get("transaction_id"); packageParams.get("bank_type"); packageParams.get("attach")); packageParams.get("time_end")); packageParams.get("openid")); packageParams.get("fee_type")); packageParams.get("fee_type")); Float.valueOf(packageParams.get("total_fee").toString()); Float.valueOf(packageParams.get("total_fee").toString()); logger.info("###流水表插入结束"); // 执行自己业务逻辑结束 logger.info("给微信回调返回成功"); // 通知微信异步成功不然会一直通知后台八次之后交易失败 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; logger.info("###该订单" + outTradeNo + "在数据库里的流水状态:" + inquiryOrderPay.toString()); } } else { logger.info("支付失败,错误信息:" + packageParams.get("err_code")); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; } // ------------------------------ // 处理业务完毕 // ------------------------------ BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } else { logger.info("通知签名验证失败"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } logger.info("==========结束处理支付回调通知=========="); }
微信退款
WXPay引入的包 //implementation group: 'com.github.wxpay',name: 'wxpay-sdk',version: '0.0.3' @Transactional @Override public String refundInquiryOrder(String transaction_id) { try { logger.info("#############################################执行微信支付退款接口refundPrescription方法开始"); logger.info("==========================微信退款开始!!========================"); Map<String,String> data = new HashMap<String,String>(); int pay = (int) inquiryOrderPay.getTotalFee(); String out_refund_no = UUIDHexGenerator.createTradeNo(); data.put("out_refund_no" , out_refund_no); data.put("transaction_id" , transaction_id); data.put("total_fee" , String.valueOf(pay)); data.put("refund_fee" , String.valueOf(pay)); PayConfig config = new PayConfig(); WXPay wxpay = new WXPay(config); data.put("appid" , config.getAppID()); data.put("mch_id" , config.getMchID()); data.put("nonce_str" , com.github.wxpay.sdk.WXPayUtil.generateNonceStr()); data.put("sign" , MD5Util.getSign(data)); Map<String,String> resp = wxpay.refund(data);//获取微信退款返回的结果 logger.info("微信返回信息:\n" + resp); String return_code = resp.get("return_code"); //返回状态码 String return_msg = resp.get("return_msg"); //返回信息 if("SUCCESS".equals(return_code)){//响应成功 String result_code = resp.get("result_code"); //业务结果 String err_code_des = resp.get("err_code_des"); //错误代码描述 if("SUCCESS".equals(result_code)){//退款成功 // 执行自己业务逻辑 }else{//退款失败 } }else{//响应失败 } logger.info("#####################################################################执行退款回调结束,退款表type: "+saveAndFlush.getType()); resMap.put("timestamp", TimeHelper.getCurrentTime()); String results = JsonHelper.parserMap(resMap); return results; } catch (Exception e) { e.printStackTrace(); return super.errorResult(e.getMessage()); } }
MD5Util类
import com.cn.ih.java.main.config.PayConfig; import com.github.wxpay.sdk.WXPayConstants; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Map; import java.util.Set; /** * @ClassName MD5Util * @Author ttaurus * @Date Create in 2020/1/21 13:56 */ public class MD5Util{ public static String getSign(Map<String,String> data) throws Exception{ PayConfig config = new PayConfig(); Set<String> keySet = data.keySet(); String[] keyArray = keySet.toArray(new String[keySet.size()]); Arrays.sort(keyArray); StringBuilder sb = new StringBuilder(); for(String k : keyArray){ if(k.equals(WXPayConstants.FIELD_SIGN)){ continue; } if(data.get(k).trim().length() > 0) // 参数值为空,则不参与签名 sb.append(k).append("=").append(data.get(k).trim()).append("&"); } sb.append("key=").append(config.getKey()); MessageDigest md = null; try{ md = MessageDigest.getInstance("MD5"); }catch(NoSuchAlgorithmException e){ e.printStackTrace(); } byte[] array = new byte[0]; array = md.digest(sb.toString().getBytes(StandardCharsets.UTF_8)); StringBuilder sb2 = new StringBuilder(); for(byte item : array){ sb2.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1 , 3)); } System.out.println("签名为:"+sb2); return sb2.toString().toUpperCase(); } }
PayConfig类
package com.cn.ih.java.main.config; import com.cn.ih.java.main.utils.WxPayConstant; import com.github.wxpay.sdk.WXPayConfig; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * @author qingshi * @date 2022/10/29 16:13 * info: */ public class PayConfig implements WXPayConfig { private byte[] certData; /** * 微信退款所需要的配置! 退款只需要证书即可。 * @throws Exception */ public PayConfig() throws Exception { //部署服务器用到的路径 绝对路径。 //String certPath = "/usr/local/app/tomcat-dev/webapps/shop/WEB-INF/classes/apiclient_cert.p12";//从微信商户平台下载的安全证书存放的目录 //本地用到的路径 相对路径 // String certPath = "E:\\JavaProject\\msgservice\\src\\main\\resources\\apiclient_cert.p12"; File file = new File(WxPayConstant.getPrivateppath()); InputStream certStream = new FileInputStream(file); this.certData = new byte[(int) file.length()]; certStream.read(this.certData); certStream.close(); } @Override public String getAppID() { return WxPayConstant.getWxappid(); //appid } public String getAPPSECRET(){ return WxPayConstant.getAppsecret(); //appSecret } @Override public String getMchID() { return WxPayConstant.getMchid(); //商户号id } @Override public String getKey() { return WxPayConstant.getPrivatekey(); //支付API密钥 } // public String getNOTIFY_URL(){ // /* // 支付回调URL 必须在https下访问。这一步无法在本地实现 必须设置在服务器上 // 此url只是作为一个样例。 // */ // return "https://www.testtest.design21/dev/user/pay/notify"; // } @Override public InputStream getCertStream() { ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData); return certBis; } @Override public int getHttpConnectTimeoutMs() { return 8000; } @Override public int getHttpReadTimeoutMs() { return 10000; } }
WxPayConstant类
在public class WxPayConstant {
public static String privateppath;
public static String getPrivateppath() {
return privateppath;
}
public static void setPrivateppath(String privateppath) {
WxPayConstant.privateppath = privateppath;
}
}
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。