支付宝和微信支付对接流程

支付宝简介

使用流程

支付宝开放平台 (alipay.com)

  • 1、登录支付宝开放平台-创建应用
    • 得到app_id
  • 2、绑定应用:在产品绑定中,绑定支付宝的相关功能
  • 3、配置应用:
    • 配置各种加密方式
  • 4、提交审核:
  • 5、把支付宝整个功能整合项目

沙箱:

  • 支付宝提前为我们创建好一个账号,用这个账号可以体验支付宝的所有功能;
  • 应用开发期间用沙箱账号,上线以后替换成线上账号即可。

产品介绍 - 支付宝文档中心 (alipay.com):电脑网站支付的所有文档

沙箱

下载密钥生成工具:密钥工具下载 - 支付宝文档中心 (alipay.com)

按照官方教程去生成自己的私钥。

支付宝整体应用流程

配置properties,方便配置支付宝appid,私钥密钥等

@Data
@ConfigurationProperties(prefix = "app.pay.alipay")
public class AlipayProperties {// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号private String app_id ;// 商户私钥,您的PKCS8格式RSA2私钥private String merchant_private_key;// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。private String alipay_public_key;// 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问private String notify_url ;// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问private String return_url;// 签名方式private String sign_type;// 字符编码格式private String charset;// 支付宝网关private String gatewayUrl;
}

在config类中放一个AlipayClient。避免每次调用都需要专门new一个。

@EnableConfigurationProperties(AlipayProperties.class)
@Configuration
public class AlipayConfig {@BeanAlipayClient alipayClient(AlipayProperties alipayProperties){return new DefaultAlipayClient( alipayProperties.getGatewayUrl(),alipayProperties.getApp_id(),alipayProperties.getMerchant_private_key(),"json",alipayProperties.getCharset(),alipayProperties.getAlipay_public_key(),alipayProperties.getSign_type());}}

