SpringBoot—支付—微信

一、支付流程 

1.1、支付准备 

1.获取商户号 
微信商户平台 申请成为商户 => 提交资料 => 签署协议 => 获取商户号 
2.获取 AppID 
微信公众平台 注册服务号 => 服务号认证 => 获取APPID => 绑定商户号 
3.申请商户证书
登录商户平台 => 选择 账户中心 => 安全中心 => API安全 => 申请API证书 包括商户证书和商户私钥 
4.获取微信的证书 
5.获取APIv3秘钥(在微信支付回调通知和商户获取平台证书使用APIv3密钥)
登录商户平台 => 选择 账户中心 => 安全中心 => API安全 => 设置APIv3密钥  

1.2、开发平台 

1.2.1、开发平台创建应用

1.2.2、开发平台获取应用ID

1.3、商户平台

1.3.1、商户平台设置API密钥 

1.3.2、商户平台查看商户号 

二、项目使用 V2

微信小程序账号:要认证、获取appid、生成secret、开通支付、关联商户号
微信商户平台账号:要认证、获取商户号mch_id、获取商户API密钥mch_key、APPID授权、配置支付接口

2.1、依赖与配置

2.1.1、依赖

<!-- 微信支付 SDK -->
<dependency>
	<groupId>com.github.wxpay</groupId>
	<artifactId>wxpay-sdk</artifactId>
	<version>0.0.3</version>
</dependency>

2.1.2、配置文件

# 微信支付配置 notifyUrl:微信支付异步回调地址
pay:
  appId: #应用id
  apiKey: #商户私钥key
  mchId: #商户id
  appSecret: #小程序密钥
  notifyUrl: #支付回调地址

2.1.3、配置类

2.1.3.1、微信支付配置类
/**
 * 微信支付配置
 */
@Data
@Component
@Configuration
@ConfigurationProperties(prefix = "pay")
public class WxPayConfig {

    /**
     * 微信公众号appid
     */
    private String appId;
 
    /**
     * 公众号设置的API v2密钥
     */
    private String apiKey;
 
    /**
     * 微信商户平台 商户id
     */
    private String mchId;
 
    /**
     *小程序密钥
     */
    private String appSecret;
 
    /**
     * 小程序支付异步回调地址
     */
    private String notifyUrl;
}
2.1.3.2、微信支付预下单实体类
/**
 * 微信支付预下单实体类
 */
@Data
@Accessors(chain = true)
public class WeChatPay {

    /**
     * 返回状态码  此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
     */
    public String return_code;
	
    /**
     * 返回信息 当return_code为FAIL时返回信息为错误原因 ,例如 签名失败 参数格式校验错误
     */
    private String return_msg;
	
    /**
     * 公众账号ID 调用接口提交的公众账号ID
     */
    private String appid;
	
    /**
     * 商户号 调用接口提交的商户号
     */
    private String mch_id;
	
    /**
     * api密钥 详见:https://pay.weixin.qq.com/index.php/extend/employee
     */
    private String api_key;
	
    /**
     * 设备号  自定义参数,可以为请求支付的终端设备号等
     */
    private String device_info;
	
    /**
     * 随机字符串  5K8264ILTKCH16CQ2502SI8ZNMTM67VS   微信返回的随机字符串
     */
    private String nonce_str;
	
    /**
     * 签名 微信返回的签名值,详见签名算法:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_3
     */
    private String sign;
	
    /**
     * 签名类型
     */
    private String sign_type;
	
    /**
     * 业务结果 SUCCESS SUCCESS/FAIL
     */
    private String result_code;
	
    /**
     * 错误代码 当result_code为FAIL时返回错误代码,详细参见下文错误列表
     */
    private String err_code;
	
    /**
     * 错误代码描述 当result_code为FAIL时返回错误描述,详细参见下文错误列表
     */
    private String err_code_des;
	
