解析Springboot集成Tile38客户端之Set命令实现示例

目录
  • set命令语法
  • 语法分析
  • 代码设计
    • POINT数据类型
    • BOUNDS数据类型
    • HASH和STRING数据类型
    • OBJECT数据类型
  • 如何使用

set命令语法

SET key id [FIELD name value ...] [EX seconds] [NX|XX] (OBJECT geojson)|(POINT lat lon z)|(BOUNDS minlat minlon maxlat maxlon)|(HASH geohash)|(STRING value)

set命令就相当于redis中的hash命令的使用,也是一个keyid的组合,但是不同的是,Tile38的set命令还可以携带更多的其他属性,比如可以自定义FIELD字段,还可以设置EX有效期等等,那么我们需要给这个语法设计一套好用的java api,以便开发人员可以更好地使用Tile38。

语法分析

首先,根据上面提供的语法,我们可以分为三部分:

1.第一部分就是命令的启示关键字SET,我们把这个关键字单独作为一部分;

2.第二部分就是key id [FIELD name value ...] [EX seconds] [NX|XX],我们把这些都作为参数;

3.第三部分就是最后的目标数据对象:

(OBJECT geojson)|(POINT lat lon z)|(BOUNDS minlat minlon maxlat maxlon)|(HASH geohash)|(STRING value)

代码设计

1.我们把第一部分的命令关键字通过枚举的方式来管理:

enum Tile38Command implements ProtocolKeyword {
    SET;
    public final byte[] bytes;
    static final String UNDERSCORE = "_";
    static final String SPACE = " ";
    Tile38Command() {
      String name = StringUtils.replace(this.name(), UNDERSCORE, SPACE);
      this.bytes = name.getBytes(StandardCharsets.US_ASCII);
    }
    @Override
    public byte[] getBytes() {
      return this.bytes;
    }
}

因为redis客户端工具在发送命令前需要对所有命令进行编码,所以要求所有的命令都必须实现ProtocolKeyword接口。如果命令的起始关键字是两个或多个单词,那么我们会使用下划线连接,转换成bytes的时候我们可以使用空格把下划线替换。

2.我们把命令的第二部分抽象成一个具体的class,通过相关的字段来进行描述:

public class SetOpts {
  private String key;
  private String id;
  //字段值必须是双精度浮点型
  private Map<String, Double> fields;
  // 单位秒
  private int ex;
  // 创建方式:
  // NX 不存在的时候创建
  // XX 存在的时候更新
  private NxXx nxXx;
  private SetOpts(Builder builder) {
    this.key = builder.key;
    this.id = builder.id;
    this.fields = builder.fields;
    this.ex = builder.ex;
    this.nxXx = builder.nxXx;
  }

  // 把所有的参数按顺序放到列表中
  public List<String> commandLine() {
    List<String> result = new LinkedList<>();
    result.add(this.key);
    result.add(this.id);
    // 添加所有的FIELD
    if (MapUtils.isNotEmpty(this.fields)) {
      for (Map.Entry<String, Double> entry : this.fields.entrySet()) {
        result.add("FIELD");
        result.add(entry.getKey());
        result.add(entry.getValue().toString());
      }
    }
    // 添加`EX`
    if (this.ex >= 0) {
      result.add("EX");
      result.add(String.valueOf(this.ex));
    }
    // 添加NX或XX
    if (Objects.nonNull(this.nxXx)) {
      result.add(this.nxXx.name());
    }
    // 返回结果
    return result;
  }

  public enum NxXx {
    NX,
    XX
  }
  // 建造者模式
  public static class Builder {
    private String key;
    private String id;
    //字段值必须是双精度浮点型
    private Map<String, Double> fields;
    // 单位秒
    private int ex = -1;
    // 创建方式:
    // NX 不存在的时候创建
    // XX 存在的时候更新
    private NxXx nxXx;
    public Builder key(String key) {
      this.key = key;
      return this;
    }
    public Builder id(String id) {
      this.id = id;
      return this;
    }
    public Builder field(String field, double value) {
      if (Objects.isNull(this.fields)) {
        this.fields = new LinkedHashMap<>();
      }
      this.fields.put(field, value);
      return this;
    }
    public Builder ex(int seconds) {
      this.ex = seconds;
      return this;
    }
    public Builder nxXx(NxXx nxXx) {
      this.nxXx = nxXx;
      return this;
    }
    public SetOpts build() throws AwesomeException {
      if (StringUtils.isEmpty(this.key)) {
        throw new AwesomeException(500, "key is empty");
      }
      if (StringUtils.isEmpty(this.id)) {
        throw new AwesomeException(500, "id is empty");
      }
      // 创建SetOpts对象
      return new SetOpts(this);
    }
  }
}

