반응형

 

Firestore를 사용하여 To-Do 앱을 만드는 방법을 설명하겠습니다. 이 예제에서는 Firebase Firestore를 사용하여 할 일 데이터를 저장하고, 읽고, 업데이트하고, 삭제하는 기능을 구현합니다.

 

1. firebase 내 데이터베이스 만들기

위와 같이 firestore 를 생성해줍니다. 

 

1. 프로젝트 설정

 

pubspec.yaml 파일 업데이트

 

최신 Firebase 패키지를 pubspec.yaml 파일에 추가합니다.

dependencies:
  flutter:
    sdk: flutter
  firebase_core: 
  firebase_auth: 
  cloud_firestore:

2. Firebase 설정

 

google-services.json 파일을 다운로드하여 android/app 디렉토리에 복사합니다. Firebase 콘솔에서 프로젝트를 설정하고 앱을 등록한 후 이 파일을 받을 수 있습니다.

 

android/build.gradle 파일 업데이트

buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:8.0.0'
        classpath 'com.google.gms:google-services:4.4.2'
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

android/app/build.gradle 파일 업데이트

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'

android {
    compileSdkVersion 34

    defaultConfig {
        applicationId "com.example.flutter_todo"
        minSdkVersion 21
        targetSdkVersion 34
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation platform('com.google.firebase:firebase-bom:32.2.2')
}

apply plugin: 'com.google.gms.google-services'

 

3. Firebase 초기화

 

main.dart

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'screens/todo_list_screen.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Firebase Todo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: TodoListScreen(),
    );
  }
}

 

4. Firestore 데이터 모델

 

models/todo.dart

class Todo {
  final String id;
  final String title;
  final bool isDone;

  Todo({
    required this.id,
    required this.title,
    this.isDone = false,
  });

  factory Todo.fromMap(Map<String, dynamic> data, String documentId) {
    return Todo(
      id: documentId,
      title: data['title'] ?? '',
      isDone: data['isDone'] ?? false,
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'title': title,
      'isDone': isDone,
    };
  }
}

5. Firestore 서비스

 

services/firestore_service.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import '../models/todo.dart';

class FirestoreService {
  final FirebaseFirestore _db = FirebaseFirestore.instance;

  Stream<List<Todo>> getTodos() {
    return _db.collection('todos').snapshots().map((snapshot) =>
        snapshot.docs.map((doc) => Todo.fromMap(doc.data(), doc.id)).toList());
  }

  Future<void> addTodo(Todo todo) {
    return _db.collection('todos').add(todo.toMap());
  }

  Future<void> updateTodo(Todo todo) {
    return _db.collection('todos').doc(todo.id).update(todo.toMap());
  }

  Future<void> deleteTodo(String id) {
    return _db.collection('todos').doc(id).delete();
  }
}

6. 프로바이더 설정

 

providers/todo_provider.dart

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '../models/todo.dart';
import '../services/firestore_service.dart';

class TodoProvider with ChangeNotifier {
  final FirestoreService _firestoreService = FirestoreService();

  late Stream<List<Todo>> _todos;
  Stream<List<Todo>> get todos => _todos;

  TodoProvider() {
    _todos = _firestoreService.getTodos();
  }

  Future<void> addTodo(Todo todo) async {
    await _firestoreService.addTodo(todo);
  }

  Future<void> updateTodo(Todo todo) async {
    await _firestoreService.updateTodo(todo);
  }

  Future<void> deleteTodo(String id) async {
    await _firestoreService.deleteTodo(id);
  }
}

7. UI 작성

 

screens/todo_list_screen.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/todo.dart';
import '../providers/todo_provider.dart';
import 'edit_todo_screen.dart';

class TodoListScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('To-Do List'),
      ),
      body: StreamBuilder<List<Todo>>(
        stream: Provider.of<TodoProvider>(context).todos,
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Center(child: CircularProgressIndicator());
          }
          final todos = snapshot.data!;
          return ListView.builder(
            itemCount: todos.length,
            itemBuilder: (ctx, i) => ListTile(
              title: Text(todos[i].title),
              trailing: Checkbox(
                value: todos[i].isDone,
                onChanged: (value) {
                  Provider.of<TodoProvider>(context, listen: false).updateTodo(
                    Todo(
                      id: todos[i].id,
                      title: todos[i].title,
                      isDone: value!,
                    ),
                  );
                },
              ),
              onLongPress: () {
                Provider.of<TodoProvider>(context, listen: false)
                    .deleteTodo(todos[i].id);
              },
              onTap: () {
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (context) => EditTodoScreen(todo: todos[i]),
                  ),
                );
              },
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showDialog(
            context: context,
            builder: (ctx) {
              TextEditingController controller = TextEditingController();
              return AlertDialog(
                title: Text('Add Todo'),
                content: TextField(
                  controller: controller,
                  decoration: InputDecoration(labelText: 'Title'),
                ),
                actions: [
                  TextButton(
                    onPressed: () {
                      if (controller.text.isNotEmpty) {
                        final newTodo = Todo(
                          id: '',
                          title: controller.text,
                        );
                        Provider.of<TodoProvider>(context, listen: false)
                            .addTodo(newTodo);
                        Navigator.of(ctx).pop();
                      }
                    },
                    child: Text('Add'),
                  ),
                ],
              );
            },
          );
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

screens/edit_todo_screen.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/todo.dart';
import '../providers/todo_provider.dart';

class EditTodoScreen extends StatelessWidget {
  final Todo todo;

  EditTodoScreen({required this.todo});

  @override
  Widget build(BuildContext context) {
    TextEditingController titleController = TextEditingController(text: todo.title);

    return Scaffold(
      appBar: AppBar(
        title: Text('Edit Todo'),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: titleController,
              decoration: InputDecoration(labelText: 'Title'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                if (titleController.text.isNotEmpty) {
                  final updatedTodo = Todo(
                    id: todo.id,
                    title: titleController.text,
                    isDone: todo.isDone,
                  );
                  Provider.of<TodoProvider>(context, listen: false)
                      .updateTodo(updatedTodo);
                  Navigator.of(context).pop();
                }
              },
              child: Text('Update'),
            ),
          ],
        ),
      ),
    );
  }
}

요약

 

1. Firestore 데이터 모델(Todo)을 정의합니다.

2. Firestore 서비스(FirestoreService)를 작성하여 Firestore와 상호작용합니다.

3. 프로바이더(TodoProvider)를 작성하여 상태 관리를 합니다.

4. UI를 작성하여 할 일 목록을 표시하고 추가, 수정, 삭제 기능을 구현합니다.

5. Firebase를 초기화하고 앱을 실행합니다.

 

이제 Firestore를 사용하여 할 일 데이터를 관리하는 간단한 To-Do 앱이 완성되었습니다. 필요에 따라 추가 기능을 구현하거나 UI를 개선할 수 있습니다.

반응형
반응형

 

1. Firebase 프로젝트 설정

 

1.1 Firebase 콘솔에서 프로젝트 생성

 

1. Firebase 콘솔에 접속하여 새 프로젝트를 만듭니다.

2. 프로젝트 이름을 입력하고, 필요한 설정을 완료합니다.

 

 

1.2 앱에 Firebase 추가

 

1. Firebase 프로젝트의 대시보드에서 Android 또는 iOS 앱을 추가합니다.

 

firebase cli 를 먼저 설치를 해줍니다. 

 

https://firebase.google.com/docs/cli?hl=ko&authuser=0&_gl=1*i16l2u*_ga*MTY1Njg1OTM5My4xNzIxNzEyMzA2*_ga_CW55HF8NVT*MTcyMTcxNjg4NS4yLjEuMTcyMTcxNzYxMi4zNy4wLjA.#windows-standalone-binary

각 os 에 맞는 방식을 클릭 후 그대로 따라합니다.

 

firebase cli 를 설치했다면 

firebase login

 으로 구글 계정 로그인 하면 됩니다. 

그 후 로그인이 잘 되었는지 확인하기 위해 프로젝트 리스트를 조회합니다.

firebase projects:list

그 후 아래 명령러를 그대로 실행해 줍니다.

 

