0201基础集成与使用-微信支付-支付模块-项目实战

文章目录

    • 一、前言
    • 二、springboot集成
      • 2.1 配置信息与配置类
      • 2.2 微信相关枚举信息
      • 2.3 工具类
      • 2.4 业务接口
    • 三、演示-支付与退款
    • 结语

一、前言

下面我以微信支付v3为例,通过spirngboot集成到我们的项目中,不依赖其他第三方框架。当然适用简单项目,后续需要更多的改进。项目为简单的一个在线课程项目,通过在线购买视频课程,生成和支付订单,完成在线内容的学习。

二、springboot集成

2.1 配置信息与配置类

  • 配置文件
# 微信支付相关参数
# 商户号
wxpay.mch-id=xxxx
# 商户API证书序列号
wxpay.mch-serial-no=xxxx

# 商户私钥文件
wxpay.private-key-path=xxxx
# APIv3密钥
wxpay.api-v3-key=XXXX
# APPID
wxpay.appid=
# 微信服务器地址
wxpay.domain=https://api.mch.weixin.qq.com
# 接收结果通知地址
# 注意:每次重新启动ngrok,都需要根据实际情况修改这个配置
wxpay.notify-domain=XXXX

# APIv2密钥
wxpay.partnerKey: XXX
  • 相应的参数值,根据官方文档自己去申请,如果只是学习研究,可以通过下面链接1获取。

  • wxpay.notify-domain:微信回调通知地址,如果有在公网部署用公网地址,没有的话通过内网地址穿透工具,这里推荐开源免费的ngrok工具。

  • 配置类

    package com.gaogzhen.paymentdemo.config;
    
    import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
    import com.wechat.pay.contrib.apache.httpclient.auth.*;
    import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
    import lombok.Data;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.nio.charset.StandardCharsets;
    import java.security.PrivateKey;
    
    
    @Configuration
    @PropertySource("classpath:wxpay.properties") //读取配置文件
    @ConfigurationProperties(prefix="wxpay") //读取wxpay节点
    @Data //使用set方法将wxpay节点中的值填充到当前类的属性中
    @Slf4j
    public class WxPayConfig {
    
        // 商户号
        private String mchId;
    
        // 商户API证书序列号
        private String mchSerialNo;
    
        // 商户私钥文件
        private String privateKeyPath;
    
        // APIv3密钥
        private String apiV3Key;
    
        // APPID
        private String appid;
    
        // 微信服务器地址
        private String domain;
    
        // 接收结果通知地址
        private String notifyDomain;
    
        // APIv2密钥
        private String partnerKey;
    
        /**
         * 获取商户的私钥文件
         * @param filename
         * @return
         */
        private PrivateKey getPrivateKey(String filename){
    
            try {
                return PemUtil.loadPrivateKey(new FileInputStream(filename));
            } catch (FileNotFoundException e) {
                throw new RuntimeException("私钥文件不存在", e);
            }
        }
    
        /**
         * 获取签名验证器
         * @return
         */
        @Bean
        public ScheduledUpdateCertificatesVerifier getVerifier(){
    
            log.info("获取签名验证器");
    
            //获取商户私钥
            PrivateKey privateKey = getPrivateKey(privateKeyPath);
    
            //私钥签名对象
            PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, privateKey);
    
            //身份认证对象
            WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);
    
            // 使用定时更新的签名验证器,不需要传入证书
            ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
                    wechatPay2Credentials,
                    apiV3Key.getBytes(StandardCharsets.UTF_8));
    
            return verifier;
        }
    
    
        /**
         * 获取http请求对象
         * @param verifier
         * @return
         */
        @Bean(name = "wxPayClient")
        public CloseableHttpClient getWxPayClient(ScheduledUpdateCertificatesVerifier verifier){
    
            log.info("获取httpClient");
    
            //获取商户私钥
            PrivateKey privateKey = getPrivateKey(privateKeyPath);
    
            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(mchId, mchSerialNo, privateKey)
                    .withValidator(new WechatPay2Validator(verifier));
            // ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
    
            // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
            CloseableHttpClient httpClient = builder.build();
    
            return httpClient;
        }
    
        /**
         * 获取HttpClient,无需进行应答签名验证,跳过验签的流程
         */
        @Bean(name = "wxPayNoSignClient")
        public CloseableHttpClient getWxPayNoSignClient(){
    
            //获取商户私钥
            PrivateKey privateKey = getPrivateKey(privateKeyPath);
    
            //用于构造HttpClient
            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    //设置商户信息
                    .withMerchant(mchId, mchSerialNo, privateKey)
                    //无需进行签名验证、通过withValidator((response) -> true)实现
                    .withValidator((response) -> true);
    
            // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
            CloseableHttpClient httpClient = builder.build();
    
            log.info("== getWxPayNoSignClient END ==");
    
            return httpClient;
        }
    
    }
    
    
    • 使用定时更新的签名验证器,不需要传入证书:这里我们需要验证传回来的信息是微信返回的那么使用的是微信平台证书;相应的微信那边需要验证它接受的信息是我们商户这边发送过去的,需要用到商户平台证书。

