SpringBoot整合Dubbo和Nacos

1.概述

dubbo是一个高性能、轻量级的开源分布式服务框架,早期由阿里巴巴进行开源。它提供了服务注册、发现、调用和负载均衡等分布式服务治理功能,为分布式开发提供了极大便利。dubbo核心概念包括:Provider(消费提供者)、Consumer(服务消费者)、Registry(注册中心)、Monitor(监控中心)等,注册中心是dubbo服务治理的核心组件,dubbo依赖注册中心的协调实现服务(地址)发现,自动化的服务发现是微服务实现动态扩缩容、负载均衡、流量治理的基础。dubbo的提供的注册中心有很多:Multicast注册中心、Zookeeper注册中心、Redis注册中心、Simple注册中心、Nacos注册中心等,本文主要介绍springboot服务整合dubbo,并实用nacos作为注册中心来进行服务注册。

2.dubbo核心概念

2.1 dubbo架构图

在这里插入图片描述

节点名称说 明
Provider暴露服务的服务提供方 ,向注册中心注册提供自己服务
Consumer调用远程服务的服务消费方,从提供者地址列表中,基于负载均衡算法,选择提供者进行调用
Monitor统计服务的调用次数和调用时间的监控中心
Registry服务注册与发现的注册中心,返回服务提供者地址列表给消费者
Container服务运行容器,负责启动、加载和运行服务提供者

图中的虚线表明服务消费者(Consumer)和服务提供者(Provider)通过异步的方式发送消息至Monitor。Consumer和Provider会将信息存放在本地磁盘,平均1min会发送一次信息。Monitor在这个架构中是可选的,并且是需要单独配置的,且Monitor的运行状态(正常或异常)不会影响服务的正常调用。

2.2 dubbo注册中心

dubbo提供的注册中心有:Multicast注册中心、Zookeeper注册中心、Redis注册中心、Simple注册中心、Nacos注册中心等。

注册中心说明
Multicast注册中心不需要任何中心节点,只要广播地址,就可以互相发现
Zookeeper注册中心是一个树形的目录服务,支持变更推送,可靠性较高,是dubbo早期使用最多的注册中心
Redis注册中心redis注册中心使用key/map结构存储数据结构,使用redis的publish/subscribe事件通知数据变更
Simple注册中心simple注册中心本身就是一个普通的dubbo服务,可以减少不必要依赖,使整体通讯方式一致
Nacos注册中心由Alibaba开源的实现动态服务发现、服务配置、服务元数据及流量管理,支持注册中心、配置中心分离和合并部署

3.案例代码

3.1 服务关系图

在这里插入图片描述

dubbo-api模块:该模块定义服务者和消费者之间的契约,描述了服务的能力和行为,UserProviderAPI是一个dubbo接口,定义了服务的insert和queryById方法;
dubbo-provider模块:服务提供者,实现了 UserProviderAPI接口。通过 dubbo中的@Service方法(dubbo
3.0以及以后是@DubboService),该服务会注册到注册中心(Nacos),供消费者发现并调用;
dubbo-consumer模块:服务消费者,通过 @Reference(dubbo 3.0以及以后是@DubboReference) 注解引用了 UserProviderAPI接口。dubbo会自动处理服务的发现、负载均衡等,使得消费者可以透明调用远程服务。
dubbo注册中心:使用 Nacos 作为 Dubbo 的注册中心。注册中心是微服务治理的关键组件之一,它负责服务的注册、发现和管理。服务提供者在启动时向注册中心注册自己的服务信息,而消费者通过注册中心获取服务提供者的信息,从而实现动态的服务调用。

代码目录结构如下:
在这里插入图片描述

3.2 核心代码

本文使用的dubbo版本为2.7.5,springboot的版本为2.3.7,springcloud的版本为2.2.3,具体代码如下:

3.2.1 dubbo-api模块

1.pom文件

 <parent>
        <artifactId>dubbo</artifactId>
        <groupId>com.eckey.lab</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dubbo-api</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.eckey.lab</groupId>
            <artifactId>nacos-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

2.UserProviderAPI接口

import com.eckey.lab.common.Result;
import com.eckey.lab.interfaces.bean.UserDTO;

public interface UserProviderAPI {

    Result insert(UserDTO user);

    Result<UserDTO> queryById(Integer id);
}

3.UserDTO实体类

import lombok.Data;

import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;

@Data
public class UserDTO implements Serializable {