我们上面通过建造者的设计模式,把所有的参数都转换成了SetOpts这个类当中,开发人员就可以通过SetOpts对象的构建来灵活地控制命令中的参数了。

3.我们需要把第三部分当中的不同数据对象转换成不同的类型:

POINT数据类型

Point关键的字段就是经纬度,除此之外,还有一个额外的字段z,用来存储额外的业务参数,可为空。

public class Point extends Element implements Serializable {
  // 经度
  private double lng;
  // 维度
  private double lat;
  // 额外的数据
  private double z;
  public Point(double lng, double lat, double z) {
    this.lat = lat;
    this.lng = lng;
    this.z = z;
  }
  public Point(double lng, double lat) {
    this(lng, lat, Integer.MIN_VALUE);
  }
  @Override
  public List<String> commandArgs() {
    List<String> result = new LinkedList<>();
    result.add("POINT");
    result.add(String.valueOf(this.lng));
    result.add(String.valueOf(this.lat));
    if (this.z != Integer.MIN_VALUE) {
      result.add(String.valueOf(this.z));
    }
    return result;
  }
}

BOUNDS数据类型

BOUNDS就是矩形,它的关键字段就是左下角和右上角两个点位,我们使用coordinate1和coordinate2来表示左下角和右上角;

@AllArgsConstructor
public class Bounds extends Element {
  private double[] coordinate1;
  private double[] coordinate2;
  @Override
  public List<String> commandArgs() {
    List<String> result = new LinkedList<>();
    result.add("BOUNDS");
    result.add(String.valueOf(coordinate1[0]));
    result.add(String.valueOf(coordinate1[1]));
    result.add(String.valueOf(coordinate2[0]));
    result.add(String.valueOf(coordinate2[1]));
    return result;
  }
}

HASH和STRING数据类型

HASH和STRING其实就是一个单独的字符串,但是我们还是把它封装一下,以便开发人员使用;

@AllArgsConstructor
public class Geohash extends Element {
  private String hash;
  @Override
  public List<String> commandArgs() {
    List<String> result = new LinkedList<>();
    result.add("HASH");
    result.add(this.hash);
    return result;
  }
}
@AllArgsConstructor
public class RawString extends Element {
  private String raw;
  @Override
  public List<String> commandArgs() {
    List<String> result = new LinkedList<>();
    result.add("STRING");
    result.add(this.raw);
    return result;
  }
}

OBJECT数据类型

OBJECT其实就是GeoJSON数据,这一类数据比较复杂一点,一共有六种类型,想了解的小伙伴可以看这里geojson.org/

Point,
LineString,
Polygon,
MultiPoint,
MultiLineString,
MultiPolygon

为了开发人员能够更好的使用这六种类型,我们同样使用建造者模式来设计一下GeoJSON数据类型:

@Data
public class GeoJson {
  public static class Builder {
    public Point.Builder point() {
      return new Point.Builder();
    }
    public MultiPoint.Builder multPoint() {
      return new MultiPoint.Builder();
    }
    public LineString.Builder lineString() {
      return new LineString.Builder();
    }
    public MultiLineString.Builder multiLineString() {
      return new MultiLineString.Builder();
    }
    public Polygon.Builder polygon() {
      return new Polygon.Builder();
    }
    public MultiPolygon.Builder multiPolygon() {
      return new MultiPolygon.Builder();
    }
  }
}

我们现在一个大类里面创建多个方法,每一个方法都把对应类型的建造者给创造出来,这样的话,就相当于这个类当中有创建六种对象的方式,每个建造者都只负责建造对应的那个对象。

下面分别是六个建造者的代码,每个对象都基于最基本的BaseGeoJson来构造,BaseGeoJson中把公共的字段type和额外的meta字段抽出来,各个类型不同的点在于坐标点的数量和层次不同,所以根据各自类型的特点,代码设计如下:

// Point类型
  public static class Point extends BaseGeoJson {
    // 坐标点
    private double[] coordinates;
    Point(Builder builder) {
      super(builder);
      this.type = GeoJsonType.Point;
      this.coordinates = builder.coordinates;
    }
    @Override
    protected Object coordinates() {
      return this.coordinates;
    }
    public static class Builder extends BaseGeoJson.Builder {
      private double[] coordinates;
      public Builder coordinate(double lon, double lat) {
        coordinates = new double[]{lat, lon};
        return this;
      }
      public Point build() {
        return new Point(this);
      }
    }
  }
// MultiPoint类型
  public static class MultiPoint extends BaseGeoJson {
    private double[][] coordinates;
    MultiPoint(Builder builder) {
      super(builder);
      this.type = GeoJsonType.MultiPoint;
      this.coordinates = builder.convert2Array();
    }
    @Override
    protected Object coordinates() {
      return this.coordinates;
    }
    public static class Builder extends BaseGeoJson.Builder {
      private List<Coordinate> coordinates;
      public Builder coordinate(double lon, double lat) {
        if (CollectionUtils.isEmpty(this.coordinates)) {
          this.coordinates = new LinkedList<>();
        }
        this.coordinates.add(new Coordinate(lat, lon));
        return this;
      }
      protected double[][] convert2Array() {
        int length = this.coordinates.size();
        double[][] result = new double[length][];
        for (int i = 0; i < length; i++) {
          result[i] = this.coordinates.get(i).convertToArray();
        }
        return result;
      }
      @Override
      public MultiPoint build() {
        return new MultiPoint(this);
      }
    }
  }
// LineString类型
  public static class LineString extends MultiPoint {
    private double[][] coordinates;
    LineString(Builder builder) {
      super(builder);
      this.type = GeoJsonType.LineString;
    }
    public static class Builder extends MultiPoint.Builder {
      @Override
      public LineString build() {
        return new LineString(this);
      }
    }
  }
// MultiLineString类型
  public static class MultiLineString extends BaseGeoJson {
    private double[][][] coordinates;
    MultiLineString(Builder builder) {
      super(builder);
      this.type = GeoJsonType.MultiLineString;
      this.coordinates = builder.convertToArray();
    }
    @Override
    protected Object coordinates() {
      return this.coordinates;
    }
    public static class Builder extends BaseGeoJson.Builder {
      private List<Line> lines = new LinkedList<>();
      public Line line() {
        return new Line(this);
      }
      void addLine(Line line) {
        lines.add(line);
      }
      double[][][] convertToArray() {
        int length = this.lines.size();
        double[][][] result = new double[length][][];
        for (int i = 0; i < length; i++) {
          Line line = this.lines.get(i);
          result[i] = line.convert2Array();
        }
        return result;
      }
      @Override
      public BaseGeoJson build() {
        return new MultiLineString(this);
      }
    }
    static class Line {
      private List<Coordinate> coordinates;
      private Builder builder;
      Line(Builder builder) {
        this.builder = builder;
        this.builder.addLine(this);
      }
      private double[][] convert2Array() {
        int length = this.coordinates.size();
        double[][] result = new double[length][];
        for (int i = 0; i < length; i++) {
          result[i] = this.coordinates.get(i).convertToArray();
        }
        return result;
      }
      public Line coordinate(double lon, double lat) {
        if (CollectionUtils.isEmpty(this.coordinates)) {
          this.coordinates = new LinkedList<>();
        }
        this.coordinates.add(new Coordinate(lat, lon));
        return this;
      }
      public Line nextLine() {
        return new Line(this.builder);
      }
      public Builder end() {
        return this.builder;
      }
    }
  }
// Polygon类型
  public static class Polygon extends MultiPoint {
    private double[][][] coordinates;
    Polygon(Builder builder) {
      super(builder);
      this.type = GeoJsonType.Polygon;
      this.coordinates = new double[][][]{builder.convert2Array()};
    }
    public static class Builder extends MultiPoint.Builder {
      @Override
      public Polygon build() {
        return new Polygon(this);
      }
    }
  }