2.2 微信相关枚举信息

  • 微信API接口枚举WxApiType

    package com.gaogzhen.paymentdemo.enums.wxpay;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    
    @AllArgsConstructor
    @Getter
    public enum WxApiType {
    
    	/**
    	 * Native下单
    	 */
    	NATIVE_PAY("/v3/pay/transactions/native"),
    
    	/**
    	 * Native下单
    	 */
    	NATIVE_PAY_V2("/pay/unifiedorder"),
    
    	/**
    	 * 查询订单
    	 */
    	ORDER_QUERY_BY_NO("/v3/pay/transactions/out-trade-no/%s"),
    
    	/**
    	 * 关闭订单
    	 */
    	CLOSE_ORDER_BY_NO("/v3/pay/transactions/out-trade-no/%s/close"),
    
    	/**
    	 * 申请退款
    	 */
    	DOMESTIC_REFUNDS("/v3/refund/domestic/refunds"),
    
    	/**
    	 * 查询单笔退款
    	 */
    	DOMESTIC_REFUNDS_QUERY("/v3/refund/domestic/refunds/%s"),
    
    	/**
    	 * 申请交易账单
    	 */
    	TRADE_BILLS("/v3/bill/tradebill"),
    
    	/**
    	 * 申请资金账单
    	 */
    	FUND_FLOW_BILLS("/v3/bill/fundflowbill");
    
    
    	/**
    	 * 类型
    	 */
    	private final String type;
    }
    
    
  • 支付状态

    package com.gaogzhen.paymentdemo.enums.wxpay;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    
    @AllArgsConstructor
    @Getter
    public enum WxApiType {
    
    	/**
    	 * Native下单
    	 */
    	NATIVE_PAY("/v3/pay/transactions/native"),
    
    	/**
    	 * Native下单
    	 */
    	NATIVE_PAY_V2("/pay/unifiedorder"),
    
    	/**
    	 * 查询订单
    	 */
    	ORDER_QUERY_BY_NO("/v3/pay/transactions/out-trade-no/%s"),
    
    	/**
    	 * 关闭订单
    	 */
    	CLOSE_ORDER_BY_NO("/v3/pay/transactions/out-trade-no/%s/close"),
    
    	/**
    	 * 申请退款
    	 */
    	DOMESTIC_REFUNDS("/v3/refund/domestic/refunds"),
    
    	/**
    	 * 查询单笔退款
    	 */
    	DOMESTIC_REFUNDS_QUERY("/v3/refund/domestic/refunds/%s"),
    
    	/**
    	 * 申请交易账单
    	 */
    	TRADE_BILLS("/v3/bill/tradebill"),
    
    	/**
    	 * 申请资金账单
    	 */
    	FUND_FLOW_BILLS("/v3/bill/fundflowbill");
    
    
    	/**
    	 * 类型
    	 */
    	private final String type;
    }
    
    
  • 退款状态

    package com.gaogzhen.paymentdemo.enums.wxpay;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    
    @AllArgsConstructor
    @Getter
    public enum WxRefundStatus {
    
        /**
         * 退款成功
         */
        SUCCESS("SUCCESS"),
    
        /**
         * 退款关闭
         */
        CLOSED("CLOSED"),
    
        /**
         * 退款处理中
         */
        PROCESSING("PROCESSING"),
    
        /**
         * 退款异常
         */
        ABNORMAL("ABNORMAL");
    
        /**
         * 类型
         */
        private final String type;
    }
    
    

