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

news2024/11/17 15:53:37

 

 

👏作者简介:大家好,我是小童,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:
  # redis
 redis:
   host: 192.168.0.159
   port: 6379
   timeout: 30000
   jedis:
     pool:
       max-active: 8
       max-wait: -1
       max-idle: 8
       min-idle: 0
dubbo:
 application:
   name: shopping_cart_service # 项目名
 registry:
   address: zookeeper://192.168.0.159 #注册中心地址
   port: 2181       # 注册中心的端口
   timeout: 10000 # 注册到zk上超时时间,ms
 protocol:
   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上超时时间,ms
 protocol:
   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 {
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public 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 {
    @DubboReference
    private CartService cartService;
    /**
     * 查询用户购物车
     * @param token 用户令牌
     * @return 用户购物车列表
     */
    @GetMapping("/findCartList")
    public BaseResult<List<CartGoods>> findCartList(@RequestHeader String token){
        Long userId = JWTUtil.getId(token); // 获取用户id
        List<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); // 获取用户id
        cartService.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); // 获取用户id
        cartService.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); // 获取用户id
        cartService.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());
           }
       }
   }
    // 将改变后所有用户购物车重新放入redis
    redisTemplate.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重新放入redis
    redisTemplate.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);
// 队列名
   }
    // 交换机绑定队列
    @Bean
    public Binding bindQueue1(@Qualifier(GOODS_EXCHANGE) Exchange exchange,
                                  @Qualifier(SYNC_GOODS_QUEUE) Queue queue)
   {
        return BindingBuilder
               .bind(queue)
               .to(exchange)
               .with("#.sync_goods.#")
               .noargs();
   }
    @Bean
    public Binding bindQueue2(@Qualifier(GOODS_EXCHANGE) Exchange exchange,
                                  @Qualifier(DEL_GOODS_QUEUE) Queue queue) {
        return BindingBuilder
               .bind(queue)
               .to(exchange)
               .with("#.del_goods.#")
               .noargs();
   }
    @Bean
    public Binding
