Say pay treasure first.

The first step: Go to Alipay to create a sandbox application and apply for opening the corresponding permission, which is the test environment. After the completion of the go to https://auth.alipay.com/login/ant_sso_index.htm?goto=https%3A%2F%2Fopenhome.alipay.com%2Fplatform%2FappDaily.htm%3Ft Ab %3Dinfo check your application, in which there will be APPID, Alipay gateway and other parameters, key and alipay public key can be generated as prompted, these parameters will be used in the code after.

Step 2: The code part of your own server. Before writing the code, import the SDK prepared by Ma Dad. Maven depends on the following.

< the dependency > < groupId > com. Alipay. The SDK < / groupId > < artifactId > alipay - SDK - Java < / artifactId > < version > 3.4.27. ALL < / version > </dependency>Copy the code

Then we need to know what the payment process is. According to the general logic, the front end takes the order ID and requests the unified ordering interface of the background. The interface sorts out the data and returns the information to the front end, and the front end requests Alipay to start the payment with the information. After the payment is completed, the front end redirects to the front page for synchronous notification according to the return_URL, and invoics the back-end interface of the server for asynchronous notification according to the notifY_URL.

Let’s get down to business:

Unified order interface: start from here is the first step in the payment process, organize data to the front to initiate payment requests, the interface parameters can refer to the official document should be https://docs.open.alipay.com/api (this is all the API documentation, find themselves need to interface). Note that return_URL and notifY_URL, return_URL: synchronous jump path, is the path of the front-end jump page after the payment is complete, usually the path of an HTML page. This jump only indicates that the payment is complete, meaning that the whole payment process is complete, not the success or failure of the payment. Notify_url is an asynchronous notification, usually a requestMapping of the back-end controller. This is the interface that really notifies the payment success or failure. The back-end needs to write an interface that accepts the information returned by Alipay. The unified order interface returns different information depending on the type of request. GET requests return JSON or XML, and POST directly returns a form with the order information. The front end can request payment after receiving the information returned by the unified single interface.

 public void alipay(UserEntity userEntity, HttpServletResponse response, Long id) {

Try {// Obtain the order information from the database according to the order ID to request the alipay interface data encapsulation (here it is best to pass the current login user together with SQL query, BookingOrderEntity BookingOrderEntity = UserDao.getorderDetail (userEntity.getid (), ID); / / encapsulation public parameters AlipayClient AlipayClient = new DefaultAlipayClient (alipayConfig. GetGatewayUrl (), alipayConfig. GetAppId (), alipayConfig.getMerchantPrivateKey(),"json", AlipayConfig.charset, alipayConfig.getAlipayPublicKey(), AlipayConfig.signType); AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest(); AlipayTradeWapPayRequest(); / / synchronization rebound in public parameters set in the front page and back asynchronous notification path alipayRequest. SetReturnUrl (alipayConfig. GetReturnUrl (.) replace ("ID", bookingOrderEntity.getId().toString())); alipayRequest.setNotifyUrl(alipayConfig.getNotifyUrl()); / / fill business parameters, namely, the order information String subject = bookingOrderEntity. GetSnapshotHotelName () +"-" + bookingOrderEntity.getBookingNo();
    alipayRequest.setBizContent("{" +
        " \"out_trade_no\":" + bookingOrderEntity.getBookingNo() + "," +
        " \"total_amount\":" + bookingOrderEntity.getPayPrice() + "," +
        " \"subject\":\"" + subject + "\"," +
        " \"product_code\":\"QUICK_WAP_WAY\"" +
        "}"); String form = AlipayClient.pageExecute (alipayRequest).getBody(); response.setContentType("text/html; charset=utf-8"); Response.getwriter ().write(form); } catch (AlipayApiException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}Copy the code

Alipay parameters entity class: I am written to the configuration file to take information, you can also be directly written as ordinary class parameters on the line.

@Component
@ConfigurationProperties(prefix = "alipay") public class AlipayConfig {/** * APPID, payid, payid */ @value ("${alipay.appId}") private String appId; /** * merchant private key, your PKCS8 format RSA2 private key */ @value ("${alipay.merchantPrivateKey}") private String merchantPrivateKey; / * * * alipay public key, check the address: https://openhome.alipay.com/platform/keyManage.htm under the corresponding APPID alipay public key. */ @Value("${alipay.alipayPublicKey}") private String alipayPublicKey; /** * The path of the server asynchronous notification page must be in the format of http://. */ @value (id=123)"${alipay.notifyUrl}") private String notifyUrl; /** * The path of the synchronization notification page is in the format of http://and cannot be added with? */ @value (id=123)"${alipay.return_url}")
  private String returnUrl; /** * @value ("${alipay.gatewayUrl}") private String gatewayUrl; /** * signType */ public static String signType ="RSA2"; Public static String charset ="utf-8";


  public String getAppId() {
    return appId;
  }

  public String getMerchantPrivateKey() {
    return merchantPrivateKey;
  }

  public String getAlipayPublicKey() {
    return alipayPublicKey;
  }

  public String getNotifyUrl() {
    return notifyUrl;
  }

  public String getReturnUrl() {
    return returnUrl;
  }

  public String getGatewayUrl() {
    return gatewayUrl;
  }

  public void setAppId(String appId) {
    this.appId = appId;
  }

  public void setMerchantPrivateKey(String merchantPrivateKey) {
    this.merchantPrivateKey = merchantPrivateKey;
  }

  public void setAlipayPublicKey(String alipayPublicKey) {
    this.alipayPublicKey = alipayPublicKey;
  }

  public void setNotifyUrl(String notifyUrl) {
    this.notifyUrl = notifyUrl;
  }

  public void setReturnUrl(String returnUrl) {
    this.returnUrl = returnUrl;
  }

  public void setGatewayUrl(String gatewayUrl) { this.gatewayUrl = gatewayUrl; }}Copy the code

POST is an auto-submitted form that can be loaded directly from the front end.


Nail internal penetration: Return_url notify_url and must be able to access to the outside web, if want to test locally, you can download a nailing Intranet through tool https://open-doc.dingtalk.com/microapp/debug/ucof2g, Here is an example of how to use Mac, Windows operation: CD to git clone directory, MAC and Windows two versions, Windows access, do not need to chmode command, this command is used to change the permission, start the command to ding-config = ding.cfg-subdomain =a 8080.

Open the penetration tool: as shown below, a is the domain prefix, which can be customized, and 8081 is the port of your local backend server.

To success: the diagram below, this as if can only use HTTP cannot use HTTPS, open after the success only need to change the notify_url to: http://a.vaiwan.com:8081/xxx/xxx.



Payment callback interface: The mechanism of Alipay is to call back after the payment is completed, and stop calling after receiving the return of SUCCESS from our server, and the whole payment process is completed. If SUCCESS we returned to Alipay is not received after 15 seconds (I don’t remember this data, please check the official document), the call will continue, and the time interval will gradually increase.

Therefore, the first step is to check whether this information has been processed in our database according to the order number returned by Alipay, because this situation may occur: Assuming that the callback interval is 15 seconds, we returned SUCCESS to Alipay at the 14th second. However, due to network reasons, Alipay did not receive our information at the 15th second, so it still responded to us. However, in fact, we had already processed the order information at the 14th second, but Alipay did not know. Therefore, if the order has been processed, no matter the payment is successful or failed, directly return SUCCESS to Alipay to tell it that Ben’s dad has known about it and back off.

The second step is to check the check. The information returned by Alipay is directly retrieved from the request. If the verification fails, it may be a malicious attack from other servers. Then return failure to Alipay. Judge APPID, payment amount, alipay to give me the success mark, etc., modify the order information payment success or failure.

  public void notify(HttpServletRequest request, HttpServletResponse response) {

Map<String, String> params = new HashMap<>(30); Map requestParams = request.getParameterMap();for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
      String name = (String) iter.next();
      String[] values = (String[]) requestParams.get(name);
      String valueStr = "";
      for (int i = 0; i < values.length; i++) {
        valueStr = (i == values.length - 1) ? valueStr + values[i]
            : valueStr + values[i] + ","; } params.put(name, valueStr); String outTradeNo = new String(request.getParameter())"out_trade_no").getBytes("ISO-8859-1"), "UTF-8"); String tradeNo = new String(request.getParameter())"trade_no").getBytes("ISO-8859-1"), "UTF-8"); String totalAmount = new String(request.getParameter())"total_amount").getBytes("ISO-8859-1"), "UTF-8"); TradeStatus = new String(request.getParameter())"trade_status").getBytes("ISO-8859-1"), "UTF-8");
    // APPID
    String appId = new String(request.getParameter("app_id").getBytes("ISO-8859-1"), "UTF-8"); // Remember that AlipayPublicKey is the publickey of Alipay, please go to open.alipay.com corresponding application to check. boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), AlipayConfig.charset, AlipayConfig.signType); Boolean isPaysuccess = payDao.getPayStatus(outTradeNo);if(isPaysuccess ! = null) { response.getWriter().write("success");
    } else{// Business processingifBigDecimal payPrice = Paydao.getPayPrice (outTradeNo); // Trade success status in normal instant receipt status String normalTradeStatus ="TRADE_FINISHED"; // Advanced Instant To Account easy success status String advancedTradeStatus ="TRADE_SUCCESS"; // Payment amount, order completion identifier, AppID Validation Boolean priceFlag = new BigDecimal(totalAmount). CompareTo (payPrice) == 0; Boolean tradeFlag = normalTradeStatus.equals(tradeStatus) || advancedTradeStatus.equals(tradeStatus); Boolean appidFlag = alipayConfig.getAppId().equals(appId);if(priceFlag && tradeFlag && appidFlag) {/ / change the order status to reserve (success) in payDao. UpdateOrderStateByNo (outTradeNo, BookingConst.STATE_BOOKING.getCode(), CommonConstant.ALIPAY, CommonConstant.PAYSUCCESS); response.getWriter().write("success");
        } else{/ / change the order status to pay failure payDao updateOrderStateByNo (outTradeNo, BookingConst. STATE_ORDER_PAY_FAIL. GetCode (), CommonConstant.ALIPAY, CommonConstant.PAYFAIL); response.getWriter().write("success"); }}else {
        response.getWriter().write("failure"); } } } catch (AlipayApiException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}Copy the code

