当前位置: 首页 > news >正文

亿级高并发电商项目-- 实战篇 --万达商城项目 十三(编写购物车、优化修改商品、下架商品方法、购物车模块监听修改商品、删除商品消息)

 

 

👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者
📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人 

 专栏:高并发项目 

编写购物车服务接口

用户购买商品的流程为: 搜索商品 > 查看商品详情 > 添加到购物车 > 生成商品订单 > 支 付 ,搜索商品和查看商品详情功能已经完成,接下来我们编写购物 车服务。购物车数据属于临时数据,为了节约数据库开销,我们会 将其存放到redis中。

在通用模块编写购物车服务接口:

// 购物车服务
public interface CartService {// 新增商品到购物车void addCart(Long userId, CartGoods cartGoods);// 修改购物车商品数量void handleCart(Long userId, Long goodId, Integer num);// 删除购物车商品void deleteCartOption(Long userId, Long goodId);// 获取用户购物车List<CartGoods> findCartList(Long userId);// 更新redis中的商品数据,在管理员更新商品后执行void refreshCartGoods(CartGoods cartGoods);// 删除redis中的商品数据,在管理员下架商品后执行void deleteCartGoods(CartGoods cartGoods);
}

创建购物车服务模块

1、创建名为 shopping_cart_service 的SpringBoot工程,添加相关依赖。

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>com.itbaizhan</groupId><artifactId>shopping_common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!-- dubbo --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.8</version></dependency><!-- 操作zookeeper --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.2.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
</dependencies>

 2、设置该工程的父工程为 shopping 。

<parent><groupId>com.ittxc</groupId><artifactId>shopping</artifactId><version>1.0-SNAPSHOT</version>
</parent>

3、给 shopping 工程设置子模块

<!-- 子模块 -->
<modules><!-- 购物车服务 --><module>shopping_cart_service</module>
</modules>

4、编写配置文件 application.yml

# 端口号
server:port: 9009
# 日志格式
logging:pattern:console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
spring:# redisredis:host: 192.168.0.159port: 6379timeout: 30000jedis:pool:max-active: 8max-wait: -1max-idle: 8min-idle: 0
dubbo:application:name: shopping_cart_service # 项目名registry:address: zookeeper://192.168.0.159 #注册中心地址port: 2181       # 注册中心的端口timeout: 10000 # 注册到zk上超时时间,msprotocol:name: dubbo # dubbo使用的协议port: -1 # dubbo自动分配端口scan:base-packages: com.itbaizhan.shopping_cart_service.service # 包扫描

5、启动类忽略数据源自动配置

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class ShoppingCartServiceApplication {public static void main(String[] args)
{SpringApplication.run(ShoppingCartServiceApplication.class, args);}
}

创建购物车Api模块

1、创建名为 shopping_cart_customer_api 的SpringBoot工程,添加相关依赖。

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- dubbo --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.8</version></dependency><!-- 操作zookeeper --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.2.0</version></dependency><dependency><groupId>com.itbaizhan</groupId><artifactId>shopping_common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-startertest</artifactId><scope>test</scope></dependency>
</dependencies>

 2、设置该工程的父工程为 shopping 。

<parent><groupId>com.ittxc</groupId><artifactId>shopping</artifactId><version>1.0-SNAPSHOT</version>
</parent>

3、给 shopping 工程设置子模块

<!-- 子模块 -->
<modules><!-- 购物车api --><module>shopping_cart_customer_api</module>
</modules>

4、编写配置文件 application.yml

# 端口号
server:port: 8005
# 日志格式
logging:pattern:console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
dubbo:application:name: shopping_cart_customer_api # 项目名registry:address: zookeeper://192.168.0.159 #注册中心地址port: 2181       # 注册中心的端口timeout: 10000 # 注册到zk上超时时间,msprotocol:name: dubbo # dubbo使用的协议port: -1 # dubbo自动分配端口

5、启动类忽略数据源自动配置

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class ShoppingUserCustomerApiApplication {public static void main(String[] args)
{SpringApplication.run(ShoppingUserCustomerApiApplication.class, args);}
}

编写查询用户购物车功能

我们将用户的购物车信息保存到redis当中,所有用户的购物车作为 一个hash类型的数据保存,hash的键是用户id,hash的值是购物车商品列表。

 在购物车服务模块创建购物车服务接口的实现类,重写查询用户购物车功能