    @NotNull(message = "userName不能为空")
    private String userName;

    @NotNull(message = "age不能为空")
    private Integer age;

    private String nickName;

    @NotNull(message = "gender不能为空")
    private String gender;

    private Date createTime;

    private Date modifyTime;

    private static final long serialVersionUID = 1L;
}

3.2.2 dubbo-provider模块

1.pom文件

<parent>
        <artifactId>dubbo</artifactId>
        <groupId>com.eckey.lab</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dubbo-provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!--java验证框架-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>com.eckey.lab</groupId>
            <artifactId>nacos-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.eckey.lab</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

2.UserProviderServiceImpl类

import com.alibaba.fastjson.JSON;
import com.eckey.lab.common.Result;
import com.eckey.lab.dubbo.bean.User;
import com.eckey.lab.dubbo.dao.UserDao;
import com.eckey.lab.interfaces.UserProviderAPI;
import com.eckey.lab.interfaces.bean.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import java.util.Date;

/**
 * @Author: ChengLiang
 * @CreateTime: 2023-11-13  10:11
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
@Service(version = "1.0.0", timeout = 6000)
@Component
public class UserProviderServiceImpl implements UserProviderAPI {

    @Resource
    private UserDao userDao;

    @Override
    public Result insert(UserDTO user) {
        log.info("添加user入库数据:{}", JSON.toJSONString(user));
        if (user == null) {
            log.error("user不为空");
            return Result.buildDataError("user不为空");
        }
        try {
            user.setCreateTime(new Date());
            user.setModifyTime(new Date());
            User userInsert = new User();
            userInsert.setUserName(user.getUserName());
            userInsert.setNickName(user.getNickName());
            userInsert.setGender(user.getGender());
            userInsert.setAge(user.getAge());
            userInsert.setCreateTime(user.getCreateTime());
            userInsert.setModifyTime(user.getModifyTime());
            userDao.insert(userInsert);
            log.info("数据添加成功:{}", JSON.toJSONString(user));
        } catch (Exception e) {
            log.error("添加数据异常:{}", e);
            return Result.buildDataError("添加数据异常");
        }
        return Result.buildResultSuccess();
    }

    @Override
    public Result<UserDTO> queryById(Integer id) {
        if (id == null) {
            log.error("id不能为空");
            return Result.buildDataError("id不能为空");
        }
        final User user = userDao.selectByPrimaryKey(id);
        final UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user, userDTO);
        log.info("查询结果为:{}", JSON.toJSONString(userDTO));
        return Result.buildDataSuccess(userDTO);
    }
}

3.application.properties

server.port=9090
spring.application.name=dubbo-provider
spring.cloud.nacos.server-addr=http://123.213.45.103:8848
spring.datasource.username=
spring.datasource.password=
spring.datasource.url=jdbc:mysql://192.168.154.10:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=1000&initialTimeout=30
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

dubbo.application.name=dubbo-provider
dubbo.application.version=1.0.0
dubbo.registry.address=
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.scan.base-packages=com.eckey.lab.dubbo.interfaces
mybatis.mapper-locations=classpath:/mybatis/*.xml

4.UserDao类

import com.eckey.lab.dubbo.bean.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserDao {

    int deleteByPrimaryKey(Integer id);

    int insert(User record);

    int insertSelective(User record);

    User selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);
}

5.UserDao.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.eckey.lab.dubbo.dao.UserDao">
  <resultMap id="BaseResultMap" type="com.eckey.lab.dubbo.bean.User">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="user_name" jdbcType="VARCHAR" property="userName" />
    <result column="age" jdbcType="INTEGER" property="age" />
    <result column="nick_name" jdbcType="VARCHAR" property="nickName" />
    <result column="gender" jdbcType="VARCHAR" property="gender" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime" />
  </resultMap>
  <sql id="Base_Column_List">
    id, user_name, age, nick_name, gender, create_time, modify_time
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from user
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from user
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.eckey.lab.dubbo.bean.User" useGeneratedKeys="true">
    insert into user (user_name, age, nick_name,
      gender, create_time, modify_time
      )
    values (#{userName,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}, #{nickName,jdbcType=VARCHAR}, 
      #{gender,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifyTime,jdbcType=TIMESTAMP}
      )
  </insert>
  <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.eckey.lab.dubbo.bean.User" useGeneratedKeys="true">
    insert into user
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="userName != null">
        user_name,
      </if>
      <if test="age != null">
        age,
      </if>
      <if test="nickName != null">
        nick_name,
      </if>
      <if test="gender != null">
        gender,
      </if>
      <if test="createTime != null">
        create_time,
      </if>
      <if test="modifyTime != null">
        modify_time,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="userName != null">
        #{userName,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        #{age,jdbcType=INTEGER},
      </if>
      <if test="nickName != null">
        #{nickName,jdbcType=VARCHAR},
      </if>
      <if test="gender != null">
        #{gender,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null">
        #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="modifyTime != null">
        #{modifyTime,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.eckey.lab.dubbo.bean.User">
    update user
    <set>
      <if test="userName != null">
        user_name = #{userName,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        age = #{age,jdbcType=INTEGER},
      </if>
      <if test="nickName != null">
        nick_name = #{nickName,jdbcType=VARCHAR},
      </if>
      <if test="gender != null">
        gender = #{gender,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null">
        create_time = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="modifyTime != null">
        modify_time = #{modifyTime,jdbcType=TIMESTAMP},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.eckey.lab.dubbo.bean.User">
    update user
    set user_name = #{userName,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      nick_name = #{nickName,jdbcType=VARCHAR},
      gender = #{gender,jdbcType=VARCHAR},
      create_time = #{createTime,jdbcType=TIMESTAMP},
      modify_time = #{modifyTime,jdbcType=TIMESTAMP}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

3.2.3 dubbo-consumer模块

pom文件与dubbo-provider模块一致,核心模块为DubboConsumerServiceImpl类,具体如下:
1.DubboConsumerServiceImpl类

import com.alibaba.fastjson.JSON;
import com.eckey.lab.common.Result;
import com.eckey.lab.consumer.bean.UserVO;
import com.eckey.lab.consumer.service.DubboConsumerService;
import com.eckey.lab.interfaces.UserProviderAPI;
import com.eckey.lab.interfaces.bean.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

/**
 * @Author: ChengLiang
 * @CreateTime: 2023-11-13  10:56
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
@Service
public class DubboConsumerServiceImpl implements DubboConsumerService {

    @Reference(interfaceClass = UserProviderAPI.class, version = "1.0.0")
    private UserProviderAPI userProviderAPI;

    @Override
    public Result insert(UserVO userVO) {
        UserDTO userDTO = new UserDTO();
        userDTO.setUserName(userVO.getUserName());
        userDTO.setNickName(userVO.getNickName());
        userDTO.setAge(userVO.getAge());
        userDTO.setGender(userVO.getGender());
        userDTO.setCreateTime(userVO.getCreateTime());
        userDTO.setModifyTime(userVO.getModifyTime());
        log.info("userDTO:{}", JSON.toJSONString(userDTO));
        return userProviderAPI.insert(userDTO);
    }

    @Override
    public Result<UserDTO> selectByKeyId(Integer id) {
        Result<UserDTO> userDTOResult = userProviderAPI.queryById(id);
        log.info("查询结果为;{}", JSON.toJSONString(userDTOResult.getData()));
        return userDTOResult;
    }
}

2.application.properties

server.port=9091
spring.application.name=dubbo-consumer
spring.cloud.nacos.server-addr=http://123.213.45.103:8848
dubbo.application.name=dubbo-consumer
dubbo.application.version=1.0.0
dubbo.registry.address=nacos://http://123.213.45.103:8848/?username=nacos&password=nacos
dubbo.protocol.name=dubbo
dubbo.protocol.port=20881

详细代码可参考文章附录部分,在上述代码中,有一些注意事项,具体如下:

1.在dubbo-provider和dubbo-consumer的启动类上,需要添加@EnableDubbo,@EnableDubbo整合了三个注解@EnableDubboConfig、@DubboComponentScan、@EnableDubboLifecycle。@EnableDubbo的功能都是由这三个注解完成的。
@EnableDubboConfig引入类DubboConfigConfigurationRegistrar,将用于解析配置相关的类注册到spring容器;
@DubboComponentScan引入类DubboComponentScanRegistrar,用于指定@Service扫描路径;
@EnableDubboLifecycle引入类DubboLifecycleComponentRegistrar,注册了两个监听器到spring容器。
一般需要配置@DubboComponentScan来定义@Service的扫描路径。如果不配置@DubboComponentScan,默认使用@EnableDubbo注解的类的包路径。
2.UserProviderServiceImpl中的注解@Service引入的是org.apache.dubbo.config.annotation.Service;
3.配置文件中,需要指定nacos的登录账户和密码,否则会报错。

3.3 测试结果

nacos注册页面上的服务列表如下:
在这里插入图片描述
调用服务消费者的接口如下:
在这里插入图片描述
服务消费者和提供者的日志如下:
在这里插入图片描述
在这里插入图片描述

4.小结

1.dubbo的注册中心有很多,本文基于nacos来进行演示,nacos的安装可查看我的博文:SpringCloud源码探析(二)-Nacos注册中心;
2.在dubbo框架中,需要先定义接口模块(定义提供者输出能力,消费者需要能力),服务提供者实现能力并注册到注册中心,供消费者进行消费;
3.dubbo和spring cloud alibaba之间有版本之间的对应关系,具体可查询dubbo官网或spring cloud官网进行对比。

5.参考文献

  1. https://zhuanlan.zhihu.com/p/638826433
  2. https://blog.csdn.net/java_cpp_/article/details/128051413
  3. https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/quick-start/api/
  4. https://juejin.cn/post/7159776981771354119
  5. https://developer.aliyun.com/article/808571

6.附录

https://gitee.com/Marinc/nacos/tree/master/dubbo

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

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

相关文章

【Windows】安装绿色版Mysql数据库 -- 可支持所有版本安装教程

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

化妆品发墨西哥专线的难点解析

化妆品发往墨西哥专线的难点主要包括以下几个方面&#xff1a; 1. 物流监管&#xff1a;墨西哥对化妆品的进口有严格的监管和法规要求&#xff0c;包括产品注册、标签规定、成分审批等。化妆品属于特殊的进口商品&#xff0c;需要满足墨西哥卫生部门(COFEPRIS)的相关规定&#…

基于springboot实现小学家校一体“作业帮”系统项目【项目源码】计算机毕业设计

基于springboot实现小学家校一体“作业帮”系统演示 Java语言简介 Java是由SUN公司推出&#xff0c;该公司于2010年被oracle公司收购。Java本是印度尼西亚的一个叫做爪洼岛的英文名称&#xff0c;也因此得来java是一杯正冒着热气咖啡的标识。Java语言在移动互联网的大背景下具…

科研绘图与学术图表绘制:从入门到精通

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 一、入门篇 1.1 软件介…

cryptopp Base64Encoder \n问题

1、问题&#xff1a; new Base64Encoder(new StringSink(out_base)) 调用库函数Base64Encoder进行base64加密后确认多出来了\n 2、原因 base64加密的问题, 由于base64一行不能超过76字符, 超过就会添加回车换行符(在Windows中是 \r\n , 在Linux中是 \n ) 3、解决 方法一、给定参…

对这套BI零售数据分析方案心动,是零售人天性

零售数据分析做了这么多年&#xff0c;难道真的没累积点经验&#xff0c;摸索出一条又快又能满足绝大多数需求的数据分析捷径&#xff1f;别人不知道&#xff0c;奥威BI还真就有这么一套标准化的BI零售数据分析方案&#xff0c;不管是服装零售、医药连锁、商超都能利用这套方案…

【JY】ANSYS Workbench在减隔震应用分析中的单元积分技术笔记

写在前文 尽管减隔震技术与有限元结合取得了众多成果&#xff0c;但仍面临诸多挑战&#xff0c;如材料非线性、模型不确定性等等。减隔震设计除了常规的宏观结构设计采用SAP2000、Etabs、Midas、SSG、Paco-SAP 或 YJK\PKPM等。 【JY】各类有限元软件计算功能赏析与探讨 我们需要…

为什么PDF文件不能打印?

正常的PDF文件是可以打印的&#xff0c;如果PDF文件打开之后发现文件不能打印&#xff0c;我们需要先查看一下自己的打印机是否能够正常运行&#xff0c;如果打印机是正常的&#xff0c;我们再查看一下&#xff0c;文件中的打印功能按钮是否是灰色的状态。 如果PDF中的大多数功…

TCP为什么需要三次握手和四次挥手?

面试官&#xff1a;说说TCP为什么需要三次握手和四次挥手&#xff1f; 一、三次握手 三次握手&#xff08;Three-way Handshake&#xff09;其实就是指建立一个TCP连接时&#xff0c;需要客户端和服务器总共发送3个包 主要作用就是为了确认双方的接收能力和发送能力是否正常、…

新生儿奶瓣:原因、科普和注意事项

引言&#xff1a; 新生儿奶瓣是一种婴儿口腔内的常见现象&#xff0c;它通常被视为正常的生理发展。然而&#xff0c;对于一些新父母而言&#xff0c;了解奶瓣的原因以及如何处理是至关重要的。本文将科普新生儿奶瓣的原因&#xff0c;提供相关信息&#xff0c;并为父母和监护…

Python 如何实现迭代器设计模式?什么是迭代器(Iterator)设计模式?

迭代器&#xff08;Iterator&#xff09;设计模式是一种行为设计模式&#xff0c;用于提供一种方法来访问一个聚合对象中的各个元素&#xff0c;而不暴露该对象的内部表示。它定义了一种迭代的方式&#xff0c;允许客户端按序访问聚合中的元素&#xff0c;而无需了解底层的数据…

4步轻松搞定烦人的WPS右键菜单

安装WPS的时候不小心勾选了很多默认选项&#xff0c;结果右键菜单惨不忍睹&#xff0c;一些没用的菜单占据了大量篇幅&#xff0c;使用起来十分不方便。考虑360&#xff0c;火绒的右键菜单管理功能没搞定&#xff0c;最后在WPS的管理功能的隐藏角落找到了设置功能&#xff0c;给…

模拟实现C语言--strstr函数

模拟实现C语言–strstr函数 文章目录 模拟实现C语言--strstr函数一、strstr函数是什么&#xff1f;二、使用示例三、模拟实现3.1 模拟实现1 一、strstr函数是什么&#xff1f; 在目标字符串中寻找字符串 char * strstr ( const char *str1, const char * str2);根据语法结构&…

Java 反射设置List属性

使用 Java 反射可以动态地设置对象的属性值&#xff0c;包括 List 类型的属性。以下是一个示例代码&#xff0c;演示如何通过反射设置 List 类型的属性&#xff1a; 假设有一个类 Person&#xff0c;包含一个 List 类型的属性 names&#xff1a; java public class Person { …

升降机械比例多路阀放大器

升降机械比例多路阀放大器是一种在液压系统中控制多个执行元件的运动方向和速度的设备。这种放大器的特点是与负载无关&#xff0c;且为无极的。它通常配置外置比例放大器&#xff0c;用于控制一个或同时操作的多个液压耗能器的运动方向和速度。 被广泛应用于升降机械中的比例…

笔记本分屏怎么操作?3个方法提高工作效率!

“有朋友知道笔记本怎么才能实现分屏吗&#xff1f;我在工作时&#xff0c;经常需要来回切换屏幕&#xff0c;效率真的太低了&#xff0c;有什么方法可以实现两个屏幕同时使用吗&#xff1f;” 在现代生活中&#xff0c;多任务处理已成为常态&#xff0c;而笔记本分屏技术为用户…

数据结构-散列表

列表&#xff08;Hash Table&#xff09;&#xff0c;又称哈希表&#xff0c;是一种数据结构&#xff0c;特点是&#xff1a;数据元素的关键字与其存储地址直接相关 例&#xff1a;有一堆数据元素&#xff0c;关键字分别为&#xff5b;19&#xff0c;14&#xff0c;23&#xff…

雅虎、美客多、Temu、Allegro、亚马逊跨境平台选品技巧方法,测评养号攻略。

&#xff08;1) Best Sellers选品法 这个方法顾名思义&#xff0c;就是大家熟悉的热销榜单选品法。 不做过多解释&#xff0c;在自己熟悉的品类&#xff0c;隔几天就会观察一下前100名里有没有冒出什么新品。 它和现有的产品相同还是不同&#xff0c;自己做哪些搭配或者迭代…

【ERROR】ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND No package.json

1、报错 启动项目的时候&#xff0c;报这个错误&#xff0c;是因为根目录错误&#xff0c;查看&#xff0c;根目录是否错误。

设计大咖亲授:Figma中文环境设置全攻略!

作为UI设计师&#xff0c;你一定很熟悉Figma&#xff0c;Figma是一款专注于UI/UX设计的在线协作工具&#xff0c;使用非常高效方便&#xff0c;不需要下载和安装。它只需要通过浏览器编辑&#xff0c;在国外很受欢迎。但是Figma对于国内的小伙伴来说&#xff0c;使用Figma有一定…