ThingsBoard的领域模型

ThingsBoard是一个开源的物联网平台,用于管理和监控物联网设备和数据。它提供了一个可扩展的架构,可以连接各种设备,并实时收集、处理和分析设备生成的数据。

领域模型

在ThingsBoard中,领域模型是一个关键概念,用于描述物联网系统中的物理实体、属性和行为。以下是ThingsBoard中的主要领域模型组件:

  1. 租户(Tenant):租户是ThingsBoard中的顶级组织单位。它代表了一个独立的实体,可以是一个用户、组织或公司。租户拥有和管理自己的设备、客户、规则和仪表板等资源。租户之间的数据和配置是相互隔离的,每个租户都有自己的独立环境。租户由系统管理员创建和管理。

  2. 租户配置(TenantProfile):用于定义租户级别的配置和属性。

  3. 客户(Customer):客户是租户下的子级实体,代表了物联网系统中的用户或组织。一个租户可以包含多个客户,每个客户都有自己的访问权限和角色。客户可以访问和监控租户下的设备和数据。客户可以有自己的设备、规则和仪表板等资源,但这些资源受到租户级别的限制。客户由租户管理员创建和管理。

  4. 用户(User):保存用户的基本信息

    1. 用户的角色(Authority):SYS_ADMIN、TENANT_ADMIN、CUSTOMER_USER、REFRESH_TOKEN、PRE_VERIFICATION_TOKEN
    2. 用户凭证(UserCredentials):保存用户的密码、激活用户 Token、重置密码 Token、密码使用历史
    3. 用户认证设置(UserAuthSettings):保存用户 2FA 认证设置
    4. 用户设置(UserSettings):保存用户的设置,包括:通用设置、通知、访问过的仪表盘等等
  5. 系统设置(AdminSettings):是用于配置和管理整个系统的全局设置和参数,包括:通用设置、邮件、JWT、连接设置等等。

    More »

TBMQ测试和源码分析

  1. 启动 TBMQ 程序,浏览器访问 http://localhost:8083,创建一个 Application,Credentials Type 为 BASIC,客户端 ID、用户名和密码均设置为 tbmq_app

    More »

2024-02-20|RateLimitAspect请求限流、调整spring-cloud-examples项目结构

今天做了什么:

  1. ChatGPT 编写一个 RateLimitAspect 类,实现基于用户的 get 查询请求的限流功能

    @Aspect
    @Component
    public class RateLimitAspect {
      private final RedisTemplate<String, Object> redisTemplate;
      private final Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);
    
      private final int maxRequests; // Maximum number of requests
      private final int timeWindow; // Time window in seconds
    
      @Autowired
      public RateLimitAspect(RedisTemplate<String, Object> redisTemplate) {
          this.redisTemplate = redisTemplate;
          this.maxRequests = 100; // Default maximum number of requests is 100
          this.timeWindow = 60; // Default time window is 60 seconds
      }
    
      @Before("@annotation(getMapping)")
      public void applyRateLimit(JoinPoint joinPoint, GetMapping getMapping) {
          HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
             .getRequestAttributes()).getRequest();
          if (request != null && HttpMethod.GET.matches(request.getMethod())) {
              String username = request.getUserPrincipal().getName(); // Get the username
              if (username != null && !username.isEmpty()) {
                  String rateLimitKey = "rate_limit:" + username;
                  incrementAndCheckRateLimit(rateLimitKey, request);
              }
          }
      }
    
      private void incrementAndCheckRateLimit(String rateLimitKey, HttpServletRequest request) {
          Long currentRequests = redisTemplate.execute((RedisCallback<Long>) connection -> {
              Object nativeConnection = connection.getNativeConnection();
              String script = "local current = redis.call('INCR', KEYS[1])\n"
                      + "if tonumber(current) == 1 then\n"
                      + "    redis.call('EXPIRE', KEYS[1], ARGV[1])\n"
                      + "end\n"
                      + "return current";
              return (Long) ((RedisOperations<?, ?>) nativeConnection).execute(
                      (RedisCallback<Object>) connection1 -> connection1.eval(
                              script.getBytes(),
                              redisTemplate.getKeySerializer(), // Use custom Key serializer
                              redisTemplate.getValueSerializer(), // Use custom Value serializer
                              Collections.singletonList(rateLimitKey.getBytes()),
                              Collections.singletonList(String.valueOf(timeWindow).getBytes())
                      )
              );
          });
    
          if (currentRequests > maxRequests) {
              String urlWithParams = getRequestUrlWithParams(request);
              logger.warn("Rate limit exceeded for key: {}. Request URL with Params: {}", 
                 rateLimitKey, urlWithParams);
              throw new RateLimitException();
          }
      }
    
      private String getRequestUrlWithParams(HttpServletRequest request) {
          String url = request.getRequestURL().toString();
          String queryString = request.getQueryString();
          if (queryString != null && !queryString.isEmpty()) {
              url += "?" + queryString;
          }
          return url;
      }
    }
    
  2. 调整 spring-cloud-examples 目录,通过源码分析 SpringBoot 2.7.18 启动过程

    More »

2024-02-05|Spring Cloud Config快速入门

今天做了什么:

  1. 创建项目 spring-cloud-examples,测试 Spring Cloud Config 使用本地文件和 git 仓库作为配置中心

Spring Cloud Config 是一个基于http协议的远程配置实现方式。通过统一的配置管理服务器进行配置管理,客户端通过http协议主动的拉取服务的的配置信息,完成配置获取。

More »