Java实现微信(主、子商户模式)及支付宝支付

技术标签: java  支付  

一、业务需求

实现APP微信、支付宝支付,后端需要做生成预支付单,响应支付结果;微信商户采用子商户模式

二、参考官方文档

微信普通商户:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

微信服务商:https://pay.weixin.qq.com/wiki/doc/api/app/app_sl.php?chapter=9_1

支付宝API开发文档:https://docs.open.alipay.com/api_1/alipay.trade.app.pay

三、准备工作

在公众平台完成入驻等操作,拿到以下信息

普通商户:

参数 API参数名 详细说明
APPID appid appid是微信公众账号或开放平台APP的唯一标识,在公众平台申请公众账号或者在开放平台申请APP账号后,微信会自动分配对应的appid,用于标识该应用。可在微信公众平台-->开发者中心查看,商户的微信支付审核通过邮件中也会包含该字段值。
微信支付商户号 mch_id 商户申请微信支付后,由微信支付分配的商户收款账号。
API密钥 key 交易过程生成签名的密钥,仅保留在商户系统和微信支付后台,不会在网络中传播。商户妥善保管该Key,切勿在网络中传输,不能在其他客户端中存储,保证key不会被泄漏。商户可根据邮件提示登录微信商户平台进行设置。也可按以下路径设置:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
Appsecret secret AppSecret是APPID对应的接口密码,用于获取接口调用凭证access_token时使用。

服务商:

参数 API参数名 详细说明
受理商户的APPID appid appid是微信公众账号或开放平台APP的唯一标识,在公众平台申请公众账号或者在开放平台申请APP账号后,微信会自动分配对应的appid,用于标识该应用。可在微信公众平台-->开发者中心查看,商户的微信支付审核通过邮件中也会包含该字段值。
受理商户的商户号 mch_id 受理商户申请微信支付后,由微信支付分配的商户账号。
受理商户的API密钥 key 交易过程生成签名的密钥,仅保留在商户系统和微信支付后台,不会在网络中传播。商户妥善保管该Key,切勿在网络中传输,不能在其他客户端中存储,保证key不会被泄漏。商户可根据邮件提示登录微信商户平台进行设置。也可按一下路径设置:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
子商户商户号 sub_mch_id 子商户申请的商户号或商户识别码
子商户应用APPID sub_appid 子商户在开放平台申请的应用APPID
商户号应用的Appsecret secret AppSecret是子商户应用APPID对应的接口密码,用于获取接口调用凭证access_token时使用。

如使用子商户,需要先进行授权

支付宝参考文档获取相关参数

四、代码

--微信

API常量类

public class TransferConstants {
/** =============================================微信================================================*/

    /**统一下单API*/
    public static final String UNIFIEDORDER_PAY = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    /**企业付款API*/
    public static final String TRANSFERS_PAY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
    /**申请退款API*/
    public static final String REFUND_PAY = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    /**企业付款查询API*/
    public static final String TRANSFERS_PAY_QUERY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo";
    /**公众账号appid*/
    public static final String APP_ID = ""  ;
    /**商户号*/
    public static final String MCH_ID = "";
    /**API密钥 填服务商的*/
    public static final String API_SECRET = "";
    /**子商户应用ID*/
    public static final String SUB_APPID = "";
    /**子商户号 */
    public static final String SUB_MCH_ID = "";

/** =============================================支付宝================================================*/
    /**支付宝网关(固定)*/
    public static final String URL = "https://openapi.alipay.com/gateway.do";
    /**APPID 即创建应用后生成*/
    public static final String APPID = "";
    /**开发者私钥,由开发者自己生成*/
    public static final String APP_PRIVATE_KEY =  "";
    /**参数返回格式,只支持 json*/
    public static final String FORMAT = "json";
    /**编码集,支持 GBK/UTF-8*/
    public static final String CHARSET = "UTF-8";
    /**支付宝公钥,由支付宝生成)*/
    public static final String ALIPAY_PUBLIC_KEY = "";
    /**商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐使用 RSA2*/
    public static final String SIGN_TYPE = "RSA2";

}

在线上支付时,遇到了支付后微信那边不能回调,后来写了一个主动回调的方法

首先在application.yml配置支付回调地址

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

获取支付回调地址

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

/**
 * 支付回调地址
 */
@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数据处理类

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;
        }
    }
}