flutterfire ~~

flutterfire configure --project=todo-프로젝트아이디

명령어를 치면 아래와 같이 나오고 원하는 os 선택 후 설치 진행합니다.

 

해당 명령어가 잘 실행된다면 콘솔에는 아래와 같이 앱을 등록했다는 로그가 남습니다. 

그리고 파이어베이스 대시보드로 이동하면 등록된 앱이 뜨게 됩니다. 

해당 작업이 완료되면
lib 폴더에 firebase_options.dart 가 생성된다고 하는데, 필자는 뜨지 않아서 새로 수동으로 만들어주었습니다. 아래 적었습니다.

 

 

안드로이드 에 firebase 권한 추가 

google-services.json 파일을 다운 후 
android > app > 경로에 google-services.json 을 넣어줍니다. 

 

프로젝트에 firebase sdk 추가 

 

 

settings.gradle 의 plugins 내부에 아래 코드를 넣어줍니다. 가이드에는 루트프로젝트의 build.gradle 라고 나옴.

settings.gradle 에 수정 

id "com.google.gms.google-services" version "4.3.15" apply false

해당 과정에서 혹시 kotlin 버젼 이슈가 있다면 (아래 와 같이 버젼 이슈)

integ.client.measurement_api_measurement_api.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.9.0, expected version is 1.7.1.

버젼을 settings.gradle 에서 올려주면 됩니다. 

id "org.jetbrains.kotlin.android" version "1.9.0" apply false

 

추가로 프로젝트내 build.gradle 에 firebae 라이브러리 추가

android > app > build.gradle

dependencies {
    implementation platform('com.google.firebase:firebase-bom:33.1.2')
    implementation 'com.google.firebase:firebase-analytics'
}

 

여기까지 추가 후 실행이 되면 firebase 사용준비는 완료되었습니다. 

 

 

Authentication 시작 

firebase 를 이용한 회원가입 및 로그인 기능을 두기 위해서는 firebase 에서 authentication 을 시작해주어야 합니다.

Authentication 설정: 좌측 메뉴에서 Authentication을 클릭합니다.

 

Sign-in Method: 상단 탭에서 Sign-in method를 선택합니다. (로그인 방법 클릭)

Email/Password: 이메일/비밀번호 인증이 활성화되어 있는지 확인합니다

활성화되지 않았다면 활성화합니다.

 

 

firebase_options.dart 수동생성

lib 폴더에 firebase_options.dart  파일을 생성합니다. 

// lib/firebase_options.dart

import 'package:firebase_core/firebase_core.dart';

class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    return const FirebaseOptions(
      apiKey: 'AIzaSyBbHR~~~~~~~~~~~~~',
      appId: '1:508050~~~~:android:7201919812b~~~~~~',
      messagingSenderId: '50805~~~~~~',
      projectId: 'todo-~~~~',
    );
  }
}

각 값에 맞는 값은 프로젝트 내 앱 설정에서 확인합니다. 

google-services.json 파일안에 해당 값들이 존재 합니다. 

 

 

회원가입 페이지
register_page.dart

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';

import 'login_page.dart';

class RegisterPage extends StatefulWidget {
  @override
  _RegisterPageState createState() => _RegisterPageState();
}

class _RegisterPageState extends State<RegisterPage> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final FirebaseAuth _auth = FirebaseAuth.instance;

  Future<void> _register() async {
    try {
      UserCredential userCredential = await _auth.createUserWithEmailAndPassword(
        email: _emailController.text,
        password: _passwordController.text,
      );
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Successfully registered!')),
      );
      // 회원가입 후 원하는 페이지로 이동
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(builder: (context) => LoginPage()),
      );
    } on FirebaseAuthException catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Failed to register: ${e.message}')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Register')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: 'Email'),
            ),
            TextField(
              controller: _passwordController,
              decoration: InputDecoration(labelText: 'Password'),
              obscureText: true,
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _register,
              child: Text('Register'),
            ),
          ],
        ),
      ),
    );
  }
}

 

회원가입이 완료되면 로그인 페이지로 리다이렉트 하게 했습니다.

 

