package com.project.common.utils; import com.project.common.constant.WechatConstants; import com.project.common.dto.UnifiedOrderRequestBean; import com.project.common.dto.UnifiedOrderResponseBean; import com.project.common.dto.WxPayDataDTO; import com.project.common.exception.base.BaseException; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpEntity; import org.apache.http.ParseException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.util.EntityUtils; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; import javax.net.ssl.SSLContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.*; /** * 微信支付工具类 **/ @Slf4j public class WxPayUtils { /** * 获取签名(MD5加密) * @throws Exception */ public static String getSign(Object bean, String mchSecret){ String signTemp = null; Map fieldMap = new HashMap<>(); // 获取对象bean中的所有变量 Field[] fields = bean.getClass().getDeclaredFields(); // 提取bean中的所有变量名及变量值 try { for (Field field : fields) { // 获取原来的变量访问控制权限 boolean accessFlag = field.isAccessible(); // 修改访问权限 field.setAccessible(true); // 获取变量值 Object value = field.get(bean); if (value == null) { continue; } else { fieldMap.put(field.getName(), value); } // 恢复访问控制权限 field.setAccessible(accessFlag); } //字符串拼接 Set keySet = fieldMap.keySet(); String[] keyArray = keySet.toArray(new String[keySet.size()]); Arrays.sort(keyArray); StringBuilder sb = new StringBuilder(); for (String key : keyArray) { if (fieldMap.get(key).toString().trim().length() > 0) // 参数值为空,则不参与签名 sb.append(key.replaceAll("[A-Z]", "_$0").toLowerCase()).append("=").append(fieldMap.get(key).toString().trim()).append("&"); } //商户支付密钥 sb.append("key=").append(mchSecret); // // system.out.println(sb); signTemp = ToMD5Upper(sb.toString()); }catch (Exception e){ e.printStackTrace(); } return signTemp; } /** * * @param inStr * @return */ public static String ToMD5Upper(String inStr){ StringBuffer hexString = null; byte[] defaultBytes = inStr.getBytes(); try { MessageDigest algorithm = MessageDigest.getInstance("MD5"); algorithm.reset(); algorithm.update(defaultBytes); byte messageDigest[] = algorithm.digest(); hexString = new StringBuffer(); for (int i = 0; i < messageDigest.length; i++) { if (Integer.toHexString(0xFF & messageDigest[i]).length() == 1) { hexString.append(0); } hexString.append(Integer.toHexString(0xFF & messageDigest[i])); } messageDigest.toString(); inStr = hexString + ""; } catch (NoSuchAlgorithmException nsae) { nsae.printStackTrace(); } return hexString.toString().toUpperCase(); } /** * 生成随机字符串 * @param length * @return */ public static String getRandomString(int length){ //1.定义一个字符串(A-Z,a-z,0-9)即62个数字字母 String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890"; //2.由Random生成随机数 Random random = new Random(); StringBuffer sb = new StringBuffer(); //3. 长度为几就循环几次 for(int i = 0; i < length; ++i){ //从62个的数字或字母中选择 int number = random.nextInt(62); //将产生的数字通过length次承载到sb中 sb.append(str.charAt(number)); } //将承载的字符转换成字符串 return sb.toString(); } /** * 实体类转换XML * @param bean 实体类对象 * @return xml字符串 * @throws JAXBException xml格式转换异常 */ public static String beanToStr(Object bean) throws JAXBException { if (bean == null) { return ""; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); JAXBContext context = JAXBContext.newInstance(bean.getClass()); Marshaller marshaller = context.createMarshaller(); marshaller.marshal(bean, baos); String result = new String(baos.toByteArray()); // // system.out.println("xmlStr : " + result); return result; } /** * XML转换实体 * @param xmlStr * @param clazz * @param * @return * @throws JAXBException */ @SuppressWarnings("unchecked") public static T strToBean(String xmlStr, Class clazz) throws JAXBException { JAXBContext context = JAXBContext.newInstance(clazz); Unmarshaller unmarshaller = context.createUnmarshaller(); T bean = (T) unmarshaller.unmarshal(new StringReader(xmlStr)); return bean; } /** * 向指定URL发送POST方法的请求,请求参数为json或xml格式,获取响应结果 * @param url * @param paramStr * @return */ public static String sendPostBodyString(String url, String paramStr) { if (url == null || url.trim().length() == 0) { try { throw new Exception("url不能为空"); } catch (Exception e) { e.printStackTrace(); } } //HttpPost httpPost = new HttpPost(url); CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; SSLContext sslContext = null; try { /*httpPost.setEntity(new StringEntity(paramStr, "UTF-8")); // 创建默认的httpClient实例. httpClient = HttpClients.createDefault(); // 执行请求 response = httpClient.execute(httpPost);*/ HttpPost httpPost = new HttpPost(url); StringEntity reqEntity = new StringEntity(paramStr, "UTF-8"); // 设置类型 reqEntity.setContentType("application/x-www-form-urlencoded"); httpPost.setEntity(reqEntity); // 创建默认的httpClient实例. httpClient = createIgnoreSSLHttpClient(); if (httpClient == null) { log.error("HttpClient create fail."); return "HttpClient create fail."; } // 执行请求 response = httpClient.execute(httpPost); } catch (Exception e) { e.printStackTrace(); } return getString(response); } public static String getString(CloseableHttpResponse response) { String reString = null; HttpEntity entity = response.getEntity(); try { reString = EntityUtils.toString(entity, "UTF-8"); } catch (ParseException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return reString; } /** * 实体类转Map * @param obj * @return */ public static Map convertBeanToMap(Object obj) { if (obj == null) { return null; } Map map = new HashMap(); try { BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass()); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor property : propertyDescriptors) { String key = property.getName(); //过滤class属性 if (!key.equals("class")) {// 得到property对应的getter方法 Method getter = property.getReadMethod(); Object value = getter.invoke(obj); if(null==value){ map.put(key,""); }else{ map.put(key,value); } } } } catch (Exception e) { e.printStackTrace(); } return map; } /** * 二次签名 * @param map * @return * @throws Exception */ public static String getSign2(Map map){ StringBuilder sb = new StringBuilder(); sb.append("appId=" + map.get("appId")).append("&nonceStr=" + map.get("nonceStr")); sb.append("&package=prepay_id=" + map.get("prepayId")).append("&signType=MD5"); sb.append("&timeStamp=" + map.get("timeStamp")); //商户支付密钥 sb.append("&key=").append(map.get("mchSecret")); // // system.out.println(sb); return ToMD5Upper(sb.toString()); } /** * 将微信的返回结果进行拼接 * @param request * @return */ public static String getResponseStream(HttpServletRequest request){ StringBuffer xmlSb = new StringBuffer(); try { BufferedReader reader = request.getReader(); String line = ""; while ((line = reader.readLine()) != null) { xmlSb.append(line); } request.getReader().close(); } catch (Exception e) { throw new BaseException(e.getMessage()); } return xmlSb.toString(); } /** * 告诉微信回调成功,且处理完数据了 */ public static void callBackWeChat(HttpServletResponse response){ String resXml = "" + "" + "" + " "; BufferedOutputStream out = null; try { out = new BufferedOutputStream( response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 调起支付,返回给前端的数据 * @param unifiedOrder * @param mchSecret * @return */ public static WxPayDataDTO returnWxPayDataDTO(UnifiedOrderRequestBean unifiedOrder, String mchSecret){ WxPayDataDTO wxPayDataDTO = new WxPayDataDTO(); try{ String paramXml = WxPayUtils.beanToStr(unifiedOrder); log.info("----------paramXml-----------" + paramXml); String result = WxPayUtils.sendPostBodyString(WechatConstants.UNIFIED_ORDER, paramXml); log.info("----------result-----------" + result); //调用统一下单,接收响应数据 UnifiedOrderResponseBean unifiedOrderResponse = WxPayUtils.strToBean(result, UnifiedOrderResponseBean.class); log.info("----------unifiedOrderResponse-----------" + unifiedOrderResponse); String returnCode = "SUCCESS"; if (unifiedOrderResponse.getReturnCode().equals(returnCode)) { // 数据组合再次签名 Long timeStamp = System.currentTimeMillis(); Map sign2Map = new HashMap(); sign2Map.put("appId", unifiedOrder.getAppid()); sign2Map.put("nonceStr", unifiedOrderResponse.getNonceStr()); sign2Map.put("signType", WechatConstants.SIGN_TYPE); sign2Map.put("prepayId", unifiedOrderResponse.getPrepayId()); sign2Map.put("timeStamp", timeStamp); sign2Map.put("mchSecret", mchSecret); //生成二次签名 String sign2 = WxPayUtils.getSign2(sign2Map).toUpperCase(); wxPayDataDTO.setAppid(unifiedOrder.getAppid()); wxPayDataDTO.setTimeStamp(String.valueOf(timeStamp)); wxPayDataDTO.setNonceStr(unifiedOrderResponse.getNonceStr()); wxPayDataDTO.setPackages("prepay_id=" + unifiedOrderResponse.getPrepayId()); wxPayDataDTO.setPrepayId(unifiedOrderResponse.getPrepayId()); wxPayDataDTO.setSign(unifiedOrderResponse.getSign()); wxPayDataDTO.setPaySign(sign2); wxPayDataDTO.setSignType(WechatConstants.SIGN_TYPE); }else { log.info("----------微信支付错误代码:" + unifiedOrderResponse.getResultCode()); log.info("----------微信支付错误信息:" + unifiedOrderResponse.getReturnMsg()); } }catch (Exception e){ e.printStackTrace(); } return wxPayDataDTO; } /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * * @param strxml * @return * @throws * @throws IOException */ public static Map doXMLParse(String strxml) throws Exception { if (null == strxml || "".equals(strxml)) { return null; } Map m = new HashMap(); InputStream in = String2Inputstream(strxml); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(in); Element root = doc.getRootElement(); List list = root.getChildren(); Iterator it = list.iterator(); while (it.hasNext()) { Element e = (Element) it.next(); String k = e.getName(); String v = ""; List children = e.getChildren(); if (children.isEmpty()) { v = e.getTextNormalize(); } else { v = getChildrenText(children); } m.put(k, v); } //关闭流 in.close(); return m; } /** * 获取子结点的xml * * @param children * @return String */ public static String getChildrenText(List children) { StringBuffer sb = new StringBuffer(); if (!children.isEmpty()) { Iterator it = children.iterator(); while (it.hasNext()) { Element e = (Element) it.next(); String name = e.getName(); String value = e.getTextNormalize(); List list = e.getChildren(); sb.append("<" + name + ">"); if (!list.isEmpty()) { sb.append(getChildrenText(list)); } sb.append(value); sb.append(""); } } return sb.toString(); } public static InputStream String2Inputstream(String str) { return new ByteArrayInputStream(str.getBytes()); } public static CloseableHttpClient createIgnoreSSLHttpClient() { try { SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build(); } catch (Exception e) { e.printStackTrace(); } return null; } }