// MultiPolygon类型
  public static class MultiPolygon extends BaseGeoJson {
    private double[][][][] coordinates;
    MultiPolygon(Builder builder) {
      super(builder);
      this.type = GeoJsonType.MultiPolygon;
      this.coordinates = new double[][][][]{builder.convert2Array()};
    }
    @Override
    protected Object coordinates() {
      return this.coordinates;
    }
    public static class Builder extends BaseGeoJson.Builder {
      private List<Polygon> polygons = new LinkedList<>();
      @Override
      public BaseGeoJson build() {
        return new MultiPolygon(this);
      }
      void addPolygon(Polygon polygon) {
        polygons.add(polygon);
      }
      private double[][][] convert2Array() {
        int length = this.polygons.size();
        double[][][] result = new double[length][][];
        for (int i = 0; i < length; i++) {
          result[i] = this.polygons.get(i).convert2Array();
        }
        return result;
      }
    }
    static class Polygon {
      private List<Coordinate> coordinates;
      private Builder builder;
      Polygon(Builder builder) {
        this.builder = builder;
        this.builder.addPolygon(this);
      }
      private double[][] convert2Array() {
        int length = this.coordinates.size();
        double[][] result = new double[length][];
        for (int i = 0; i < length; i++) {
          result[i] = this.coordinates.get(i).convertToArray();
        }
        return result;
      }
      public Polygon coordinate(double lon, double lat) {
        if (CollectionUtils.isEmpty(this.coordinates)) {
          this.coordinates = new LinkedList<>();
        }
        this.coordinates.add(new Coordinate(lat, lon));
        return this;
      }
      public Polygon nextLine() {
        return new Polygon(this.builder);
      }
      public Builder end() {
        return this.builder;
      }
    }
  }
// 基类BaseGeoJson
  public abstract static class BaseGeoJson extends Element {
    // 公共字段type
    protected GeoJsonType type;
    // 公共字段metadata
    private Map<String, String> metadata;
    BaseGeoJson(Builder builder) {
      this.metadata = builder.metadata;
    }
    protected abstract Object coordinates();
    // 转换成命令参数
    @Override
    public List<String> commandArgs() {
      List<String> result = new LinkedList<>();
      result.add("OBJECT");
      result.add(toJson());
      return result;
    }
    // 提供统一的转json方法
    protected String toJson() {
      Map<String, Object> map = new LinkedHashMap<>();
      map.put("type", this.type);
      map.put("coordinates", coordinates());
      if (!CollectionUtils.isEmpty(this.metadata)) {
        for (Map.Entry<String, String> entry : this.metadata.entrySet()) {
          map.put(entry.getKey(), entry.getValue());
        }
      }
      return JsonUtil.obj2String(map);
    }
    abstract static class Builder {
      private Map<String, String> metadata;
      public Builder meta(String key, String value) {
        if (MapUtils.isEmpty(this.metadata)) {
          this.metadata = new LinkedHashMap<>();
        }
        this.metadata.put(key, value);
        return this;
      }
      public abstract BaseGeoJson build();
    }
    static class Coordinate {
      private double lat;
      private double lon;
      Coordinate(double lat, double lon) {
        this.lat = lat;
        this.lon = lon;
      }
      public double[] convertToArray() {
        return new double[]{this.lat, this.lon};
      }
    }
    // GeoJSON所有的数据类型
    enum GeoJsonType {
      Point,
      LineString,
      Polygon,
      MultiPoint,
      MultiLineString,
      MultiPolygon
    }
  }

最后,再补充一个基类Element:

public abstract class Element implements Serializable {
  public abstract List<String> commandArgs();
}

如何使用

我们针对所有的数据类型全部转换成具体的代码设计,下面我们看看如何使用:

private String setElement(SetOpts setOpts, Element element) {
    List<String> args1 = setOpts.commandLine();
    List<String> commandArgs = element.commandArgs();
    return execute(Tile38Command.SET, args1, commandArgs);
}
/**
   * 设置点位
   *
   * @param setOpts
   * @param point
   * @return
   */
  public String setPoint(SetOpts setOpts, Point point) {
    return setElement(setOpts, point);
  }
  /**
   * 设置对象
   *
   * @param setOpts
   * @param geoJson
   * @return
   */
  public String setObject(SetOpts setOpts, GeoJson.BaseGeoJson geoJson) {
    return setElement(setOpts, geoJson);
  }
  /**
   * 设置矩形边界
   *
   * @param setOpts
   * @param bounds
   * @return
   */
  public String setBounds(SetOpts setOpts, Bounds bounds) {
    return setElement(setOpts, bounds);
  }
  /**
   * 设置geohash
   *
   * @param setOpts
   * @param geohash
   * @return
   */
  public String setGeohash(SetOpts setOpts, Geohash geohash) {
    return setElement(setOpts, geohash);
  }
  /**
   * 设置String
   *
   * @param setOpts
   * @param string
   * @return
   */
  public String setString(SetOpts setOpts, RawString string) {
    return setElement(setOpts, string);
  }