Alipay payment is completed, all the tools used above are packaged in the SDK, Ma Dad is really good! Be sure to change the parameters to the production environment online.



Next, wechat.

First of all, wechat does not have the same sandbox environment as Alipay and can only be directly written in the real environment. The process is still the same: the front end takes the order ID to request the background to place a unified order interface; the back end sorts out all kinds of data and returns to the front end. The front end takes these data to request wechat Pay. Wechat Pay does not have return_url, and the front end writes the callback function by itself.

Here emphasis: wechat pay callback can only use port 80!!

Here emphasis: wechat pay callback can only use port 80!!

Here emphasis: wechat pay callback can only use port 80!!

By pit vomited blood to have ??????

Unified ordering interface: openId and so on can be based on their own projects, I have stored in the database, other points need to pay attention to I have annotated. It can be divided into two parts: The first part, through the order information and public parameters to get the prepayment ID prepay_id. Part two: Regenerating the signature back to the front end by putting this parameter together with other partial parameters.

public Map<Object, Object> wechatPay(HttpServletRequest request, HttpServletResponse response, Long userId, Long id) { SortedMap<Object, Object> param = new TreeMap<>(); Openid = userdao.geTopenId (userId); // Obtain openID from the database. BookingOrderEntity BookingOrderEntity = UserDao.getorderDetail (userId, ID); SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>(); packageParams.put("appid", wechatPayConfig.getAppId());
    packageParams.put("mch_id", wechatPayConfig.getMchId()); Packageparams.put (packageparams.put (packageparams.put ("nonce_str", RandomUtil.generateStr(32));
    packageParams.put("out_trade_no", bookingOrderEntity.getBookingNo());
    packageParams.put("openid", openid); // wechat API requires the incoming amount in minutes packageparams.put ("total_fee", bookingOrderEntity.getPayPrice().setScale(2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString());
    packageParams.put("spbill_create_ip", HttpUtil.getRealIp(request));
    packageParams.put("notify_url", wechatPayConfig.getNotifyUrl());
    packageParams.put("trade_type", wechatPayConfig.getTradeType());
    packageParams.put("body", wechatPayConfig.getBody()); String sign = payCommonUtil.createsign (String sign = payCommonUtil.createsign ("UTF-8", packageParams, wechatPayConfig.getAppKey());
    packageParams.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(packageParams); / / request unified order interface (mainly to obtain prepay_id this parameter) String resXml = HttpUtil. PostData (wechatPayConfig. GetUfdorUrl (), requestXML, null); Map<String, Object> map = XmlUtil.doXMLParse(resXml); // Determine the request result ifreturnIf Code and resultCode are both SUCCESS, the signature is re-generated according to the new parameters and returned to the front end for the front end to request payment interface String mark ="SUCCESS";
    String returnCode = "return_code";
    String resultCode = "result_code";
    if (mark.equals(map.get(returnCode)) && mark.equals(map.get(resultCode))) {
      param.put("appId", wechatPayConfig.getAppId());
      param.put("nonceStr", RandomUtil.generateStr(32));
      param.put("package"."prepay_id=" + map.get("prepay_id"));
      param.put("signType"."Md5");
      param.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); // Generate a new signature with new parameters String paySign = payCommonUtil.createsign ("UTF-8", param, wechatPayConfig.getAppKey());
      param.put("paySign", paySign);
    } else {
      throw new SzException("Unified order error!");
    }
  } catch (JDOMException e) {
    e.printStackTrace();
  } catch (IOException e) {
    e.printStackTrace();
  }
  return param;
}Copy the code

Result of unified single interface:



Entity class of wechat Payment parameters:

/** * @author FZX * @date 2018/11/12 */ @component @configurationProperties (prefix ="wechatpay") public class WechatPayConfig {/** * @value ("${wechatpay.appId}") private String appId; /** */ @value ("${wechatpay.appSecret}") private String appSecret; /** * @value ("${wechatpay.appKey}") private String appKey; /** * @value ("${wechatpay.mchId}") private String mchId; /** * @value ("${wechatpay.notifyUrl}") private String notifyUrl; /** * private String body ="Flash Platform Hotel Reservation"; /** * tradeType: public number pay */ private String tradeType ="JSAPI"; /** * @value ("${wechatpay.ufdorUrl}") private String ufdorUrl; /** * @value ("${wechatpay.orderQuery}") private String orderQuery; /** * Get openID from code */ @value ("${wechatpay.clientAccessTokenUrl}") private String clientAccessTokenUrl; /** * accessToken address */ private String accessTokenUrl ="https://api.weixin.qq.com/cgi-bin/token?"; /** * Obtain the jsApiTicket address */ private String jsApiTicketUrl ="https://api.weixin.qq.com/cgi-bin/ticket/getticket?";

  public void setAccessTokenUrl(String accessTokenUrl) {
    this.accessTokenUrl = accessTokenUrl;
  }

  public void setJsApiTicketUrl(String jsApiTicketUrl) {
    this.jsApiTicketUrl = jsApiTicketUrl;
  }

  public void setAppId(String appId) {
    this.appId = appId;
  }

  public void setAppSecret(String appSecret) {
    this.appSecret = appSecret;
  }

  public void setAppKey(String appKey) {
    this.appKey = appKey;
  }

  public void setMchId(String mchId) {
    this.mchId = mchId;
  }

  public void setNotifyUrl(String notifyUrl) {
    this.notifyUrl = notifyUrl;
  }

  public void setBody(String body) {
    this.body = body;
  }

  public void setTradeType(String tradeType) {
    this.tradeType = tradeType;
  }

  public void setUfdorUrl(String ufdorUrl) {
    this.ufdorUrl = ufdorUrl;
  }

  public void setOrderQuery(String orderQuery) {
    this.orderQuery = orderQuery;
  }

  public void setClientAccessTokenUrl(String clientAccessTokenUrl) {
    this.clientAccessTokenUrl = clientAccessTokenUrl;
  }

  public String getAppId() {
    return appId;
  }

  public String getAppSecret() {
    return appSecret;
  }

  public String getAppKey() {
    return appKey;
  }

  public String getMchId() {
    return mchId;
  }

  public String getNotifyUrl() {
    return notifyUrl;
  }

  public String getBody() {
    return body;
  }

  public String getTradeType() {
    return tradeType;
  }

  public String getUfdorUrl() {
    return ufdorUrl;
  }

  public String getOrderQuery() {
    return orderQuery;
  }

  public String getClientAccessTokenUrl() {
    return clientAccessTokenUrl;
  }


  public String getAccessTokenUrl() {
    return accessTokenUrl;
  }

  public String getJsApiTicketUrl() {
    returnjsApiTicketUrl; }}Copy the code

Tools:

/** * @author FZX * @date 2018/11/15 */ public class PayCommonUtil {public static String createSign(String) characterEncoding, SortedMap<Object, Object> packageParams, String apiKey) { StringBuffer sb = new StringBuffer(); Set es = packageParams.entrySet(); Iterator it = es.iterator();while (it.hasNext()) {
      Map.Entry entry = (Map.Entry) it.next();
      String k = (String) entry.getKey();
      String v = (String) entry.getValue();
      if(null ! = v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
        sb.append(k + "=" + v + "&");
      }
    }
    sb.append("key=" + apiKey);
    String sign = Md5.calc(sb.toString()).toUpperCase();
    return sign;
  }

  public static void main(String[] args) {
    SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
    packageParams.put("appid"."wx399ce4c35a00290f");
    packageParams.put("attach"."Payment test");
    packageParams.put("body"."H5 Payment Test");
    packageParams.put("mch_id"."1503803601");
    packageParams.put("nonce_str"."ibuaiVcKdpRxkhJA");
    packageParams.put("notify_url"."http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php");
    packageParams.put("out_trade_no"."1415659990");
    packageParams.put("scene_info"."{\" h5_info \ ": {\" type \ ": \" IOS \ "and \" app_name \ ": \" king glory \ ", \ "package_name \" : \ "com. Tencent. TMGP. Sgame \"}}");
    packageParams.put("spbill_create_ip"."125.118.106.114");
    packageParams.put("total_fee"."1");
    packageParams.put("trade_type"."MWEB");

    System.out.println(createSign("utf-8", packageParams, "981BF84C66A78E328FDE7469F697B4DA")); } /** * @param parameters request parameters * @return* @author * @date 2016-4-22 * @description: Public static string getRequestXml(SortedMap<Object, Object> parameters) { StringBuffer sb = new StringBuffer(); sb.append("<xml>");
    Set es = parameters.entrySet();
    Iterator it = es.iterator();
    while (it.hasNext()) {
      Map.Entry entry = (Map.Entry) it.next();
      String k = (String) entry.getKey();
      String v = (String) entry.getValue();
      if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k) || "return_code".equalsIgnoreCase(k) || "return_msg".equalsIgnoreCase(k)) {
        sb.append("<" + k + ">" + "
       + v + "]] > "/" + k + ">");
      } else {
        if ("total_fee".equalsIgnoreCase(k)) {
          sb.append("<" + k + ">" + Integer.parseInt(v) + "< /" + k + ">");
        } else {
          sb.append("<" + k + ">" + v + "< /" + k + ">");
        }
      }
    }
    sb.append("</xml>");
    returnsb.toString(); } /** * verify the callback signature ** @return
   */
  public static boolean isTenpaySign(Map<String, String> map, String appKey) {
    String charset = "utf-8";
    String signFromAPIResponse = map.get("sign");
    if (signFromAPIResponse == null || "".equals(signFromAPIResponse)) {
      return false; } // Filter empty Settings TreeMap SortedMap<String, String> packageParams = new TreeMap();for (String parameter : map.keySet()) {
      String parameterValue = map.get(parameter);
      String v = "";
      if(null ! = parameterValue) { v = parameterValue.trim(); } packageParams.put(parameter, v); } StringBuffer sb = new StringBuffer(); Set es = packageParams.entrySet(); Iterator it = es.iterator();while (it.hasNext()) {
      Map.Entry entry = (Map.Entry) it.next();
      String k = (String) entry.getKey();
      String v = (String) entry.getValue();
      if (!"sign".equals(k) && null ! = v && !"".equals(v)) {
        sb.append(k + "=" + v + "&");
      }
    }
    sb.append("key="+ appKey); // Calculate the new signature according to the data returned by API using the signature algorithm, which is used to compare with the signature returned by API"";
    String tobesign = sb.toString();

    if (null == charset || "".equals(charset)) {
      resultSign = Md5.calc(tobesign).toUpperCase();
    } else {
      try {
        resultSign = Md5.calc(tobesign).toUpperCase();
      } catch (Exception e) {
        resultSign = Md5.calc(tobesign).toUpperCase();
      }
    }

    String tenpaySign = (packageParams.get("sign")).toUpperCase();
    returntenpaySign.equals(resultSign); }}Copy the code