支付工具类

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 创建时间:2019/5/6 14:13
 */
public class PayUtil {

    private static final Logger logger = LoggerFactory.getLogger(PayUtil.class);
    /**
     * 生成订单号
     *
     * @return
     */
    public static String getOrderNo() {
        // 自增8位数 00000001
        return "ONO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * 退款单号
     *
     * @return
     */
    public static String getRefundNo() {
        // 自增8位数 00000001

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

    /**
     * 交易单号
     *
     * @return
     */
    public static String getTransferNo() {
        // 自增8位数 00000001
        return "TNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * 支付单号
     *
     * @return
     */
    public static String getPayNo() {
        // 自增8位数 00000001
        return "PNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * 门店进账单号
     *
     * @return
     */
    public static String getReceiptNo() {
        // 自增8位数 00000001
        return "SRNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * 参团编号
     *
     * @return
     */
    public static String getGroupNo() {
        // 自增8位数 00000001
        return "GNO" + DateUtils.dateTimeNow() + "00000001";
    }

    /**
     * 返回客户端ip
     *
     * @param request
     * @return
     */
    public static String getRemoteAddrIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值,第一个ip才是真实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();
    }

    /**
     * 获取服务器的ip地址
     *
     * @param request
     * @return
     */
    public static String getLocalIp(HttpServletRequest request) {
        return request.getLocalAddr();
    }

    /**
     * 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
     * @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());


        //对所有传入参数按照字段名的ASCII码从小到大排序(字典序)
        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();
    }

    /**
     * 退款时生成签名
     * @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();
    }

    /**
     * 构造签名
     *
     * @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))) // 参数为空不参与签名
                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();
    }

    /**
     * 构造退款时签名
     *
     * @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))) // 参数为空不参与签名
                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();
    }

    /**
     * 创建支付随机字符串
     *
     * @return
     */
    public static String getNonceStr() {
        return StringUtils.getRandomString(32);
    }

    /**
     * 支付时间戳
     *
     * @return
     */
    public static String payTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

}

xml、map转换工具类

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 = "]]>";

    /**
     * 转化成xml, 单层无嵌套
     *
     * @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,转化成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();
    }

    /**
     * 解析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"); // 为xml设置要解析的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,解析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"); // 为xml设置要解析的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加密工具类

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 {
            // 得到一个信息摘要器
            MessageDigest digest = MessageDigest.getInstance("md5");
            byte[] result = digest.digest(s.getBytes());
            StringBuffer buffer = new StringBuffer();
            // 把每一个byte 做一个与运算 0xff;
            for (byte b : result) {
                // 与运算
                int number = b & 0xff;// 加盐
                String str = Integer.toHexString(number);
                if (str.length() == 1) {
                    buffer.append("0");
                }
                buffer.append(str);
            }

            // 标准的md5加密后的结果
            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" };
}

微信签名相关工具类

@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); //公众账号appid
            parameters.put("mch_id", TransferConstants.MCH_ID); //商户号
            parameters.put("sub_appid", TransferConstants.SUB_APPID); //子商户应用ID
            parameters.put("sub_mch_id", TransferConstants.SUB_MCH_ID); //子商户号
            parameters.put("nonce_str", PayUtil.getNonceStr()); //随机字符串
            parameters.put("out_trade_no", (String) map.get("transferNo")); //商户订单号
            parameters.put("total_fee", (String)map.get("money")); //转账金额
            parameters.put("body", (String) map.get("desc")); //企业付款描述信息
            parameters.put("spbill_create_ip", (String) map.get("ip")); //Ip地址
            parameters.put("notify_url", PayConstants.wxNotifyUrl);              //回调通知地址
            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);
            //生成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);
            //生成签名
            resultMap = createSecondSign(params2);

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

    /**
     * 微信支付签名算法sign
     *
     * @param parameters
     * @return
     */
    public static Map<Object, Object> createSecondSign(Map<Object, Object> parameters) {
        Map<Object, Object> resultMap = new HashMap<>();
        //微信支付
        String xml = XmlUtil.xmlFormatObject(parameters, false);
        log.info("----签名-------"+ xml);
        String restxml = HttpUtilA.posts(TransferConstants.UNIFIEDORDER_PAY, XmlUtil.xmlFormatObject(parameters, false));
        log.info("----发送签名-------"+ restxml);
        Map<String, String> returnMap = null;
        try {
            returnMap = XmlUtil.xmlParse(restxml);
            log.info("-----------"+ JSONObject.valueAsStr(returnMap));
            // 通信标识和交易标识都为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");// 预支付交易会话标识
                String noncestr = returnMap.get("nonce_str");// 微信返回的随机字符串
                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());
                //生成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>统一下单</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);
            // 通信标识和交易标识都为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", "微信扫码支付");
            } else {
                resultMap.put("returnCode", returnMap.get("return_code"));
                resultMap.put("returnMsg", returnMap.get("return_msg"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    /**
     * <p>微信支付统一下单</p>
     *
     * @return
     * @throws Exception
     */
    private Map<String, String> wxUnifieldOrder(Map map) throws Exception {
        //封装参数
        SortedMap<String, String> parameters = new TreeMap<String, String>();
        parameters.put("mch_appid", TransferConstants.APP_ID); //公众账号appid
        parameters.put("mchid", TransferConstants.MCH_ID); //商户号
        parameters.put("nonce_str", PayUtil.getNonceStr()); //随机字符串
        parameters.put("partner_trade_no", (String) map.get("transferNo")); //商户订单号
        parameters.put("openid", (String) map.get("openId")); //用户openid oCVr20N2YLH9VQztnkZTaCj2aYYY
        parameters.put("check_name", "NO_CHECK"); //校验用户姓名选项 OPTION_CHECK
        //parameters.put("re_user_name", "安迪"); //check_name设置为FORCE_CHECK或OPTION_CHECK,则必填
        parameters.put("amount", (String) map.get("money")); //转账金额
        parameters.put("desc", (String) map.get("desc")); //企业付款描述信息
        parameters.put("spbill_create_ip", (String) map.get("ip")); //Ip地址
//            parameters.put("notify_url", notifyUrl);              //回调通知地址
        parameters.put("trade_type", "APP");                  //支付类型
        parameters.put("sign", createSign(parameters, ""));
        //转换为xml
        String xmlData = mapToXml(parameters);
        //请求微信后台
        String resXml = HttpUtilA.posts(TransferConstants.UNIFIEDORDER_PAY, xmlData);
        log.info("【微信支付】 统一下单响应:\n" + resXml);
        return xmlStrToMap(resXml);
    }

    /**
     * Map转换为 Xml
     *
     * @return Xml
     * @throws Exception
     */
    public static String mapToXml(SortedMap<String, String> map) throws Exception {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        //防止XXE攻击
        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;
    }

    /**
     * 创建签名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字符串转换为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;
    }
}

 微信异步请求处理

/**
     * 微信异步请求逻辑处理
     *
     * @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)) {
                // 支付失败
                return_data.put("return_code", "FAIL");
                return_data.put("return_msg", "return_code不正确");
                code = 4;
            } else {
                System.out.println("===============付款成功==============");
                String outTradeNo = String.valueOf(Long.parseLong(params.get("out_trade_no").split("O")[0]));
                // 查询订单
                AppOrders appOrders = appOrdersService.selectAppOrdersByOrderNo(outTradeNo);
                if ("0".equals(appOrders.getStatus())){
                    log.info("-----微信异步回调,修改订单状态--------------"+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");
                // 只处理支付成功的订单: 修改交易表状态,支付成功
                //更新交易表中状态
                int returnResult = appTransactionHistoryService.updateTransactionHistoryByTransactionNo(outTradeNo, transactionId);
                log.info("==================returnResult:" + returnResult);
                if (returnResult > 0) {
                    log.info("==================更新交易表中状态成功:" + transactionId);
                    return_data.put("return_code", "SUCCESS");
                    return_data.put("return_msg", "OK");
                    code = 0;
                } else {
                    return new ResultData(4, "更新交易表失败 !");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
        return new ResultData(code, XmlUtil.xmlFormat(return_data, false));
    }

--支付宝

支付宝实体类

public class AlipaymentOrderDto {
    //支付宝分配给开发者的应用Id
    private String appId;
    //通知时间:yyyy-MM-dd HH:mm:ss
    private String notifyTime;
    //交易创建时间:yyyy-MM-dd HH:mm:ss
    private String gmtCreate;
    //交易付款时间
    private String gmtPayment;
    //交易退款时间
    private String gmtRefund;
    //交易结束时间
    private String gmtClose;
    //支付宝的交易号
    private String tradeNo;
    //获取商户之前传给支付宝的订单号(商户系统的唯一订单号)
    private String outTradeNo;
    //商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)
    private String outBizNo;
    //买家支付宝账号
    private String buyerLogonId;
    //卖家支付宝用户号
    private String sellerId;
    //卖家支付宝账号
    private String sellerEmail;
    //订单金额:本次交易支付的订单金额,单位为人民币(元)
    private Double totalAmount;
    //实收金额:商家在交易中实际收到的款项,单位为元
    private Double receiptAmount;
    //开票金额:用户在交易中支付的可开发票的金额
    private Double invoiceAmount;
    //付款金额:用户在交易中支付的金额
    private Double buyerPayAmount;
    // 获取交易状态
    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;
    }
}

支付宝支付工具类

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);

    // 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
//    public static String notify_url = "http://工程公网访问地址/alipay.trade.page.pay-JAVA-UTF-8/notify_url.jsp";
    // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
//    public static String return_url = "http://工程公网访问地址/alipay.trade.page.pay-JAVA-UTF-8/return_url.jsp";
    // 字符编码格式
    public static String charset = "utf-8";

    /**
     * 支付
     *
     * @param map
     * @return
     */
    public static String pay(Map map) {
//    public static JSONObject pay(Map map) {
        //最终返回加签之后的,app需要传给支付宝app的订单信息字符串
        String result = "";
//        JSONObject result = new JSONObject();
        try {
            //商户订单号,商户网站订单系统中唯一订单号,必填
            String out_trade_no = (String) map.get("orderNo");
            //付款金额,必填
            String total_amount = (String) map.get("money");
            //订单名称,必填
            String subject = (String) map.get("orderName");

            //实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
            AlipayClient alipayClient = new DefaultAlipayClient(TransferConstants.URL, TransferConstants.APPID, TransferConstants.APP_PRIVATE_KEY, "json", charset, TransferConstants.ALIPAY_PUBLIC_KEY, TransferConstants.SIGN_TYPE);

            //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
            AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();

            //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

            //业务参数传入,可以传很多,参考API
            //model.setPassbackParams(URLEncoder.encode(request.getBody().toString())); //公用参数(附加数据)
//            model.setBody(orderTest.getBody());                       //对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。

            model.setSubject(subject);                 //商品名称
            log.info("====================商户订单号:" + out_trade_no);
            model.setOutTradeNo(out_trade_no);           //商户订单号(自动生成)
            // model.setTimeoutExpress("30m");     			  //交易超时时间
            model.setTotalAmount(total_amount);         //支付金额
//            model.setProductCode("QUICK_MSECURITY_PAY");              //销售产品码(固定值)
            ali_request.setBizModel(model);
            log.info("====================异步通知的地址为:" + PayConstants.aliNotifyUrl);
            ali_request.setNotifyUrl(PayConstants.aliNotifyUrl);        //异步回调地址(后台)
//            ali_request.setReturnUrl(return_url);        //同步回调地址(APP)

            // 这里和普通的接口调用不同,使用的是sdkExecute
            AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request); //返回支付宝订单信息(预处理)
            log.info("-------------" + JSONObject.toJSONString(alipayTradeAppPayResponse));
            result = alipayTradeAppPayResponse.getBody();//就是orderString 可以直接给APP请求,无需再做处理。
            if (alipayTradeAppPayResponse.isSuccess()) {
//                log.info("调用成功");
//                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("与支付宝交互出错,未能生成订单,请检查代码!");
                return null;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.info("与支付宝交互出错,未能生成订单,请检查代码!");
        }
        return result;
    }

    /**
     * 支付宝异步请求逻辑处理
     *
     * @return
     */
    public static AlipaymentOrderDto notify(Map<String, String> conversionParams) {
        AlipaymentOrderDto alipaymentOrder = new AlipaymentOrderDto();
        log.info("==================支付宝异步请求逻辑处理");
        //签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
        boolean signVerified = false;
        try {
            //调用SDK验证签名
            signVerified = AlipaySignature.rsaCheckV1(conversionParams, TransferConstants.ALIPAY_PUBLIC_KEY, TransferConstants.CHARSET, TransferConstants.SIGN_TYPE);

        } catch (AlipayApiException e) {
            log.info("==================验签失败 !");
            e.printStackTrace();
        }
        //对验签进行处理
        if (signVerified) {
            //验签通过
            //获取需要保存的数据
            String appId = conversionParams.get("app_id");//支付宝分配给开发者的应用Id
            String notifyTime = conversionParams.get("notify_time");//通知时间:yyyy-MM-dd HH:mm:ss
            String gmtCreate = conversionParams.get("gmt_create");//交易创建时间:yyyy-MM-dd HH:mm:ss
            String gmtPayment = conversionParams.get("gmt_payment");//交易付款时间
            String gmtRefund = conversionParams.get("gmt_refund");//交易退款时间
            String gmtClose = conversionParams.get("gmt_close");//交易结束时间
            String tradeNo = conversionParams.get("trade_no");//支付宝的交易号
            String outTradeNo = conversionParams.get("out_trade_no");//获取商户之前传给支付宝的订单号(商户系统的唯一订单号)
            String outBizNo = conversionParams.get("out_biz_no");//商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)
            String buyerLogonId = conversionParams.get("buyer_logon_id");//买家支付宝账号
            String sellerId = conversionParams.get("seller_id");//卖家支付宝用户号
            String sellerEmail = conversionParams.get("seller_email");//卖家支付宝账号
            String totalAmount = conversionParams.get("total_amount");//订单金额:本次交易支付的订单金额,单位为人民币(元)
            String receiptAmount = conversionParams.get("receipt_amount");//实收金额:商家在交易中实际收到的款项,单位为元
            String invoiceAmount = conversionParams.get("invoice_amount");//开票金额:用户在交易中支付的可开发票的金额
            String buyerPayAmount = conversionParams.get("buyer_pay_amount");//付款金额:用户在交易中支付的金额
            String tradeStatus = conversionParams.get("trade_status");// 获取交易状态
            //赋值
            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);
            //支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
            if (!TransferConstants.APPID.equals(appId)) {
                return null;
            }
        }
        return alipaymentOrder;
    }
}

支付宝异步请求处理

/**
     * 支付宝异步请求逻辑处理
     *
     * @param aliParams
     * @return
     */
    @Transactional
    @Override
    public ResultData notify(Map<String, String[]> aliParams) {
        //用以存放转化后的参数集合
        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] + ",";
            }
            // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
//             valueStr = new String(valueStr.getBytes("ISO-8859-1"), "uft-8");
            log.info("---------------------" + valueStr);
            conversionParams.put(key, valueStr);
        }

        log.info("==================返回参数集合:" + conversionParams);
        AlipaymentOrderDto alipaymentOrder = AliPayUtil.notify(conversionParams);
        if (alipaymentOrder != null) {
            // 查询订单
            AppOrders appOrders = appOrdersService.selectAppOrdersByOrderNo(alipaymentOrder.getOutTradeNo());
            if ("0".equals(appOrders.getStatus())){
                log.info("-----微信异步回调,修改订单状态--------------"+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);
            }
            //支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
            if (alipaymentOrder.getTradeStatus().equals("TRADE_SUCCESS")) {
                //只处理支付成功的订单: 修改交易表状态,支付成功
                //更新交易表中状态
                int returnResult = appTransactionHistoryService.updateTransactionHistoryByTransactionNo(alipaymentOrder.getOutTradeNo(), alipaymentOrder.getTradeNo());
                log.info("==================returnResult:" + returnResult);
                if (returnResult > 0) {
                    log.info("==================更新交易表中状态成功:" + alipaymentOrder.getTradeNo());
                    return ResultData.success();
                } else {
                    return new ResultData(4, "更新交易表失败 !");
                }
            } else {
                return new ResultData(4, "验签失败 !");
            }
        } else {
            return new ResultData(4, "验签失败 !");
        }
    }

以上是支付的步骤,欢迎大家提供好的建议或问题!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Captain_JC/article/details/104232529

智能推荐

c语言描述链串的类型定义,数据结构第四章:串_火锅与理想的博客-程序员宅基地

4.1 串类型的定义字符串可以看作是一种特殊的线性表,字符串的数据对象约束为字符集(非数值数据)。不同的应用所处理的串的特点亦不相同。在线性表的基本操作中,大多以“单个元素”作为操作对象,而在串中则是以“串的整体”或一部分作为操作对象。串的定义:串(String)是零个或多个字符组成的有限序列。一般记为:s=′a1a2…an′ (n≥0)s是串的名字, a1a2…an是串s的值ai可以是字母、数...

dockerfile 生成php,构建第一个Dockerfile文件_Batyr的博客-程序员宅基地

首先,我们需要创建一个空的 Dokcerfile 文件;mkdir dockerfile_testcd dockerfile_test/touch Dockerfilenano Dockerfile紧接着,我们需要编写一个 Dockerfile 文件,代码清单如下:FROM centos:7MAINTAINER LiangGzone "[email protected]"RUN rpm -ivh...

c语言修饰符1,c语言的volatile修饰符(转)_轻风慢越的博客-程序员宅基地

作为一个变量类型修饰符, volatile的作用就是被设计用来修饰被不同线程访问和修改的变量. 在原子操作中同样会用到. 如果没有它, 很有可能使得编程写的多线程程序出现不可预期的错误, 也可能因为编译器的各种优化而导致编译后的结果表达了不同的意思, 使得程序出现难以发现的错误.被volatile修饰的变量是说这个变量可能会被意想不到地被改变, 这样, 编译器就不会在编译会访问该变量的语句的时候,...

matlab散点聚合,matlab – 时间序列聚合效率_weixin_39907939的博客-程序员宅基地

我通常需要总结具有给定聚合函数的不规则定时的时间序列(即,总和,平均等).但是,我现有的解决方案似乎效率低,速度慢.采取聚合功能:function aggArray = aggregate(array, groupIndex, collapseFn)groups = unique(groupIndex, 'rows');aggArray = nan(size(groups, 1), size(ar...

微软ios服务器,iOS 客户端入门_紫薯萝卜的博客-程序员宅基地

iOS 客户端入门07/15/2021本文内容适用范围:Windows Server 2022、Windows 10、Windows 8.1、Windows Server 2019、Windows Server 2016、Windows Server 2012 R2可以使用适用于 iOS 的远程桌面客户端从 iOS 设备(iPhone 和 iPad)处理 Windows 应用、资源和桌面。请参考以...

随便推点

JAVA Web项目的编码过滤器_weixin_30902675的博客-程序员宅基地

首先写一个EncodeFilter的过滤类:packagecom.djtu.wy.common;importjava.io.IOException;importjavax.servlet.Filter;importjavax.servlet.FilterChain;importjavax.servlet.FilterConfig;importjavax.servlet.Servle...

Django1.10配置Jinja2模板(20161130更新)_weixin_34116110的博客-程序员宅基地

Django自动的扩展jinja2模板的功能并不好用,还是使用django-jinja插件比较靠谱。1、安装Jinja2模块:pipinstalldjango-jinja2、配置settings:INSTALLED_APPS+=('django_jinja',)TEMPLATES=[{"BACKEND":"django_jinja...

linux传参更改控制台波特率,linux – RS232控制台通信 – 将波特率设置为1 MBaud_weixin_39695701的博客-程序员宅基地

在bash脚本中,我使用以下内容:$stty -F /dev/ttyUSB0 921600 raw$echo -n "some test data" &gt;/dev/ttyUSB0它按预期工作.使用PL2303 USB转RS232适配器:$lsusb...Bus 006 Device 010: ID 067b:2303 Prolific Technology, Inc. PL2303 Seria...

java interface泛型_java – 使用泛型和接口实现组合_春三吉的博客-程序员宅基地

我正在努力实现以下目标:我的类X有一个通用的Y.然而,这个泛型Y需要访问X的资源,我想通过接口来处理它,以便允许其他人继承任意选择的类.然而,我目前的方法会产生一系列泛型:public interface X&gt;&gt; {Object getO();}public interface Y&gt;&gt; {void doSomething();}我想要实现的目标:public class G...

c++学习之:根据GetLastError()返回值获取错误信息_weixin_33907511的博客-程序员宅基地

VC中GetLastError()获取错误信息的使用在VC中编写应用程序时,经常需要涉及到错误处理问题。许多函数调用只用TRUE和FALSE来表明函数的运行结果。一旦出现错误,MSDN中往往会指出请用GetLastError()函数来获得错误原因。     可问题是,GetLastError()返回的只是一个双字节数值(DWORD)。OH,MY GOD!目前Win32的出错编号已经从0排到11...

推荐文章

热门文章

相关标签