@DubboService
public class CartServiceImpl implements CartService {@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic List<CartGoods> findCartList(Long userId) {Object cartList = redisTemplate.boundHashOps("cartList").get(userId);if (cartList == null) {return new ArrayList<CartGoods>();} else {return (List<CartGoods>)cartList;}}
}

 编写添加商品到购物车方法

@Override
public void addCart(Long userId, CartGoods cartGoods) {// 1.根据用户id获取用户购物车列表List<CartGoods> cartList = findCartList(userId);// 2.查询购物车是否有该商品,如果有商品,添加商品数量for (CartGoods cartGoods1 : cartList) {if(cartGoods.getGoodId().equals(cartGoods1.getGoodId())){int newNum = cartGoods1.getNum() + cartGoods.getNum();cartGoods1.setNum(newNum);redisTemplate.boundHashOps("cartList").put(userId,cartList);return;}}// 3.如果购物车没有该商品,将商品添加到购物车列表cartList.add(cartGoods);redisTemplate.boundHashOps("cartList").put(userId,cartList);
}

编写修改购物车商品数量方法

@Override
public void handleCart(Long userId, Long goodId, Integer num) {// 获取用户购物车列表List<CartGoods> cartList = findCartList(userId);// 遍历列表找到对应商品for (CartGoods cartGoods : cartList) {if(goodId.equals(cartGoods.getGoodId())) {// 改变商品数量cartGoods.setNum(num);break;}}// 将新的购物车列表保存到redis中redisTemplate.boundHashOps("cartList").put(userId, cartList);
}

编写删除购物车商品方法

@Override
public void deleteCartOption(Long userId,Long goodId) {// 获取用户购物车列表List<CartGoods> cartList = findCartList(userId);// 将商品移出列表for (CartGoods cartGoods : cartList) {if (goodId.equals(cartGoods.getGoodId())) {cartList.remove(cartGoods);break;}}// 将新的购物车列表保存到redis中redisTemplate.boundHashOps("cartList").put(userId, cartList);
}

编写购物车控制器

在进行购物车操作之前,要先获取用户的Id,而用户的令牌中只保存了用户名,所以我们要修改JWT工具类,让令牌中也保存用户的 Id:

1、修改JWT工具类

public class JWTUtil {//token过期时间,一天private static final Long EXPIRE_DATE = 1000*60*60*24L;// 秘钥private static final String SECRET = "xiaotong";// 签发者private static final String ISSUER = "XIAOTONG";/*** 签名生成* @param shoppingUser* @return*/public static String sign(ShoppingUser shoppingUser){String token = JWT.create().withIssuer(ISSUER) // 签发者.withIssuedAt(new Date())// 签发时间.withExpiresAt(new Date(new Date().getTime() + EXPIRE_DATE))// 过期时间.withSubject(shoppingUser.getUsername())// 保存用户名.withClaim("userId",shoppingUser.getId())// 保存用户id.sign(Algorithm.HMAC256(SECRET)); // 秘钥return token;}/*** 签名解析* @param token 签名字符串* @return 解析得出的用户名*/public static String verify(String token){try {String username = JWT.require(Algorithm.HMAC256(SECRET)).withIssuer(ISSUER).build().verify(token).getSubject();return username;} catch (Exception e){throw new BusException(CodeEnum.VERIFY_TOKEN_ERROR);}}/*** 签名解析,获取用户id* @param token 签名字符串* @return 用户id*/public static Long getId(String token){try {Long userId = JWT.require(Algorithm.HMAC256(SECRET)).withIssuer(ISSUER).build().verify(token).getClaim("userId").asLong();return userId;} catch (Exception e){throw new BusException(CodeEnum.VERIFY_TOKEN_ERROR);}}
}

2、在购物车Api模块编写购物车控制器