    /**
     * 交易类型 JSAPI JSAPI -JSAPI支付 NATIVE -Native支付 APP -APP支付 说明详见;https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_2
     */
    private String trade_type;
	
    /**
     * 预支付交易会话标识 微信生成的预支付会话标识,用于后续接口调用中使用,该值有效期为2小时
     */
    private String prepay_id;
	
    /**
     * 二维码链接 weixin://wxpay/bizpayurl/up?pr=NwY5Mz9&groupid=00 trade_type=NATIVE时有返回,此url用于生成支付二维码,然后提供给用户进行扫码支付。注意:code_url的值并非固定,使用时按照URL格式转成二维码即可
     */
    private String code_url;
	
    /**
     * 商品描述  商品简单描述,该字段请按照规范传递,具体请见 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_2
     */
    private String body;
	
    /**
     * 商家订单号 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一。详见商户订单号 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_2
     */
    private String out_trade_no;
	
    /**
     * 标价金额 订单总金额,单位为分,详见支付金额 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_2
     */
    private String total_fee;
	
    /**
     * 终端IP 支持IPV4和IPV6两种格式的IP地址。用户的客户端IP
     */
    private String spbill_create_ip;
	
    /**
     * 通知地址 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。公网域名必须为https,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用http
     */
    private String notify_url;
	
    /**
     * 子商户号 sub_mch_id 非必填(商户不需要传入,服务商模式才需要传入) 微信支付分配的子商户号
     */
    private String sub_mch_id;
	
    /**
     * 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
     */
    private String attach;
	
    /**
     * 商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
     */
    private String out_refund_no;
	
    /**
     * 退款总金额,单位为分,只能为整数,可部分退款。详见支付金额 https://pay.weixin.qq.com/wiki/doc/api/native_sl.php?chapter=4_2
     */
    private String refund_fee;
	
    /**
     * 退款原因 若商户传入,会在下发给用户的退款消息中体现退款原因 注意:若订单退款金额≤1元,且属于部分退款,则不会在退款消息中体现退款原因
     */
    private String refund_desc;
	
    /**
     * 交易结束时间 订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则 注意:最短失效时间间隔必须大于5分钟
     */
    private String time_expire;
	
    /**
     * 用户标识 trade_type=JSAPI,此参数必传,用户在主商户appid下的唯一标识。openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。下单前需要调用【网页授权获取用户信息: https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html 】接口获取到用户的Openid。
     */
    private String openid;
	
    /**
     * 时间戳
     */
    private String time_stamp;
	
    /**
     * 会员类型
     */
    private String memberShipType;
}
2.1.3.3、预下单成功之后返回结果实体类
/**
 * 预下单成功之后返回结果实体类
 */
@Data
public class OrderReturnInfo {
 
    private String return_code;
 
    private String return_msg;
 
    private String result_code;
 
    private String appid;
 
    private String mch_id;
 
    private String nonce_str;
 
    private String sign;
 
    private String prepay_id;
 
    private String trade_type;
}
2.1.3.4、查询订单返回的实体类
/**
 * 查询订单返回实体类
 */
@Data
public class QueryReturnInfo {
 
    private String return_code;
 
    private String return_msg;
 
    private String result_code;
 
    private String err_code;
 
    private String err_code_des;
 
    private String appid;
 
    private String mch_id;
 
    private String nonce_str;
 
    private String sign;
 
    private String prepay_id;
 
    private String trade_type;
 
    private String device_info;
 
    private String openid;
 
    private String is_subscribe;
 
    private String trade_state;
 
    private String bank_type;
 
    private int total_fee;
 
    private int settlement_total_fee;
 
    private String fee_type;
 
    private int cash_fee;
 
    private String cash_fee_type;
 
    private int coupon_fee;
 
    private int coupon_count;
 
    private String coupon_type_$n;
 
    private String coupon_id_$n;
 
    private String transaction_id;
 
    private String out_trade_no;
 
    private String time_end;
 
