zoukankan      html  css  js  c++  java
  • 微信APP支付-java后台实现

    不说废话,直接上代码

    先是工具类(注意签名时要排序):

      1 import java.io.BufferedReader;
      2 import java.io.ByteArrayInputStream;
      3 import java.io.File;
      4 import java.io.FileInputStream;
      5 import java.io.InputStream;
      6 import java.io.InputStreamReader;
      7 import java.io.OutputStream;
      8 import java.net.ConnectException;
      9 import java.net.HttpURLConnection;
     10 import java.net.URL;
     11 import java.security.KeyStore;
     12 import java.util.ArrayList;
     13 import java.util.Collections;
     14 import java.util.Iterator;
     15 import java.util.List;
     16 import java.util.Map;
     17 import java.util.Random;
     18 import java.util.Set;
     19 import java.util.SortedMap;
     20 import java.util.TreeMap;
     21 
     22 import javax.net.ssl.HttpsURLConnection;
     23 import javax.net.ssl.SSLContext;
     24 
     25 import org.apache.http.Consts;
     26 import org.apache.http.HttpEntity;
     27 import org.apache.http.client.methods.CloseableHttpResponse;
     28 import org.apache.http.client.methods.HttpPost;
     29 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
     30 import org.apache.http.entity.StringEntity;
     31 import org.apache.http.impl.client.CloseableHttpClient;
     32 import org.apache.http.impl.client.HttpClients;
     33 import org.apache.http.ssl.SSLContexts;
     34 import org.apache.http.util.EntityUtils;
     35 import org.jdom.Document;
     36 import org.jdom.Element;
     37 import org.jdom.input.SAXBuilder;
     38 
     39 import com.system.property.WXProperty;
     40 import com.system.util.Tools;
     41 
     42 public class PayCommonUtil {
     43     
     44     
     45     /**
     46        * post请求并得到返回结果
     47        * @param requestUrl
     48        * @param requestMethod
     49        * @param output
     50        * @return
     51        */
     52       public static String httpsRequest21(String requestUrl, String requestMethod, String output) {
     53         try{
     54           URL url = new URL(requestUrl);
     55           HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
     56           connection.setDoOutput(true);
     57           connection.setDoInput(true);
     58           connection.setUseCaches(false);
     59           connection.setRequestMethod(requestMethod);
     60           if (null != output) {
     61             OutputStream outputStream = connection.getOutputStream();
     62             outputStream.write(output.getBytes("UTF-8"));
     63             outputStream.close();
     64           }
     65           // 从输入流读取返回内容
     66           InputStream inputStream = connection.getInputStream();
     67           InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
     68           BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
     69           String str = null;
     70           StringBuffer buffer = new StringBuffer();
     71           while ((str = bufferedReader.readLine()) != null) {
     72             buffer.append(str);
     73           }
     74           bufferedReader.close();
     75           inputStreamReader.close();
     76           inputStream.close();
     77           inputStream = null;
     78           connection.disconnect();
     79           return buffer.toString();
     80         }catch(Exception ex){
     81           ex.printStackTrace();
     82         }
     83 
     84         return "";
     85       }
     86     
     87 
     88     // 随机字符串生成
     89     public static String getRandomString(int length) { // length表示生成字符串的长度
     90         String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     91         Random random = new Random();
     92         StringBuffer sb = new StringBuffer();
     93         for (int i = 0; i < length; i++) {
     94             int number = random.nextInt(base.length());
     95             sb.append(base.charAt(number));
     96         }
     97         return sb.toString();
     98     }
     99 
    100     // 请求xml组装
    101     public static String getRequestXml(SortedMap<String, Object> parameters) {
    102         StringBuffer sb = new StringBuffer();
    103         sb.append("<xml>");
    104         Set es = parameters.entrySet();
    105         
    106         Iterator it = es.iterator();
    107         while (it.hasNext()) {
    108             Map.Entry entry = (Map.Entry) it.next();
    109             String key = (String) entry.getKey();
    110             // String value = (String) entry.getValue();
    111             Object value = entry.getValue();
    112             // || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)
    113             if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
    114                 sb.append("<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">");
    115             } else {
    116                 sb.append("<" + key + ">" + value + "</" + key + ">");
    117             }
    118         }
    119         sb.append("</xml>");
    120         return sb.toString();
    121     }
    122 
    123 
    124     // 生成签名
    125     public static String createSign(String characterEncoding, SortedMap<String, Object> parameterMap) {
    126         if (parameterMap == null) {
    127             return null;
    128         }
    129         StringBuffer sb = new StringBuffer();
    130         List<String> keys = new ArrayList<>(parameterMap.keySet());
    131         Collections.sort(keys);
    132 
    133         for (int i = 0; i < keys.size(); i++) {
    134             String key = keys.get(i);
    135             // String value = (String) parameters.get(key);
    136             Object value = parameterMap.get(key);
    137             // if (Tools.notEmpty(value)) {
    138             sb.append((i == 0 ? "" : "&") + key + "=" + value);
    139             // }
    140         }
    141         sb.append("&key=" + WXProperty.get("API_KEY"));
    142         System.out.println("【生成签名   】" + sb.toString());
    143         String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
    144         return sign;
    145     }
    146 
    147 
    148     // 微信支付请求
    149     public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
    150         try {
    151             URL url = new URL(requestUrl);
    152             HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    153             conn.setDoOutput(true);
    154             conn.setDoInput(true);
    155             conn.setUseCaches(false);
    156             // 设置请求方式(GET/POST)
    157             conn.setRequestMethod(requestMethod);
    158             conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
    159             // 当outputStr不为null时向输出流写数据
    160             if (null != outputStr) {
    161                 OutputStream outputStream = conn.getOutputStream();
    162                 // 注意编码格式
    163                 outputStream.write(outputStr.getBytes("UTF-8"));
    164                 outputStream.close();
    165             }
    166             // 从输入流读取返回内容
    167             InputStream inputStream = conn.getInputStream();
    168             InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
    169             BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    170             String str;
    171             StringBuffer buffer = new StringBuffer();
    172             while ((str = bufferedReader.readLine()) != null) {
    173                 buffer.append(str);
    174             }
    175             // 释放资源
    176             bufferedReader.close();
    177             inputStreamReader.close();
    178             inputStream.close();
    179             conn.disconnect();
    180             return buffer.toString();
    181         } catch (ConnectException ce) {
    182             System.out.println("连接超时:" + ce);
    183         } catch (Exception e) {
    184             System.out.println("https请求异常" + e);
    185         }
    186         return null;
    187     }
    188 
    189     // 退款的请求方法
    190     public static String httpsRequest2(String requestUrl, String requestMethod, String outputStr) throws Exception {
    191         KeyStore keyStore = KeyStore.getInstance("PKCS12");
    192         StringBuilder res = new StringBuilder("");
    193         FileInputStream instream = new FileInputStream(new File("/home/apiclient_cert.p12"));
    194         try {
    195             keyStore.load(instream, "".toCharArray());
    196         } finally {
    197             instream.close();
    198         }
    199 
    200         // Trust own CA and all self-signed certs
    201         SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "1313329201".toCharArray()).build();
    202         // Allow TLSv1 protocol only
    203         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
    204                 SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
    205         CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
    206         try {
    207 
    208             HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
    209             httpost.addHeader("Connection", "keep-alive");
    210             httpost.addHeader("Accept", "*/*");
    211             httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    212             httpost.addHeader("Host", "api.mch.weixin.qq.com");
    213             httpost.addHeader("X-Requested-With", "XMLHttpRequest");
    214             httpost.addHeader("Cache-Control", "max-age=0");
    215             httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
    216             StringEntity entity2 = new StringEntity(outputStr, Consts.UTF_8);
    217             httpost.setEntity(entity2);
    218             System.out.println("executing request" + httpost.getRequestLine());
    219 
    220             CloseableHttpResponse response = httpclient.execute(httpost);
    221 
    222             try {
    223                 HttpEntity entity = response.getEntity();
    224 
    225                 System.out.println("----------------------------------------");
    226                 System.out.println(response.getStatusLine());
    227                 if (entity != null) {
    228                     System.out.println("Response content length: " + entity.getContentLength());
    229                     BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
    230                     String text = "";
    231                     res.append(text);
    232                     while ((text = bufferedReader.readLine()) != null) {
    233                         res.append(text);
    234                         System.out.println(text);
    235                     }
    236 
    237                 }
    238                 EntityUtils.consume(entity);
    239             } finally {
    240                 response.close();
    241             }
    242         } finally {
    243             httpclient.close();
    244         }
    245         return res.toString();
    246 
    247     }
    248 
    249     // xml解析
    250     public static SortedMap<String, Object> doXMLParse(String strxml){
    251         strxml = strxml.replaceFirst("encoding=".*"", "encoding="UTF-8"");
    252 
    253         if (null == strxml || "".equals(strxml)) {
    254             return null;
    255         }
    256 
    257         SortedMap<String, Object> m = new TreeMap<>();
    258 
    259         InputStream in;
    260         try {
    261             in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
    262             SAXBuilder builder = new SAXBuilder();
    263             Document doc = builder.build(in);
    264             Element root = doc.getRootElement();
    265             List list = root.getChildren();
    266             Iterator it = list.iterator();
    267             while (it.hasNext()) {
    268                 Element e = (Element) it.next();
    269                 String k = e.getName();
    270                 String v = "";
    271                 List children = e.getChildren();
    272                 if (children.isEmpty()) {
    273                     v = e.getTextNormalize();
    274                 } else {
    275                     v = getChildrenText(children);
    276                 }
    277 
    278                 m.put(k, v);
    279             }
    280 
    281             // 关闭流
    282             in.close();
    283         } catch (Exception e1) {
    284             e1.printStackTrace();
    285         }
    286 
    287         return m;
    288     }
    289 
    290     public static String getChildrenText(List children) {
    291         StringBuffer sb = new StringBuffer();
    292         if (!children.isEmpty()) {
    293             Iterator it = children.iterator();
    294             while (it.hasNext()) {
    295                 Element e = (Element) it.next();
    296                 String name = e.getName();
    297                 String value = e.getTextNormalize();
    298                 List list = e.getChildren();
    299                 sb.append("<" + name + ">");
    300                 if (!list.isEmpty()) {
    301                     sb.append(getChildrenText(list));
    302                 }
    303                 sb.append(value);
    304                 sb.append("</" + name + ">");
    305             }
    306         }
    307 
    308         return sb.toString();
    309     }
    310     
    311     /**
    312      * 验证微信回调签名
    313       * @Description
    314       * @Author zhaozhenhua
    315       * @date   2018年5月10日
    316       * @param pd
    317       * @return
    318       * @throws Exception
    319      */
    320     public static boolean checkWXSign(SortedMap<String, Object> receiveMap) {
    321         String signFromAPIResponse = (String) receiveMap.get("sign");
    322         if (Tools.isEmpty(signFromAPIResponse)) {
    323             System.out.println("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
    324             return false;
    325         }
    326         //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
    327         receiveMap.remove("sign");
    328         String responseSign = createSign("utf-8", receiveMap);
    329         if (!responseSign.equals(signFromAPIResponse)) {
    330             //签名验不过,表示这个API返回的数据有可能已经被篡改了
    331             System.out.println("API返回的数据签名验证不通过,有可能被第三方篡改!!! responseSign生成的签名为" + responseSign);
    332             return false;
    333         }
    334 
    335         System.out.println("服务器回包里面的签名是:" + signFromAPIResponse);
    336         return true;
    337     }
    338     
    339 }

    配置文件信息读取:

     1 import java.io.FileNotFoundException;
     2 import java.io.IOException;
     3 import java.io.InputStream;
     4 import java.util.Properties;
     5 
     6 import org.slf4j.Logger;
     7 import org.slf4j.LoggerFactory;
     8 
     9 public class WXProperty {
    10     private static final Logger logger = LoggerFactory.getLogger(WXProperty.class);
    11 
    12     
    13     private static Properties props;
    14     static{
    15         loadProps();
    16     }
    17 
    18     synchronized static private void loadProps(){
    19         props = new Properties();
    20         InputStream in = null;
    21 
    22         try {
    23             in = WXProperty.class.getClassLoader().getResourceAsStream("wxinfo.properties");          
    24             props.load(in);
    25         } catch (FileNotFoundException e) {
    26             logger.error("payment.properties文件未找到");
    27         } catch (IOException e) {
    28             logger.error("出现IOException");
    29         } finally {
    30             try {
    31                 if(null != in) {
    32                     in.close();
    33                 }
    34             } catch (IOException e) {
    35                 logger.error("payment.properties文件流关闭出现异常");
    36             }
    37         }
    38     }
    39 
    40     //读取key对应的value
    41     public static String get(String key){
    42         if(null == props) {
    43             loadProps();
    44         }
    45         return props.getProperty(key);
    46     }
    47 
    48 }

    配置文件(前三个配置为微信申请APP支付通过后给的,而回调地址是自己定义的,在微信统一下单成功后会随着相应信息返回给前端,前端处理成功后执行这个回调接口):

     1 #服务号的应用ID
     2 APP_ID = XXXXXX
     3 #商户号
     4 MCH_ID = XXXXXXX
     5 #API密钥(前三个为微信申请获得)
     6 API_KEY = XXXXXXX
     7 #签名加密方式
     8 SIGN_TYPE = MD5
     9 #微信支付证书名称
    10 CERT_PATH = XXXXX
    11 #微信回调地址(自己定义)
    12 notify_url = XXXXX/success

    MD5加密方法:

     1 public class MD5Util {
     2 
     3     private static String byteArrayToHexString(byte b[]) {
     4         StringBuffer resultSb = new StringBuffer();
     5         for (int i = 0; i < b.length; i++)
     6             resultSb.append(byteToHexString(b[i]));
     7 
     8         return resultSb.toString();
     9     }
    10 
    11     private static String byteToHexString(byte b) {
    12         int n = b;
    13         if (n < 0)
    14             n += 256;
    15         int d1 = n / 16;
    16         int d2 = n % 16;
    17         return hexDigits[d1] + hexDigits[d2];
    18     }
    19 
    20     public static String MD5Encode(String origin, String charsetname) {
    21         String resultString = null;
    22         try {
    23             resultString = new String(origin);
    24             MessageDigest md = MessageDigest.getInstance("MD5");
    25             if (charsetname == null || "".equals(charsetname))
    26                 resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
    27             else
    28                 resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
    29         } catch (Exception exception) {
    30         }
    31         return resultString;
    32     }
    33 
    34     private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
    35 }

    微信支付统一下单接口封装的方法:

     1 public synchronized static SortedMap<String, Object> weixinPrePay (PageData pd) throws JDOMException, IOException{
     2         Map<String,String> returnMap = new HashMap<>();
     3             String trade_no = (String) pd.get("ORDERNUMBER");
     4             //支付金额
     5             BigDecimal totalAmount =  new BigDecimal((String)pd.get("ORDERMONEY"));
     6             //描述(以商品标题做为描述)
     7             String description = "XXXX:"+trade_no;
     8             //预支付
     9             SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();  
    10              parameterMap.put("appid", WXProperty.get("APP_ID"));  
    11              parameterMap.put("mch_id", WXProperty.get("MCH_ID"));  
    12              parameterMap.put("nonce_str", PayCommonUtil.getRandomString(32));  
    13              parameterMap.put("body", description);
    14              parameterMap.put("out_trade_no", trade_no);
    15              parameterMap.put("fee_type", "CNY");  
    16              BigDecimal total = totalAmount.multiply(new BigDecimal(100));  
    17              //parameterMap.put("total_fee", total.intValue()+"");  
    18              parameterMap.put("total_fee", 1+"");  
    19              parameterMap.put("spbill_create_ip", pd.get("spbillCreateIp"));  
    20              parameterMap.put("notify_url", WXProperty.get("notify_url"));
    21              parameterMap.put("trade_type", "APP");
    22              parameterMap.put("sign_type", "MD5");
    23              parameterMap.put("attach", pd.get("ORDERTYPE"));//附加数据
    24              String sign = PayCommonUtil.createSign("UTF-8", parameterMap) ;
    25              parameterMap.put("sign", sign);
    26              
    27              String requestXML = PayCommonUtil.getRequestXml(parameterMap);
    28              
    29              System.out.println("【转换为xml格式的参数】   "+requestXML);  
    30              String resultXML = PayCommonUtil.httpsRequest(  
    31                      "https://api.mch.weixin.qq.com/pay/unifiedorder","POST", requestXML); 
    32              
    33              System.out.println("【返回的XML】 " + resultXML);
    34              Map mapResult = PayCommonUtil.doXMLParse(resultXML);
    35             String returnCode = (String) mapResult.get("return_code");
    36              System.out.println("【返回内容   】   "+returnCode);  
    37             if("SUCCESS".equals(returnCode)){
    38                 String resultCode = (String) mapResult.get("result_code");
    39                 if("SUCCESS".equals(resultCode)){
    40                     String prepay_id = (String) mapResult.get("prepay_id");
    41                     
    42                     SortedMap<String, Object> finalpackage = new TreeMap<String, Object>();
    43                     finalpackage.put("appid", WXProperty.get("APP_ID"));
    44                     finalpackage.put("partnerid", WXProperty.get("MCH_ID"));
    45                     finalpackage.put("prepayid", prepay_id);
    46                     String noncestr = PayCommonUtil.getRandomString(32);
    47                     finalpackage.put("noncestr", noncestr);
    48                     String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
    49                     finalpackage.put("timestamp", timestamp);
    50                     finalpackage.put("package", "Sign=WXPay");
    51                     sign = PayCommonUtil.createSign("UTF-8", finalpackage) ;
    52                     SortedMap<String, Object> returnmap = new TreeMap<String, Object>();
    53                     returnmap.put("appid", WXProperty.get("APP_ID"));
    54                     returnmap.put("partnerId", WXProperty.get("MCH_ID"));
    55                     returnmap.put("prepayId", prepay_id);
    56                     returnmap.put("nonceStr", noncestr);
    57                     returnmap.put("timeStamp", timestamp);
    58                     returnmap.put("package", "Sign=WXPay");
    59                     returnmap.put("sign", sign);
    60                     return returnmap;
    61                 }else{
    62                     String errCodeDes = (String) mapResult.get("err_code_des");
    63                     returnMap.put("errCodeDes", errCodeDes);
    64                 }
    65             }else{
    66                 String returnMsg = (String) mapResult.get("return_msg");
    67                 returnMap.put("returnMsg", returnMsg);
    68             }
    69             return null;
    70     }

    微信支付回调地址:

     1  @RequestMapping(value = "/success")
     2          public String wxpaySucc(HttpServletRequest request){
     3              logger.info("微信支付回调");
     4              
     5              //商户处理后同步返回给微信参数:
     6              String xmlResultSuccess = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
     7              String xmlResultFailure = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
     8              
     9              SortedMap<String, Object> params = null;
    10             try {
    11                 InputStream inStream = request.getInputStream();
    12                 ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    13                 byte[] buffer = new byte[1024];
    14                 int len = 0;
    15                 while ((len = inStream.read(buffer)) != -1) {
    16                     outSteam.write(buffer, 0, len);
    17                 }
    18                 String resultxml = new String(outSteam.toByteArray(), "utf-8");
    19                 params =  PayCommonUtil.doXMLParse(resultxml);
    20                 logger.info("微信回调的信息:解析XML得到key:value");
    21                 for (Object b : params.keySet()) {
    22                     logger.info("key="+b+":"+"value="+params.get(b));
    23                 }
    24                 outSteam.close();
    25                 inStream.close();
    26             } catch (Exception e) {
    27                 e.printStackTrace();
    28                 logger.info("回调xml解析失败");
    29             }
    30             //验证签名
    31              boolean signVerified = PayCommonUtil.checkWXSign(params);
    32              logger.info("验证签名:"+signVerified);
    33              if (!signVerified) {
    34                  // 支付失败,失败业务逻辑处理
    35                  //将订单状态设置为待支付
    36                  
    37                  return xmlResultFailure;
    38              } else {
    39                      String return_code = (String) params.get("return_code");//状态
    40                      String out_trade_no = (String) params.get("out_trade_no");//订单号
    41                      String ORDERTYPE = (String) params.get("attach");//商家数据包
    42                      System.out.println("订单号out_trade_no:"+out_trade_no);
    43                      
    44                      //防止微信重复通知
    45                      PageData pd = new PageData();
    46                      pd.put("ORDERNUMBER", out_trade_no);
    47                      try {
    48                         PageData payInfo = alipayInService.getPayInfo(pd);
    49                         if(payInfo != null){
    50                             return xmlResultSuccess;
    51                         }
    52                     } catch (Exception e1) {
    53                         e1.printStackTrace();
    54                     }
    55                      
    56                      if (return_code.equals("SUCCESS")) {
    57                          if (out_trade_no != null) {
    58                              //付款成功业务逻辑处理
    59                                     return xmlResultSuccess;
    60                                 default:
    61                                     break;
    62                                 }
    63                             } catch (Exception e) {
    64                                 e.printStackTrace();
    65                             }
    66                          }
    67                      }else{
    68                          logger.info("微信手机支付回调失败订单号:{}"+out_trade_no);
    69                          return xmlResultFailure;
    70                      }
    71              }
    72             return null;
    73          }
    74          
  • 相关阅读:
    webpack基础+webpack配置文件常用配置项介绍+webpack-dev-server
    webpack 支持的模块方法
    在nodejs中引进模块要经历的步骤
    git 学习笔记(常用命令)
    http缓存(http caching)
    http协议——cookie详解
    JavaScript实现排序二叉树的相关算法
    JavaScript将小写金额转换成大写
    React——组件的生命周期函数
    React——高阶组件
  • 原文地址:https://www.cnblogs.com/zhanglingbing/p/9073217.html
Copyright © 2011-2022 走看看