Versuchen Sie, über JPA von JavaEE (WildFly) auf MySQL GIS-Daten zuzugreifen. Dieses Mal werde ich die Informationen "Breite / Länge" verwenden, die als am häufigsten verwendet gelten. Die Felder der GIS-Daten werden in einer eigenen Binärdatei gespeichert. So können Sie darauf zugreifen ...
Erstellen wir einen Mechanismus zum Speichern von Positionsinformationen (Breiten- / Längengrad) über RestAPI und zur Entfernungsberechnung mithilfe der GIS-Funktion. Speziell 1: POST-Breiten- / Längengradinformationen zusammen mit der ID von der Rest-API 2: Speichern Sie GIS-Daten für die ID in MySQL 3: GET durch Angabe der ID aus der Rest-API 4: Holen Sie sich Datensätze von MySQL 5: Berechnen Sie die Entfernung zu sich selbst mithilfe der GIS-Funktion von MySQL 6: Sortieren und in aufsteigender Reihenfolge der Entfernung ausgeben Ich werde versuchen, den Prozess umzusetzen. (Die Umgebung ist WildFly14 + MySQL8.0.13 + Connector / J8.0.13)
GIS-Daten sind unter Java vom Typ Byte []. (Original binär ...) Die Konvertierung von Breite / Länge in Binär kann mit der Funktion "ST_GeomFromText (" POINT (Längsbreite) ") erfolgen. Es ist jedoch mühsam," createNativeQuery "aufzurufen, um die Binärdatei abzurufen und als Setter zu speichern Ich werde es mit generieren.
createtable.sql
CREATE TABLE `position` (
`id` varchar(64) NOT NULL,
`longitude` varchar(256) DEFAULT NULL,
`latitude` varchar(256) DEFAULT NULL,
`location` point GENERATED ALWAYS AS (st_geomfromtext(concat(_utf8mb4'POINT(',`longitude`,_utf8mb4' ',`latitude`,_utf8mb4')'))) STORED,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
Die Entität auf der Java-Seite dafür ist
Position.java
@Entity
@Table(name="position")
public class Position implements Serializable {
@Id
private String id;
private String latitude;
private String longitude;
@Column(
name = "location",
insertable = false,
updatable = false
)
private byte[] location;
private static final long serialVersionUID = 1L;
//Unter Getter und Setter
//Der Standort ist jedoch nur Getter
}
Es wird sein. Die generierte Spalte muss so verarbeitet werden, dass sie zum Zeitpunkt des Einfügens / Aktualisierens nicht geschrieben wird.
Der Code, der POST mit JAX-RS empfängt, lautet
API.java
@RequestScoped
@Path("/api")
@Produces("application/json")
@Consumes("application/json")
public class API {
@PersistenceContext(unitName = "geotest")
private EntityManager em;
@POST
@Path("{ID}")
@Transactional
public Response setPosition(@PathParam("ID") String ID, Point point) {
Position position = new Position();
position.setId(ID);
position.setLatitude(point.getLatitude());
position.setLongitude(point.getLongitude());
em.persist(position);
return Response.ok().status(201).build();
}
}
Point.java
public class Point {
private String Latitude;
private String Longitude;
//Unter Getter und Setter
}
Wenn Sie JSON auf "http: // .... / {ID}" setzen, werden die GIS-Daten für {ID} gespeichert.
Es wäre schön, wenn es eine Java-Version von Boost.Geometry gäbe, aber es gibt nichts, was nicht da ist ... Also habe ich beschlossen, die GIS-Funktion von MySQL von EntityManager über createNativeQuery zu verwenden.
GeoPoint.java
@Stateless
public class GeoPoint {
@PersistenceContext(unitName = "geotest")
private EntityManager em;
public String distance(byte[] pt1, byte[] pt2) {
return String.valueOf(em.createNativeQuery("select ST_Distance_Sphere(unhex('" + tohex(pt1) + "'), unhex('" + tohex(pt2) + "'))").getSingleResult());
}
private String tohex(byte[] bin) {
String p = "";
for(int i=0; i<bin.length; i++) {
p = p + String.format("%02x", bin[i]);
}
return p;
}
}
Ich mache viel Arbeit, um Binärdaten abzufragen und einzugeben, aber es kann einen saubereren Weg geben. Auf jeden Fall kann durch Einfügen von EJB das Ergebnis der Funktion "ST_Distance_Sphere" als Zeichenfolge empfangen werden.
Fügen Sie die GET-Methode zum Abrufen der Liste zur zuvor erstellten Registrierungs-API (API.java) hinzu.
API.java
@RequestScoped
@Path("/api")
@Produces("application/json")
@Consumes("application/json")
public class API {
@PersistenceContext(unitName = "geotest")
private EntityManager em;
@EJB
private GeoPoint geoPoint;
@GET
@Path("{ID}")
public Response getPosition(@PathParam("ID") String ID) {
Position mypos = em.find(Position.class, ID);
List<Position> pos = em.createQuery("select p from Position p", Position.class).getResultList();
List <Result> results = pos.stream()
.filter(p -> !p.getId().equals(mypos.getId()))
.map(p -> {
Result result = new Result();
result.setID(p.getId());
result.setDistance(Double.parseDouble(geoPoint.distance(mypos.getLocation(), p.getLocation())));
return result;
})
.sorted(comparing(Result::getDistance))
.collect(Collectors.toList());
return Response.ok(results).build();
}
@POST
@Path("{ID}")
@Transactional
public Response setPosition(@PathParam("ID") String ID, Point point) {
Position position = new Position();
position.setId(ID);
position.setLatitude(point.getLatitude());
position.setLongitude(point.getLongitude());
em.persist(position);
return Response.ok().status(201).build();
}
}
Result.java
public class Result {
private String ID;
private Double Distance;
//Unter Getter und Setter
}
result.setDistance (Double.parseDouble (geoPoint.distance (mypos.getLocation (), p.getLocation ()));
Teil ist die Verarbeitung in Bezug auf GIS.
GIS-Binärdaten werden der Entfernungsberechnung EJB "geoPoint.distance (byte [] pos1, byte [] pos2)" zugewiesen, die zuvor mit "mypos.getLocation ()" und "p.getLocation ()" erstellt wurde. ..
Ich habe versucht, den Breiten- und Längengrad der Station über die API zu registrieren.
Wenn Sie dagegen die Station http: // ..... / Osaka und die Methode Get auslösen, wird Folgendes zurückgegeben.
result.json
[
{
"ID": "Sannomiya Station",
"distance": 26586.663958186175
},
{
"ID": "Kyoto Station",
"distance": 39434.1794831947
},
{
"ID": "Nagoya Station",
"distance": 134598.65725231185
}
]
Es wird in der Reihenfolge der Nähe sortiert und zurückgegeben ♪
--GIS-Daten sind vom Typ Byte [] für Entität --Encode / Decord mit Koordinaten wie Längen- und Breitengrad ist praktisch für die generierte Spalte
Wenn Sie jedoch die GIS-Funktion verwenden, um eine große Anzahl von Berechnungen durchzuführen, kann sich der Aufwand für die Ausgabe von Abfragen erhöhen. Daher muss möglicherweise eine StoredFunction auf der MySQL-Seite erstellt und aufgerufen werden. Gibt es nicht eine Java-Version von Boost.Geometry ... www