[Spring Boot] Firebase 연동 방법.
spring boot - 파이어베이스 realtime database 연결
Firebase Realtime Database 조금 더 자세히
지역쿼리
Android에서 데이터 읽기 및 쓰기
Q. firebase에서 모든 멤버의 location을 다 가져온 뒤 spingboot에서 각 멤버와 targetlocation의 거리를 일괄로 전부 계산할 것인지, firebase에서 미리 계산한 뒤 인근 user의 id만 보내줄 것인지?
-> 이 문제는 바보같이 생각했다.. 애초에 Springboot랑 firebase를 연동할 필요가 없었다. 어차피 firebase는 서버리스이기 때문에 안드로이드에서 유저가 인근 유저들에게 메세지를 전송할 때, 안드로이드 단에서 firebase 쿼리문으로 인근 유저들을 전부 가져오면 된다. 그리고 그 인근 유저들에게 메세지를 보내겠다고 안드로이드에서 서버로 메세지 전송 api 만 보내주면 되는것..
Geohash는 위치 기반 서비스에서 쿼리가 복잡하기 때문에 해당 쿼리를 간단한 코드만으로 사용할 수 있도록 한다.
// Add this to your app/build.gradle
implementation 'com.firebase:geofire-android-common:3.1.0'
Geohash를 사용하여 쿼리를 쓰기 위해서는 real time db에 저장된 데이터 자체가 Geohash 형태로 저장이 되어있어야 한다. 따라서 그에 맞게 기존 코드를 수정해주었다.
@IgnoreExtraProperties
public class UserLocation {
private String id;
private double latitude;
private double longitude;
private String geohash; //📌추가
protected UserLocation(){}
public Double getLatitude() {
return latitude;
}
public void setLatitude(Double latitude) {
this.latitude = latitude;
}
public Double getLongitude() {
return longitude;
}
public void setLongitude(Double longitude) {
this.longitude = longitude;
}
public UserLocation(String id, Double latitude, Double longitude) {
this.id = id;
this.latitude = latitude;
this.longitude = longitude;
this.geohash = GeoFireUtils.getGeoHashForLocation(new GeoLocation(latitude, longitude)); //📌추가
}
}
package org.techtown.knockknock.location;
import android.util.Log;
import androidx.annotation.NonNull;
import com.firebase.geofire.GeoFireUtils;
import com.firebase.geofire.GeoLocation;
import com.firebase.geofire.GeoQueryBounds;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;
import java.util.ArrayList;
import java.util.List;
public class GeoQuery {
private static FirebaseFirestore db = FirebaseFirestore.getInstance();
private static List<String> userId = new ArrayList<>();
public static List<String> findUserIdsNear(double targetlatitude, double targetlongitude){
final GeoLocation target = new GeoLocation(targetlatitude,targetlongitude);
final double radiusInM = 1*1000; // 1km 로 범위 설정
List<GeoQueryBounds> bounds = GeoFireUtils.getGeoHashQueryBounds(target,radiusInM);
List<Task<QuerySnapshot>> tasks = new ArrayList<>();
for(GeoQueryBounds b: bounds){
Query q = db.collection("userlocation")
.orderBy("geohash")
.startAt(b.startHash)
.endAt(b.endHash);
tasks.add(q.get());
}
Tasks.whenAllComplete(tasks)
.addOnCompleteListener(new OnCompleteListener<List<Task<?>>>() {
@Override
public void onComplete(@NonNull Task<List<Task<?>>> t) {
List<DocumentSnapshot> matchingDocs = new ArrayList<>();
for(Task<QuerySnapshot> task: tasks){
QuerySnapshot snap = task.getResult();
for(DocumentSnapshot doc: snap.getDocuments()){
double lat = doc.getDouble("lat");
double lng = doc.getDouble("lng");
GeoLocation docLocation = new GeoLocation(lat,lng);
double distanceInM = GeoFireUtils.getDistanceBetween(docLocation,target);
if(distanceInM<=radiusInM){
matchingDocs.add(doc);
userId.add(doc.getId());
}
}
}
}
});
for(String id: userId){
Log.d("GeoQuery","target 위치 인근 유저 아이디: "+id);
}
return userId;
}
}