地理位置服务:MongoDB实现 - 使用样例
地理位置服务:MongoDB实现 - 使用样例
1 更新用户地理位置
客户端检测用户的地理位置,当变化大于500米时或每隔5分钟,向服务端发送地理位置。
dubbo - pojo
package com.tanhua.dubbo.server.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "user_location")
@CompoundIndex(name = "location_index", def = "{'location': '2dsphere'}")
public class UserLocation implements java.io.Serializable{
private static final long serialVersionUID = 4508868382007529970L;
@Id
private ObjectId id;
@Indexed
private Long userId; //用户id
private GeoJsonPoint location; //x:经度 y:纬度
private String address; //位置描述
private Long created; //创建时间
private Long updated; //更新时间
private Long lastUpdated; //上次更新时间
}
dubbo - 接口
package com.tanhua.dubbo.server.api;
public interface UserLocationApi {
/**
* 更新用户地理位置
*
* @return
*/
String updateUserLocation(Long userId, Double longitude, Double latitude, String address);
}
dubbo - 实现
package com.tanhua.dubbo.server.api;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.dubbo.server.pojo.UserLocation;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
@Service(version = "1.0.0")
public class UserLocationApiImpl implements UserLocationApi {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public String updateUserLocation(Long userId, Double longitude, Double latitude, String address) {
UserLocation userLocation = new UserLocation();
userLocation.setAddress(address);
userLocation.setLocation(new GeoJsonPoint(longitude, latitude));
userLocation.setUserId(userId);
Query query = Query.query(Criteria.where("userId").is(userLocation.getUserId()));
UserLocation ul = this.mongoTemplate.findOne(query, UserLocation.class);
if (ul == null) {
//新增
userLocation.setId(ObjectId.get());
userLocation.setCreated(System.currentTimeMillis());
userLocation.setUpdated(userLocation.getCreated());
userLocation.setLastUpdated(userLocation.getCreated());
this.mongoTemplate.save(userLocation);
return userLocation.getId().toHexString();
} else {
//更新
Update update = Update
.update("location", userLocation.getLocation())
.set("updated", System.currentTimeMillis())
.set("lastUpdated", ul.getUpdated());
this.mongoTemplate.updateFirst(query, update, UserLocation.class);
}
return ul.getId().toHexString();
}
}
server - APP服务接口实现
package com.tanhua.server.controller;
import com.tanhua.server.service.BaiduService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("baidu")
public class BaiduController {
@Autowired
private BaiduService baiduService;
/**
* 更新位置
*
* @param param
* @return
*/
@PostMapping("location")
public ResponseEntity<Void> updateLocation(@RequestBody Map<String, Object> param) {
try {
Double longitude = Double.valueOf(param.get("longitude").toString());
Double latitude = Double.valueOf(param.get("latitude").toString());
String address = param.get("addrStr").toString();
Boolean bool = this.baiduService.updateLocation(longitude, latitude, address);
if (bool) {
return ResponseEntity.ok(null);
}
} catch (Exception e) {
e.printStackTrace();
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
package com.tanhua.server.service;
import com.alibaba.dubbo.config.annotation.Reference;
import com.tanhua.dubbo.server.api.UserLocationApi;
import com.tanhua.server.pojo.User;
import com.tanhua.server.utils.UserThreadLocal;
import org.springframework.stereotype.Service;
@Service
public class BaiduService {
@Reference(version = "1.0.0")
private UserLocationApi userLocationApi;
public Boolean updateLocation(Double longitude, Double latitude, String address) {
try {
User user = UserThreadLocal.get();
this.userLocationApi.updateUserLocation(user.getId(), longitude, latitude, address);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
2 搜附近功能
在首页中点击“搜附近”可以搜索附近的好友,效果如下:
dubbo - 接口
package com.tanhua.dubbo.server.api;
import com.tanhua.dubbo.server.vo.UserLocationVo;
import java.util.List;
public interface UserLocationApi {
/**
* 更新用户地理位置
*
* @return
*/
String updateUserLocation(Long userId, Double longitude, Double latitude, String address);
/**
* 查询用户地理位置
*
* @param userId
* @return
*/
UserLocationVo queryByUserId(Long userId);
/**
* 根据地理位置查询用户
*
* @param longitude
* @param latitude
* @return
*/
List<UserLocationVo> queryUserFromLocation(Double longitude, Double latitude, Integer range);
}
由于UserLocation不能序列化,所以要再定义UserLocationVo进行返回数据。
package com.tanhua.dubbo.server.vo;
import com.tanhua.dubbo.server.pojo.UserLocation;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserLocationVo implements java.io.Serializable {
private static final long serialVersionUID = 4133419501260037769L;
private String id;
private Long userId; //用户id
private Double longitude; //经度
private Double latitude; //维度
private String address; //位置描述
private Long created; //创建时间
private Long updated; //更新时间
private Long lastUpdated; //上次更新时间
public static final UserLocationVo format(UserLocation userLocation) {
UserLocationVo userLocationVo = new UserLocationVo();
userLocationVo.setAddress(userLocation.getAddress());
userLocationVo.setCreated(userLocation.getCreated());
userLocationVo.setId(userLocation.getId().toHexString());
userLocationVo.setLastUpdated(userLocation.getLastUpdated());
userLocationVo.setUpdated(userLocation.getUpdated());
userLocationVo.setUserId(userLocation.getUserId());
userLocationVo.setLongitude(userLocation.getLocation().getX());
userLocationVo.setLatitude(userLocation.getLocation().getY());
return userLocationVo;
}
public static final List<UserLocationVo> formatToList(List<UserLocation> userLocations) {
List<UserLocationVo> list = new ArrayList<>();
for (UserLocation userLocation : userLocations) {
list.add(format(userLocation));
}
return list;
}
}
dubbo - 实现
package com.tanhua.dubbo.server.api;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.dubbo.server.pojo.UserLocation;
import com.tanhua.dubbo.server.vo.UserLocationVo;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import java.util.List;
@Service(version = "1.0.0")
public class UserLocationApiImpl implements UserLocationApi {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public UserLocationVo queryByUserId(Long userId) {
Query query = Query.query(Criteria.where("userId").is(userId));
UserLocation userLocation = this.mongoTemplate.findOne(query, UserLocation.class);
if (userLocation != null) {
return UserLocationVo.format(userLocation);
}
return null;
}
@Override
public List<UserLocationVo> queryUserFromLocation(Double longitude, Double latitude, Integer range) {
//中心点
GeoJsonPoint geoJsonPoint = new GeoJsonPoint(longitude, latitude);
//转换为2dsphere的距离
Distance distance = new Distance(range / 1000, Metrics.KILOMETERS);
//画一个圆
Circle circle = new Circle(geoJsonPoint, distance);
Query query = Query.query(Criteria.where("location").withinSphere(circle));
return UserLocationVo.formatToList(this.mongoTemplate.find(query, UserLocation.class));
}
}
dubbo - 测试
坐标查询: http://api.map.baidu.com/lbsapi/getpoint/
package com.tanhua.dubbo.server.api;
import com.tanhua.dubbo.server.vo.UserLocationVo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class TestUserLocationApi {
@Autowired
private UserLocationApi userLocationApi;
@Test
public void testQuery() {
Double longitude = 121.512253;
Double latitude = 31.24094;
Integer range = 1000;
List<UserLocationVo> userLocationVos = this.userLocationApi.queryUserFromLocation(longitude, latitude, range);
for (UserLocationVo userLocationVo : userLocationVos) {
System.out.println(userLocationVo);
}
}
@Test
public void testSaveTestData() {
this.userLocationApi.updateUserLocation(1L, 121.512253,31.24094, "金茂大厦");
this.userLocationApi.updateUserLocation(2L, 121.506377, 31.245105, "东方明珠广播电视塔");
this.userLocationApi.updateUserLocation(10L, 121.508815,31.243844, "陆家嘴地铁站");
this.userLocationApi.updateUserLocation(12L, 121.511999,31.239185, "上海中心大厦");
this.userLocationApi.updateUserLocation(25L, 121.493444,31.240513, "上海市公安局");
this.userLocationApi.updateUserLocation(27L, 121.494108,31.247011, "上海外滩美术馆");
this.userLocationApi.updateUserLocation(30L, 121.462452,31.253463, "上海火车站");
this.userLocationApi.updateUserLocation(32L, 121.81509,31.157478, "上海浦东国际机场");
this.userLocationApi.updateUserLocation(34L, 121.327908,31.20033, "虹桥火车站");
this.userLocationApi.updateUserLocation(38L, 121.490155,31.277476, "鲁迅公园");
this.userLocationApi.updateUserLocation(40L, 121.425511,31.227831, "中山公园");
this.userLocationApi.updateUserLocation(43L, 121.594194,31.207786, "张江高科");
}
}
server - controller
/**
* 搜附近
*
* @param gender
* @param distance
* @return
*/
@GetMapping("search")
public ResponseEntity<List<NearUserVo>> queryNearUser(@RequestParam(value = "gender", required = false) String gender,
@RequestParam(value = "distance", defaultValue = "2000") String distance) {
try {
List<NearUserVo> list = this.todayBestService.queryNearUser(gender, distance);
return ResponseEntity.ok(list);
} catch (Exception e) {
e.printStackTrace();
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
package com.tanhua.server.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NearUserVo {
private Long userId;
private String avatar;
private String nickname;
}
service
@Reference(version = "1.0.0")
private UserLocationApi userLocationApi;
public List<NearUserVo> queryNearUser(String gender, String distance) {
User user = UserThreadLocal.get();
// 查询当前用户的位置信息
UserLocationVo userLocationVo = this.userLocationApi.queryByUserId(user.getId());
Double longitude = userLocationVo.getLongitude();
Double latitude = userLocationVo.getLatitude();
// 根据当前用户的位置信息查询附近的好友
List<UserLocationVo> userLocationList = this.userLocationApi
.queryUserFromLocation(longitude, latitude, Integer.valueOf(distance));
if (CollectionUtils.isEmpty(userLocationList)) {
return Collections.emptyList();
}
List<Long> userIds = new ArrayList<>();
for (UserLocationVo locationVo : userLocationList) {
userIds.add(locationVo.getUserId());
}
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.in("user_id", userIds);
if (StringUtils.equalsIgnoreCase(gender, "man")) {
queryWrapper.in("sex", SexEnum.MAN);
} else if (StringUtils.equalsIgnoreCase(gender, "woman")) {
queryWrapper.in("sex", SexEnum.WOMAN);
}
List<UserInfo> userInfoList = this.userInfoService.queryUserInfoList(queryWrapper);
List<NearUserVo> nearUserVoList = new ArrayList<>();
for (UserLocationVo locationVo : userLocationList) {
if (locationVo.getUserId().longValue() == user.getId().longValue()) {
// 排除自己
continue;
}
for (UserInfo userInfo : userInfoList) {
if (locationVo.getUserId().longValue() == userInfo.getUserId().longValue()) {
NearUserVo nearUserVo = new NearUserVo();
nearUserVo.setUserId(userInfo.getUserId());
nearUserVo.setAvatar(userInfo.getLogo());
nearUserVo.setNickname(userInfo.getNickName());
nearUserVoList.add(nearUserVo);
break;
}
}
}
return nearUserVoList;
}