Java realizes WeChat (main and subsidiary business mode) and Alipay payment.

1, Business requirements

To achieve APP WeChat and Alipay payment, the back end needs to generate advance payment and respond to payment results; WeChat merchants adopt sub business mode.

2, Refer to official documents

Wechat ordinary merchant: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

Wechat service provider: https://pay.weixin.qq.com/wiki/doc/api/app/app_sl.php?chapter=9_1

Alipay API development documentation: https://docs.open.alipay.com/api_1/alipay.trade.app.pay

3, Preparations

Complete the entry and other operations on the public platform, and get the following information

General merchants:

parameter API parameter name Detailed description
APPID appid Appid is the unique identification of wechat public account or open platform APP. After applying for public account on public platform or APP account on open platform, wechat will automatically assign the corresponding appid to identify the application. It can be viewed in the developer center of wechat public platform, and the value of this field will also be included in the wechat payment approval email of the merchant.
Wechat payment merchant No mch_id After the merchant applies for wechat payment, the merchant collection account assigned by wechat payment.
API key key The signed key generated in the transaction process is only kept in the merchant system and wechat payment background, and will not be spread in the network. The merchant shall keep the key properly, and shall not transmit it in the network or store it in other clients to ensure that the key will not be disclosed. Merchants can log in to wechat merchant platform for setting according to email prompts. It can also be set in the following path: wechat merchant platform (pay. Weixin. QQ. Com) -- > account setting -- > API security -- > key setting
Appsecret secret AppSecret is the interface password corresponding to APPID, which is used to obtain the interface call voucher access_token.

Service provider:

parameter API parameter name Detailed description
APPID of accepting merchant appid Appid is the unique identification of wechat public account or open platform APP. After applying for public account on public platform or APP account on open platform, wechat will automatically assign the corresponding appid to identify the application. It can be viewed in the developer center of wechat public platform, and the value of this field will also be included in the wechat payment approval email of the merchant.
Merchant number of accepting merchant mch_id After accepting the merchant's application for wechat payment, the merchant account assigned by wechat payment.
Accept merchant's API key key The signed key generated in the transaction process is only kept in the merchant system and wechat payment background, and will not be spread in the network. The merchant shall keep the key properly, and shall not transmit it in the network or store it in other clients to ensure that the key will not be disclosed. Merchants can log in to wechat merchant platform for setting according to email prompts. You can also click the following path to set: wechat merchant platform (pay. Weixin. QQ. Com) -- > account setting -- > API security -- > key setting
Sub merchant merchant No sub_mch_id Merchant number or merchant identification number applied by the sub merchant
Sub merchant app APPID sub_appid APPID applied by sub merchants in open platform
Appsecret of merchant number application secret AppSecret is the interface password corresponding to APPID applied by the sub merchant, which is used to obtain the interface call voucher access_token.

If you use a sub merchant, you need to authorize it first

Alipay reference document gets relevant parameters

Four, code

-- WeChat

API constant class

public class TransferConstants {
/** =============================================Wechat================================================*/

    /**Unified order API*/
    public static final String UNIFIEDORDER_PAY = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    /**Enterprise payment API*/
    public static final String TRANSFERS_PAY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
    /**Apply for refund API*/
    public static final String REFUND_PAY = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    /**Enterprise payment query API*/
    public static final String TRANSFERS_PAY_QUERY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo";
    /**Public account appid*/
    public static final String APP_ID = ""  ;
    /**Merchant number*/
    public static final String MCH_ID = "";
    /**API Key filling service provider's*/
    public static final String API_SECRET = "";
    /**Sub merchant application ID*/
    public static final String SUB_APPID = "";
    /**Sub merchant number */
    public static final String SUB_MCH_ID = "";

/** =============================================Alipay = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
    /**Alipay gateway (fixed)*/
    public static final String URL = "https://openapi.alipay.com/gateway.do";
    /**APPID That is, build after creating the application*/
    public static final String APPID = "";
    /**Developer private key, generated by the developer himself*/
    public static final String APP_PRIVATE_KEY =  "";
    /**Parameter return format, only json is supported*/
    public static final String FORMAT = "json";
    /**Codeset, support GBK/UTF-8*/
    public static final String CHARSET = "UTF-8";
    /**Alipay public key, paid by Bao Shengcheng)*/
    public static final String ALIPAY_PUBLIC_KEY = "";
    /**The type of signature algorithm used by the merchant to generate the signature string currently supports RSA2 and RSA, and RSA2 is recommended*/
    public static final String SIGN_TYPE = "RSA2";

}

When paying online, wechat failed to call back after payment, and later wrote an active call back method

First, configure the payment callback address in application.yml

wxAndAli:
    aliNotifyUrl: http://192.168.1.15:8082/app/appPay/aliPayNotify
    wxNotifyUrl: http://192.168.1.15:8082/app/appPay/wxPayNotify

Get payment callback address

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * Payment callback address
 */
@Component
public class PayConstants {
    public static String aliNotifyUrl;
    public static String wxNotifyUrl;

    @Value("${wxAndAli.aliNotifyUrl}")
    public void setAliNotifyUrl(String aliNotifyUrl) {
        this.aliNotifyUrl = aliNotifyUrl;
    }

