ZQN
2024-06-17 b1ff19545212508d3f65741ab889f0b6df82a511
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
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<String, Object> 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<String> 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 <T>
     * @return
     * @throws JAXBException
     */
    @SuppressWarnings("unchecked")
    public static <T> T strToBean(String xmlStr, Class<T> 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<String, Object> convertBeanToMap(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        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<String, Object> 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 = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        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<String, Object> sign2Map = new HashMap<String, Object>();
                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("</" + name + ">");
            }
        }
 
        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;
    }
}