    private String trade_state_desc;
}
2.1.3.5、签名实体类
/**
 * 签名实体类
 */
@Data
public class SignInfo {
 
    private String appId;//小程序ID
 
    private String timeStamp;//时间戳
 
    private String nonceStr;//随机串
 
    @XStreamAlias("package")
    private String repay_id;
 
    private String signType;//签名方式
 
    public String getAppId() {
        return appId;
    }
 
    public void setAppId(String appId) {
        this.appId = appId;
    }
 
    public String getTimeStamp() {
        return timeStamp;
    }
 
    public void setTimeStamp(String timeStamp) {
        this.timeStamp = timeStamp;
    }
 
    public String getNonceStr() {
        return nonceStr;
    }
 
    public void setNonceStr(String nonceStr) {
        this.nonceStr = nonceStr;
    }
 
    public String getRepay_id() {
        return repay_id;
    }
	
    public void setRepay_id(String repay_id) {
        this.repay_id = repay_id;
    }
	
    public String getSignType() {
        return signType;
    }
	
    public void setSignType(String signType) {
        this.signType = signType;
    }
}

2.2、工具类

2.2.1、微信支付API地址

/**
 * 微信支付API地址
 */
public class WeChatPayUrlConstants {
 
    /**
     * 统一下单预下单接口url
     */
    public static final String Uifiedorder = "https://api.mch.weixin.qq.com/pay/unifiedorder";
 
    /**
     * 订单状态查询接口URL
     */
    public static final String Orderquery = "https://api.mch.weixin.qq.com/pay/orderquery";
 
    /**
     * 订单申请退款
     */
    public static final String Refund = "https://api.mch.weixin.qq.com/secapi/pay/refund";
 
    /**
     * 付款码 支付
     */
    public static final String MicroPay = "https://api.mch.weixin.qq.com/pay/micropay";
 
    /**
     * 微信网页授权 获取“code”请求地址
     */
    public static final String GainCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize";
 
    /**
     * 微信网页授权 获取“code” 回调地址
     */
    public static final String GainCodeRedirect_uri = "http://i5jmxe.natappfree.cc/boss/WeChatPayMobile/SkipPage.html";
}

2.2.2、Http工具类

/**
 * Http工具类
 */
public class HttpRequest {

    //连接超时时间,默认10秒
    private static final int socketTimeout = 10000;
	
    //传输超时时间,默认30秒
    private static final int connectTimeout = 30000;
	
    /**
     * post请求
     */
    public static String sendPost(String url, Object xmlObj) throws ClientProtocolException, IOException, UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException {
        HttpPost httpPost = new HttpPost(url);
        //解决XStream对出现双下划线的bug
        XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
        xStreamForRequestPostData.alias("xml", xmlObj.getClass());
        //将要提交给API的数据对象转换成XML格式数据Post给API
        String postDataXML = xStreamForRequestPostData.toXML(xmlObj);
        //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
        StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(postEntity);
        //设置请求器的配置
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
        httpPost.setConfig(requestConfig);
        HttpClient httpClient = HttpClients.createDefault();
        HttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity = response.getEntity();
        String result = EntityUtils.toString(entity, "UTF-8");
        return result;
    }
 
    /**
     * 自定义证书管理器,信任所有证书
     */
    public static class MyX509TrustManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1)throws CertificateException {
        }
		
        @Override
        public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1)throws CertificateException {
        }
		
        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
}

2.2.3、微信签名

/**
 * 微信签名
 */