    @Value("${wxAndAli.wxNotifyUrl}")
    public void setWxNotifyUrl(String wxNotifyUrl) {
        this.wxNotifyUrl = wxNotifyUrl;
    }
}

JSON data processing class

public class JSONObject extends LinkedHashMap<String, Object>
{
    private static final long serialVersionUID = 1L;
    private static final Pattern arrayNamePattern = Pattern.compile("(\\w+)((\\[\\d+\\])+)");
    private static final ObjectMapper objectMapper = new ObjectMapper();

public static String valueAsStr(Object value)
    {
        if (value instanceof String)
        {
            return (String) value;
        }
        else if (value != null)
        {
            return value.toString();
        }
        else
        {
            return null;
        }
    }
}

Payment instruments

import com.github.pagehelper.util.StringUtil;
import com.spa.common.utils.security.Md5Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * @author JC
 * @version Creation time: 14:13, May 6, 2019
 */
public class PayUtil {

    private static final Logger logger = LoggerFactory.getLogger(PayUtil.class);
    /**
     * Generate order number
     *
     * @return
     */
    public static String getOrderNo() {
        // Self increasing 8 digits 00000001
        return "ONO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * Refund number
     *
     * @return
     */
    public static String getRefundNo() {
        // Self increasing 8 digits 00000001

        return "RNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * Transaction number
     *
     * @return
     */
    public static String getTransferNo() {
        // Self increasing 8 digits 00000001
        return "TNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * Payment number
     *
     * @return
     */
    public static String getPayNo() {
        // Self increasing 8 digits 00000001
        return "PNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * Store receipt No
     *
     * @return
     */
    public static String getReceiptNo() {
        // Self increasing 8 digits 00000001
        return "SRNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * Delegation number
     *
     * @return
     */
    public static String getGroupNo() {
        // Self increasing 8 digits 00000001
        return "GNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * Return to client ip
     *
     * @param request
     * @return
     */
    public static String getRemoteAddrIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            // There will be multiple ip values after multiple reverse proxy. The first ip is the real ip
            int index = ip.indexOf(",");
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            return ip;
        }
        return request.getRemoteAddr();
    }

    /**
     * Get the ip address of the server
     *
     * @param request
     * @return
     */
    public static String getLocalIp(HttpServletRequest request) {
        return request.getLocalAddr();
    }

    /**
     * Sort all the passed in parameters according to the ASCII code of the field name from small to large (dictionary order)
     * @param params
     * @return
     */
    public static Map<Object,Object> formatASCIIMap(Map<String, String> params){
        Map<String, String> tmpMap = params;
        Map<Object, Object> params1 = new LinkedHashMap<>();
        List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());


        //Sort all the passed in parameters according to the ASCII code of the field name from small to large (dictionary order)
        Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
            public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                return (o1.getKey()).toString().compareTo(o2.getKey());
            }
        });


        for (Map.Entry<String, String> item : infoIds) {
            if (StringUtils.isNotBlank((CharSequence) item.getKey())) {
                String key = item.getKey();
                String value = item.getValue();
                params1.put(key,value);
            }
        }

        return params1;
    }

    public static String getSign(Map<Object, Object> params, String paternerKey) throws UnsupportedEncodingException {

        return Md5Utils.MD5Encode(createSign(params, false) + "&key=" + paternerKey).toUpperCase();
    }

    /**
     * Generate signature on refund
     * @param params
     * @param paternerKey
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String getRefundSign(Map<Object, Object> params, String paternerKey) throws UnsupportedEncodingException {
        return Md5Utils.MD5Encode(createRefundSign(params, false) + "&key=" + paternerKey).toUpperCase();
    }

    /**
     * Structured signature
     *
     * @param params
     * @param encode
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String createSign(Map<Object, Object> params, boolean encode) throws UnsupportedEncodingException {
        Set<Object> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuffer temp = new StringBuffer();
        boolean first = true;
        for (Object key : keys) {
            if (key == null || StringUtils.isNull(params.get(key))) // Empty parameter does not participate in signature
                continue;
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueStr = "";
            if (null != value) {
                valueStr = value.toString();
            }
            if (encode) {
                temp.append(URLEncoder.encode(valueStr, "UTF-8"));
            } else {
                temp.append(valueStr);
            }
        }
        return temp.toString();
    }

    /**
     * Sign when building a refund
     *
     * @param params
     * @param encode
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String createRefundSign(Map<Object, Object> params, boolean encode) throws UnsupportedEncodingException {
        Set<Object> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuffer temp = new StringBuffer();
        boolean first = true;
        for (Object key : keys) {
            if (key == null || StringUtils.isNull(params.get(key))) // Empty parameter does not participate in signature
                continue;
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueStr = "";
            if (null != value) {
                valueStr = value.toString();
            }
            if (encode) {
                temp.append(URLEncoder.encode(valueStr, "UTF-8"));
            } else {
                temp.append(valueStr);
            }
        }
        return temp.toString();
    }

    /**
     * Create payment random string
     *
     * @return
     */
    public static String getNonceStr() {
        return StringUtils.getRandomString(32);
    }

    /**
     * Payment time stamp
     *
     * @return
     */
    public static String payTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

}

xml, map conversion tool class

