课程说明
- 上报地位位置
- 实现搜附近功能
- 实现探花功能
- 用户基本信息维护
1、上报地理位置
当客户端检测用户的地理位置,当变化大于500米时或每隔5分钟,向服务端上报地理位置。
用户的地理位置存储到Elasticsearch中,需要使用环境提供的ES集群,如下:
1.1、dubbo服务
用户地理位置的服务独立一个新的工程来实现,名字为:my-tanhua-dubbo-es。
1.1.1、创建工程
pom.ml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>my-tanhua-dubbo</artifactId>
<groupId>cn.itcast.tanhua</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-tanhua-dubbo-es</artifactId>
<dependencies>
<!--引入interface依赖-->
<dependency>
<groupId>cn.itcast.tanhua</groupId>
<artifactId>my-tanhua-dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!--dubbo的springboot支持-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!--dubbo框架-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!--zk依赖-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
</project>
application.properties文件:
# Spring boot application
spring.application.name = itcast-tanhua-dubbo-es
# dubbo 扫描包配置
dubbo.scan.basePackages = com.tanhua.dubbo.es
dubbo.application.name = dubbo-provider-es
#dubbo 对外暴露的端口信息
dubbo.protocol.name = dubbo
dubbo.protocol.port = 20882
#dubbo注册中心的配置
dubbo.registry.address = zookeeper://192.168.31.81:2181
dubbo.registry.client = zkclient
dubbo.registry.timeout = 60000
#ES集群配置
spring.data.elasticsearch.cluster-name=es-tanhua-cluster
spring.data.elasticsearch.cluster-nodes=192.168.31.81:9300,192.168.31.81:9301,192.168.31.81:9302
启动类:
package com.tanhua.dubbo.es;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
@SpringBootApplication(exclude = {
MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) //排除mongo的自动配置
public class ESApplication {
public static void main(String[] args) {
SpringApplication.run(ESApplication.class, args);
}
}
1.1.2、定义pojo
在my-tanhua-dubbo-interface中创建:
package com.tanhua.dubbo.server.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.elasticsearch.common.geo.GeoPoint;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "tanhua", type = "user_location", shards = 6, replicas = 2)
public class UserLocation {
@Id
private Long userId; //用户id
@GeoPointField
private GeoPoint location; //lon:经度 lat:纬度
@Field(type = FieldType.Keyword)
private String address; //位置描述
@Field(type = FieldType.Long)
private Long created; //创建时间
@Field(type = FieldType.Long)
private Long updated; //更新时间
@Field(type = FieldType.Long)
private Long lastUpdated; //上次更新时间
}
package com.tanhua.dubbo.server.vo;
import cn.hutool.core.bean.BeanUtil;
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 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 = BeanUtil.toBean(userLocation, UserLocationVo.class);
userLocationVo.setLongitude(userLocation.getLocation().getLon());
userLocationVo.setLatitude(userLocation.getLocation().getLat());
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;
}
}
由于UserLocation不能序列化,所以要再定义UserLocationVo进行返回数据。
在my-tanhua-dubbo-interface中添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
1.1.3、定义dubbo接口
在my-tanhua-dubbo-interface工程中。
package com.tanhua.dubbo.server.api;
public interface UserLocationApi {
/**
* 更新用户地理位置
*
* @param userId 用户id
* @param longitude 经度
* @param latitude 纬度
* @param address 地址名称
* @return
*/
Boolean updateUserLocation(Long userId, Double longitude, Double latitude, String address);
}
1.1.4、编写实现
package com.tanhua.dubbo.es.api;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.dubbo.server.api.UserLocationApi;
import com.tanhua.dubbo.server.pojo.UserLocation;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.common.geo.GeoPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.*;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
@Service(version = "1.0.0")
@Slf4j
public class UserLocationApiImpl implements UserLocationApi {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
/**
* 初始化索引库
*
*/
@PostConstruct
public void initIndex(){
//判断索引库是否存在,如果不存在,需要创建
if(!this.elasticsearchTemplate.indexExists("tanhua")){
this.elasticsearchTemplate.createIndex(UserLocation.class);
}
//判断表是否存在,如果不存在,需要创建
if(!this.elasticsearchTemplate.typeExists("tanhua", "user_location")){
this.elasticsearchTemplate.putMapping(UserLocation.class);
}
}
@Override
public Boolean updateUserLocation(Long userId, Double longitude, Double latitude, String address) {
//查询个人的地理位置数据,如果不存在,需要新增,如果是存在数据,更新数据
try {
GetQuery getQuery = new GetQuery();
getQuery.setId(String.valueOf(userId)<