/**
* 购物车
*/
@RestController
@RequestMapping("/user/cart")
public class CartController {@DubboReferenceprivate CartService cartService;/*** 查询用户购物车* @param token 用户令牌* @return 用户购物车列表*/@GetMapping("/findCartList")public BaseResult<List<CartGoods>> findCartList(@RequestHeader String token){Long userId = JWTUtil.getId(token); // 获取用户idList<CartGoods> cartList = cartService.findCartList(userId);return BaseResult.ok(cartList);}/*** 新增商品到购物车* @param cartGoods 购物车商品* @param token 用户令牌* @return 操作结果*/@PostMapping("/addCart")public BaseResult addCart(@RequestBody CartGoods cartGoods,@RequestHeader String token){Long userId = JWTUtil.getId(token); // 获取用户idcartService.addCart(userId,cartGoods);return BaseResult.ok();}/*** 修改购物车商品数量* @param token 用户令牌* @param goodId 商品id* @param num 修改后的数量* @return 操作结果*/@GetMapping("/handleCart")public BaseResult addCart(@RequestHeader String token,Long goodId,Integer num){Long userId = JWTUtil.getId(token); // 获取用户idcartService.handleCart(userId,goodId,num);return BaseResult.ok();}/*** 删除购物车商品* @param token 用户令牌* @param goodId 商品id* @return 操作结果*/@DeleteMapping("/deleteCart")public BaseResult addCart(@RequestHeader String token,Long goodId){Long userId = JWTUtil.getId(token); // 获取用户idcartService.deleteCartOption(userId,goodId);return BaseResult.ok();}
}

编写修改所有用户购物车商品方法

当管理员修改了商品的价格等数据后,需要将数据同步到用户购物车中,所以我们要编写给所有用户的购物车中修改某件商品的方法。

@Override
public void refreshCartGoods(CartGoods
cartGoods) {// 获取所有用户购物车商品BoundHashOperations cartList = redisTemplate.boundHashOps("cartList");Map<Long,List<CartGoods>> allCartGoods = cartList.entries();Set<Map.Entry<Long, List<CartGoods>>> entries = allCartGoods.entrySet();// 遍历所有用户的购物车for (Map.Entry<Long, List<CartGoods>> entry : entries) {List<CartGoods> goodsList = entry.getValue();// 遍历一个用户购物车的所有商品for (CartGoods goods : goodsList) {// 如果该商品是被更新的商品,修改商品数据if(cartGoods.getGoodId().equals(goods.getGoodId())){goods.setGoodsName(cartGoods.getGoodsName());goods.setHeaderPic(cartGoods.getHeaderPic());goods.setPrice(cartGoods.getPrice());}}}// 将改变后所有用户购物车重新放入redisredisTemplate.delete("cartList");redisTemplate.boundHashOps("cartList").putAll(allCartGoods);
}

编写删除所有用户购物车商品方法

当管理员下架某件商品后,所有用户的购物车中该商品也应该被删除,所以我们要编写给所有用户的购物车中删除某件商品的方法。

@Override
public void deleteCartGoods(CartGoods cartGoods) {BoundHashOperations cartList = redisTemplate.boundHashOps("cartList");// 所有用户的购物车Map<String,List<CartGoods>> allCartGoods = cartList.entries();Set<Map.Entry<String, List<CartGoods>>> entries = allCartGoods.entrySet();// 遍历所有用户的购物车for (Map.Entry<String, List<CartGoods>> entry : entries) {List<CartGoods> goodsList = entry.getValue();// 遍历一个用户购物车的所有商品for (CartGoods goods : goodsList) {// 如果该商品是被删除的商品if (cartGoods.getGoodId().equals(goods.getGoodId())){goodsList.remove(goods);break;}}}// 将改变后的map重新放入redisredisTemplate.delete("cartList");redisTemplate.boundHashOps("cartList").putAll(allCartGoods);
}

