MongoDB offers a number of indexes and query mechanisms to handle geospatial information, below are some of the features offered by the database :
- Surfaces
- Location Data
- Query Operations
- Geospatial indexes
- .....
More detailed information can be found at their website : MongoDB Geospatial queries
In this 3 part post we will be creating a sample REST API application using Spring Boot, Spring Data and MongoDB to determinate if a given "Interest Point" is within a certain distance of the provided coordinates
1. Setup
So let's get things started, we will be using Gradle as our build tool for this project, if you're not familiar with this build tool you can read the documentation
Below is the build file used to build our project, there is some noise in here that is related to IDE support as well as a few things needed to deploy this application in heroku which can be avoided but I've chosen to leave here for the sake of completion, the most interesting parts for us are the dependencies
buildscript { ext { springBootVersion = '1.5.2.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'spring-boot' jar { baseName = 'spring_mongodb_geospatial_api' version = '0.0.1-SNAPSHOT' } sourceCompatibility = 1.8 targetCompatibility = 1.8 repositories { mavenCentral() } task stage { dependsOn build } task wrapper(type: Wrapper) { gradleVersion = '2.6' } task copyToLib(type: Copy) { into "$buildDir/lib" from(configurations.compile) } stage.dependsOn(copyToLib) dependencies { compile('org.springframework.boot:spring-boot-starter-data-mongodb') { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' } compile('org.springframework.boot:spring-boot-starter-web') { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' } compile('org.springframework.boot:spring-boot-starter-actuator'){ exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' } compile('org.springframework.boot:spring-boot-starter-log4j') compileOnly ("org.projectlombok:lombok:1.16.14") testCompile('org.springframework.boot:spring-boot-starter-test'){ exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' } } eclipse { classpath { containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER') containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8' } }
Let's configure our spring boot application with the base info for our application to run (default profile, MongoDB info, etc.):
spring: application: name: spring_mongodb_geospatial_api profiles: active: dev --- spring: profiles: dev data: mongodb: host: localhost port: 27017 repositories: enabled: true
Let's now configure our bootstrap class :
package com.ufasoli.tutorials.mongogeospatial.ws; import com.fasterxml.jackson.databind.Module; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.geo.GeoJsonModule; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @Configuration @EnableAsync public class SpringMongoDBGeospatial { public static void main(String[] args) { SpringApplication.run(SpringMongoDBGeospatial.class, args); } //Register a custom Serializer/Deserializer for the geospatial information @Bean public Module registerGeoJsonModule(){ return new GeoJsonModule(); } }
This is a pretty standard spring boot class except for the fact that we are declaring a custom JSON Serializer/Deserializer for handling geospatial information
Finally let's create our data model :
package com.ufasoli.tutorials.mongogeospatial.ws.model; import lombok.Data; import java.util.Date; @Data public class Updatable { private Date createdAt; private Date updatedAt; private Long updatedTimestamp; }
package com.ufasoli.tutorials.mongogeospatial.ws.model; import lombok.Data; import org.hibernate.validator.constraints.NotBlank; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.geo.GeoJsonPoint; import org.springframework.data.mongodb.core.index.GeoSpatialIndexType; import org.springframework.data.mongodb.core.index.GeoSpatialIndexed; import org.springframework.data.mongodb.core.mapping.Document; import java.io.Serializable; import java.util.List; @Document @Data public class InterestPoint extends Updatable implements Serializable { @Id private String uuid; @NotBlank private String displayName; private String displayPhoto; private Listcategories; @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE) private GeoJsonPoint location; public InterestPoint() { } public InterestPoint(String uuid, String displayName) { this.uuid = uuid; this.displayName = displayName; } public InterestPoint(String uuid, String displayName, GeoJsonPoint location) { this.uuid = uuid; this.displayName = displayName; this.location = location; } }
package com.ufasoli.tutorials.mongogeospatial.ws.model; import java.io.Serializable; /** * Created by ufasoli */ public enum Category implements Serializable{ CAFE, BAR, RESTAURANT, MUSEUM, BANK, METRO_STATION, BUS_STATION, THEATRE, HOTEL }
And that it's for today, on the next part we will set up the web application and controllers
No comments:
Post a Comment