2.3 工具类

  • 接口协议为http,通过HttpClientUtils工具类执行接口请求,或者可以使用其他的http工具类比如基础封装HttpClient,OkHttp或者hutool封装的http工具类,或者Forest框架等等是,这里我们就简单封装下,代码如下:

    package com.gaogzhen.paymentdemo.util;
    
    import org.apache.http.Consts;
    import org.apache.http.HttpEntity;
    import org.apache.http.NameValuePair;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.*;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLContextBuilder;
    import org.apache.http.conn.ssl.TrustStrategy;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.util.EntityUtils;
    
    import javax.net.ssl.SSLContext;
    import java.io.IOException;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.text.ParseException;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    
    /**
     * http请求客户端
     */
    public class HttpClientUtils {
    	private String url;
    	private Map<String, String> param;
    	private int statusCode;
    	private String content;
    	private String xmlParam;
    	private boolean isHttps;
    
    	public boolean isHttps() {
    		return isHttps;
    	}
    
    	public void setHttps(boolean isHttps) {
    		this.isHttps = isHttps;
    	}
    
    	public String getXmlParam() {
    		return xmlParam;
    	}
    
    	public void setXmlParam(String xmlParam) {
    		this.xmlParam = xmlParam;
    	}
    
    	public HttpClientUtils(String url, Map<String, String> param) {
    		this.url = url;
    		this.param = param;
    	}
    
    	public HttpClientUtils(String url) {
    		this.url = url;
    	}
    
    	public void setParameter(Map<String, String> map) {
    		param = map;
    	}
    
    	public void addParameter(String key, String value) {
    		if (param == null)
    			param = new HashMap<String, String>();
    		param.put(key, value);
    	}
    
    	public void post() throws ClientProtocolException, IOException {
    		HttpPost http = new HttpPost(url);
    		setEntity(http);
    		execute(http);
    	}
    
    	public void put() throws ClientProtocolException, IOException {
    		HttpPut http = new HttpPut(url);
    		setEntity(http);
    		execute(http);
    	}
    
    	public void get() throws ClientProtocolException, IOException {
    		if (param != null) {
    			StringBuilder url = new StringBuilder(this.url);
    			boolean isFirst = true;
    			for (String key : param.keySet()) {
    				if (isFirst) {
    					url.append("?");
    					isFirst = false;
    				}else {
    					url.append("&");
    				}
    				url.append(key).append("=").append(param.get(key));
    			}
    			this.url = url.toString();
    		}
    		HttpGet http = new HttpGet(url);
    		execute(http);
    	}
    
    	/**
    	 * set http post,put param
    	 */
    	private void setEntity(HttpEntityEnclosingRequestBase http) {
    		if (param != null) {
    			List<NameValuePair> nvps = new LinkedList<NameValuePair>();
    			for (String key : param.keySet())
    				nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
    			http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
    		}
    		if (xmlParam != null) {
    			http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
    		}
    	}
    
    	private void execute(HttpUriRequest http) throws ClientProtocolException,
    			IOException {
    		CloseableHttpClient httpClient = null;
    		try {
    			if (isHttps) {
    				SSLContext sslContext = new SSLContextBuilder()
    						.loadTrustMaterial(null, new TrustStrategy() {
    							// 信任所有
    							public boolean isTrusted(X509Certificate[] chain,
    									String authType)
    									throws CertificateException {
    								return true;
    							}
    						}).build();
    				SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
    						sslContext);
    				httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
    						.build();
    			} else {
    				httpClient = HttpClients.createDefault();
    			}
    			CloseableHttpResponse response = httpClient.execute(http);
    			try {
    				if (response != null) {
    					if (response.getStatusLine() != null)
    						statusCode = response.getStatusLine().getStatusCode();
    					HttpEntity entity = response.getEntity();
    					// 响应内容
    					content = EntityUtils.toString(entity, Consts.UTF_8);
    				}
    			} finally {
    				response.close();
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			httpClient.close();
    		}
    	}
    
    	public int getStatusCode() {
    		return statusCode;
    	}
    
    	public String getContent() throws ParseException, IOException {
    		return content;
    	}
    
    }
    
    

2.4 业务接口

也就是我们controller中对外暴露的接口,代码如下

package com.gaogzhen.paymentdemo.controller;

import com.gaogzhen.paymentdemo.service.WxPayService;
import com.gaogzhen.paymentdemo.util.HttpUtils;
import com.gaogzhen.paymentdemo.util.WechatPay2ValidatorForRequest;
import com.gaogzhen.paymentdemo.vo.R;
import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@CrossOrigin //跨域
@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "网站微信支付APIv3")
@Slf4j
public class WxPayController {

    @Resource
    private WxPayService wxPayService;

    @Resource
    private Verifier verifier;