로그인 페이지

login_page.dart

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  Future<void> _login() async {
    try {
      UserCredential userCredential = await _auth.signInWithEmailAndPassword(
        email: _emailController.text,
        password: _passwordController.text,
      );
      // 로그인 성공 시 처리
      Navigator.of(context).pushReplacement(
        MaterialPageRoute(builder: (context) => TodoListScreen()), // ListPage로 이동
      );
    } on FirebaseAuthException catch (e) {
      String message;
      switch (e.code) {
        case 'user-not-found':
          message = 'No user found for that email.';
          break;
        case 'wrong-password':
          message = 'Wrong password provided for that user.';
          break;
        default:
          message = 'An error occurred. Please try again.';
      }
      // 에러 메시지를 스낵바로 출력
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(message)),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('An error occurred. Please try again.')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Login')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: 'Email'),
            ),
            TextField(
              controller: _passwordController,
              decoration: InputDecoration(labelText: 'Password'),
              obscureText: true,
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _login,
              child: Text('Login'),
            ),
          ],
        ),
      ),
    );
  }
}

 

main 메소드 
firebase 메소드를 추가해줍니다. 

void main() async{

  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(
      child: MyApp(),
    ),
  );
}
반응형
반응형

vue 프론트를 배포하려면 구글 플랫폼에서는 google cloud run 및 firebase hosting 을 통해 배포할 수 있습니다.  

cloud storage 에 정적 파일로 올릴 수 있지만 이 경우에 vue router 등 프론트에서 라우트 기능을 사용한다면 

경로 오류가 생길 수 있습니다. 

완전 static 하게 경로 이동 없는 경우에 cloud storage 이용하는게 좋습니다.

 

 

Firebase Hosting

  • 비용: Firebase Hosting은 정적 파일(HTML, CSS, JS 등)을 호스팅하기 위한 것이므로, 주로 네트워크 대역폭과 저장 공간에 대한 비용이 발생합니다. Firebase는 무료 티어를 제공하며, 이는 작은 프로젝트나 테스트 용도로 충분한 경우가 많습니다. 무료 티어를 초과하는 사용량에 대해서는 비용이 청구됩니다.
  • 무료 티어 제공: 예, 제공됩니다. 일정 수준의 사용량(예: 일정 GB의 저장 공간 및 월간 대역폭)은 무료입니다.
  • 적합한 사용 사례: 정적 웹 사이트 및 SPA(Single Page Application).

Cloud Run

  • 비용: Cloud Run은 사용한 컴퓨팅 자원(메모리와 CPU), 요청 수, 네트워크 대역폭에 따라 비용이 청구됩니다. Cloud Run도 무료 티어를 제공하며, 이에는 월간 요청 수, 컴퓨팅 자원 사용량에 대한 무료 할당량이 포함됩니다. 무료 사용량을 초과하면 비용이 발생하며, 이는 애플리케이션의 복잡도와 트래픽에 따라 달라집니다.
  • 무료 티어 제공: 예, 제공됩니다. 무료 티어는 일정량의 컴퓨팅 자원 사용과 요청 수에 대해 무료로 제공됩니다.
  • 적합한 사용 사례: 동적 웹 애플리케이션, API 백엔드, 마이크로서비스.

비교 및 선택

  • 정적 컨텐츠: 당신의 애플리케이션이 주로 정적 컨텐츠를 제공한다면, Firebase Hosting이 더 경제적일 수 있습니다. 이 서비스는 정적 파일을 효율적으로 서빙하기 위해 최적화되어 있습니다.
  • 동적 처리가 필요한 경우: 애플리케이션이 서버 사이드에서 동적 컨텐츠를 생성하거나, 사용자 인증, 데이터베이스 연동 등 복잡한 백엔드 로직을 필요로 한다면, Cloud Run이 더 적합할 수 있습니다. 이 경우 추가적인 비용이 발생할 수 있지만, 더 강력한 기능과 유연성을 제공합니다.