所有的开发人员只需要按照上面的方法来使用就可以很方便地执行Tile38的命令了,至此,我们所有关于SET命令的设计都已经讲解完毕。

以上就是解析Springboot集成Tile38客户端之Set命令实现示例的详细内容,更多关于Springboot集成Tile客户端Set命令的资料请关注我们其它相关文章!

(0)

相关推荐

  • springboot中如何实现kafa指定offset消费

    这篇文章主要介绍了springboot中如何实现kafa指定offset消费,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 kafka消费过程难免会遇到需要重新消费的场景,例如我们消费到kafka数据之后需要进行存库操作,若某一时刻数据库down了,导致kafka消费的数据无法入库,为了弥补数据库down期间的数据损失,有一种做法我们可以指定kafka消费者的offset到之前某一时间的数值,然后重新进行消费. 首先创建kafka消费服务 @S

  • 详解springboot设置默认参数Springboot.setDefaultProperties(map)不生效解决

    我们都知道springboot 由于内置tomcat(中间件)直接用启动类就可以启动了. 而且我们有时想代码给程序设置一些默认参数,所以使用方法Springboot.setDefaultProperties(map) SpringApplication application = new SpringApplication(startClass); // Map<String, Object> params = new HashMap<>(); params.put("l

  • springboot反爬虫组件kk-anti-reptile的使用方法

      大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标!   今天小编推荐一款反爬虫组件叫kk-anti-reptile,一款可快速接入的反爬虫.接口防盗刷spring boot stater组件. 1. 系统要求 基于spring-boot开发(spring-boot1.x, spring-boot2.x均可) 需要使用redis 2. 工作流程   kk-anti-reptile

  • 关于SpringBoot整合redis使用Lettuce客户端超时问题

    参考的博客 问题起因 做毕设的时候,使用到Lettuce连接redis,一段时间后不操作,再去操作redis,会报连接超时错误,在其重连后又可使用. 原因是:Lettuce 自适应拓扑刷新(Adaptive updates)与定时拓扑刷新(Periodic updates) 是默认关闭的导致问题的出现 解决的方案 1.重写连接工厂实例,更改其LettuceClientConfiguration 为开启拓扑更新 @Configuration public class RedisConfig { @

  • SpringBoot使用Redis的zset统计在线用户信息

    统计在线用户的数量,是应用很常见的需求了.如果需要精准的统计到用户是在线,离线状态,我想只有客户端和服务器通过保持一个TCP长连接来实现.如果应用本身并非一个IM应用的话,这种方式成本极高. 现在的应用都趋向于使用心跳包来标识用户是否在线.用户登录后,每隔一段时间,往服务器推送一个消息,表示当前用户在线.服务器则可以定义一个时间差,例如:5分钟内收到过客户端心跳消息,视为在线用户. 在线用户统计的实现 基于数据库实现 最简单的办法,就是在用户表,添加一个最后心跳包的日期时间字段 last_act

  • SpringBoot 接口开发教程(httpclient客户端)

    目录 SpringBoot接口开发 服务端 客户端post请求 get请求 SpringBoot之httpclient使用 引入相关依赖 编写相关工具类 业务代码中使用 SpringBoot接口开发 服务端 @RestController @RequestMapping("/landary") public class landaryController { @RequestMapping("adduser") public JSONObject addUser(@

  • 解析Springboot集成Tile38客户端之Set命令实现示例

    目录 set命令语法 语法分析 代码设计 POINT数据类型 BOUNDS数据类型 HASH和STRING数据类型 OBJECT数据类型 如何使用 set命令语法 SET key id [FIELD name value ...] [EX seconds] [NX|XX] (OBJECT geojson)|(POINT lat lon z)|(BOUNDS minlat minlon maxlat maxlon)|(HASH geohash)|(STRING value) set命令就相当于re

  • SpringBoot集成POI实现Excel导入导出的示例详解

    目录 知识准备 什么是POI POI中基础概念 实现案例 Pom依赖 导出Excel 导入Excel 示例源码 知识准备 需要了解POI工具,以及POI对Excel中的对象的封装对应关系. 什么是POI Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能.POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”. A

  • 解析springboot集成AOP实现日志输出的方法

    开发接口系统中主要的一环就是日志输出,如果系统出现问题,日志能帮我们去定位问题,最常见的日志是调用方 所调用的IP 接口地址 对应方法 参数值 以及接口方接收到请求 所返回的参数.如果这需要在每一个controller层去写的话代码过于重复,于是就使用AOP定义切面 对其接口调用前后进行拦截日志输出. 1.加入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr

  • SpringBoot 集成短信和邮件的配置示例详解

    目录 依赖 配置 编码 1.邮件 2.短信 准备工作 1.集成邮件 以QQ邮箱为例 在发送邮件之前,要开启POP3和SMTP协议,需要获得邮件服务器的授权码,获取授权码: 1.设置>账户 在账户的下面有一个开启SMTP协议的开关并进行密码验证: 2.获取成功的授权码 2.集成短信 以阿里云短信服务为例 1.登陆阿里云—>进入控制台—>开通短信服务 进入后根据提示开通短信服务即可. 2.充值 后期发短信测试需要,暂时可以跳过此步骤. 3.获取AccessKey和AccessSercet 文

  • SpringBoot集成Redisson实现分布式锁的方法示例

    上篇 <SpringBoot 集成 redis 分布式锁优化>对死锁的问题进行了优化,今天介绍的是 redis 官方推荐使用的 Redisson ,Redisson 架设在 redis 基础上的 Java 驻内存数据网格(In-Memory Data Grid),基于NIO的 Netty 框架上,利用了 redis 键值数据库.功能非常强大,解决了很多分布式架构中的问题. Github的wiki地址: https://github.com/redisson/redisson/wiki 官方文档

  • Spring-Boot 集成Solr客户端的详细步骤

    Solr 是基于 Lucene 的全文检索服务器,可配置.可扩展,并对索引和搜索性能进行了优化.Solr 多用于电子商务网站.门户.论坛这类网站的站内搜索.Solr 可以独立运行在 Jetty.Tomcat 等这些 Servlet 容器中.Solr 索引的实现非常简单,用 POST 方法去向 Solr服务器发送一个描述 Field 及其内容的 JSON 文档,Solr 根据 JSON 文件增删改索引.Solr 搜索只需要发送 HTTP GET 请求,然后对 Solr 返回 JSON 格式的查询结

  • SpringBoot集成SFTP客户端实现文件上传下载实例

    目录 背景 依赖 创建工具类 SFTP链接池化 SFTP链接池的使用 集成到SpringBoot中 配置 java Bean注入 背景 在项目开发中,一般文件存储很少再使用SFTP服务,但是也不排除合作伙伴使用SFTP来存储项目中的文件或者通过SFTP来实现文件数据的交互. 我遇到的项目中,就有银行和保险公司等合作伙伴通过SFTP服务来实现与我们项目的文件数据的交互. 为了能够顺利地完成与友商的SFTP服务的连通,我们需要在自己的项目中实现一套SFTP客户端工具.一般我们会采用Jsch来实现SF

  • Springboot集成Kafka实现producer和consumer的示例代码

    本文介绍如何在springboot项目中集成kafka收发message. Kafka是一种高吞吐量的分布式发布订阅消息系统,有如下特性: 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能.高吞吐量:即使是非常普通的硬件Kafka也可以支持每秒数百万的消息.支持通过Kafka服务器和消费机集群来分区消息.支持Hadoop并行数据加载. 安装Kafka 因为安装kafka需要zookeeper的支持,所以Windows安装时需要将zookee

  • springboot集成fastDfs过程代码实例

    这篇文章主要介绍了springboot集成fastDfs过程代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 pom.xml 引入依赖 <dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.26.1-RELEASE</vers

  • springboot集成tkmapper及基本使用教程

    目录 一. 简介 二.集成mybatis&tkmapper 2.1.所需依赖 2.2.配置yml 2.3.主启动类上加注解扫描 三.基本使用 3.1.创建BaseMapper接口 3.2.entity实体层 3.3.mapper持久层 3.4.service服务层 四.测试 五.注意: 参考资料 SpringBoot使用tkmapper 1.加载依赖 2.引入逆向工程的插件 3.插件配置文件 4.错误 一. 简介 tkMapper是⼀个MyBatis插件,是在MyBatis的基础上提供了很多工具

随机推荐