1、配置 pom.xml,在原有的spring项目中添加以下2个即可。
<!-- mongo db 驱动-->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.2.2</version>
</dependency>
<!-- spring-data-mongodb -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.9.2.RELEASE</version>
</dependency>
2、配置 spring-data-mongo.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- Default bean name is 'mongo' -->
<mongo:mongo host="localhost" port="27017"/>
<!-- Offers convenience methods and automatic mapping between MongoDB JSON documents and your domain classes. -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo"/>
<constructor-arg name="databaseName" value="test"/>
</bean>
</beans>
3、mongodb 父接口类
package com.zjp.cache;
import java.util.List;
import com.mongodb.DBObject;
/**
* mongodb 父接口类
* @author babylon
* @version 1.1
* @date 2016年7月12日-下午1:22:23
*/
public interface MongoDao {
public DBObject findOne(String collection, DBObject query, DBObject fields);
public List<DBObject> find(String collection, DBObject query, DBObject fields, DBObject orderBy, int pageNum, int pageSize);
public List<DBObject> find(String collection, DBObject query, DBObject fields, DBObject orderBy, int limit);
public void delete(String collection, DBObject dbObject);
public void save(String collection, DBObject dbObject);
public void update(String collection, DBObject query, DBObject update, boolean upsert, boolean multi);
public Long count(String collection, DBObject query);
public List<?> distinct(String collection, String key, DBObject query);
}
4、Mondodb 地址运算 接口类
package com.zjp.cache;
import com.mongodb.DBObject;
import java.util.List;
/**
* Mondodb 地址运算 接口类
*
* @author babylon
* @version 1.1
* @date 2016年7月12日-下午1:42:06
*/
public interface MongoGeoDao extends MongoDao{
/**
* 聚合查询,查询一个点附近的点,并返回每一个点到该中心点的距离,在坐标表分片的情况下$nearSphere不支持,
* 可以使用该方法进行查询
* @param collection 集合名称
* @param query 查询条件
* @param point 中心点坐标
* @param limit 返回记录数量限制
* @param maxDistance 最大距离
* @return 非NULL的list
*/
public List<DBObject> geoNear(String collection, DBObject query, Point point,int limit, long maxDistance) ;
/**
* 查询在圆形区域内的坐标点,需要指定中心点坐标和半径,半径单位是米
*
* @param collection 集合名称
* @param locationField 坐标字段
* @param center 中心点坐标[经度,纬度]
* @param radius 半径 单位:米
* @param fields 查询字段
* @param query 查询条件
* @param limit 返回记录限制数量
* @return 非NULL的list
*/
public List<DBObject> withinCircle(String collection,String locationField, Point center, long radius,
DBObject fields, DBObject query, int limit);
/**
* 指定一个点,返回该点附近的坐标点且是由近到远,$nearSphere 需要建立索引2dsphere 或者2d,并且支持GeoJSON和一般坐标对
* 注意: $nearSphere在分片的集群中无效,使用geoNear
*
* @param collection 集合名称
* @param locationField 坐标字段
* @param center 中心点坐标[经度,纬度]
* @param minDistance 最近距离
* @param maxDistance 最远距离
* @param query 查询条件
* @param fields 查询字段
* @param limit 返回记录限制数量
* @return 非NULL的list
*/
public List<DBObject> nearSphere(String collection, String locationField, Point center, long minDistance, long maxDistance, DBObject query, DBObject fields, int limit);
/**
* 查询位于指定一个封闭多边形内的所有坐标点,给定的多边形坐标点必须首位相接形成封闭的多边形
* 如三角形
* final LinkedList<double[]> polygon = new LinkedList<>();
* polygon.addLast(new double[] { 121.36, 31.18 });
* polygon.addLast(new double[] { 121.35, 31.36 });
* polygon.addLast(new double[] { 121.39, 31.17 });
* polygon.addLast(new double[] { 121.36, 31.18 });
*
* MongoDB将多边形的边界也作为查询形状的一部分
* @param collection 集合名称
* @param locationField 坐标字段
* @param polygon 多边形坐标
* @param fields 查询字段
* @param query 查询条件
* @param limit 返回记录限制数量
* @return 非NULL的list
*/
public List<DBObject> withinPolygon(String collection,String locationField,
List<double[]> polygon,DBObject fields,DBObject query,int limit);
/**
* 查询位于指定多个封闭多边形内的所有坐标点,给定的多边形坐标点必须首位相接形成封闭的多边形
* @param collection 集合名称
* @param locationField 坐标字段
* @param polygons 多边形坐标 数组
* @param fields 查询字段
* @param query 查询条件
* @param limit 返回记录限制数量
* @return 非NULL的list
*/
public List<DBObject> withinMultiPolygon(String collection,String locationField,
List<List<double[]>> polygons,DBObject fields,DBObject query,int limit);
/**
* 在矩形区域内查找坐标点,该方法仅仅在2d索引是支持,在2dsphere中不支持
* @param collection 集合名称
* @param locationField 坐标字段
* @param bottomLeft 左下角
* @param upperRight 右上角
* @param fields 查询字段
* @param query 查询条件
* @param limit 返回记录限制数量
* @return 非NULL的list
*/
@Deprecated
public List<DBObject> withinBox(String collection, String locationField,
Point bottomLeft, Point upperRight, DBObject fields, DBObject query,int limit);
}
5、mongodb 服务实现类
package com.zjp.service.impl;
import com.mongodb.AggregationOptions;
import com.mongodb.BasicDBObject;
import com.mongodb.Cursor;
import com.mongodb.DBObject;
import com.zjp.cache.MongoGeoDao;
import com.zjp.cache.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* mongodb 服务实现类
*
* @author babylon
* @version 1.1
* @date 2016年7月12日-下午1:36:50
*/
@Repository
public class MongoDaoImpl implements MongoGeoDao {
private static Logger logger = LoggerFactory.getLogger(MongoDaoImpl.class);
@Autowired
private MongoTemplate mongoTemplate;
@Override
public DBObject findOne(String collection, DBObject query, DBObject fields) {
return mongoTemplate.getCollection(collection).findOne(query, fields);
}
@Override
public List<DBObject> find(String collection, DBObject query, DBObject fields, DBObject orderBy, int pageNum, int pageSize) {
List<DBObject> list = new ArrayList<>();
Cursor cursor = mongoTemplate.getCollection(collection).find(query, fields).skip((pageNum - 1) * pageSize).limit(pageSize).sort(orderBy);
while (cursor.hasNext()) {
list.add(cursor.next());
}
return list.size() > 0 ? list : null;
}
@Override
public List<DBObject> find(String collection, DBObject query, DBObject fields, DBObject orderBy, int limit) {
List<DBObject> list = new ArrayList<>();
Cursor cursor = mongoTemplate.getCollection(collection).find(query, fields).sort(orderBy).limit(limit);
while (cursor.hasNext()) {
list.add(cursor.next());
}
return list.size() > 0 ? list : null;
}
@Override
public void delete(String collection, DBObject dbObject) {
mongoTemplate.getCollection(collection).remove(dbObject);
}
@Override
public void save(String collection, DBObject dbObject) {
mongoTemplate.getCollection(collection).save(dbObject);
}
@Override
public void update(String collection, DBObject query, DBObject update, boolean upsert, boolean multi) {
mongoTemplate.getCollection(collection).update(query, update, upsert, multi);
}
@Override
public Long count(String collection, DBObject query) {
return mongoTemplate.getCollection(collection).count(query);
}
@Override
public List<?> distinct(String collection, String key, DBObject query) {
return mongoTemplate.getCollection(collection).distinct(key, query);
}
@Override
public List<DBObject> geoNear(String collection, DBObject query, Point point, int limit, long maxDistance) {
if(query==null)
query = new BasicDBObject();
List<DBObject> pipeLine = new ArrayList<>();
BasicDBObject aggregate = new BasicDBObject("$geoNear",
new BasicDBObject("near",new BasicDBObject("type","Point").append("coordinates",new double[]{118.783799, 31.979234}))
.append("distanceField","dist.calculated")
.append("query", new BasicDBObject())
.append("num", 5)
.append("maxDistance", 5000)
.append("spherical",true)
);
pipeLine.add(aggregate);
Cursor cursor=mongoTemplate.getCollection(collection).aggregate(pipeLine, AggregationOptions.builder().build());
List<DBObject> list = new LinkedList<>();
while (cursor.hasNext()) {
list.add(cursor.next());
}
return list;
}
@Override
public List<DBObject> withinCircle(String collection,String locationField, Point center,
long radius, DBObject fields, DBObject query, int limit) {
LinkedList<Object> circle = new LinkedList<>();
//Set the center coordinate
circle.addLast(new double[]{center.getLng(),center.getLat()});
//Set the radius. unit:meter
circle.addLast(radius/6378137.0);
if(query==null)
query = new BasicDBObject();
query.put(locationField, new BasicDBObject("$geoWithin", new BasicDBObject("$centerSphere", circle)));
logger.info("withinCircle:{}",query.toString());
return mongoTemplate.getCollection(collection).find(query, fields).limit(limit).toArray();
}
@Override
public List<DBObject> nearSphere(String collection, String locationField, Point center,
long minDistance, long maxDistance, DBObject query, DBObject fields, int limit) {
if(query==null)
query = new BasicDBObject();
query.put(locationField,
new BasicDBObject("$nearSphere",
new BasicDBObject("$geometry",
new BasicDBObject("type","Point")
.append("coordinates",new double[]{center.getLng(),center.getLat()}))
.append("$minDistance",minDistance)
.append("$maxDistance",maxDistance)
));
logger.info("nearSphere:{}",query.toString());
return mongoTemplate.getCollection(collection).find(query, fields).limit(limit).toArray();
}
@Override
public List<DBObject> withinPolygon(String collection, String locationField,
List<double[]> polygon, DBObject fields, DBObject query, int limit) {
if(query==null)
query = new BasicDBObject();
List<List<double[]>> polygons = new LinkedList<>();
polygons.add(polygon);
query.put(locationField, new BasicDBObject("$geoWithin",
new BasicDBObject("$geometry",
new BasicDBObject("type","Polygon")
.append("coordinates",polygons))));
logger.info("withinPolygon:{}",query.toString());
return mongoTemplate.getCollection(collection).find(query, fields).limit(limit).toArray();
}
@Override
public List<DBObject> withinMultiPolygon(String collection, String locationField, List<List<double[]>> polygons, DBObject fields, DBObject query, int limit) {
if(query==null)
query = new BasicDBObject();
List<List<List<double[]>>> list = new LinkedList<>();
for (List<double[]> polygon : polygons) {
List<List<double[]>> temp = new LinkedList<>();
temp.add(polygon);
list.add(temp);
}
query.put(locationField, new BasicDBObject("$geoWithin",
new BasicDBObject("$geometry",
new BasicDBObject("type","MultiPolygon")
.append("coordinates",list))));
logger.info("withinMultiPolygon:{}",query.toString());
return mongoTemplate.getCollection(collection).find(query, fields).limit(limit).toArray();
}
@Override
public List<DBObject> withinBox(String collection, String locationField, Point bottomLeft, Point upperRight, DBObject fields, DBObject query, int limit) {
if(query==null)
query = new BasicDBObject();
LinkedList<double[]> box = new LinkedList<>();
box.add(new double[]{bottomLeft.getLng(), bottomLeft.getLat()});
box.add(new double[]{upperRight.getLng(), upperRight.getLat()});
query.put(locationField, new BasicDBObject("$geoWithin", new BasicDBObject("$box", box)));
logger.info("withinBox:{}",query.toString());
return mongoTemplate.getCollection(collection).find(query, fields).limit(limit).toArray();
}
}
db.point.test.insert({"address" : "南京 禄口国际机场","loc" : { "type": "Point", "coordinates": [118.783799,31.979234]}})
db.point.test.insert({"address" : "南京 浦口公园","loc" : { "type": "Point", "coordinates": [118.639523,32.070078]}})
db.point.test.insert({"address" : "南京 火车站","loc" : { "type": "Point", "coordinates": [118.803032,32.09248]}})
db.point.test.insert({"address" : "南京 新街口","loc" : { "type": "Point", "coordinates": [118.790611,32.047616]}})
db.point.test.insert({"address" : "南京 张府园","loc" : { "type": "Point", "coordinates": [118.790427,32.03722]}})
db.point.test.insert({"address" : "南京 三山街","loc" : { "type": "Point", "coordinates": [118.788135,32.029064]}})
db.point.test.insert({"address" : "南京 中华门","loc" : { "type": "Point", "coordinates": [118.781161,32.013023]}})
db.point.test.insert({"address" : "南京 安德门","loc" : { "type": "Point", "coordinates": [118.768964,31.99646]}})
7、必须加索引 (为什么:https://docs.mongodb.com/manual/reference/operator/aggregation/geoNear/)
db.point.test.ensureIndex( { loc : "2dsphere" } )
8、调用实例
@Autowired
private MongoDaoImpl mongoDao;
DBObject query = new BasicDBObject();
Point point = new Point();
point.setLng(118.783799);
point.setLat(31.979234);
int limit = 5;
Long maxDistance = 5000L; // 米
List<DBObject> list = mongoDao.geoNear("point.test", query, point, limit, maxDistance);
for(DBObject obj : list)
System.out.println(obj);