    /**
     * Native下单
     * @param productId
     * @return
     * @throws Exception
     */
    @ApiOperation("调用统一下单API,生成支付二维码")
    @PostMapping("/native/{productId}")
    public R nativePay(@PathVariable Long productId) throws Exception {

        log.info("发起支付请求 v3");

        //返回支付二维码连接和订单号
        Map<String, Object> map = wxPayService.nativePay(productId);

        return R.ok().setData(map);
    }

    /**
     * 支付通知
     * 微信支付通过支付通知接口将用户支付成功消息通知给商户
     */
    @ApiOperation("支付通知")
    @PostMapping("/native/notify")
    public String nativeNotify(HttpServletRequest request, HttpServletResponse response){

        Gson gson = new Gson();
        Map<String, String> map = new HashMap<>();//应答对象

        try {

            //处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
            String requestId = (String)bodyMap.get("id");
            log.info("支付通知的id ===> {}", requestId);
            //log.info("支付通知的完整数据 ===> {}", body);
            //int a = 9 / 0;

            //签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
                    = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if(!wechatPay2ValidatorForRequest.validate(request)){

                log.error("通知验签失败");
                //失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return gson.toJson(map);
            }
            log.info("通知验签成功");

            //处理订单
            wxPayService.processOrder(bodyMap);

            //应答超时
            //模拟接收微信端的重复通知
            TimeUnit.SECONDS.sleep(5);

            //成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return gson.toJson(map);

        } catch (Exception e) {
            e.printStackTrace();
            //失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return gson.toJson(map);
        }

    }

    /**
     * 用户取消订单
     * @param orderNo
     * @return
     * @throws Exception
     */
    @ApiOperation("用户取消订单")
    @PostMapping("/cancel/{orderNo}")
    public R cancel(@PathVariable String orderNo) throws Exception {

        log.info("取消订单");

        wxPayService.cancelOrder(orderNo);
        return R.ok().setMessage("订单已取消");
    }

    /**
     * 查询订单
     * @param orderNo
     * @return
     * @throws Exception
     */
    @ApiOperation("查询订单:测试订单状态用")
    @GetMapping("/query/{orderNo}")
    public R queryOrder(@PathVariable String orderNo) throws Exception {

        log.info("查询订单");

        String result = wxPayService.queryOrder(orderNo);
        return R.ok().setMessage("查询成功").data("result", result);

    }


    @ApiOperation("申请退款")
    @PostMapping("/refunds/{orderNo}/{reason}")
    public R refunds(@PathVariable String orderNo, @PathVariable String reason) throws Exception {

        log.info("申请退款");
        wxPayService.refund(orderNo, reason);
        return R.ok();
    }

    /**
     * 查询退款
     * @param refundNo
     * @return
     * @throws Exception
     */
    @ApiOperation("查询退款:测试用")
    @GetMapping("/query-refund/{refundNo}")
    public R queryRefund(@PathVariable String refundNo) throws Exception {

        log.info("查询退款");

        String result = wxPayService.queryRefund(refundNo);
        return R.ok().setMessage("查询成功").data("result", result);
    }


    /**
     * 退款结果通知
     * 退款状态改变后,微信会把相关退款结果发送给商户。
     */
    @ApiOperation("退款结果通知")
    @PostMapping("/refunds/notify")
    public String refundsNotify(HttpServletRequest request, HttpServletResponse response){

        log.info("退款通知执行");
        Gson gson = new Gson();
        Map<String, String> map = new HashMap<>();//应答对象

        try {
            //处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
            String requestId = (String)bodyMap.get("id");
            log.info("支付通知的id ===> {}", requestId);

            //签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
                    = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if(!wechatPay2ValidatorForRequest.validate(request)){

                log.error("通知验签失败");
                //失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return gson.toJson(map);
            }
            log.info("通知验签成功");

            //处理退款单
            wxPayService.processRefund(bodyMap);

            //成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return gson.toJson(map);

        } catch (Exception e) {
            e.printStackTrace();
            //失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return gson.toJson(map);
        }
    }

    @ApiOperation("获取账单url:测试用")
    @GetMapping("/querybill/{billDate}/{type}")
    public R queryTradeBill(
            @PathVariable String billDate,
            @PathVariable String type) throws Exception {

        log.info("获取账单url");

        String downloadUrl = wxPayService.queryBill(billDate, type);
        return R.ok().setMessage("获取账单url成功").data("downloadUrl", downloadUrl);
    }

