mirror of
https://github.com/ChangJoo-Park/learn-flutter.git
synced 2025-06-07 21:23:07 +00:00
docs: update for JSONConverter
This commit is contained in:
parent
de8cce04b4
commit
32144e21d4
3 changed files with 91 additions and 37 deletions
|
@ -9,6 +9,7 @@ title: 변경사항
|
|||
- 📦 1. 시작하기에 **변경사항** 추가
|
||||
- 💡 2. Dart 언어 기초 중 컬렉션과 반복문에 collection 패키지 안내 추가
|
||||
- `flutter pub run build_runner build` 를 `dart run build_runner build` 로 변경
|
||||
- JSON 직렬화 (freezed, json_serializable)에 freezed_annotation 팁 추가
|
||||
|
||||
### 2025년 05월 14일
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
---
|
||||
title: JSON 직렬화 (freezed, json_serializable)
|
||||
---
|
||||
import { Aside } from '@astrojs/starlight/components';
|
||||
|
||||
|
||||
REST API와 통신할 때 JSON 형식의 데이터를 주고받는 경우가 많습니다. Flutter/Dart에서는 이러한 JSON 데이터를 Dart 객체로 변환하고, 반대로 Dart 객체를 JSON으로 직렬화하는 과정이 필요합니다. 이 장에서는 `json_serializable`과 `freezed` 패키지를 활용한 JSON 직렬화 방법을 살펴보겠습니다.
|
||||
|
||||
|
@ -164,6 +166,73 @@ class Product {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
<Aside type="tip">
|
||||
|
||||
[freezed_annotation](https://pub.dev/packages/freezed_annotation)의 JSONConverter를 이용하면 조금 더 쉽게 JSON 직렬화를 하실 수 있습니다.
|
||||
|
||||
```sh
|
||||
dart pub add freezed_annotation
|
||||
```
|
||||
|
||||
</Aside>
|
||||
|
||||
```dart title="color_converter.dart"
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
/// Color 객체와 String(HEX) 간의 변환을 처리하는 JSONConverter
|
||||
class ColorConverter implements JsonConverter<Color, String> {
|
||||
const ColorConverter();
|
||||
|
||||
@override
|
||||
Color fromJson(String json) {
|
||||
// '#RRGGBB' 형태의 HEX 문자열을 Color 객체로 변환
|
||||
return Color(int.parse(json.substring(1), radix: 16) + 0xFF000000);
|
||||
}
|
||||
|
||||
@override
|
||||
String toJson(Color object) {
|
||||
// Color 객체를 '#RRGGBB' 형태의 HEX 문자열로 변환
|
||||
return '#${object.value.toRadixString(16).substring(2)}';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```dart title="product.dart"
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'product.g.dart';
|
||||
part 'product.freezed.dart';
|
||||
|
||||
/// 객체 생성
|
||||
/// final Product product = Product(
|
||||
/// id: 1,
|
||||
/// name: '빨간 상품',
|
||||
/// color: Colors.red,
|
||||
/// );
|
||||
///
|
||||
/// JSON으로 변환 - color는 자동으로 '#ff0000' 같은 문자열로 변환됨
|
||||
/// final Map<String, dynamic> json = product.toJson();
|
||||
/// print(json); // {id: 1, name: 빨간 상품, color: #ff0000}
|
||||
///
|
||||
/// JSON에서 객체로 변환 - '#ff0000' 같은 문자열은 자동으로 Color 객체로 변환됨
|
||||
/// final Product loadedProduct = Product.fromJson(json);
|
||||
/// print(loadedProduct.color); // Color(0xFFFF0000)
|
||||
@freezed
|
||||
class Product with _$Product {
|
||||
factory Product({
|
||||
required int id,
|
||||
required String name,
|
||||
@ColorConverter() required Color color, // JSONConverter 적용
|
||||
}) = _Product;
|
||||
|
||||
factory Product.fromJson(Map<String, dynamic> json) => _$ProductFromJson(json);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 중첩 객체 처리
|
||||
|
||||
```dart
|
|
@ -62,9 +62,7 @@ Flutter에서 멀티 모듈 아키텍처를 구현하는 여러 방법이 있습
|
|||
|
||||
#### 각 모듈의 pubspec.yaml 설정
|
||||
|
||||
**app/pubspec.yaml**:
|
||||
|
||||
```yaml
|
||||
```yaml title="app/pubspec.yaml"
|
||||
name: my_app
|
||||
description: Main application module
|
||||
version: 1.0.0+1
|
||||
|
@ -87,9 +85,7 @@ dependencies:
|
|||
path: ../packages/feature_profile
|
||||
```
|
||||
|
||||
**packages/core/pubspec.yaml**:
|
||||
|
||||
```yaml
|
||||
```yaml title="packages/core/pubspec.yaml"
|
||||
name: core
|
||||
description: Core module with shared functionality
|
||||
version: 0.0.1
|
||||
|
@ -106,9 +102,7 @@ dependencies:
|
|||
shared_preferences: ^2.2.0
|
||||
```
|
||||
|
||||
**packages/feature_auth/pubspec.yaml**:
|
||||
|
||||
```yaml
|
||||
```yaml title="packages/feature_auth/pubspec.yaml"
|
||||
name: feature_auth
|
||||
description: Authentication feature module
|
||||
version: 0.0.1
|
||||
|
@ -141,7 +135,7 @@ dart pub global activate melos
|
|||
|
||||
2. 프로젝트 루트에 `melos.yaml` 파일 생성:
|
||||
|
||||
```yaml
|
||||
```yaml title="melos.yaml"
|
||||
name: my_flutter_project
|
||||
|
||||
packages:
|
||||
|
@ -179,8 +173,7 @@ melos test
|
|||
|
||||
멀티 모듈 아키텍처는 Flutter Flavors와 결합하여 다양한 앱 버전(개발, 스테이징, 프로덕션 등)을 관리할 수 있습니다:
|
||||
|
||||
```dart
|
||||
// app/lib/main_dev.dart
|
||||
```dart title="app/lib/main_dev.dart"
|
||||
import 'package:core/config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app.dart';
|
||||
|
@ -240,15 +233,15 @@ void main() {
|
|||
|
||||
#### 인터페이스 기반 통신 예시
|
||||
|
||||
```dart
|
||||
// core/lib/src/auth/auth_service.dart
|
||||
```dart title="core/lib/src/auth/auth_service.dart"
|
||||
abstract class AuthService {
|
||||
Future<User?> getCurrentUser();
|
||||
Future<User> signIn(String email, String password);
|
||||
Future<void> signOut();
|
||||
}
|
||||
```
|
||||
|
||||
// feature_auth/lib/src/services/firebase_auth_service.dart
|
||||
```dart title="feature_auth/lib/src/services/firebase_auth_service.dart"
|
||||
class FirebaseAuthService implements AuthService {
|
||||
@override
|
||||
Future<User?> getCurrentUser() {
|
||||
|
@ -265,8 +258,9 @@ class FirebaseAuthService implements AuthService {
|
|||
// Firebase 구현
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
// app/lib/di/service_locator.dart
|
||||
```dart title="app/lib/di/service_locator.dart"
|
||||
void setupServiceLocator() {
|
||||
GetIt.I.registerSingleton<AuthService>(FirebaseAuthService());
|
||||
}
|
||||
|
@ -308,8 +302,7 @@ void setupServiceLocator() {
|
|||
|
||||
각 모듈은 명확한 공개 API를 정의해야 합니다. 모듈 내부 구현은 숨기고 필요한 기능만 노출하는 것이 좋습니다.
|
||||
|
||||
```dart
|
||||
// feature_auth/lib/feature_auth.dart
|
||||
```dart title="feature_auth/lib/feature_auth.dart"
|
||||
library feature_auth;
|
||||
|
||||
// 공개 API
|
||||
|
@ -319,8 +312,7 @@ export 'src/domain/entities/user.dart';
|
|||
export 'src/di/auth_module.dart';
|
||||
```
|
||||
|
||||
```dart
|
||||
// feature_auth/lib/src/di/auth_module.dart
|
||||
```dart title="feature_auth/lib/src/di/auth_module.dart"
|
||||
import 'package:get_it/get_it.dart';
|
||||
import '../data/repositories/auth_repository_impl.dart';
|
||||
import '../data/datasources/auth_remote_datasource.dart';
|
||||
|
@ -375,8 +367,7 @@ class AuthModule {
|
|||
|
||||
코어 모듈은 다른 모든 모듈에서 사용하는 공통 기능을 포함합니다:
|
||||
|
||||
```dart
|
||||
// core/lib/core.dart
|
||||
```dart title="core/lib/core.dart"
|
||||
library core;
|
||||
|
||||
export 'src/config/app_config.dart';
|
||||
|
@ -387,8 +378,7 @@ export 'src/di/service_locator.dart';
|
|||
export 'src/navigation/router.dart';
|
||||
```
|
||||
|
||||
```dart
|
||||
// core/lib/src/config/app_config.dart
|
||||
```dart title="core/lib/src/config/app_config.dart"
|
||||
enum Environment { dev, staging, prod }
|
||||
|
||||
class AppConfig {
|
||||
|
@ -416,8 +406,7 @@ class AppConfig {
|
|||
|
||||
UI 키트 모듈은 앱 전체에서 사용되는 공통 UI 컴포넌트를 포함합니다:
|
||||
|
||||
```dart
|
||||
// ui_kit/lib/ui_kit.dart
|
||||
```dart title="ui_kit/lib/ui_kit.dart"
|
||||
library ui_kit;
|
||||
|
||||
export 'src/buttons/primary_button.dart';
|
||||
|
@ -426,8 +415,7 @@ export 'src/theme/app_theme.dart';
|
|||
export 'src/inputs/text_field.dart';
|
||||
```
|
||||
|
||||
```dart
|
||||
// ui_kit/lib/src/buttons/primary_button.dart
|
||||
```dart title="ui_kit/lib/src/buttons/primary_button.dart"
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PrimaryButton extends StatelessWidget {
|
||||
|
@ -458,8 +446,7 @@ class PrimaryButton extends StatelessWidget {
|
|||
|
||||
상품 기능 모듈은 상품 목록, 상세 정보, 검색 등의 기능을 담당합니다:
|
||||
|
||||
```dart
|
||||
// feature_products/lib/feature_products.dart
|
||||
```dart title="feature_products/lib/feature_products.dart"
|
||||
library feature_products;
|
||||
|
||||
export 'src/presentation/pages/product_list_page.dart';
|
||||
|
@ -468,8 +455,7 @@ export 'src/domain/entities/product.dart';
|
|||
export 'src/di/products_module.dart';
|
||||
```
|
||||
|
||||
```dart
|
||||
// feature_products/lib/src/presentation/pages/product_list_page.dart
|
||||
```dart title="feature_products/lib/src/presentation/pages/product_list_page.dart"
|
||||
import 'package:core/core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
@ -516,8 +502,7 @@ class ProductListPage extends ConsumerWidget {
|
|||
|
||||
앱 모듈은 모든 기능 모듈을 통합하고 앱의 진입점 역할을 합니다:
|
||||
|
||||
```dart
|
||||
// app/lib/main_dev.dart
|
||||
```dart title="app/lib/main_dev.dart"
|
||||
import 'package:core/core.dart';
|
||||
import 'package:feature_auth/feature_auth.dart';
|
||||
import 'package:feature_products/feature_products.dart';
|
||||
|
@ -548,8 +533,7 @@ void main() {
|
|||
}
|
||||
```
|
||||
|
||||
```dart
|
||||
// app/lib/app.dart
|
||||
```dart title="app/lib/app.dart"
|
||||
import 'package:core/core.dart';
|
||||
import 'package:ui_kit/ui_kit.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -587,7 +571,7 @@ class MyApp extends StatelessWidget {
|
|||
- 필요한 경우 이벤트 기반 통신을 사용합니다.
|
||||
- 공통 코드를 코어 모듈로 이동시킵니다.
|
||||
|
||||
```dart
|
||||
```dart title="core/lib/core.dart"
|
||||
// 이벤트 기반 통신 예시 (core 모듈)
|
||||
class AppEvent {
|
||||
// 이벤트 정의
|
||||
|
|
Loading…
Add table
Reference in a new issue