在payService实现生成支付页的方法

    @Overridepublic String generatePayPage(Long orderId, Long userId) throws AlipayApiException {//创建一个AlipayClient//创建一个支付请求AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();alipayRequest.setReturnUrl(alipayProperties.getReturn_url());//同步回调 支付成功后浏览器跳转到的地址alipayRequest.setNotifyUrl(alipayProperties.getNotify_url());//通知回调 支付成功后通知的地址//准备待支付的订单数据//远程调用订单服务获取其基本信息 基于此数据生成订单页OrderInfo orderInfo = orderFeignClient.getOrderInfoById(orderId).getData();//商户订单号,商户网站订单系统中唯一订单号,必填String outTradeNo = orderInfo.getOutTradeNo();//付款金额,必填BigDecimal totalAmount =orderInfo.getTotalAmount();//订单名称,必填String orderName = "尚品汇-订单-"+outTradeNo;//商品描述,可空String tradeBody = orderInfo.getTradeBody();Map<String,Object> bizContent= new HashMap<>();bizContent.put("out_trade_no",outTradeNo);bizContent.put("total_amount",totalAmount);bizContent.put("subject",orderName);bizContent.put("body",tradeBody);bizContent.put("product_code","FAST_INSTANT_TRADE_PAY");alipayRequest.setBizContent(JSON.toJSONString(bizContent));//请求String page = alipayClient.pageExecute(alipayRequest).getBody();return page;}

需要一个方法去接受支付宝支付成功的回调。此处将其放入mq消息队列中。等待消费。修改订单状态

    /*** 支付成功后支付宝会给这里发送支付结果通知 异步* @param params* @return*/@PostMapping("/notify/success")public String paySuccessNotify(@RequestParam Map<String,String> params) throws AlipayApiException {log.info("收到支付宝支付消息通知:{}", JSON.toJSONString(params));//验证签名boolean signVerified = AlipaySignature.rsaCheckV1(params,alipayProperties.getAlipay_public_key(),alipayProperties.getCharset(),alipayProperties.getSign_type());//调用SDK验证签名if(signVerified){log.info("验签通过,准备修改订单状态");String trade_status = params.get("trade_status");if("TRADE_SUCCESS".equals(trade_status)){//修改订单状态 通过消息传递机制mqService.send(params, MqConst.ORDER_EVENT_EXCHANGE,MqConst.ORDER_PAYED_RK);}}//什么时候给支付宝返回successreturn "success";}

修改订单状态 如果用户在临关单前的极限时间支付后,为了避免用户订单被强制改为关单。我们需要设置较高的优先级。

    @Overridepublic void payedOrder(String outTradeNo, Long userId) {//关单消息和支付消息同时抵达的话,以支付为准,将其改为已支付//订单是未支付或是已关闭都可以改为已支付ProcessStatus payed = ProcessStatus.PAID;//修改订单状态为已支付boolean update = orderInfoService.lambdaUpdate().set(OrderInfo::getOrderStatus, payed.getOrderStatus().name()).set(OrderInfo::getProcessStatus, payed.name()).eq(OrderInfo::getUserId, userId).eq(OrderInfo::getOutTradeNo, outTradeNo).in(OrderInfo::getOrderStatus, OrderStatus.UNPAID.name(), OrderStatus.CLOSED.name()).in(OrderInfo::getProcessStatus, ProcessStatus.UNPAID.name(), ProcessStatus.CLOSED.name()).update();log.info("修改订单:{} 状态为已支付成功:{}",outTradeNo,update);}

修改状态后,将payment_info也存入数据

  /*** 监听所有成功单队列*/@RabbitListener(queues = MqConst.ORDER_PAYED_QUEUE)public void listen(Message message, Channel channel) throws IOException {long tag = message.getMessageProperties().getDeliveryTag();String json = new String(message.getBody());try {Map<String, String> content = JSON.parseObject(json, new TypeReference<Map<String, String>>() {});log.info("修改订单状态为已支付");//订单的唯一对外交易号String out_trade_no = content.get("out_trade_no");//知道用户idString[] split = out_trade_no.split("-");Long userId = Long.parseLong(split[split.length - 1]);//根据唯一对外交易号和用户id修改orderBizService.payedOrder(out_trade_no,userId);PaymentInfo info = preparePaymentInfo(json, content, out_trade_no, userId);paymentInfoService.save(info);channel.basicAck(tag,false);} catch (NumberFormatException | IOException e) {mqService.retry(channel,tag,json,5);}}private PaymentInfo preparePaymentInfo(String json, Map<String, String> content, String out_trade_no, Long userId) {//保存此次支付的回调信息到payment_info里PaymentInfo info = new PaymentInfo();//查询orderInfoOrderInfo orderInfo = orderInfoService.lambdaQuery().eq(OrderInfo::getOutTradeNo, out_trade_no).eq(OrderInfo::getUserId, userId).one();info.setOutTradeNo(out_trade_no);info.setUserId(userId);info.setOrderId(orderInfo.getId());info.setPaymentType(orderInfo.getPaymentWay());//支付宝给的流水号String trade_no = content.get("trade_no");info.setTradeNo(trade_no);String total_amount = content.get("total_amount");info.setTotalAmount(new BigDecimal(total_amount));info.setSubject(content.get("subject"));info.setPaymentStatus(content.get("trade_status"));info.setCreateTime(new Date());info.setCallbackTime(new Date());info.setCallbackContent(json);return info;}

微信支付

微信支付V2

准备环境

C扫B需求要求可以手机网页交互,微信JSAPI/NATIVE支付符合需求。

总结步骤:

  1. 微信支付商户平台申请支付商户,填写企业资质认证后,可以在用户信息中获取 商户号
  2. 以企业身份注册微信公众号 https://mp.weixin.qq.com/
  3. 登录公众号,点击左侧菜单 “微信支付” 开通微信支付,需要提供营业执照、身份证等信息。
  4. 缴纳认证费用,等待1-3工作日审核。
  5. 审核通过后在支付设置中获取 APPID
  6. 审核通过后需要在 微信支付商户平台 中绑定APPID
  7. 绑定成功后需要申请 支付相关API秘钥
快速入门

参考文档:https://pay.weixin.qq.com/wiki/doc/api/index.html

支付产品: https://pay.weixin.qq.com/static/product/product_index.shtml

退款:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_4

微信支付目前有两个大版本是公司使用的分别是V2 和 V3 版本,旧项目-V2 新项目-V3

V3新版本:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml

官方SDK与DEMO代码:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

开发流程:

在这里插入图片描述

注意:demo用的是微信V2版本,实际项目用的是微信V3版本

NATIVE代码实现:

(1)添加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>com.github.tedzhdz</groupId><artifactId>wxpay-sdk</artifactId><version>3.0.10</version>
</dependency>

(2)编写配置类

package com.itheima.pay.config;
import com.github.wxpay.sdk.IWXPayDomain;
import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayConstants;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class WXPayConfigCustom extends WXPayConfig {/*** 开发者ID(AppID)* @return*/@Overrideprotected String getAppID() {return "wx0ca99a203b1e9943";}/*** 商户号* @return*/@Overrideprotected String getMchID() {return "1561414331";}/*** appkey  API密钥* @return*/@Overrideprotected String getKey() {return "CZBK51236435wxpay435434323FFDuis";}// 退款:必须强制使用API证书@Overrideprotected InputStream getCertStream() {try {String path = ClassLoader.getSystemResource("").getPath();return new FileInputStream(new File(path+"apiclient_cert.p12"));} catch (FileNotFoundException e) {e.printStackTrace();}return null;}@Overrideprotected IWXPayDomain getWXPayDomain() {return new IWXPayDomain() {@Overridepublic void report(String s, long l, Exception e) {}@Overridepublic DomainInfo getDomain(WXPayConfig wxPayConfig) {return new DomainInfo(WXPayConstants.DOMAIN_API, true);}};}
}

注意:

  • 退款操作需要API证书,将资料中的证书(apiclient_cert.p12)放到resources路径下

(3)编写下单测试方法

package com.itheima.pay.controller;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.itheima.pay.config.WXPayConfigCustom;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/*** @Description:* @Version: V1.0*/
@Slf4j
@RestController
@RequestMapping("wxpay")
public class WxpayController {/*** 支付回调通知* @param request* @param response* @return*/@RequestMapping("notify")public String payNotify(HttpServletRequest request, HttpServletResponse response) {try {String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());Map<String, String> map = WXPayUtil.xmlToMap(xmlResult);// 加入自己处理订单的业务逻辑,需要判断订单是否已经支付过,否则可能会重复调用String orderId = map.get("out_trade_no");String tradeNo = map.get("transaction_id");String totalFee = map.get("total_fee");String returnCode = map.get("return_code");String resultCode = map.get("result_code");return WxPayNotifyResponse.success("处理成功!");} catch (Exception e) {log.error("微信回调结果异常,异常原因{}", e.getMessage());return WxPayNotifyResponse.fail(e.getMessage());}}/*** 下单操作* @param code* @return* @throws Exception*/@GetMapping("unifiedOrder/{code}")public String unifiedOrder(@PathVariable String code) throws Exception {WXPayConfigCustom config = new WXPayConfigCustom();WXPay wxpay = new WXPay(config);Map<String, String> data = new HashMap<String, String>();data.put("body", "餐掌柜-餐饮消费");
//        data.put("out_trade_no", "2138091910595900001012");data.put("out_trade_no", code);data.put("device_info", "");data.put("fee_type", "CNY");data.put("total_fee", "1");data.put("spbill_create_ip", "123.12.12.123");data.put("notify_url", "http://itheima.ngrok2.xiaomiqiu.cn/wxpay/notify");data.put("trade_type", "NATIVE");  // NATIVE 指定为扫码支付  JSAPI 网站支付
//        data.put("openid", "12");try {Map<String, String> resp = wxpay.unifiedOrder(data);System.out.println("支付结果:"+resp);return resp.get("code_url");} catch (Exception e) {e.printStackTrace();}return "OK";}/*** 退款* @param code 订单号* @param refund_no 退款号* @return* @throws Exception*/@GetMapping("refunds/{code}/{refund_no}")public Map<String, String> refunds(@PathVariable String code, @PathVariable String refund_no) throws Exception {WXPayConfigCustom config = new WXPayConfigCustom();WXPay wxpay = new WXPay(config);Map<String, String> data = new HashMap<String, String>();data.put("out_trade_no", code);data.put("out_refund_no", refund_no);data.put("notify_url", "http://484cd438.cpolar.io/wxpay/notify");data.put("refund_desc", "已经售罄");data.put("refund_fee", "1");data.put("total_fee", "1");data.put("refund_fee_type", "CNY");System.out.println("请求参数:" + data);Map<String, String> map = wxpay.refund(data);return map;}
}

微信支付V3

V3版本。文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/index.shtml

微信官方并没有提供类似支付宝的EasySDK,只提供了基于HttpClient封装的SDK包,在项目中我们对于此SDK做了二次封装。微信接口都是基于RESTful进行提供的。


/*** 微信支付远程调用对象*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WechatPayHttpClient {private String mchId; //商户号private String appId; //应用号private String privateKey; //私钥字符串private String mchSerialNo; //商户证书序列号private String apiV3Key; //V3密钥private String domain; //请求域名private String notifyUrl; //请求地址public static WechatPayHttpClient get(Long enterpriseId) {// 查询配置PayChannelService payChannelService = SpringUtil.getBean(PayChannelService.class);PayChannelEntity payChannel = payChannelService.findByEnterpriseId(enterpriseId, TradingConstant.TRADING_CHANNEL_WECHAT_PAY);if (ObjectUtil.isEmpty(payChannel)) {throw new SLException(TradingEnum.CONFIG_EMPTY);}//通过渠道对象转化成微信支付的client对象JSONObject otherConfig = JSONUtil.parseObj(payChannel.getOtherConfig());return WechatPayHttpClient.builder().appId(payChannel.getAppId()).domain(payChannel.getDomain()).privateKey(payChannel.getMerchantPrivateKey()).mchId(otherConfig.getStr("mchId")).mchSerialNo(otherConfig.getStr("mchSerialNo")).apiV3Key(otherConfig.getStr("apiV3Key")).notifyUrl(payChannel.getNotifyUrl()).build();}/**** 构建CloseableHttpClient远程请求对象* @return org.apache.http.impl.client.CloseableHttpClient*/public CloseableHttpClient createHttpClient() throws Exception {// 加载商户私钥(privateKey:私钥字符串)PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes(StandardCharsets.UTF_8)));// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, merchantPrivateKey);WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);// 向证书管理器增加需要自动更新平台证书的商户信息CertificatesManager certificatesManager = CertificatesManager.getInstance();certificatesManager.putMerchant(mchId, wechatPay2Credentials, apiV3Key.getBytes(StandardCharsets.UTF_8));// 初始化httpClientreturn com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator(new WechatPay2Validator(certificatesManager.getVerifier(mchId))).build();}/**** 支持post请求的远程调用** @param apiPath api地址* @param params 携带请求参数* @return 返回字符串*/public WeChatResponse doPost(String apiPath, Map<String, Object> params) throws Exception {String url = StrUtil.format("https://{}{}", this.domain, apiPath);HttpPost httpPost = new HttpPost(url);httpPost.addHeader("Accept", "application/json");httpPost.addHeader("Content-type", "application/json; charset=utf-8");String body = JSONUtil.toJsonStr(params);httpPost.setEntity(new StringEntity(body, CharsetUtil.UTF_8));CloseableHttpResponse response = this.createHttpClient().execute(httpPost);return new WeChatResponse(response);}/**** 支持get请求的远程调用* @param apiPath api地址* @param params 在路径中请求的参数* @return 返回字符串*/public WeChatResponse doGet(String apiPath, Map<String, Object> params) throws Exception {URI uri = UrlBuilder.create().setHost(this.domain).setScheme("https").setPath(UrlPath.of(apiPath, CharsetUtil.CHARSET_UTF_8)).setQuery(UrlQuery.of(params)).setCharset(CharsetUtil.CHARSET_UTF_8).toURI();return this.doGet(uri);}/**** 支持get请求的远程调用* @param apiPath api地址* @return 返回字符串*/public WeChatResponse doGet(String apiPath) throws Exception {URI uri = UrlBuilder.create().setHost(this.domain).setScheme("https").setPath(UrlPath.of(apiPath, CharsetUtil.CHARSET_UTF_8)).setCharset(CharsetUtil.CHARSET_UTF_8).toURI();return this.doGet(uri);}private WeChatResponse doGet(URI uri) throws Exception {HttpGet httpGet = new HttpGet(uri);httpGet.addHeader("Accept", "application/json");CloseableHttpResponse response = this.createHttpClient().execute(httpGet);return new WeChatResponse(response);}
}

代码说明:

  • 通过get(Long enterpriseId)方法查询商户对应的配置信息,最后封装到WechatPayHttpClient对象中。
  • 通过createHttpClient()方法封装了请求微信接口必要的参数,最后返回CloseableHttpClient对象。
  • 封装了doGet()、doPost()方便对微信接口进行调用。
        try {WeChatResponse response = client.doPost(apiPath, params);if(!response.isOk()){throw new SLException(TradingEnum.NATIVE_PAY_FAIL);}tradingEntity.setPlaceOrderCode(Convert.toStr(response.getStatus())); //返回的编码tradingEntity.setPlaceOrderMsg(JSONUtil.parseObj(response.getBody()).getStr("code_url")); //二维码需要展现的信息tradingEntity.setPlaceOrderJson(JSONUtil.toJsonStr(response));tradingEntity.setTradingState(TradingStateEnum.FKZ);} catch (Exception e) {throw new SLException(TradingEnum.NATIVE_PAY_FAIL);}

PS:接收回调地址的话需要用到内网穿透工具,如果没开内网穿透则无法接收到。推荐用cpolar或者natapp

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Web的航空航天数字博物馆推荐系统

介绍 项目背景&#xff1a; 航空航天数字博物馆推荐系统是一个基于Web开发的应用&#xff0c;旨在为用户提供一个全面的航空航天领域的数字博物馆体验。通过展品展示、分类筛选和个性化推荐等功能&#xff0c;用户可以更好地了解航空航天知识和文化&#xff0c;并丰富参观体验…

【计算机组成-算术逻辑单元】

课程链接&#xff1a;北京大学陆俊林老师的计算机组成原理课 1. 算术运算和逻辑运算 算数运算 逻辑运算 算数逻辑运算的需求 算数运算&#xff1a;两个32-bit数的加减法&#xff0c;结果为一个32-bit数&#xff1b;检查加减法的结果是否溢出逻辑运算&#xff1a;两个32-bit数…

【JavaScript】js实现滚动触底加载事件

一、html和css 可视区固定500px&#xff0c;设置overflow-y: auto 来实现滚动。 1.1、html <template><div class"scroll"refscrollscroll"onScroll"><div class"crad"v-for"i in 10":key"i"></div&…

【目标检测】YOLOv7算法实现(一):模型搭建

本系列文章记录本人硕士阶段YOLO系列目标检测算法自学及其代码实现的过程。其中算法具体实现借鉴于ultralytics YOLO源码Github&#xff0c;删减了源码中部分内容&#xff0c;满足个人科研需求。   本系列文章在YOLOv5算法实现的基础上&#xff0c;进一步完成YOLOv7算法的实现…

2020年认证杯SPSSPRO杯数学建模C题(第二阶段)抗击疫情,我们能做什么全过程文档及程序

2020年认证杯SPSSPRO杯数学建模 C题 抗击疫情&#xff0c;我们能做什么 原题再现&#xff1a; 2020 年 3 月 12 日&#xff0c;世界卫生组织&#xff08;WHO&#xff09;宣布&#xff0c;席卷全球的冠状病毒引发的病毒性肺炎&#xff08;COVID-19&#xff09;是一种大流行病。…

【Spring】SpringBoot 统一功能处理

文章目录 前言1. 拦截器1.1 什么是拦截器1.2 拦截器的使用1.2.1 自定义拦截器1.2.2 注册配置拦截器 1.3 拦截器详解1.3.1 拦截路径1.3.2 拦截器执行流程1.3.3 适配器模式 2. 统一数据返回格式3. 统一异常处理 前言 在日常使用 Spring 框架进行开发的时候&#xff0c;对于一些板…

《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)

目录 开头语内存飙升问题分析与案例问题背景&#xff1a;我华为云的一个服务器运行我的一个项目“csdn-automatic-triplet-0.0.1-SNAPSHOT.jar”&#xff0c;由于只是用来测试的服务器&#xff0c;只有2G&#xff0c;所以分配给堆的内存1024M查询内存使用&#xff08;top指令&a…

恒温器探针样品座

恒温器探针样品座是一种用采用可移动探针完成恒温器电缆和被测样品的电学连接&#xff0c;避免了每次样品电引线的焊接&#xff0c;探针可移动&#xff0c;5mm--20mm大小的样品均可适用&#xff0c;探针可以安装6个&#xff0c;标准配置探针数量为4个。 恒温器探针样品座由T型…

云渲染农场渲染和自己搭建农场渲染怎么选?哪个更划算?

&#xfeff;当我们面临繁重或紧急的渲染任务时&#xff0c;通常会选择云渲染的解决方案。可能很多人会问&#xff0c;我们是否能够自行建立一个小型的个人农场进行渲染呢&#xff1f;与云渲染农场相比&#xff0c;哪个更划算&#xff1f;更方便&#xff1f;接下来就带大家看看…

vue-echarts踩坑,本地开发可以渲染echarts图表,线上环境图表渲染不出来

main.js全局注册v-chart组件 import VueECharts from "vue-echarts"; Vue.component("v-chart", VueECharts);在页面中使用 如上图&#xff0c;我开始写的静态数据&#xff0c;在data中定义了chartOption1:{…配置项…}, 在接口数据返回之后&#xff0c;…

Nodejs基础3之fs模块的文件重命名和移动、文件的删除、文件夹操作、查看资源状态、fs路径

Nodejs基础二 fs模块文件重命名和移动文件的重命名文件的移动同步重命名和移动 文件的删除使用unlink进行删除unlink异步删除unlinkSync同步删除 使用rm进行删除rm异步删除rmSync同步删除 文件夹操作创建文件夹递归创建文件夹 读取文件夹删除文件夹rmdir删除文件夹删除递归文件…

电脑怎么把照片的kb缩小?三种方法帮你解决

电脑怎么把照片的kb缩小&#xff1f;我们在进行上传图片的时候&#xff0c;经常遇到图片太大&#xff0c;请压缩后再上传的情况&#xff0c;这就是我们开头所需要了解的压缩图片大小的方法&#xff0c;图片缩小kb可以通过三种处理方式来达到效果&#xff0c;我们可以直接图片压…

在线协作白板WBO本地部署启动并结合内网穿透实现远程协同办公

文章目录 推荐前言1. 部署WBO白板2. 本地访问WBO白板3. Linux 安装cpolar4. 配置WBO公网访问地址5. 公网远程访问WBO白板6. 固定WBO白板公网地址 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击…

【LeetCode: 208. 实现 Trie (前缀树)】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

一分钟带你了解--电商控价

电商行业发展至今带来了许多机遇&#xff0c;但同时也伴随着一些挑战。品牌电商在运营过程中&#xff0c;面临着诸如乱价、低价、窜货和假货等问题&#xff0c;这些问题不仅损害了品牌的形象和价值&#xff0c;也破坏了市场秩序&#xff0c;侵害了消费者的权益。 电商控价是解…

深度探讨 Golang 中并发发送 HTTP 请求的最佳技术

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在 Golang 领域&#xff0c;并发发送 HTTP 请求…

java常用API(2)

1&#xff1a;String 1.1 String(构造方法) 首先&#xff0c;我们先来学习String类&#xff0c;它涉及到两个案例&#xff1a;用户登录和聊天室。 先来看用户登录案例&#xff1a;需要输入用户名和密码&#xff0c;和已知的用户名和密码进行比较&#xff0c;涉及到比较的方法…

抖音小店如何选品?新手怎么选有潜力的产品?常用选品玩法分享

大家好&#xff0c;我是电商花花。 选品是我们店铺出单的关键&#xff0c;也是我们做电商行业的小伙伴非常关心的一个点。 我们想要选好商品&#xff0c;我们就要先搞清楚&#xff0c;什么样的产品才算是有潜力的产品&#xff0c;什么样的产品才能出单&#xff0c;什么样的产…

【HTML5】 canvas 绘制图形

文章目录 一、基本用法二、用法详见2.0、方法属性2.1、绘制线条2.2、绘制矩形2.3、绘制圆形2.4、绘制文本2.5、填充图像 一、基本用法 canvas 标签&#xff1a;可用于在网页上绘制图形&#xff08;使用 JavaScript 在网页上绘制图像&#xff09;画布是一个矩形区域&#xff0c…

MATLAB R2023b for Mac 中文

MATLAB R2023b 是 MathWorks 发布的最新版本的 MATLAB&#xff0c;适用于进行算法开发、数据可视化、数据分析以及数值计算等任务的工程师和科学家。它包含了一系列新增功能和改进&#xff0c;如改进了数据导入工具&#xff0c;增加了对数据帧和表格对象的支持&#xff0c;增强…