    @ApiOperation("下载账单")
    @GetMapping("/downloadbill/{billDate}/{type}")
    public R downloadBill(
            @PathVariable String billDate,
            @PathVariable String type) throws Exception {

        log.info("下载账单");
        String result = wxPayService.downloadBill(billDate, type);

        return R.ok().data("result", result);
    }

}

tips::

  • 这里我们只做简单集成,如果生成中使用,需要更完善的配置,比如跨域可以单独做更详细的配置,统一的错误处理,分布式并发一致性,性能优化等等。

三、演示-支付与退款

  1. 确认支付,获取二维码在这里插入图片描述

  2. 微信扫码,支付回调在这里插入图片描述

  3. 输入支付密码,完成支付,调用我们自己的后续处理逻辑在这里插入图片描述

退款流程我们不在详述,看下我们的微信支付记录:在这里插入图片描述

微信支付基础使用,演示完毕,完整前后端代码通过链接1 sgg的视频教程获取。后续我们会借助这个项目,通过集成一些开源的支付工具或者框架,比如jeepay,IJPay,roncoo-pay,spring-boot-pay 来集成支付功能。

在这里插入图片描述

结语

欢迎小伙伴一起学习交流,需要啥工具或者有啥问题随时联系我。

❓QQ:806797785

⭐️源代码地址:https://github.com/gaogzhen

[1]微信支付&支付宝支付视频[CP/OL]

[2]微信支付官方文档[CP/OL]

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

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

相关文章

软考--软件设计师(软件工程总结2)

目录 1.测试方法 2.软件项目管理 3.软件容错技术 4.软件复杂性度量 5.结构化分析方法&#xff08;一种面向数据流的开发方法&#xff09; 6.数据流图 1.测试方法 软件测试&#xff1a;静态测试&#xff08;被测程序采用人工检测&#xff0c;计算机辅助静态分析的手段&…

Unity开发之音效相关

目录 音频文件的导入 音频源相关 麦克风输入相关 获取麦克风设备信息 开始录制 获取音频数据用于存储或者传输 代码控制音频源 动态控制音效播放 示例 音频文件的导入 常用格式&#xff1a;wav,mp3,ogg,aiff Force To Mono(多声道转单声道)Normalize(强制为单声道&am…

C++入门 (2) >>引用>>内联函数>>auto关键字

1 引用 定义&#xff1a;给变量起别名。 方法&#xff1a;在类型后面加上&符号。 主要作用&#xff1a;代替函数传指针。 例&#xff1a; void test(int& a) //参数为int&类型 {a 10; }int main() {int m 3;int& z m; //给m起别名叫z&#xff0…

基于springboot+vue+Mysql的在线考试系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

MySQL8,体验不一样的安装方式!

MySQL官网中下载YUM源rpm安装包。 1、把上面的rpm文件下载下来放到服务器上 #或者在linux系统中通过wget命令下载 wget http://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm2、下载完成后使用yum命令本地安装yum源 yum localinstall mysql80-community-rel…

Linux云计算之Linux基础3——Linux基本认识操作

1、终端 终端(terminal)&#xff1a;人和系统交互的必要设备&#xff0c;人机交互最后一个界面&#xff08;包含独立的输入输出设备&#xff09; 物理终端(console)&#xff1a;直接接入本机器的键盘设备和显示器虚拟终端(tty)&#xff1a;通过软件方式虚拟实现的终端。它可以…

IP-guard WebServer 任意文件读取漏洞复现

0x01 产品简介 IP-guard是由溢信科技股份有限公司开发的一款终端安全管理软件,旨在帮助企业保护终端设备安全、数据安全、管理网络使用和简化IT系统管理。 0x02 漏洞概述 由于IP-guard WebServer /ipg/static/appr/lib/flexpaper/php/view.php接口处未对用户输入的数据进行严…

VMamba: Visual State Space Model

VMamba: Visual State Space Model VMamba&#xff1a;视觉状态空间模型 论文链接&#xff1a;http://arxiv.org/abs/2401.10166 代码链接&#xff1a;https://github.com/MzeroMiko/VMamba 1、摘要 借鉴了最近引入的状态空间模型SSM&#xff0c;提出了Visual State Space M…

如何保证Redis的缓存和数据库中的数据的一致性?

Redis的缓存如何和数据库中的数据保持一致性&#xff1f; 我们都知道&#xff0c;Redis是一个基于内存的键值存储系统&#xff0c;数据完全存放在内存中&#xff0c;这使得它的读写速度远超传统的硬盘存储数据库。对于高访问频率、低修改率的数据&#xff0c;通过将它们缓存在…