 优化修改商品、下架商品方法

接下来我们修改商品服务模块代码,在修改商品后发送消息同步修 改购物车数据;在下架商品后发送消息同步删除购物车数据:

1、在MQ配置文件创建队列,绑定队列到交换机:

@Configuration
public class RabbitConfig {// 交换机private final String GOODS_EXCHANGE = "goods_exchange";// 同步商品数据队列private final String SYNC_GOODS_QUEUE = "sync_goods_queue";// 删除商品数据队列private final String DEL_GOODS_QUEUE = "del_goods_queue";// 向购物车同步商品队列private final String SYNC_CART_QUEUE = "sync_cart_queue";// 向购物车删除商品队列private final String DEL_CART_QUEUE = "del_cart_queue";// 创建交换机@Bean(GOODS_EXCHANGE)public Exchange getExchange() {return ExchangeBuilder.topicExchange(GOODS_EXCHANGE) // 交换机类型.durable(true) // 是否持久化.build();}// 创建队列@Bean(SYNC_GOODS_QUEUE)public Queue getQueue1() {return new Queue(SYNC_GOODS_QUEUE); // 队列名}@Bean(DEL_GOODS_QUEUE)public Queue getQueue2() {return new Queue(DEL_GOODS_QUEUE);// 队列名}@Bean(SYNC_CART_QUEUE)public Queue getQueue3() {return new Queue(SYNC_CART_QUEUE);// 队列名}@Bean(DEL_CART_QUEUE)public Queue getQueue4() {return new Queue(DEL_CART_QUEUE);
// 队列名}// 交换机绑定队列@Beanpublic Binding bindQueue1(@Qualifier(GOODS_EXCHANGE) Exchange exchange,@Qualifier(SYNC_GOODS_QUEUE) Queue queue){return BindingBuilder.bind(queue).to(exchange).with("#.sync_goods.#").noargs();}@Beanpublic Binding bindQueue2(@Qualifier(GOODS_EXCHANGE) Exchange exchange,@Qualifier(DEL_GOODS_QUEUE) Queue queue) {return BindingBuilder.bind(queue).to(exchange).with("#.del_goods.#").noargs();}@Beanpublic Binding
bindQueue3(@Qualifier(GOODS_EXCHANGE)
Exchange exchange,@Qualifier(SYNC_CART_QUEUE) Queue queue)
{return BindingBuilder.bind(queue).to(exchange).with("#.sync_cart.#").noargs();}@Beanpublic Binding bindQueue4(@Qualifier(GOODS_EXCHANGE) Exchange exchange,@Qualifier(DEL_CART_QUEUE) Queue queue) {return BindingBuilder.bind(queue).to(exchange).with("#.del_cart.#").noargs();}
}
@DubboService
public class GoodsServiceImpl implements
GoodsService {@Autowiredprivate GoodsMapper goodsMapper;@Autowiredprivate GoodsImageMapper goodsImageMapper;@Autowiredprivate RabbitTemplate rabbitTemplate;@Overridepublic void update(Goods goods) {// 删除旧图片数据Long goodsId = goods.getId(); //商品idQueryWrapper<GoodsImage> queryWrapper = new QueryWrapper();queryWrapper.eq("goodsId",goodsId);goodsImageMapper.delete(queryWrapper);// 删除旧规格项数据goodsMapper.deleteGoodsSpecificationOption(goodsId);// 插入商品数据goodsMapper.updateById(goods);// 插入图片数据List<GoodsImage> images = goods.getImages(); // 商品图片for (GoodsImage image : images) {image.setGoodsId(goodsId); // 给图片设置商品idgoodsImageMapper.insert(image); // 插入图片}// 插入商品_规格项数据List<Specification> specifications = goods.getSpecifications(); // 获取规格List<SpecificationOption> options = new ArrayList(); // 规格项集合// 遍历规格,获取规格中的所有规格项for (Specification specification : specifications) {options.addAll(specification.getSpecificationOptions());}// 遍历规格项,插入商品_规格项数据for (SpecificationOption option : options) {goodsMapper.addGoodsSpecificationOption(goodsId,option.getId());}rabbitTemplate.convertAndSend("goods_exchange","sync_goods",findById(goodsId));// 将商品修改数据同步到用户购物车CartGoods cartGoods = new CartGoods();cartGoods.setGoodId(goods.getId());cartGoods.setGoodsName(goods.getGoodsName());cartGoods.setHeaderPic(goods.getHeaderPic());cartGoods.setPrice(goods.getPrice());rabbitTemplate.convertAndSend("goods_exchange","sync_cart",cartGoods);}@Overridepublic void putAway(Long id, Boolean isMarketable) {goodsMapper.putAway(id,isMarketable);if (isMarketable){// 上架时同步到ESrabbitTemplate.convertAndSend("goods_exchange","sync_goods",findById(id));}else{// 下架删除ES数据rabbitTemplate.convertAndSend("goods_exchange","del_goods",id);// 商品下架删除用户购物车CartGoods cartGoods = new CartGoods();cartGoods.setGoodId(id);rabbitTemplate.convertAndSend("goods_exchange","del_cart",cartGoods);}}
}

购物车模块监听修改商品、删除商品消息

1、在购物车服务模块添加RabbitMQ依赖

<!-- RabbitMQ -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2、添加RabbitMQ配置

spring:# redisredis:host: 192.168.0.159port: 6379timeout: 30000jedis:pool:max-active: 8max-wait: -1max-idle: 8min-idle: 0# rabbitmqrabbitmq:host: 192.168.0.159port: 5672username: guestpassword: guestvirtual-host: /

3、修改购物车服务接口实现类,监听队列 

@DubboService
@Service
public class CartServiceImpl implements CartService {@Autowiredprivate RedisTemplate redisTemplate;// 监听修改购物车商品队列@RabbitListener(queues = "sync_cart_queue")public void listenSyncQueue(CartGoods cartGoods){refreshCartGoods(cartGoods);}// 监听删除购物车商品队列@RabbitListener(queues = "del_cart_queue")public void listenDelQueue(CartGoods cartGoods){deleteCartGoods(cartGoods);}
}

4、测试管理员修改商品、下架商品,看用户购物车是否发生改变。

相关文章:

亿级高并发电商项目-- 实战篇 --万达商城项目 十三(编写购物车、优化修改商品、下架商品方法、购物车模块监听修改商品、删除商品消息)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是小童&#xff0c;Java开发工程师&#xff0c;CSDN博客博主&#xff0c;Java领域新星创作者 &#x1f4d5;系列专栏&#xff1a;前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶 &#x1f4…...

springboot 虚拟线程demo

jd19支持虚拟线程&#xff0c;虚拟线程是轻量级的线程&#xff0c;它们不与操作系统线程绑定&#xff0c;而是由 JVM 来管理。它们适用于“每个请求一个线程”的编程风格&#xff0c;同时没有操作系统线程的限制。我们能够创建数以百万计的虚拟线程而不会影响吞吐。 做个 spri…...

CTFer成长之路之逻辑漏洞

逻辑漏洞CTF 访问url: http://1b43ac78-61f7-4b3c-9ab7-d7e131e7da80.node3.buuoj.cn/ 登录页面用随意用户名密码登录 访问url&#xff1a; http://1b43ac78-61f7-4b3c-9ab7-d7e131e7da80.node3.buuoj.cn/user.php 登陆后有商品列表&#xff0c;共三个商品,点击购买flag 钱…...

入门力扣自学笔记238 C++ (题目编号:1144)

1144. 递减元素使数组呈锯齿状 题目&#xff1a; 给你一个整数数组 nums&#xff0c;每次 操作 会从中选择一个元素并 将该元素的值减少 1。 如果符合下列情况之一&#xff0c;则数组 A 就是 锯齿数组&#xff1a; 每个偶数索引对应的元素都大于相邻的元素&#xff0c;即 A…...

蓝桥杯-寒假作业

没有白走的路&#xff0c;每一步都算数&#x1f388;&#x1f388;&#x1f388; 题目描述&#xff1a; 有四个等式&#xff0c;每个等式的运算规则已经定好了&#xff0c;也就是我们常见的小学的四则运算&#xff0c;但是能够用来四则运算的数字非常有限&#xff0c;包括1~13…...

测试用例篇

1.测试用例的意义 测试用例&#xff08;Test Case&#xff09;是为了实施测试而向被测试的系统提供的一组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素。 测试用例的意义是为了帮助测试人员了解测什么&#xff0c;怎么测 eg&#x…...

自动驾驶自主避障概况

文章目录前言1. 自主避障在自动驾驶系统架构中的位置2. 自主避障算法分类2.1 人工势场法&#xff08;APF&#xff09;2.1.1引力势场的构建2.1.2斥力势场的构建2.1.3人工势场法的改进2.2 TEB&#xff08;Timed-Eastic-Band, 定时弹性带&#xff09;2.3 栅格法2.4 向量场直方图(V…...

Python实用的库排名…

Python 是一个功能强大的编程语言&#xff0c;有着丰富的第三方库和模块&#xff0c;可以帮助你解决各种各样的问题。以下是一些比较厉害的 Python 库&#xff1a; NumPy&#xff1a;一个强大的数值计算库&#xff0c;提供了高效的数组和矩阵操作功能。 Pandas&#xff1a;提供…...

【YOLO系列】YOLOv4论文超详细解读1(翻译 +学习笔记)

前言 经过上一期的开篇介绍&#xff0c;我们知道YOLO之父Redmon在twitter正式宣布退出cv界&#xff0c;大家都以为YOLO系列就此终结的时候&#xff0c;天空一声巨响&#xff0c;YOLOv4闪亮登场&#xff01;v4作者是AlexeyAB大神&#xff0c;虽然换人了&#xff0c;但论文中给出…...

【神经网络】Transformer基础问答

1.Transforme与LSTM的区别 transformer和LSTM最大的区别就是LSTM的训练是迭代的&#xff0c;无法并行训练&#xff0c;LSTM单元计算完T时刻信息后&#xff0c;才会处理T1时刻的信息&#xff0c;T 1时刻的计算依赖 T-时刻的隐层计算结果。而transformer的训练是并行了&#xff0…...

制定防火墙策略的步骤和建议

制定防火墙策略是保护企业网络环境安全的关键一步。下面是一些制定防火墙策略的步骤和建议&#xff0c;供参考&#xff1a; 识别网络资产&#xff1a;确定企业网络环境中所有的网络资产&#xff0c;包括服务器、应用程序、数据库、移动设备和终端用户设备等&#xff0c;并进行…...

新必应(New Bing)国内申请与使用教程

微软的新必应&#xff08;New Bing&#xff09;基于GPT4模型&#xff0c;比ChatGPT的GPT3.5模型领先半个世代。并且集成了Edge浏览器的数据资源&#xff0c;功能更加强大。经过不断的踩坑&#xff0c;终于申请到了New Bing的使用权限&#xff0c;且国内网络也能够正常使用&…...

博客系统——项目测试报告

目录 前言 博客系统——项目介绍 1、测试计划 1.1、功能测试 1.1.1、编写测试用例 1.1.2、实际执行步骤 1.2、使用Selenium进行Web自动化测试 1.2.1、引入依赖 1.2.2、提取共性&#xff0c;实现代码复用 1.2.3、创建测试套件类 1.2.4、博客登录页自动化测试 1.2.5、…...

Macbook M1 安装PDI(Kettle) 9.3

Macbook M1 安装PDI(Kettle) 9.3 当前 PDI&#xff08;Kettle&#xff09;最新版为9.3&#xff0c;依赖Java JDK 11。因为没有专门用于 M1的程序&#xff0c;需要下载并安装x86_64架构的JDK及依赖软件&#xff0c;并 “强制在Intel模式下运行shell” 的方式来实现 Kettle 的正…...

机器学习——模型评估

在学习得到的模型投放使用之前&#xff0c;通常需要对其进行性能评估。为此&#xff0c;需使用一个“测试集”(testing set&#xff09;来测试模型对新样本的泛化能力&#xff0c;然后以测试集上的“测试误差( tootino error)作为泛化误差的近似。我们假设测试集是从样本真实分…...

react react-redux学习记录

react react-redux学习记录1.原理2.怎么用呢2.1 容器组件2.2UI组件2.3 App.jsx3.简化3.1简写mapDispatch3.2 Provider组件的使用3.3整合UI组件和容器组件1.原理 UI组件:不能使用任何redux的api&#xff0c;只负责页面的呈现、交互等。 容器组件&#xff1a;负责和redux通信&…...

nodejs环境配置

啥是node.js 简单理解就是js运行环境 啥是npm 简单理解就是nodejs包管理工具&#xff0c;全称Node Package Manager 啥是cnpm npm的开源镜像&#xff0c;在国内使用cnpm替代npm可以起到加速的效果 https://npmmirror.com/ ①安装node.js https://nodejs.org/en/download/ 下载…...

数据治理之元数据管理Atlas

数据治理之元数据管理的利器——Atlas 一、数据治理与元数据管理 1.1 背景 为什么要做数据治理&#xff1f; 业务繁多&#xff0c;数据繁多&#xff0c;业务数据不断迭代。人员流动&#xff0c;文档不全&#xff0c;逻辑不清楚&#xff0c;对于数据很难直观理解&#xff0c;…...

15 Nacos客户端实例注册源码分析

Nacos客户端实例注册源码分析 实例客户端注册入口 流程图&#xff1a; 实际上我们在真实的生产环境中&#xff0c;我们要让某一个服务注册到Nacos中&#xff0c;我们首先要引入一个依赖&#xff1a; <dependency><groupId>com.alibaba.cloud</groupId>&l…...

C++将派生类赋值给基类(向上转型)

1.将派生类对象赋值给基类对象 #include <iostream> using namespace std;//基类 class A{ public:A(int a); public:void display(); public:int m_a; }; A::A(int a): m_a(a){ } void A::display(){cout<<"Class A: m_a"<<m_a<<endl; }//…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...