** * Http tool class, send Http request, * * @author FZX * @date 2018/11/5 */ public class HttpUtil {private static final Loggerlog = LoggerFactory.getLogger(HttpUtil.class);
  private static final CloseableHttpClient HTTP_CLIENT = HttpClients.createDefault();
  private static final String USERAGENT = "Mozilla / 5.0 (Windows NT 6.2; Win64; X64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36";
  private final static int CONNECT_TIMEOUT = 5000;
  private final static String DEFAULT_ENCODING = "UTF-8"; /** ** Send HttpGet request ** @param URL * request address * @returnReturn String */ public static String sendGet(String URL) {String result = null; CloseableHttpResponse response = null; try { HttpGet httpGet = new HttpGet(url); httpGet.setHeader("User-Agent", USERAGENT);
      response = HTTP_CLIENT.execute(httpGet);
      HttpEntity entity = response.getEntity();
      if(entity ! = null) { result = EntityUtils.toString(entity); } } catch (Exception e) { log.error("Processing failed {}" + e);
      e.printStackTrace();
    } finally {
      if(response ! = null) { try { response.close(); } catch (IOException e) { log.error(e.getMessage()); }}}returnresult; } /** * send an HttpPost request with the parameters map ** @param URL * @param map * request parameters * @returnPublic static String sendPost(String url, Map<String, Formparams = new ArrayList<NameValuePair>();for(Map.Entry<String, String> entry : map.entrySet()) { formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } // UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formParams, consts.utf_8); HttpPost HttpPost = new HttpPost(URL); // Prevent httppost.setheader being added as an attack ("User-Agent", USERAGENT); // place the argument into Entity httpPost.setentity (formEntity); CloseableHttpResponse response = null; String result = null; Try {// Perform post request response = http_client.execute (httpPost); // getEntity HttpEntity entity = response.getentity (); // Get string result = entityutils.toString (entity); } catch (IOException e) { log.error(e.getMessage()); } finally {if(response ! = null) { try { response.close(); } catch (IOException e) { log.error(e.getMessage()); }}}return result;
  }


  public static String postData(String urlStr, String data, String contentType) {
    BufferedReader reader = null;
    try {
      URL url = new URL(urlStr);
      URLConnection conn = url.openConnection();
      conn.setDoOutput(true);
      conn.setConnectTimeout(CONNECT_TIMEOUT);
      conn.setReadTimeout(CONNECT_TIMEOUT);
      if(contentType ! = null) { conn.setRequestProperty("content-type", contentType);
      }
      OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
      if (data == null) {
        data = "";
      }
      writer.write(data);
      writer.flush();
      writer.close();

      reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
      StringBuilder sb = new StringBuilder();
      String line = null;
      while((line = reader.readLine()) ! = null) { sb.append(line); sb.append("\r\n");
      }
      return sb.toString();
    } catch (IOException e) {
    } finally {
      try {
        if(reader ! = null) { reader.close(); } } catch (IOException e) { } }returnnull; } /** ** Obtain the real IP address through the Apache proxy can also obtain the real IP address ** @param request * @return   
   */
  public static String getRealIp(HttpServletRequest request) {
    String ip = request.getHeader("x-forwarded-for");
    String unkonwType = "unknown";
    if (ip == null || ip.length() == 0 || unkonwType.equalsIgnoreCase(ip)) {
      ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || unkonwType.equalsIgnoreCase(ip)) {
      ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || unkonwType.equalsIgnoreCase(ip)) {
      ip = request.getRemoteAddr();
    }
    returnip; }}Copy the code