public class XmlUtil {

    private static final String PREFIX_XML = "<xml>";

    private static final String SUFFIX_XML = "</xml>";

    private static final String PREFIX_CDATA = "<![CDATA[";

    private static final String SUFFIX_CDATA = "]]>";

    /**
     * Convert to xml, single layer without nesting
     *
     * @param parm
     * @param isAddCDATA
     * @return
     */
    public static String xmlFormat(Map<String, String> parm, boolean isAddCDATA) {

        StringBuffer strbuff = new StringBuffer(PREFIX_XML);
        if (CollectionUtil.isNotEmpty(parm)) {
            for (Entry<String, String> entry : parm.entrySet()) {
                strbuff.append("<").append(entry.getKey()).append(">");
                if (isAddCDATA) {
                    strbuff.append(PREFIX_CDATA);
                    if (StringUtil.isNotEmpty(entry.getValue())) {
                        strbuff.append(entry.getValue());
                    }
                    strbuff.append(SUFFIX_CDATA);
                } else {
                    if (StringUtil.isNotEmpty(entry.getValue())) {
                        strbuff.append(entry.getValue());
                    }
                }
                strbuff.append("</").append(entry.getKey()).append(">");
            }
        }
        return strbuff.append(SUFFIX_XML).toString();
    }

    /**
     * Object,Converted to xml
     * @param parm
     * @param isAddCDATA
     * @return
     */
    public static String xmlFormatObject(Map<Object, Object> parm, boolean isAddCDATA) {

        StringBuffer strbuff = new StringBuffer(PREFIX_XML);
        if (CollectionUtil.isNotEmpty(parm)) {
            for (Entry<Object, Object> entry : parm.entrySet()) {
                strbuff.append("<").append(entry.getKey()).append(">");
                if (isAddCDATA) {
                    strbuff.append(PREFIX_CDATA);
                    if (StringUtils.isNotNull(entry.getValue())) {
                        strbuff.append(entry.getValue());
                    }
                    strbuff.append(SUFFIX_CDATA);
                } else {
                    if (StringUtils.isNotNull(entry.getValue())) {
                        strbuff.append(entry.getValue());
                    }
                }
                strbuff.append("</").append(entry.getKey()).append(">");
            }
        }
        return strbuff.append(SUFFIX_XML).toString();
    }

    /**
     * Parsing xml
     *
     * @param xml
     * @return
     * @throws XmlPullParserException
     * @throws IOException
     */
    public static Map<String, String> xmlParse(String xml) throws XmlPullParserException, IOException {
        Map<String, String> map = null;
        if (StringUtil.isNotEmpty(xml)) {
            InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
            XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();
            pullParser.setInput(inputStream, "UTF-8"); // Set xml data to parse for xml
            int eventType = pullParser.getEventType();

            while (eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {
                    case XmlPullParser.START_DOCUMENT:
                        map = new HashMap<String, String>();
                        break;
                    case XmlPullParser.START_TAG:
                        String key = pullParser.getName();
                        if (key.equals("xml"))
                            break;
                        String value = pullParser.nextText().trim();
                        map.put(key, value);
                        break;
                    case XmlPullParser.END_TAG:
                        break;
                }
                eventType = pullParser.next();
            }
        }
        return map;
    }

    /**
     * Object,Parsing xml
     * @param xml
     * @return
     * @throws XmlPullParserException
     * @throws IOException
     */
    public static Map<Object, Object> xmlParseObject(String xml) throws XmlPullParserException, IOException {
        Map<Object, Object> map = null;
        if (StringUtil.isNotEmpty(xml)) {
            InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
            XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();
            pullParser.setInput(inputStream, "UTF-8"); // Set xml data to parse for xml
            int eventType = pullParser.getEventType();

            while (eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {
                    case XmlPullParser.START_DOCUMENT:
                        map = new HashMap<Object, Object>();
                        break;
                    case XmlPullParser.START_TAG:
                        String key = pullParser.getName();
                        if (key.equals("xml"))
                            break;
                        String value = pullParser.nextText().trim();
                        map.put(key, value);
                        break;
                    case XmlPullParser.END_TAG:
                        break;
                }
                eventType = pullParser.next();
            }
        }
        return map;
    }
}

Md5 encryption tool class

public class Md5Utils
{
    private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);

    private static byte[] md5(String s)
    {
        MessageDigest algorithm;
        try
        {
            algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(s.getBytes("UTF-8"));
            byte[] messageDigest = algorithm.digest();
            return messageDigest;
        }
        catch (Exception e)
        {
            log.error("MD5 Error...", e);
        }
        return null;
    }

    private static final String toHex(byte hash[])
    {
        if (hash == null)
        {
            return null;
        }
        StringBuffer buf = new StringBuffer(hash.length * 2);
        int i;

        for (i = 0; i < hash.length; i++)
        {
            if ((hash[i] & 0xff) < 0x10)
            {
                buf.append("0");
            }
            buf.append(Long.toString(hash[i] & 0xff, 16));
        }
        return buf.toString();
    }

    public static String hash(String s)
    {
        try
        {
            return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8");
        }
        catch (Exception e)
        {
            log.error("not supported charset...{}", e);
            return s;
        }
    }

    public static String MD5Encode(String s) {

        try {
            // Get an information digester
            MessageDigest digest = MessageDigest.getInstance("md5");
            byte[] result = digest.digest(s.getBytes());
            StringBuffer buffer = new StringBuffer();
            // Make a and operation 0xff for each byte;
            for (byte b : result) {
                // And operation
                int number = b & 0xff;// Salt addition
                String str = Integer.toHexString(number);
                if (str.length() == 1) {
                    buffer.append("0");
                }
                buffer.append(str);
            }

            // Standard md5 encrypted results
            return buffer.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return "";
        }

    }

    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }

    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}

