spring java mongodb geo 位置搜索服务 示例

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();
    }
 
}


6、添加数据


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);


<think>嗯,用户想了解Java后端开发的学习路线和相关内容,包括教程、技能点和最佳实践。首先,我需要根据用户提供的引用内容来整理信息。引用1提到可以通过视频系统学习,适合初学者,比如在W3Cschool或编程狮APP上有相关课程。引用3强调了体系化的学习资料,涵盖95%以上的Java知识点。引用4则是一份2024年的最新学习路线,可能包含多个技术领域,比如数据库、框架、分布式系统等。 用户的需求很明确,他们需要一条清晰的学习路径,涵盖从基础到进阶的内容,以及最佳实践。我应该分阶段来组织内容,比如基础阶段、进阶阶段、框架学习、分布式系统、数据库、云原生、性能优化、安全、项目实战和持续学习。每个阶段需要列出关键技能点和推荐的学习资源,同时结合引用中的资料,比如引用1中的视频课程和引用3的体系化资料。 要注意用户可能是一个初学者,所以需要从Java基础开始,逐步深入。同时,最佳实践部分需要结合引用2,强调高效、可维护和安全的开发实践。此外,项目实战部分很重要,引用3提到有零基础和进阶课程,可以推荐真实项目案例。 还要确保回答结构清晰,分点列出,帮助用户逐步学习。可能的问题包括学习资源推荐、如何选择框架、性能优化方法等,这些都需要在相关问题部分体现。需要检查引用标记是否正确,确保每个引用对应正确的内容来源。最后,语言要简洁明了,使用中文,避免技术术语过于复杂,适合不同层次的学习者。</think>### Java 后端开发学习路线与技能点解析 #### 一、学习路线分阶段规划 1. **基础阶段** - **Java核心语法**:掌握变量、流程控制、集合框架(如$List<T>$、$Map<K,V>$)、IO流等 - **面向对象编程**:类与对象、继承、多态、接口设计原则 - **JVM基础**:内存模型、垃圾回收机制、字节码文件结构[^3] 2. **进阶阶段** - **并发编程**:线程池(如$ExecutorService$)、锁机制($synchronized$、$ReentrantLock$)、原子类 - **网络编程**:TCP/UDP协议、NIO模型($Channel$、$Buffer$) - **设计模式**:单例模式(双重检查锁)、工厂模式、观察者模式[^4] 3. **框架与工具** - **Spring生态**:IoC容器($BeanFactory$)、AOP(切面编程)、Spring Boot自动配置原理 - **ORM框架**:MyBatis动态SQL($<if>$标签)、Hibernate缓存机制 - **构建工具**:Maven依赖管理($pom.xml$)、Gradle多模块配置 #### 二、关键技能点详解 1. **数据库技术栈** - **MySQL优化**:索引B+树结构、Explain执行计划、分库分表策略 - **Redis应用**:分布式锁($SETNX$命令)、缓存穿透/雪崩解决方案 - **NoSQL扩展**:MongoDB聚合管道、Elasticsearch倒排索引 2. **分布式系统** - **微服务架构**:Spring Cloud Netflix($Eureka$注册中心)、Alibaba Nacos配置中心 - **消息队列**:Kafka分区策略($Partitioner$)、RocketMQ事务消息 - **分布式事务**:Seata AT模式、TCC补偿机制[^2] 3. **云原生技术** - **容器化部署**:Dockerfile编写、Kubernetes Pod调度策略 - **服务网格**:Istio流量管理($VirtualService$配置) - **Serverless**:函数计算冷启动优化 #### 三、最佳实践指南 1. **代码规范** - 遵循阿里巴巴Java开发手册(如方法参数不超过5个) - 使用Checkstyle进行代码静态检查[^2] 2. **性能调优** - **JVM参数**:设置$\-Xmx$和$\-Xms$保持堆内存一致 - **SQL优化**:避免$SELECT *$,使用覆盖索引 - **压测工具**:JMeter分布式压测配置 3. **安全防护** - 防止SQL注入:MyBatis使用$#{}$占位符 - XSS防御:采用Jackson的$@JsonFormat$过滤特殊字符 - OAuth2.0授权:配置Spring Security的$ResourceServerConfigurer$ #### 四、学习资源推荐 1. **体系化课程** - 编程狮APP《Java架构师成长之路》含分布式事务实战 - 极客时间《Java核心技术36讲》深入解析JVM 2. **项目实战** - 电商系统:实现秒杀系统的库存扣减(Redis+Lua原子操作) - 物流系统:基于GeoHash算法的位置服务开发 3. **文档与社区** - Spring官方文档(最新6.x特性) - GitHub trending项目分析(如Spring Authorization Server) ```java // 示例Spring Boot缓存注解使用 @Cacheable(value = "users", key = "#userId") public User getUserById(String userId) { return userRepository.findById(userId).orElse(null); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值