public class SignUtils {
    /**
     * 签名算法
     * @param o 要参与签名的数据对象
     * @return 签名
     */
    public static String getSign(Object o) throws IllegalAccessException {
        ArrayList<String> list = new ArrayList<String>();
        Class cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            if (f.get(o) != null && f.get(o) != "") {
                String name = f.getName();
                XStreamAlias anno = f.getAnnotation(XStreamAlias.class);
                if (anno != null) {
                    name = anno.value();
                }
                list.add(name + "=" + f.get(o) + "&");
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + Configure.getKey();
        System.out.println("签名数据:" + result);
        result = MD5.MD5Encode(result).toUpperCase();
        return result;
    }
 
    public static String getSign(Map<String, Object> map) {
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue() != "") {
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + Configure.getKey();
        result = MD5.MD5Encode(result).toUpperCase();
        return result;
    }
}

2.2.4、MD5加密工具类

/**
 * MD5加密工具类
 */
public class MD5 {
	
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7","8", "9", "a", "b", "c", "d", "e", "f"};
 
    /**
     * 转换字节数组为16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }
 
    /**
     * 转换byte到16进制
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }
 
    /**
     * MD5编码
     */
    public static String MD5Encode(String origin) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }
}

2.3、业务接口 

/**
 * 业务接口
 */
@Slf4j
public class WxPayInfo {
 
    @Resource
    private WxPayConfig payProperties;
 
    private static final DecimalFormat df = new DecimalFormat("#");
 
    /**
     * 插入订单记录
     */
    @Transactional
    public Map insertPayRecord(PayParameterVO payParameterVO) {
            //接收返回的参数
            Map<String, Object> map = new HashMap<>();
            String title = "koko测试点数";
            //金额 * 100 以分为单位
            BigDecimal fee = BigDecimal.valueOf(1);
            BigDecimal RMB = new BigDecimal(100);
            BigDecimal totalFee = fee.multiply(RMB);
            try {
                WeChatPay weChatPay = new WeChatPay();
                weChatPay.setAppid(payProperties.getAppId());
                weChatPay.setMch_id(payProperties.getMchId());
                weChatPay.setNonce_str(getRandomStringByLength(32));
                weChatPay.setBody(title);
                weChatPay.setOut_trade_no(getRandomStringByLength(32));
                weChatPay.setTotal_fee( df.format(Double.parseDouble(String.valueOf(totalFee))));
                weChatPay.setSpbill_create_ip("127.0.0.1");
                weChatPay.setNotify_url(payProperties.getNotifyUrl());
                weChatPay.setTrade_type("JSAPI");
                //这里直接使用当前用户的openid
                weChatPay.setOpenid("oOKq*******xj8o");
                weChatPay.setSign_type("MD5");
                //生成签名
                String sign = SignUtils.getSign(weChatPay);
                weChatPay.setSign(sign);
                String result = HttpRequest.sendPost(WeChatPayUrlConstants.Uifiedorder, weChatPay);
                System.out.println(result);
                //将返回结果从xml格式转换为map格式
                Map<String, String> wxResultMap = WXPayUtil.xmlToMap(result);
                if (ObjectUtil.isNotEmpty(wxResultMap.get("return_code")) && wxResultMap.get("return_code").equals("SUCCESS")){
                    if (wxResultMap.get("result_code").equals("FAIL")){
                        map.put("msg", "统一下单失败");
                        map.put("status",500);
                        map.put("data", wxResultMap.get("err_code_des"));
                        return map;
                    }
                }
                XStream xStream = new XStream();
                xStream.alias("xml", OrderReturnInfo.class);
                OrderReturnInfo returnInfo = (OrderReturnInfo) xStream.fromXML(result);
                // 二次签名
                if ("SUCCESS".equals(returnInfo.getReturn_code()) && returnInfo.getReturn_code().equals(returnInfo.getResult_code())) {
                    SignInfo signInfo = new SignInfo();
                    signInfo.setAppId(payProperties.getAppId());
                    long time = System.currentTimeMillis() / 1000;
                    signInfo.setTimeStamp(String.valueOf(time));
                    signInfo.setNonceStr(WXPayUtil.generateNonceStr());
                    signInfo.setRepay_id("prepay_id=" + returnInfo.getPrepay_id());
                    signInfo.setSignType("MD5");
                    //生成签名
                    String sign1 = SignUtils.getSign(signInfo);
                    Map<String, String> payInfo = new HashMap<>();
                    payInfo.put("timeStamp", signInfo.getTimeStamp());
                    payInfo.put("nonceStr", signInfo.getNonceStr());
                    payInfo.put("package", signInfo.getRepay_id());
                    payInfo.put("signType", signInfo.getSignType());
                    payInfo.put("paySign", sign1);
                    map.put("status", 200);
                    map.put("msg", "统一下单成功!");
                    map.put("data", payInfo);
                    //预下单成功,处理业务逻辑
                    //****************************//
                    // 业务逻辑结束 回传给小程序端唤起支付
                    return map;
                }
                map.put("status", 500);
                map.put("msg", "统一下单失败!");
                map.put("data", null);
                return map;
            } catch (Exception e) {
                e.printStackTrace();
            }
        return null;
    }
 
