当前位置: 首页 > 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; }//…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...