결국 선택은 애플리케이션의 요구 사항, 예상 트래픽, 그리고 예산에 달려 있습니다. 무료 티어로 시작하여 요구 사항이나 사용량이 증가함에 따라 서비스를 조정하는 것이 좋습니다.

 

정적 컨텐츠일 경우에는 Firebase Hosting 이 좋을 것 같아 

Firebase Hosting 하는 법 소개합니다. 

 

Firebase Hosting

https://console.firebase.google.com/u/1/ 

로 들어가서 프로젝트를 추가합니다.

프로젝트 추가 후 

Hosting 메뉴를 추가합니다.

여기에서 배포된 어플리케이션 확인 가능합니다.

 

하지만 따로 웹사이트에서 작업해줘야 할 것은 없고 로컬에서 firebase 설치해서 아래 가이드대로 설치해주시면 됩니다.

 

 

FIREBASE_TOKEN은 Firebase CLI를 사용해 생성할 수 있는 인증 토큰입니다. 이 토큰은 Firebase 프로젝트에 대한 비밀 액세스 권한을 제공하며, CI/CD 파이프라인(예: GitHub Actions)에서 Firebase 서비스에 자동으로 인증하기 위해 사용됩니다. 토큰을 생성하고 GitHub Secrets에 저장하는 방법은 다음과 같습니다:

Firebase 토큰 생성 방법

1. Firebase CLI 설치: Firebase CLI가 로컬 시스템에 설치되어 있지 않은 경우, 먼저 설치해야 합니다. 터미널에서 다음 명령어를 실행하여 설치할 수 있습니다:이 명령은 Firebase CLI를 글로벌로 설치합니다.

npm install -g firebase-tools

 

2. Firebase에 로그인: 다음 명령어를 사용해 Firebase에 로그인합니다:이 명령은 기본 웹 브라우저를 열고 Firebase 인증 프로세스를 시작합니다. 로그인 과정을 완료하세요.

firebase login

위 명령어 사용시 브라우져 창에서 firebase 계졍 인정하도록 화면이 뜨게 됩니다.

 

위 완료 메시지 뜨면 로그인 완료되었습니다.

 

3. CI용 Firebase 토큰 생성: Firebase CLI에서 CI(지속적 통합) 환경을 위한 인증 토큰을 생성하려면, 다음 명령어를 실행합니다:이 명령은 새로운 인증 토큰을 생성하고, 이 토큰을 터미널에 출력됩니다. 출력된 토큰을 복사하세요.

firebase login:ci

 

4. 프로젝트 폴더에 firebase.json 이 있어야 하는데, 아래 명령어 통해서 세팅하면 됩니다.

firebase init hosting

 

프로젝트가 없으면 새로 생성, 미리 firebase 에서 프로젝트 생성 하면 됩니다. 

있으면 프로젝트 선택하면 됩니다.

github workflow 에 넣냐는 말이 있는데, 여기에서 프로젝트 유저명/프로젝트명 을 넣어줍니다.

필요한 옵션을 알아서 선택해주자.

firebase.json

이 아래와 같이 생성되는데 혹시 잘못해서 안되면 나중에 덮어씌어도 됩니다.

여기까지 작성 후 

firebase deploy


를 하게 되면 프론트 소스가 배포 됩니다. 

 

 

선택해야 하는 옵션 이 너무 잘 되어 있어 

github actions 파일까지 생성해 줍니다.

옵션만 잘 따라가 주면 됩니다

 

옵션을 잘 못 선택해주었을 경우를 대비하여 firebase.json 및 firebase-hosting-merge.yml 공유합니다.
굳이 먼저 생성안해도 firebase init 통해서 actions 파일까지 생성해 줍니다.

npm ci 가 동작안할 수 있는데 

이때 steps 만 나눠서 실행 다시 해보세요.

 
반응형
반응형

 

firebase 가 클라이언트 사이드에서 구현하기 위한 severless db 로 많이 쓰이는데, 

나 같은 경우는 db 를 구축하기 일단 비용 및 인프라가 없어서 간단히 만들려고 firebase 를 서버에서 사용하기 위한 db 로 일단은 선택했다.

 

일정량 이하는 free 로 사용할 수 있다.

 

firebase 프로젝트 생성