/** ** XML utility class ** @author miklchen */ public class XmlUtil {/** ** parses XML and returns the first level element key/value pair. If the first-level element has child nodes, the value of this node is the XML data for the child node. * * @param strxml * @return
   * @throws JDOMException
   * @throws IOException
   */
  public static Map doXMLParse(String strxml) throws JDOMException, IOException {
    strxml = strxml.replaceFirst("encoding=\".*\""."encoding=\"UTF-8\"");

    if (null == strxml || "".equals(strxml)) {
      return null;
    }

    Map m = new HashMap(10);

    InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
    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 = XmlUtil.getChildrenText(children); } m.put(k, v); } // Close the stream in.close();returnm; } /** * get the XML of the child ** @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(XmlUtil.getChildrenText(list)); } sb.append(value); sb.append("< /" + name + ">"); }}returnsb.toString(); }}Copy the code

Payment callback: Wechat Pay callback information exists in the stream and needs to be taken out by itself. The processing logic is similar to alipay.

In addition, there is no internal penetration of the pin (no port 80), use natApp.

public void wechatPayNotify(HttpServletRequest request, HttpServletResponse response) {
  SortedMap<Object, Object> map = new TreeMap<>();
  try {
    InputStream inStream = request.getInputStream();
    ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len;
    while ((len = inStream.read(buffer)) ! = -1) { outSteam.write(buffer, 0, len); } outSteam.close();inStream.close();

    String resultStr = new String(outSteam.toByteArray(), "utf-8");
    Map<String, String> resultMap = XmlUtil.doXMLParse(resultStr);
    PayCommonUtil.isTenpaySign(resultMap, wechatPayConfig.getAppKey());
    String outTradeNo = resultMap.get("out_trade_no");
    String resultCode = resultMap.get("result_code");
    String returnCode = resultMap.get("return_code"); Boolean isPaysuccess = paydao.getPayStatus (outTradeNo);if(isPaysuccess ! = null) { map.put("return_code"."SUCCESS");
      map.put("return_msg"."OK");
      response.getWriter().write(PayCommonUtil.getRequestXml(map));
    } else{/ / attestationif(PayCommonUtil isTenpaySign (resultMap, wechatPayConfig getAppKey ())) {/ / WeChat notice. Asynchronous confirmation successful map.put("return_code"."SUCCESS");
        map.put("return_msg"."OK");
        response.getWriter().write(PayCommonUtil.getRequestXml(map));
        String mark = "SUCCESS";
        if (mark.equals(resultCode) && mark.equals(returnCode)) {/ / change the order status to reserve (success) in payDao. UpdateOrderStateByNo (outTradeNo, BookingConst. STATE_BOOKING. GetCode (), CommonConstant.WECHATPAY, CommonConstant.PAYSUCCESS); }else{/ / change the order status to pay failure payDao updateOrderStateByNo (outTradeNo, BookingConst. STATE_ORDER_PAY_FAIL. GetCode (), CommonConstant.WECHATPAY, CommonConstant.PAYFAIL); map.put("return_code"."SUCCESS");
          map.put("return_msg"."OK"); response.getWriter().write(PayCommonUtil.getRequestXml(map)); }}else{// Notify wechat. Asynchronous confirmation failure map.put("FAIL"."ERROR"); response.getWriter().write(PayCommonUtil.getRequestXml(map)); } } } catch (IOException e) { e.printStackTrace(); } catch (JDOMException e) { e.printStackTrace(); }}Copy the code