SET キー ID [フィールド名 値 ...] [EX 秒] [NX|XX] (OBJECT geojson )|(POINT lat lon z)|(BOUNDS minlat minlon maxlat maxlon)|(HASH geohash)|(STRING 値)
#set コマンドは、redis の # と同等です。 ##hash
コマンドの key
と id
の組み合わせでもありますが、違いは、Tile38 の set
コマンドは、より多くのその他の属性も保持できることです。 FIELD
フィールドのカスタマイズや EX
有効期間の設定など、この構文に役立つ java api## を設計する必要があります。開発者が Tile38 をより適切に使用できるようになります。
文法分析
SET
、このキーワードを別個の部分として扱います;2. 2 番目の部分は
key id [FIELD name value ...] [EX 秒] [NX| XX]
3. 3 番目の部分は、最終的なターゲット データ オブジェクトです:
(OBJECT geojson)|(POINT lat lon z) |(BOUNDS minlat minlon maxlat maxlon)|(HASH geohash)|(STRING 値)
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; } }
インターフェイスを実装する必要があります。コマンドの開始キーワードが 2 つ以上の単語の場合は、それらをアンダースコアで接続します。バイトに変換する場合は、アンダースコアをスペースで置き換えることができます。
2. コマンドの 2 番目の部分を特定のクラスに抽象化し、関連フィールドを通じてそれを記述します: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:java;">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);
}
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
上記では、ビルダーの設計モードを使用してすべてのパラメータを配置します。 SetOpts クラスを使用すると、開発者は SetOpts オブジェクトの構築を通じてコマンド内のパラメーターを柔軟に制御できます。
3. 3 番目の部分のさまざまなデータ オブジェクトをさまざまなタイプに変換する必要があります:
POINT データ型
Point のキー フィールドは経度と緯度です。さらに、追加フィールド
zpublic 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 は長方形であり、そのキー フィールドは左下隅と右上隅です。左下隅と右上隅を表すには、座標 1 と座標 2 を使用します。 ;
@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 は実際には別の文字列ですが、開発者が使用できるようにカプセル化しています;
@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 は実際には GeoJSON データです。このタイプのデータは少し複雑です。全部で 6 つのタイプがあります。詳しく知りたい方は、ここを参照してください。 geojson.org/
Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon
@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(); } } }
ここで、大きなクラスに複数のメソッドを作成し、各メソッドに対応するタイプのビルダーを配置します。この場合、これは、このクラスでオブジェクトを作成する方法が 6 つあることと同等であり、各ビルダーは対応するオブジェクトを構築することのみを担当します。
以下は 6 つのビルダーのコードです。各オブジェクトは最も基本的な BaseGeoJson に基づいて構築されています。パブリック フィールド タイプと追加のメタ フィールドは BaseGeoJson から抽出されます。各タイプの違いは座標にあります。ポイントの数やレベルが異なるため、それぞれのタイプの特性に応じて、次のようなコード設計になります。
// 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 } }
最後に、基本クラスの要素を追加します。
public abstract class Element implements Serializable { public abstract List<String> commandArgs(); }
使い方
We All データ型は特定のコード設計に変換されます。使用方法を見てみましょう:
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); }
以上がSpringboot統合タイルクライアントのSetコマンドの実装方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。