动态规划:线性dp

1.最长公共子序列(LCS) dp[i][j]含义&#xff1a;序列Ai(a1-ai)和Bj(b1-bj)的最长公共子序列长度 分析两种情况&#xff1a; &#xff08;1&#xff09;当ai bj时&#xff0c;已经求得Ai-1和Bj-1的最长公共子序列 dp[i][j] dp[i-1][j-1] 1 &#xff08;2&#xff09;当…

C++:比较运算符(18)

就是进行数据的比较&#xff0c;表达式正确的话就是真&#xff0c;错的话就是假&#xff0c;真假则由bool值来代替&#xff0c;非0即真 等于&#xff08;为赋值&#xff0c;为比较&#xff09;10 200!不等于10 ! 201>大于10 > 200<小于10 < 201>大于等于20 >…

windows安装Openssl

openssl官网:[ Downloads ] - /source/index.html Windows 安装方法 OpenSSL 官网没有提供 Windows 版本的安装包&#xff0c;可以选择其他开源平台提供的工具 Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 等待下载完成 捐不起 配置环境变量 ope…

【图论】【基环内向树】【广度优先】【深度优先】2127. 参加会议的最多员工数

作者推荐 视频算法专题 本文涉及知识点 图论 基环内向树 LeetCode2127. 参加会议的最多员工数 一个公司准备组织一场会议&#xff0c;邀请名单上有 n 位员工。公司准备了一张 圆形 的桌子&#xff0c;可以坐下 任意数目 的员工。 员工编号为 0 到 n - 1 。每位员工都有一位…

XML --java学习笔记

XML(全称EXtensible Markup Language&#xff0c;可扩展标记语言) 本质是一种数据的格式&#xff0c;可以用来存储复杂的数据结构&#xff0c;和数据关系 XML的特点 XML中的“<标签名>”称为一个标签或一个元素&#xff0c;一般是成对出现的XML中的标签名可以自己定义…

数字信号处理实验---FFT分析

一、题目&#xff1a; 二、实验要求&#xff1a; 1、绘制图形时&#xff0c;尽量选用已经提供的函数。 2、所有的图形&#xff0c;需要加上横坐标、纵坐标以及标题的说明。 3、将设计的程序保存为脚本文件&#xff0c;在实验报告中&#xff0c;需写出程序语句。 4、Matlab程…

【GlobalMapper精品教程】073:像素到点(Pixels-to-Points)从无人机图像轻松生成点云

文章目录 一、工具介绍二、生成点云三、生成正射四、生成3D模型五、注意事项一、工具介绍 Global Mapper v19引入的新的像素到点工具使用摄影测量原理,从重叠图像生成高密度点云、正射影像及三维模型。它使LiDAR模块成为已经功能很强大的的必备Global Mapper扩展功能。 打开…

安装geopandas很简单。。。

创建新环境 创建新环境并不是绝对必要的&#xff0c;但考虑到安装来自不同通道的其他地理空间包可能会导致依赖冲突 &#xff0c;安装新环境可能是很好的做法&#xff0c;在干净的环境中堆叠&#xff0c;重新开始。 以下命令创建一个名为geo_env的新环境&#xff0c; 将其配置…

CANoe之使用以及车载项目实操总结

以下是我通过8年的项目实操自我总结的一些经验和技术&#xff0c;作为一名奋斗在一线的研发人员&#xff0c;无时无刻不在做自我总结&#xff0c;所有的总结都是通过日报、周报、月报提炼出来的&#xff0c;实践是检验技术的唯一标准&#xff1b; 欢迎大家的交流和分享 思维导…

VSCODE使用VSIX安装扩展

VSCode安装扩展特别慢&#xff0c;使用命令行安装告别龟速&#xff1a; code --install-extension当然&#xff0c;我这个是在WSL 的linux上安装的&#xff0c;Windows一样的。 VSCode扩展商店网页链接&#xff1a;https://marketplace.visualstudio.com/vscode

时序预测 | Matlab实现SOM-BP自组织映射结合BP神经网络时间序列预测

时序预测 | Matlab实现SOM-BP自组织映射结合BP神经网络时间序列预测 目录 时序预测 | Matlab实现SOM-BP自组织映射结合BP神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现SOM-BP自组织映射结合BP神经网络时间序列预测&#xff08;完整源码…