Wechat signature related tool class

@Slf4j
public class WXPayUtil1 {
    private static final Logger log = LoggerFactory.getLogger(WXPayUtil1.class);

    public static Map<Object, Object> wxPay(Map map) {
        Map<Object, Object> resultMap = new HashMap<>();
        Map<String, String> parameters = null;
        try {
            parameters = new LinkedHashMap<>();
            parameters.put("appid", TransferConstants.APP_ID); //Public account appid
            parameters.put("mch_id", TransferConstants.MCH_ID); //Merchant number
            parameters.put("sub_appid", TransferConstants.SUB_APPID); //Sub merchant application ID
            parameters.put("sub_mch_id", TransferConstants.SUB_MCH_ID); //Sub merchant number
            parameters.put("nonce_str", PayUtil.getNonceStr()); //Random string
            parameters.put("out_trade_no", (String) map.get("transferNo")); //Merchant order number
            parameters.put("total_fee", (String)map.get("money")); //Transfer amount
            parameters.put("body", (String) map.get("desc")); //Enterprise payment description
            parameters.put("spbill_create_ip", (String) map.get("ip")); //Ip address
            parameters.put("notify_url", PayConstants.wxNotifyUrl);              //Callback notification address
            parameters.put("trade_type", "APP");
//            String sign = PayUtil.getSign(parameters, TransferConstants.WX_KEY);
            Map<String, String> tmpMap = parameters;
            Map<Object,Object> params1 = PayUtil.formatASCIIMap(tmpMap);
            //Generate sign
            String sign = PayUtil.getSign(params1, TransferConstants.API_SECRET);
            parameters.put("sign", sign);
           Map<String, String> tmpMap2 = parameters;
           Map<Object,Object> params2 = PayUtil.formatASCIIMap(tmpMap2);
            //Generate signature
            resultMap = createSecondSign(params2);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    /**
     * Wechat payment signature algorithm sign
     *
     * @param parameters
     * @return
     */
    public static Map<Object, Object> createSecondSign(Map<Object, Object> parameters) {
        Map<Object, Object> resultMap = new HashMap<>();
        //WeChat payment
        String xml = XmlUtil.xmlFormatObject(parameters, false);
        log.info("----autograph-------"+ xml);
        String restxml = HttpUtilA.posts(TransferConstants.UNIFIEDORDER_PAY, XmlUtil.xmlFormatObject(parameters, false));
        log.info("----Sending signature-------"+ restxml);
        Map<String, String> returnMap = null;
        try {
            returnMap = XmlUtil.xmlParse(restxml);
            log.info("-----------"+ JSONObject.valueAsStr(returnMap));
            // The communication ID and transaction ID are SUCCESS
            if (CollectionUtil.isNotEmpty(returnMap) && "SUCCESS".equals(returnMap.get("return_code")) && "SUCCESS".equals(returnMap.get("result_code"))) {
                SortedMap<Object,Object> parameterMap = new TreeMap<Object,Object>();
                String prepayid = returnMap.get("prepay_id");// Pre payment transaction session ID
                String noncestr = returnMap.get("nonce_str");// Random string returned by wechat
                parameterMap.put("appid", TransferConstants.SUB_APPID);
                parameterMap.put("partnerid", TransferConstants.SUB_MCH_ID);
                parameterMap.put("prepayid", prepayid);
                parameterMap.put("package", "Sign=WXPay");
                parameterMap.put("noncestr", noncestr);
                parameterMap.put("timestamp", PayUtil.payTimestamp());
                //Generate sign
                String sign = PayUtil.getSign(parameterMap, TransferConstants.API_SECRET);
                parameterMap.put("sign", sign);
                log.info("-----------"+ JSONObject.valueAsStr(parameterMap));
                resultMap.put("code", "200");
                resultMap.put("msg", parameterMap);
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultMap;
    }

     /**
     * <p>Unified order</p>
     *
     * @return
     * @throws Exception
     */
    public Map<Object, Object> pay(Map map) {
        Map<Object, Object> resultMap = new HashMap<>();
        Map<String, String> returnMap = null;
        try {
            returnMap = wxUnifieldOrder(map);
            // The communication ID and transaction ID are SUCCESS
            if (CollectionUtil.isNotEmpty(returnMap) && "SUCCESS".equals(returnMap.get("return_code")) && "SUCCESS".equals(returnMap.get("result_code"))) {
                resultMap.put("returnCode", returnMap.get("return_code"));
                resultMap.put("returnMsg", "OK");
                resultMap.put("codeUrl", returnMap.get("code_url"));
                resultMap.put("payMethod", "Wechat code scanning payment");
            } else {
                resultMap.put("returnCode", returnMap.get("return_code"));
                resultMap.put("returnMsg", returnMap.get("return_msg"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    /**
     * <p>Unified order of wechat payment</p>
     *
     * @return
     * @throws Exception
     */
    private Map<String, String> wxUnifieldOrder(Map map) throws Exception {
        //Package parameters
        SortedMap<String, String> parameters = new TreeMap<String, String>();
        parameters.put("mch_appid", TransferConstants.APP_ID); //Public account appid
        parameters.put("mchid", TransferConstants.MCH_ID); //Merchant number
        parameters.put("nonce_str", PayUtil.getNonceStr()); //Random string
        parameters.put("partner_trade_no", (String) map.get("transferNo")); //Merchant order number
        parameters.put("openid", (String) map.get("openId")); //User openid oCVr20N2YLH9VQztnkZTaCj2aYYY
        parameters.put("check_name", "NO_CHECK"); //Option "check
        //Parameters.put ("re? User? Name", "Andy"); / / check? Name is set to force? Check or option? Check, which is required
        parameters.put("amount", (String) map.get("money")); //Transfer amount
        parameters.put("desc", (String) map.get("desc")); //Enterprise payment description
        parameters.put("spbill_create_ip", (String) map.get("ip")); //Ip address
//            Parameters. Put ("notify" URL ", notifyurl); / / callback notification address
        parameters.put("trade_type", "APP");                  //Payment type
        parameters.put("sign", createSign(parameters, ""));
        //Convert to xml
        String xmlData = mapToXml(parameters);
        //Request wechat background
        String resXml = HttpUtilA.posts(TransferConstants.UNIFIEDORDER_PAY, xmlData);
        log.info("[Wechat Payment] unified order response:\n" + resXml);
        return xmlStrToMap(resXml);
    }

    /**
     * Map Convert to Xml
     *
     * @return Xml
     * @throws Exception
     */
    public static String mapToXml(SortedMap<String, String> map) throws Exception {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        //Prevent XXE attacks
        documentBuilderFactory.setXIncludeAware(false);
        documentBuilderFactory.setExpandEntityReferences(false);
        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 : map.keySet()) {
            String value = map.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();
        try {
            writer.close();
        } catch (Exception ex) {
        }
        return output;
    }

    /**
     * Create signature Sign
     *
     * @param key
     * @param parameters
     * @return
     */
    public static String createSign(SortedMap<String, String> parameters, String key) {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();
        Iterator<?> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            if (entry.getValue() != null || !"".equals(entry.getValue())) {
                String v = String.valueOf(entry.getValue());
                if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                    sb.append(k + "=" + v + "&");
                }
            }
        }
        sb.append("key=" + key);
        String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
        return sign;
    }

    /**
     * Xml String to Map
     *
     * @param xmlStr
     * @return
     */
    public static Map<String, String> xmlStrToMap(String xmlStr) {
        Map<String, String> map = new HashMap<String, String>();
        Document doc;
        try {
            doc = DocumentHelper.parseText(xmlStr);
            Element root = doc.getRootElement();
            List children = root.elements();
            if (children != null && children.size() > 0) {
                for (int i = 0; i < children.size(); i++) {
                    Element child = (Element) children.get(i);
                    map.put(child.getName(), child.getTextTrim());
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return map;
    }
}

Wechat asynchronous request processing

/**
     * Wechat asynchronous request logic processing
     *
     * @param inStream
     * @return
     */
    @Override
    public ResultData wxNotify(InputStream inStream) {
        int code = -1;
        Map<String, String> return_data = new HashMap<String, String>();
        try {
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            String resultxml = new String(outSteam.toByteArray(), "utf-8");
            Map<String, String> params = XmlUtil.xmlParse(resultxml);
            outSteam.close();
            inStream.close();

            if (!PayCommonUtil.isTenpaySign("utf-8", params)) {
                // Failure to pay
                return_data.put("return_code", "FAIL");
                return_data.put("return_msg", "return_code Incorrect");
                code = 4;
            } else {
                System.out.println("===============Successful payment==============");
                String outTradeNo = String.valueOf(Long.parseLong(params.get("out_trade_no").split("O")[0]));
                // Enquiry order
                AppOrders appOrders = appOrdersService.selectAppOrdersByOrderNo(outTradeNo);
                if ("0".equals(appOrders.getStatus())){
                    log.info("-----Wechat asynchronous callback, modify order status--------------"+appOrders.toString());
                    String totalFee = params.get("total_fee");
                    Map map = new HashMap();
                    map.put("orderNo", appOrders.getOrderNo());
                    map.put("payIntegral", appOrders.getPayIntegral());
                    map.put("payMoney", totalFee);
                    map.put("payWay", "2");
                    map.put("discountMoney", appOrders.getDiscountMoney());
                    appOrdersService.updateOrderStatusToPay(map);
                }

                String transactionId = params.get("transaction_id");
                // Process only orders with successful payment: modify transaction table status, payment succeeded
                //Update status in transaction table
                int returnResult = appTransactionHistoryService.updateTransactionHistoryByTransactionNo(outTradeNo, transactionId);
                log.info("==================returnResult: " + returnResult);
                if (returnResult > 0) {
                    log.info("==================Update status in transaction table succeeded:" + transactionId);
                    return_data.put("return_code", "SUCCESS");
                    return_data.put("return_msg", "OK");
                    code = 0;
                } else {
                    return new ResultData(4, "Failed to update transaction table!");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
        return new ResultData(code, XmlUtil.xmlFormat(return_data, false));
    }

-- Alipay

Alipay entity class

public class AlipaymentOrderDto {
    //Application Id allocated to developers by Alipay
    private String appId;
    //Notification time: yyyy MM DD HH: mm: SS
    private String notifyTime;
    //Transaction creation time: yyyy MM DD HH: mm: SS
    private String gmtCreate;
    //Transaction payment time
    private String gmtPayment;
    //Transaction refund time
    private String gmtRefund;
    //Transaction end time
    private String gmtClose;
    //Alipay's transaction number
    private String tradeNo;
    //Get the order number before the merchant passed to Alipay (the unique order number of the merchant system).
    private String outTradeNo;
    //Merchant business number (merchant business ID, mainly the serial number of refund application returned in refund notice)
    private String outBizNo;
    //Buyer Alipay account
    private String buyerLogonId;
    //Seller Alipay user number
    private String sellerId;
    //Seller Alipay account
    private String sellerEmail;
    //Order amount: the order amount paid in this transaction, unit: RMB (yuan)
    private Double totalAmount;
    //Amount actually received: the amount actually received by the merchant in the transaction, unit: Yuan
    private Double receiptAmount;
    //Invoiced amount: the invoiced amount paid by the user in the transaction
    private Double invoiceAmount;
    //Payment amount: the amount paid by the user in the transaction
    private Double buyerPayAmount;
    // Get transaction status
    private String tradeStatus;

    public String getAppId() {
        return appId;
    }

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

    public String getNotifyTime() {
        return notifyTime;
    }

    public void setNotifyTime(String notifyTime) {
        this.notifyTime = notifyTime;
    }

    public String getGmtCreate() {
        return gmtCreate;
    }

    public void setGmtCreate(String gmtCreate) {
        this.gmtCreate = gmtCreate;
    }

    public String getGmtPayment() {
        return gmtPayment;
    }

    public void setGmtPayment(String gmtPayment) {
        this.gmtPayment = gmtPayment;
    }

    public String getGmtRefund() {
        return gmtRefund;
    }

    public void setGmtRefund(String gmtRefund) {
        this.gmtRefund = gmtRefund;
    }

    public String getGmtClose() {
        return gmtClose;
    }

    public void setGmtClose(String gmtClose) {
        this.gmtClose = gmtClose;
    }

    public String getTradeNo() {
        return tradeNo;
    }

    public void setTradeNo(String tradeNo) {
        this.tradeNo = tradeNo;
    }

    public String getOutTradeNo() {
        return outTradeNo;
    }

    public void setOutTradeNo(String outTradeNo) {
        this.outTradeNo = outTradeNo;
    }

    public String getOutBizNo() {
        return outBizNo;
    }

    public void setOutBizNo(String outBizNo) {
        this.outBizNo = outBizNo;
    }

    public String getBuyerLogonId() {
        return buyerLogonId;
    }

    public void setBuyerLogonId(String buyerLogonId) {
        this.buyerLogonId = buyerLogonId;
    }

    public String getSellerId() {
        return sellerId;
    }

    public void setSellerId(String sellerId) {
        this.sellerId = sellerId;
    }

    public String getSellerEmail() {
        return sellerEmail;
    }

    public void setSellerEmail(String sellerEmail) {
        this.sellerEmail = sellerEmail;
    }

    public Double getTotalAmount() {
        return totalAmount;
    }

    public void setTotalAmount(Double totalAmount) {
        this.totalAmount = totalAmount;
    }

    public Double getReceiptAmount() {
        return receiptAmount;
    }

    public void setReceiptAmount(Double receiptAmount) {
        this.receiptAmount = receiptAmount;
    }

    public Double getInvoiceAmount() {
        return invoiceAmount;
    }

    public void setInvoiceAmount(Double invoiceAmount) {
        this.invoiceAmount = invoiceAmount;
    }

    public Double getBuyerPayAmount() {
        return buyerPayAmount;
    }

    public void setBuyerPayAmount(Double buyerPayAmount) {
        this.buyerPayAmount = buyerPayAmount;
    }

    public String getTradeStatus() {
        return tradeStatus;
    }

    public void setTradeStatus(String tradeStatus) {
        this.tradeStatus = tradeStatus;
    }
}

Alipay payment tools

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.spa.app.controller.app.constants.PayConstants;
import com.spa.app.controller.app.dto.AlipaymentOrderDto;
import com.spa.common.constant.TransferConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;

public class AliPayUtil {
    private static final Logger log = LoggerFactory.getLogger(AliPayUtil.class);

    // The path of the asynchronous notification page of the server requires a complete path in the format of http: / /. You cannot add such custom parameters as? id=123. You must be able to access it normally through the external network
//    Public static string notify uurl = "http: / / public network access address of the project / alipay.trade.page.pay-java-utf-8 / notify uurl. JSP";
    // The path of the page Jump synchronization notification page needs a complete path in the format of http: / /. You cannot add such custom parameters as? id=123. You must be able to access it normally through the Internet
//    Public static string return "url =" http: / / public network access address of the project / alipay.trade.page.pay-java-utf-8 / return "URL. JSP";
    // Character encoding format
    public static String charset = "utf-8";

    /**
     * payment
     *
     * @param map
     * @return
     */
    public static String pay(Map map) {
//    public static JSONObject pay(Map map) {
        //After the final return, the order information string that app needs to pass to Alipay app is signed.
        String result = "";
//        JSONObject result = new JSONObject();
        try {
            //Merchant order number, the only order number in the order system of merchant website, required
            String out_trade_no = (String) map.get("orderNo");
            //Payment amount, required
            String total_amount = (String) map.get("money");
            //Order name, required
            String subject = (String) map.get("orderName");

            //Instantiation of the client (parameters: gateway address, merchant appid, business private key, format, encoding, Alipay public key, encryption type), in order to obtain prepaid order information
            AlipayClient alipayClient = new DefaultAlipayClient(TransferConstants.URL, TransferConstants.APPID, TransferConstants.APP_PRIVATE_KEY, "json", charset, TransferConstants.ALIPAY_PUBLIC_KEY, TransferConstants.SIGN_TYPE);

            //Instantiate specific API corresponding to request class, class name and interface name corresponding, the current call interface name: alipay.trade.app.pay
            AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();

            //The SDK has encapsulated the public parameters. Only the business parameters need to be passed in here. The following method is the model input method of SDK
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

            //Many business parameters can be passed in. Refer to API
            //Model. Setpassbackparams (urlencoder. Encode (request. Getbody(). Tostring()); / / common parameters (additional data)
//            model.setBody(orderTest.getBody()); / / the specific description of a transaction. If there are multiple products, please add up the product description string and pass it to the body.

            model.setSubject(subject);                 //Trade name
            log.info("====================Merchant order number:" + out_trade_no);
            model.setOutTradeNo(out_trade_no);           //Merchant order number (automatically generated)
            // model.setTimeoutExpress("30m"); / / transaction timeout
            model.setTotalAmount(total_amount);         //Payment amount
//            Model. Setproductcode ("quick" msecurity "pay"); / / sales product code (fixed value)
            ali_request.setBizModel(model);
            log.info("====================The asynchronous notification address is:" + PayConstants.aliNotifyUrl);
            ali_request.setNotifyUrl(PayConstants.aliNotifyUrl);        //Asynchronous callback address (background)
//            ali_request.setReturnUrl(return_url); / / synchronize callback address (APP)

            // This is different from the normal interface call. SDK execute is used
            AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request); //Return to Alipay order information (preprocessing)
            log.info("-------------" + JSONObject.toJSONString(alipayTradeAppPayResponse));
            result = alipayTradeAppPayResponse.getBody();//That is, orderString can directly request to APP without further processing.
            if (alipayTradeAppPayResponse.isSuccess()) {
//                log.info("call succeeded");
//                String sign = DigestUtils.md5Hex(out_trade_no).toUpperCase();
//                result.put("code", "SUCCESS");
//                result.put("out_trade_no", out_trade_no);
//                result.put("sign", sign);
//                result.put("orderStr", result);
//                log.info(result.toJSONString());
//                log.info(result.toString());
            } else {
                log.info("Interaction with Alipay failed to generate the order. Please check the code!");
                return null;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.info("Interaction with Alipay failed to generate the order. Please check the code!");
        }
        return result;
    }

    /**
     * Alipay asynchronous request logic processing
     *
     * @return
     */
    public static AlipaymentOrderDto notify(Map<String, String> conversionParams) {
        AlipaymentOrderDto alipaymentOrder = new AlipaymentOrderDto();
        log.info("==================Alipay asynchronous request logic processing");
        //Signature verification (validation of the data returned by Alipay is determined by Alipay's return).
        boolean signVerified = false;
        try {
            //Call SDK to verify signature
            signVerified = AlipaySignature.rsaCheckV1(conversionParams, TransferConstants.ALIPAY_PUBLIC_KEY, TransferConstants.CHARSET, TransferConstants.SIGN_TYPE);

        } catch (AlipayApiException e) {
            log.info("==================Signature verification failed!");
            e.printStackTrace();
        }
        //Handle the signature check
        if (signVerified) {
            //Pass by inspection
            //Get the data to be saved
            String appId = conversionParams.get("app_id");//Application Id allocated to developers by Alipay
            String notifyTime = conversionParams.get("notify_time");//Notification time: yyyy MM DD HH: mm: SS
            String gmtCreate = conversionParams.get("gmt_create");//Transaction creation time: yyyy MM DD HH: mm: SS
            String gmtPayment = conversionParams.get("gmt_payment");//Transaction payment time
            String gmtRefund = conversionParams.get("gmt_refund");//Transaction refund time
            String gmtClose = conversionParams.get("gmt_close");//Transaction end time
            String tradeNo = conversionParams.get("trade_no");//Alipay's transaction number
            String outTradeNo = conversionParams.get("out_trade_no");//Get the order number before the merchant passed to Alipay (the unique order number of the merchant system).
            String outBizNo = conversionParams.get("out_biz_no");//Merchant business number (merchant business ID, mainly the serial number of refund application returned in refund notice)
            String buyerLogonId = conversionParams.get("buyer_logon_id");//Buyer Alipay account
            String sellerId = conversionParams.get("seller_id");//Seller Alipay user number
            String sellerEmail = conversionParams.get("seller_email");//Seller Alipay account
            String totalAmount = conversionParams.get("total_amount");//Order amount: the order amount paid in this transaction, unit: RMB (yuan)
            String receiptAmount = conversionParams.get("receipt_amount");//Amount actually received: the amount actually received by the merchant in the transaction, unit: Yuan
            String invoiceAmount = conversionParams.get("invoice_amount");//Invoiced amount: the invoiced amount paid by the user in the transaction
            String buyerPayAmount = conversionParams.get("buyer_pay_amount");//Payment amount: the amount paid by the user in the transaction
            String tradeStatus = conversionParams.get("trade_status");// Get transaction status
            //assignment
            alipaymentOrder.setNotifyTime(notifyTime);
            alipaymentOrder.setGmtCreate(gmtCreate);
            alipaymentOrder.setGmtPayment(gmtPayment);
            alipaymentOrder.setGmtRefund(gmtRefund);
            alipaymentOrder.setGmtClose(gmtClose);
            alipaymentOrder.setTradeNo(tradeNo);
            alipaymentOrder.setOutTradeNo(outTradeNo);
            alipaymentOrder.setOutBizNo(outBizNo);
            alipaymentOrder.setBuyerLogonId(buyerLogonId);
            alipaymentOrder.setSellerId(sellerId);
            alipaymentOrder.setSellerEmail(sellerEmail);
            alipaymentOrder.setTotalAmount(Double.parseDouble(totalAmount));
            alipaymentOrder.setReceiptAmount(Double.parseDouble(receiptAmount));
            alipaymentOrder.setInvoiceAmount(Double.parseDouble(invoiceAmount));
            alipaymentOrder.setBuyerPayAmount(Double.parseDouble(buyerPayAmount));
            alipaymentOrder.setTradeStatus(tradeStatus);
            //Alipay official recommended calibration value (out_trade_no, total_amount, sellerId, app_id)
            if (!TransferConstants.APPID.equals(appId)) {
                return null;
            }
        }
        return alipaymentOrder;
    }
}

Alipay asynchronous request processing

/**
     * Alipay asynchronous request logic processing
     *
     * @param aliParams
     * @return
     */
    @Transactional
    @Override
    public ResultData notify(Map<String, String[]> aliParams) {
        //Used to store the transformed parameter set
        Map<String, String> conversionParams = new HashMap<String, String>();
        for (Iterator<String> iter = aliParams.keySet().iterator(); iter.hasNext(); ) {
            String key = iter.next();
            String[] values = aliParams.get(key);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // Garbled code solution, this code is used when there is garbled code. You can also use this code conversion if mysign and sign are not equal
//             valueStr = new String(valueStr.getBytes("ISO-8859-1"), "uft-8");
            log.info("---------------------" + valueStr);
            conversionParams.put(key, valueStr);
        }

        log.info("==================Return parameter set:" + conversionParams);
        AlipaymentOrderDto alipaymentOrder = AliPayUtil.notify(conversionParams);
        if (alipaymentOrder != null) {
            // Enquiry order
            AppOrders appOrders = appOrdersService.selectAppOrdersByOrderNo(alipaymentOrder.getOutTradeNo());
            if ("0".equals(appOrders.getStatus())){
                log.info("-----Wechat asynchronous callback, modify order status--------------"+appOrders.toString());
                Double totalFee = alipaymentOrder.getTotalAmount();
                Map map = new HashMap();
                map.put("orderNo", appOrders.getOrderNo());
                map.put("payIntegral", appOrders.getPayIntegral());
                map.put("payMoney", totalFee);
                map.put("payWay", "1");
                map.put("discountMoney", appOrders.getDiscountMoney());
                appOrdersService.updateOrderStatusToPay(map);
            }
            //Alipay official recommended calibration value (out_trade_no, total_amount, sellerId, app_id)
            if (alipaymentOrder.getTradeStatus().equals("TRADE_SUCCESS")) {
                //Process only orders with successful payment: modify transaction table status, payment succeeded
                //Update status in transaction table
                int returnResult = appTransactionHistoryService.updateTransactionHistoryByTransactionNo(alipaymentOrder.getOutTradeNo(), alipaymentOrder.getTradeNo());
                log.info("==================returnResult: " + returnResult);
                if (returnResult > 0) {
                    log.info("==================Update status in transaction table succeeded:" + alipaymentOrder.getTradeNo());
                    return ResultData.success();
                } else {
                    return new ResultData(4, "Failed to update transaction table!");
                }
            } else {
                return new ResultData(4, "Signature verification failed!");
            }
        } else {
            return new ResultData(4, "Signature verification failed!");
        }
    }

The above is the payment steps, welcome to provide good suggestions or questions!

Published 3 original articles, won praise 5, visited 1398
Private letter follow

Tags: xml network Java JSON

Posted on Sun, 09 Feb 2020 06:35:22 -0800 by Kodak07