    /**
     * 查询订单
     * @param out_trade_no 订单号
     * @return 返回结果
     */
    public Map orderQuery(String out_trade_no){
        Map<String, Object> map = new HashMap<>();
        try {
            WeChatPay weChatPay = new WeChatPay();
            weChatPay.setAppid(payProperties.getAppId());
            weChatPay.setMch_id(payProperties.getMchId());
            weChatPay.setNonce_str(WXPayUtil.generateNonceStr());
            weChatPay.setOut_trade_no(out_trade_no);
            //order.setSign_type("MD5");
            //生成签名
            String sign = SignUtils.getSign(weChatPay);
            weChatPay.setSign(sign);
            String result = HttpRequest.sendPost(WXPayConstants.ORDERQUERY_URL, weChatPay);
            System.out.println(result);
            XStream xStream = new XStream();
            xStream.alias("xml", QueryReturnInfo.class);
            QueryReturnInfo returnInfo = (QueryReturnInfo) xStream.fromXML(result);
            map.put("status", 500);
            map.put("msg", "统一下单失败!");
            map.put("data", returnInfo);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
	
    /**
     * 微信小程序支付成功回调
     */
    public String callBack(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("接口已被调用");
        ServletInputStream inputStream = request.getInputStream();
        String notifyXml = StreamUtils.inputStream2String(inputStream, "utf-8");
        System.out.println(notifyXml);
        // 解析返回结果
        Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml);
        // 判断支付是否成功
        if ("SUCCESS".equals(notifyMap.get("result_code"))) {
            //支付成功时候,处理业务逻辑
            System.out.println("支付成功");
            System.out.println("<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ");
            /**
             * 注意
             * 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了
             * return返回的结果一定是这种格式,当result_code返回的结果是SUCCESS时,则不进行调用了
             * 如果不返回下面的格式,业务逻辑会出现回调多次的情况,我就遇到过这种情况。
             */
            return "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        }
        // 创建响应对象:微信接收到校验失败的结果后,会反复的调用当前回调函数
        Map<String, String> returnMap = new HashMap<>();
        returnMap.put("return_code", "FAIL");
        returnMap.put("return_msg", "");
        String returnXml = WXPayUtil.mapToXml(returnMap);
        response.setContentType("text/xml");
        System.out.println("校验失败");
        return returnXml;
    }
	
   /**
     * 获取一定长度的随机字符串
     */
    public static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
}

三、项目使用 V3 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/288138.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kali Linux实现UEFI和传统BIOS(Legacy)引导启动

默认Kali linux安装会根据当前启动的引导模式进行安装 例:以UEFI引导启动安装程序,安装后仅能在UEFI引导模式下进入系统 安装Kali系统 这边基于VirtualBox虚拟机镜像实战操作 首先创建一个Kali虚拟机 这里需要注意,把启动 EFI (只针对某些操作系统)选项勾选上,内存、处理器…

I.MX6ULL_Linux_驱动篇(52)linux CAN驱动

CAN 是目前应用非常广泛的现场总线之一&#xff0c;主要应用于汽车电子和工业领域&#xff0c;尤其是汽车领域&#xff0c;汽车上大量的传感器与模块都是通过 CAN 总线连接起来的。 CAN 总线目前是自动化领域发展的热点技术之一&#xff0c;由于其高可靠性&#xff0c; CAN 总线…

酷雷曼精彩亮相CMC 2023中国元宇宙大会,助力云上VR直播

12月23日&#xff0c;2023中关村论坛系列活动——CMC 2023中国元宇宙大会在石景山首钢园冰壶馆成功举办。酷雷曼VR作为元宇宙领域代表企业之一受邀出席会议&#xff0c;分享元宇宙技术研发成果及应用方案&#xff0c;并为大会提供VR直播技术支持。 大咖云集&#xff0c;共商元宇…

数据库进阶教学——主从复制(Ubuntu22.04主+Win10从)

目录 一、概述 二、原理 三、搭建 1、备份数据 2、主库配置Ubuntu22.04 2.1、设置阿里云服务器安全组 2.2、修改配置文件 /etc/my.cnf 2.3、重启MySQL服务 2.4、登录mysql&#xff0c;创建远程连接的账号&#xff0c;并授予主从复制权限 2.5、通过指令&#xff0c;查…

进程终结之道:kill与pskill的神奇战斗

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 进程终结之道&#xff1a;kill与pskill的神奇战斗 前言基本用法kill命令&#xff1a;基础语法&#xff1a;选项&#xff1a;示例&#xff1a; pskill命令&#xff1a;基础语法&#xff1a;选项&#x…

kbdnecnt.DLL文件缺失,软件或游戏无法启动运行,怎样快速修复?

不少人都在问“kbdnecnt.DLL文件”是什么&#xff1f;为什么电脑总是报错提示说“kbdnecnt.DLL文件缺失&#xff0c;软件无法启动”&#xff1f; 首先&#xff0c;先来了解“kbdnecnt.DLL文件”是什么&#xff1f; kbdnecnt.DLL是Windows操作系统中的一个动态链接库文件&#…

JOSEF约瑟 断电延时继电器 SRTD-220VDC-2H2D 导轨安装

系列型号&#xff1a; SRTD-24VDC-1H1D断电延时继电器&#xff1b;SRTD-110VDC-1H1D断电延时继电器&#xff1b; SRTD-220VDC-1H1D断电延时继电器&#xff1b;SRTD-110VAC-1H1D断电延时继电器&#xff1b; SRTD-220VAC-1H1D断电延时继电器&#xff1b;SRTD-24VDC-2H断电延时继电…

考PMP真的有用吗?看完立马不犹豫了!

其实我个人觉得在你考证之前&#xff0c;值得反思的是&#xff1a;为什么要考这个证书&#xff1f;是因为公司需要&#xff1f;个人职业发展&#xff1f;还是受到新闻报道或广告的影响&#xff0c;觉得PMP证书有价值&#xff0c;只是想了解一下。这样就会导致很多人会说&#x…

golang并发编程-channel

在golang 并发编程里&#xff0c;经常会听到一句话&#xff1a;不要通过共享内存进行通信&#xff0c;通过通信来共享内存。下面我们会介绍下channel, 通过源码的方式去了解channel是怎么工作的。 基本结构 流程图 代码解读 type hchan struct {qcount uint // …

HubSpot邮件营销好用吗?

HubSpot的邮件营销工具通常被认为是非常强大和易用的&#xff0c;但用户的体验和满意度会因个人需求和经验而异。以下是一些通常与HubSpot邮件营销工具相关的优势&#xff1a; 全面的功能&#xff1a; HubSpot的邮件营销工具提供了丰富的功能&#xff0c;包括电子邮件自动化、…

西门子消防主机电源维修控制器BCB8005

火灾自动报警部分主要由各个部位的火灾探测器及手动报警按钮、消火栓按钮等设备组成。火灾探测器就如同火灾报警系统的“眼睛”,通过各自的火灾探测器采集现场的火警信号&#xff0c;实时传送给火灾报警控制器&#xff0c;火灾报警控制器进行各种智能的分析判断后发出火灾报警&…

【力扣题解】P700-二叉搜索树中的搜索-Java题解

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【力扣题解】 文章目录 【力扣题解】P700-二叉搜索树中的搜索-Java题解&#x1f30f;题目描述&#x1f4a1;题解&#x1f…

Python 从入门到精通之通俗易懂学闭包

系列 Python从入门到精通之安装与快速入门-CSDN博客 Python从入门到精通之基本数据类型和变量-CSDN博客 Python从入门到精通之集合&#xff08;List列表、Tuple元组、Dict字典、Set&#xff09;-CSDN博客 Python从入门到精通之条件语句、循环语句和函数-CSDN博客 Python从…

【双指针算法】-- 左右指针

左右指针 前言一、双指针算法二、左右指针1.用于在已排序数组中找到两个数使其和为特定值2.在字符串中判断是否为回文 总结 前言 今天在刷Leetcode的时候觉得自己双指针掌握的还是不错的记录一下,写个学习笔记,也方便以后翻阅,如果也帮助到你了,那真是太好啦! 本篇介绍的是左右…

八大算法排序@希尔排序(C语言版本)

目录 希尔排序概念算法思想示例分析结论算法步骤选择增量序列按增量分组逐步缩小增量 算法优势 代码实现核心算法希尔排序代码实现&#xff1a; 时间复杂度空间复杂度特性总结 该排序会关联到直接插入排序的知识点&#xff0c;如果对于直接插入排序还有所疑惑&#xff0c;可以跳…

Stable Diffusion模型概述

Stable Diffusion 1. Stable Diffusion能做什么&#xff1f;2. 扩散模型2.1 正向扩散2.2 反向扩散 3. 训练如何进行3.1 反向扩散3.2 Stable Diffusion模型3.3 潜在扩散模型3.4 变分自动编码器3.5 图像分辨率3.6 图像放大 4. 为什么潜在空间是可能的&#xff1f;4.1 在潜在空间中…

uniapp:签字版、绘画板 插件l-signature

官方网站&#xff1a;LimeUi - 多端uniapp组件库 使用步骤&#xff1a; 1、首先从插件市场将代码下载到项目 海报画板 - DCloud 插件市场 2、下载后&#xff0c;在项目中的uni_modules目录 3、最后 没有其它步骤&#xff0c;直接官网代码复制到vue文件中就可以了&#xff0c…

挑战 ChatGPT 和 Google Bard 的防御

到目前为止&#xff0c;科学家已经创建了基于人工智能的聊天机器人&#xff0c;可以帮助内容生成。我们还看到人工智能被用来创建像 WormGPT 这样的恶意软件&#xff0c;尽管地下社区对此并不满意。但现在正在创建聊天机器人&#xff0c;可以使用生成人工智能通过即时注入活动来…

stable diffusion 基础教程-文生图

置顶大模型插件资源链接 你如果没有魔法上网,请自取 百度云盘链接:链接:https://pan.baidu.com/s/1_xAu47XMdDNlA86ufXqAuQ?pwd=23wi 提取码:23wi 界面介绍 参数解释 参数解释Sampling method扩散去噪算法的采样模式,不同采样模式会带来不一样的效果steps模型生成图片的迭…

OpenCV-Python(24):模板匹配

原理及介绍 模板匹配是一种常用的图像处理技术&#xff0c;它用于在一幅图像中寻找与给定模板最匹配的区域(在一副大图中搜寻查找模版图像位置的方法)。模板匹配的基本思想是将模板图像在目标图像上滑动&#xff0c;并计算它们的相似度&#xff0c;找到相似度最高的位置即为匹配…