대쉬보드에서 프로젝트 추가를 통해 프로젝트를 생성

console.firebase.google.com/

 

firestore Database 를 생성하자.

주의 할 것은 realtime database 와 firestore database 는 다르다.

다른 점으로는 과금 정책도 다르고, realtime 이 더 비싸다고 한다.

둘의 차이점은 아래 링크 문서에 있다.

firebase.google.com/docs/database/rtdb-vs-firestore?hl=ko

 

프로젝트 설정 에서 account 관련 키 파일을 다운받아야 한다.

프로젝트 개요 > 프로젝트 설정 > 서비스 계정 > Firebase Admin SDK 

에서 자바 를 클릭 후 

새 비공개 키 생성 으로 파일을 다운받자. 

다운 받으면 ~~~~.json 파일로 다운받아진다.

 

스프링 spring boot 코드 

pom.xml 라이브러리 다운

<dependency>
	<groupId>com.google.firebase</groupId>
	<artifactId>firebase-admin</artifactId>
	<version>6.11.0</version>
</dependency>

 

스프링 init 코드

@Service
public class FirebaseInitialize {

    @PostConstruct //has to be Run during the Start of
    public void initialize() {
        try {
            FileInputStream serviceAccount =
                    new FileInputStream("src/main/resources/serviceAccountKey.json");

            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                    .setDatabaseUrl("https://{{데이터베이스명}}.firebaseio.com")
                    .build();

            FirebaseApp.initializeApp(options);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

}

 

위에서 다운받은 json 파일을 이름을 변경해주고 resources 하위 경로에 넣자.

databaseUrl 은 따로 나오는 곳은 없어 보였는데, 프로젝트 명 에 뒤에 .firebaseio.com 을 붙이면 된다.

데이터베이스명은 firestore 조회 화면에 바로 나온다.

 

데이터 샘플로 넣고 조회하기

@Slf4j
@Service
public class FirebaseService {

    public static final String COLLECTION_NAME = "user";

    public void insertUser() throws Exception {

        Firestore db = FirestoreClient.getFirestore();
        User user = new User();
        user.setId("4444");
        user.setName("4444");
        ApiFuture<WriteResult> apiFuture = db.collection(COLLECTION_NAME).document("user_4").set(user);

        log.info(apiFuture.get().getUpdateTime().toString());
    }


    public void selectUser() throws Exception {

        Firestore db = FirestoreClient.getFirestore();
        User user = null;
        ApiFuture<DocumentSnapshot> apiFuture = db.collection(COLLECTION_NAME).document("user_4").get();
        DocumentSnapshot documentSnapshot = apiFuture.get();
        if(documentSnapshot.exists()) {
            user = documentSnapshot.toObject(User.class);
            log.info(user.toString());
        }
    }
}

 

User 라는 pojo 클래스를 만들고 넣어줘도 되고 HashMap 으로 만들어서 넣어줘도 된다.

collection 과 document 라는 개념이 몽고db 와 흡사하다.

collection 이라는 개념은 db와 같고, 하위의 document 가 테이블 과 개념이 같다. 조금 다른 점이 있다면 document 가 하위로 계속 들어갈 수 있다.

사용 

    @Resource
    FirebaseService firebaseService;

    @Test
    public void 테스트() throws Exception {
        firebaseService.insertUser();
        firebaseService.selectUser();
    }

이 정도 코드는 사실 안남겨도 되는데, 혹시나.

 

결과 

 

나 같은 경우는 저 코드를 작성했는데 한참 동작하지 않아서 이것저것 삽질을 조금 했다.

나중에 시간이 지나고 되는걸 보면 database 를 생성하고 일정시간이 지나야 되는거 같긴 한데, 이건 확실치 않다.

혹시 안되는 사람은 2시간 정도 경과하고 한번 다시 해보도록

 

혹시나 권한 때문에 안되는 사람은 규칙(rule)을 확인하자.

production 모드로 한 사람은 규칙에서 test 모드로 변경하면 된다.

2021 년 6월 3일 까지는 read write 권한이 된다는 코드이다.

반응형

+ Recent posts