bindQueue3(@Qualifier(GOODS_EXCHANGE)
Exchange exchange,
                            
@Qualifier(SYNC_CART_QUEUE) Queue queue)
{
        return BindingBuilder
               .bind(queue)
               .to(exchange)
               .with("#.sync_cart.#")
               .noargs();
   }
    @Bean
    public 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 {
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private GoodsImageMapper goodsImageMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Override
    public void update(Goods goods) {
        // 删除旧图片数据
        Long goodsId = goods.getId(); //商品id
        QueryWrapper<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); // 给图片设置商品id
            goodsImageMapper.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);
   }
    @Override
    public void putAway(Long id, Boolean isMarketable) {
      goodsMapper.putAway(id,isMarketable);
        if (isMarketable){
            // 上架时同步到ES
          rabbitTemplate.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:
  # redis
 redis:
   host: 192.168.0.159
   port: 6379
   timeout: 30000
   jedis:
     pool:
       max-active: 8
       max-wait: -1
       max-idle: 8
       min-idle: 0
  # rabbitmq
 rabbitmq:
   host: 192.168.0.159
   port: 5672
   username: guest
   password: guest
   virtual-host: /

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

@DubboService
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private 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、测试管理员修改商品、下架商品,看用户购物车是否发生改变。

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

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

相关文章

SSL证书对虚拟主机的用处有哪些?

虚拟主机是指在同一台服务器上&#xff0c;通过不同的域名或IP地址为多个网站提供服务的一种网络主机。而SSL证书则是一种数字证书&#xff0c;它用于加密网站与用户之间的通信&#xff0c;确保数据传输的安全性和完整性。在虚拟主机上&#xff0c;SSL证书有以下几个用处&#…

SQL Server2008详细安装步骤(保姆式教程)

安装包下载 链接&#xff1a;https://pan.baidu.com/s/1Rjx4DHJBeCW2asC_4Kzo6Q?pwdchui 提取码&#xff1a;chui 安装过程 1.解压后使用管理员身份打开安装程序 2.选择全新安装或向现有安装添加新功能 3.确认 4.输入产品密钥&#xff08;上方网盘安装包里有&#xff0…

【路径规划】基于前向动态规划算法在地形上找到最佳路径(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【ArcGIS Pro二次开发】(10):属性表字段(field)的修改

在ArcGIS Pro中&#xff0c;经常会遇到用字段计算器对要素的属性表进行计算。下面以一个例子演示如何在ArcGIS Pro SDK二次开发中实现。 一、要实现的功能 如上图所示的要素图层&#xff0c;要实现如下功能&#xff1a; 当字段【市级行政区】的值为【泉州市】时&#xff0c;将…

用 .NET 启动你的 DJI Ryze Tello 无人机

大疆的 DJI Ryze Tello 是入门级的无人机&#xff0c;不仅在 STEM 教育中有非常广泛的应用&#xff0c;也可以作为编程入门的首选。通过 UDP 协议调用 DJI Ryze Tello SDK 可以让 DJI Ryze Tello 无人机执行起飞&#xff0c;降落&#xff0c;转向以及不同的花式动作。本文将会通…

Parasoft的自动化测试平台到底强在哪?

在如今产品迭代如此之快的大背景下&#xff0c;软件测试这项工作越来越被大家所重视&#xff0c;但是通常情况下大家都是选择在产品上线前再去做测试&#xff0c;这个时候就会面临很多麻烦和挑战。首先&#xff0c;产品已经开发好之后&#xff0c;体量比较大&#xff0c;要从哪…

BurpSuite配置抓取HTTPS数据包

简介 我们在渗透测试的过程中&#xff0c;经常会遇到HTTPS的网站&#xff0c;Burp默认是没有办法抓取HTTPS的包的&#xff0c;想要让Burp抓取Https的包也很好办&#xff0c;只需要浏览器安装相关的证书即可&#xff0c;接下来将配置过程做一个记录。 前置条件&#xff1a; 1.J…

HashMap原理(一):哈希函数的设计

哈希函数的作用与本质 HashMap用来存储存在映射关系的数据对{key, value},在内部通过构造复合数据结构来封装数据对&#xff0c;即 //伪代码&#xff0c;非源码 class Pair<K, V> {public K key;public V value; }假设用来存储数据对的哈希数表为table&#xff0c;数据…

TCP状态转换

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 TCP状态转换专栏&#xff1a;《Linux从小白到大神》《网络编程》 TCP状态转换示意图如下 针对上面的示…

项目结束先别着急庆祝,项目经理还有这些事要做

项目管理生命周期结束阶段的目的是确认项目可交付成果的完成&#xff0c;使项目发起人满意&#xff0c;并向所有参与者和利益相关者传达项目的最终处置和状态。 项目结束确保项目的所有参与者和利益相关者都清楚后续活动&#xff08;如新项目、服务过渡、SLA等&#xff09;&a…

【ChatGPT情商大考验】ChatGPT教我谈恋爱

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

graph在细粒度分类中的应用

目录基于Graph-Propagation的相关性学习AAAI2020基于graph的高阶关系发现CVPR2021基于Graph-Propagation的相关性学习AAAI2020 来源&#xff1a;Graph-Propagation Based Correlation Learning for Weakly Supervised Fine-Grained Image Classification&#xff08;这或许是第…

MATLAB R2022b 安装教程

MATLAB R2022b 安装教程MathWorks 于2022年9月发布了 MATLAB 和 Simulink 产品系列的最新版本 Matlab R2022b版本 &#xff0c;加入两个新产品&#xff1a; Medical Imaging Toolbox — 可视化、配准、分割和标注二维及三维医学图像Simscape Battery — 设计和仿真电池和储能系…

HiveSql一天一个小技巧:如何巧用分布函数percent_rank()求去掉最大最小值的平均薪水问题

0 问题描述参考链接(3条消息) HiveSql面试题12--如何分析去掉最大最小值的平均薪水&#xff08;字节跳动&#xff09;_莫叫石榴姐的博客-CSDN博客文中已经给出了三种解法&#xff0c;这里我们借助于此题&#xff0c;来研究如何用percent_rank()函数求解&#xff0c;简化解题思路…

Kafka(五)生产者向发送消息的执行流程

&#xff08;1&#xff09;生产者要往 Kafka 发送消息时&#xff0c;需要创建 ProducerRecoder,代码如下&#xff1a; ProducerRecord<String,String> record new ProducerRecoder<>("CostomerCountry","Precision Products","France&q…

新闻稿的制作流程:从确定新闻稿目的到将其分发给媒体

对于任何希望向媒体和公众传达具有新闻价值的信息的组织来说&#xff0c;新闻稿都是必不可少的工具。精心制作的新闻稿可以帮助您宣传您的业务、产品或服务&#xff0c;并可以产生有价值的媒体报道。在本文中&#xff0c;我们将指导您完成新闻稿的制作过程&#xff0c;从确定新…

08_MySQL聚合函数

1. 聚合函数介绍什么是聚合函数聚合函数作用于一组数据&#xff0c;并对一组数据返回一个值。聚合函数类型AVG()SUM()MAX()MIN()COUNT()注意&#xff1a;聚合函数不能嵌套调用。比如不能出现类似“AVG(SUM(字段名称))”形式的调用。1.1 AVG和SUM函数可以对数值型数据使用AVG 和…

上海亚商投顾:ChatGPT概念领跌 两市约3800股下跌

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪三大指数今日继续调整&#xff0c;创业板指午后一度跌超1%。ChatGPT、AIGC概念股集体走低&#xff0c;三六零跌超8%&…

面试阿里测开岗,被面试官针对,当场翻脸,把我的简历还给我,疑似被拉黑...

好家伙&#xff0c;金三银四一到&#xff0c;这奇葩事可真是多&#xff0c;前两天和粉丝聊天&#xff0c;他说前段时间面试阿里的测开岗&#xff0c;最后和面试官干起来了。 我问他为什么&#xff0c;他说没啥&#xff0c;就觉得面试官太装了&#xff0c;就爱问一些虚而不实的…

2023CS双非保研985经验分享(南大、华科、中科大科学岛、国防科大、西交、中南、深圳大学、北邮、中科院等)

前言&#xff1a; 2022保研以来&#xff0c;因为自己的双非背景&#xff0c;要与985、211的排名靠前的计科大佬竞争&#xff0c;不自信、焦虑无时无刻的包围着我&#xff1b;所幸&#xff0c;一路以受到了许多学长、学姐耐心的帮助&#xff0c;也有很多保研的同学一路互相支撑。…