Essayez d'accéder aux données MySQL GIS via JPA de JavaEE (WildFly). Cette fois, j'utiliserai les informations de "latitude / longitude" qui sont considérées comme étant le plus souvent utilisées. Les champs de données SIG sont stockés dans leur propre binaire, alors comment y accéder ...
Créons un mécanisme pour stocker les informations de position (latitude / longitude) via RestAPI et pour le calcul de distance à l'aide de la fonction SIG. En particulier 1: informations de latitude / longitude POST avec ID de l'API Rest 2: Enregistrer les données SIG pour l'ID dans MySQL 3: GET en spécifiant l'ID de l'API Rest 4: Obtenez des enregistrements de MySQL 5: Calculez la distance à vous-même en utilisant la fonction SIG de MySQL 6: Tri et sortie par ordre croissant de distance Je vais essayer de mettre en œuvre le processus. (L'environnement est WildFly14 + MySQL8.0.13 + Connector / J8.0.13)
Les données SIG sont de type octet [] sur Java. (Binaire d'origine ...)
La conversion de latitude / longitude en binaire peut être faite avec la fonction ST_GeomFromText ('POINT (latitude longitudinale)')
, mais il est difficile d'appeler createNativeQuery pour obtenir le binaire et l'enregistrer en tant que setter
, donc GenerateColumn Je vais le générer avec.
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
L'entité du côté Java pour cela est
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;
//Ci-dessous Getter et Setter
//Cependant, l'emplacement est uniquement Getter
}
Ce sera. Il est nécessaire de traiter la colonne générée pour qu'elle ne soit pas écrite au moment de l'insertion / mise à jour.
Le code qui reçoit POST avec JAX-RS est
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;
//Ci-dessous Getter et Setter
}
POSTER JSON sur http: // .... / {ID}
sauvegardera les données SIG pour {ID}.
Ce serait bien s'il y avait une version Java de Boost.Geometry, mais il n'y a rien qui n'y soit pas ... J'ai donc décidé d'utiliser la fonction SIG de MySQL d'EntityManager via createNativeQuery.
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;
}
}
Je fais beaucoup de travail pour interroger et taper des données binaires, mais il peut y avoir un moyen plus propre.
Quoi qu'il en soit, en injectant avec EJB, le résultat de la fonction ST_Distance_Sphere
peut être reçu sous forme de chaîne de caractères.
Ajoutez la méthode GET pour obtenir la liste dans l'API d'inscription (API.java) créée précédemment.
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;
//Ci-dessous Getter et Setter
}
result.setDistance (Double.parseDouble (geoPoint.distance (mypos.getLocation (), p.getLocation ())));
une partie est le traitement lié au SIG.
Les données binaires SIG sont affectées à l'EJB de calcul de distance geoPoint.distance (byte [] pos1, byte [] pos2)
créé précédemment avec mypos.getLocation ()
et p.getLocation ()
. ..
J'ai essayé d'enregistrer la latitude et la longitude de la station via l'API.
D'un autre côté, si vous lancez la station http: // ..... / Osaka et la méthode Get, ce qui suit sera retourné.
result.json
[
{
"ID": "Gare de Sannomiya",
"distance": 26586.663958186175
},
{
"ID": "Gare de Kyoto",
"distance": 39434.1794831947
},
{
"ID": "Gare de Nagoya",
"distance": 134598.65725231185
}
]
Il est trié par ordre de proximité et renvoyé ♪
Cependant, si vous utilisez la fonction SIG pour effectuer une grande quantité de calculs, la surcharge liée à l'émission des requêtes peut augmenter, il peut donc être nécessaire de créer une fonction StoredFunction côté MySQL et de l'appeler. N'existe-t-il pas une version Java de Boost.Geometry ... www