플러터(flutter)

플러터에서 Json 형태로 데이터 저장하기-1

기계공학 주인장 2024. 5. 9. 09:36
반응형

이번 구현은 다음과 같은 방법으로 실시할 예정입니다.

 

  1. 필요한 depedency import
  2. 필요한 Model 생성
  3. Model에 JsonSerializable 적용하기
  4. Json 데이터 생성하기
  5. shared_preferences를 사용하여 Json 데이터 저장하기
  6. 저장된 Json 데이터를 수정, 삭제 하기

Json 데이터로 저장하기 위해 필요한 Dependency

 

필요한 Depedency는 다음과 같습니다.

 

dependencies:
    # shared_preferences - https://pub.dev/packages/shared_preferences/install
    shared_preferences: ^2.2.3

    # json_annotation - https://pub.dev/packages/json_annotation/install
    json_annotation: ^4.9.0

    # build_runner - https://pub.dev/packages/build_runner/install
    build_runner: ^2.4.9

 

다음은 dev_depedencies에 설치해야하는 패키지입니다.

dev_dependencies:
  json_serializable: ^6.6.0

 

 

제가 올린 것을 복사해서 사용해도 괜찮고

 

직접 각각의 Flutter 패키지에 들어가서 버전을 확인하고 설치해도 상관없습니다.

 

참고로 Flutter에 새로운 패키지를 설치, 업데이트할 때 Android Studio에 뜨는 기능은 다음과 같습니다.

 

  • Pub get: pubspec.yaml 파일에 명시된 의존성들을 다운로드하고 설치
  • Pub upgrade: 이미 설치된 패키지들을 최신 버전으로 업그레이드하는 데 사용 (pubspec.yaml 파일에서 명시한 버전 범위 내에서)
  • Pub outdated:  프로젝트의 의존성 중에서 업데이트가 가능한 패키지들을 확인하는 데 사용

필요한 Model 생성

 

다음은 예시로 사용할 Model을 정의합니다.

 

저는 개인 프로젝트에 사용할 모델을 여기서 그대로 사용하겠습니다.

 

제가 정의한 모델은 다음과 같습니다.

 

모델이 되는 모든 class에 @JsonSerializable를 붙여줘야합니다.

 

또한 제일 위에 있는 part 'chat.g.dart';를 반드시 넣어줘야합니다.

import 'package:json_annotation/json_annotation.dart';
part 'chat.g.dart';

@JsonSerializable()
class ChatList {
  final List<Chat>? chatList;

  ChatList({this.chatList});
}

@JsonSerializable()
class Chat {
  // 채팅 타이틀
  final String title;

  // 채팅 내용
  final List<Message> messageList;

  // 채팅하고 있는 멤버
  final List<Friend> chatMember;

  // 채팅에 있는 공지 사항 내용
  Noti? notification;

  // 해당 채팅의 제일 최근 수정된 날짜 - 메시지만 카운트함
  DateTime modifiedDate;

  Chat(
      {required this.title,
      required this.messageList,
      required this.chatMember,
      required this.modifiedDate});
}

@JsonSerializable()
class Noti {
  final String id;
  final String message;

  Noti({required this.id, required this.message});
}

@JsonSerializable()
class Message {
  final String id;
  final DateTime messageTime;
  final String message;
  final MessageType messageType;
  final bool isMe;

  Message({
    required this.id,
    required this.messageTime,
    required this.message,
    required this.messageType,
    required this.isMe,
  });
}

enum MessageType { message, date, state }

 

그리고 위 코드에서 사용중인 Friend 모델의 내부는 다음과 같습니다.

 

Friend 모델의 경우 다른 곳에서 사용하기 위해 손으로 toMap 동작을 구현했습니다.

 

또한 Chat 모델에서 JsonSerializable()을 사용하고 있기 때문에 Friend에도 해당 어노테이션을 붙여줍니다.

@JsonSerializable()
class Friend {
  final String id;
  final String name;
  String message;
  String profileImgPath;
  int me;

  Friend({
    required this.id,
    required this.name,
    this.message = "",
    this.profileImgPath = Strings.defaultProfileImgPath,
    this.me = 0
  });

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'name': name,
      'message': message,
      'profileImgPath': profileImgPath,
      'me': me
    };
  }

  factory Friend.fromMap(Map<String, dynamic> map) {
    return Friend(
      id: map['id'],
      name: map['name'],
      message: map['message'],
      profileImgPath: map['profileImgPath'],
      me: map['me']
    );
  }
  @override
  String toString() {
    return "Friend(id: $id, name: $name, message: $message, profileImgPath: $profileImgPath, me: $me)";
  }
}

 

이렇게 하면 일단 Model에 대한 정의는 끝납니다.

 

이제 해당 Model을 사용해서 필요한 파일을 build합니다.

 


Model에 JsonSerializable 적용하기

프로젝트의 루트 부분에서 다음과 같은 커맨드를 실행합니다.

 

dart run build_runner build

 

 

그리고 다음과 같이 성공하면 여기까진 문제가 없는 것입니다.

 

 

성공한다면 위에서 정의한 Model 파일과 같은 위치에 g.dart라는 파일이 생성된 것을 확인할 수 있습니다.

 

 

그 안에는 다음과 같이 되어있습니다.

 

 

이제 자동으로 생성된 g.dart 파일을 각각의 모델에 적용합니다.

 

적용된 chat.dart의 모습은 다음과 같습니다.

 

import 'package:json_annotation/json_annotation.dart';
part 'chat.g.dart';

@JsonSerializable()
class ChatList {
  final List<Chat>? chatList;

  ChatList({this.chatList});

  factory ChatList.fromJson(Map<String, dynamic> json) => _$ChatListFromJson(json);
  Map<String, dynamic> toJson() => _$ChatListToJson(this);
}

@JsonSerializable()
class Chat {
  // 채팅 타이틀
  final String title;

  // 채팅 내용
  final List<Message> messageList;

  // 채팅하고 있는 멤버
  final List<Friend> chatMember;

  // 채팅에 있는 공지 사항 내용
  Noti? notification;

  // 해당 채팅의 제일 최근 수정된 날짜 - 메시지만 카운트함
  @JsonKey(fromJson: _fromJson, toJson: _toJson)
  DateTime modifiedDate;

  Chat(
      {required this.title,
      required this.messageList,
      required this.chatMember,
      required this.modifiedDate});

  factory Chat.fromJson(Map<String, dynamic> json) => _$ChatFromJson(json);
  Map<String, dynamic> toJson() => _$ChatToJson(this);

  static DateTime _fromJson(int millisecondsSinceEpoch) =>
      DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch);

  static int _toJson(DateTime date) => date.millisecondsSinceEpoch;
}

@JsonSerializable()
class Noti {
  final String id;
  final String message;

  Noti({required this.id, required this.message});

  factory Noti.fromJson(Map<String, dynamic> json) => _$NotiFromJson(json);
  Map<String, dynamic> toJson() => _$NotiToJson(this);
}

@JsonSerializable()
class Message {
  final String id;
  final DateTime messageTime;
  final String message;
  final MessageType messageType;
  final bool isMe;

  Message({
    required this.id,
    required this.messageTime,
    required this.message,
    required this.messageType,
    required this.isMe,
  });

  factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(json);
  Map<String, dynamic> toJson() => _$MessageToJson(this);
}

enum MessageType { message, date, state }

 

chat.dart에 추가한 각각의 코드의 의미는 다음과 같습니다.

 


@JsonKey(fromJson: _fromJson, toJson: _toJson)
final DateTime modifiedDate;

 

@JsonKey 어노테이션은 json_annotation 패키지에서 제공하는 기능으로 JSON의 직렬화 / 역직렬화 방식을 커스텀할 때 사용한다.

@JsonKey 어노테이션은 다음과 같은 두 매개변수를 받을 수 있다.

  • fromJson: JSON 데이터를 역직렬화 할 때 사용할 함수를 지정
  • toJson: JSON 데이터를 직렬화 할 때 사용할 함수를 지정

@JsonKey에 사용되는 직렬화 / 역직렬화 함수는 다음과 같습니다

static DateTime _fromJson(int millisecondsSinceEpoch) =>
    DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch);

static int _toJson(DateTime date) => date.millisecondsSinceEpoch;

 

  • millisecondsSinceEpoch는 UNIX 타임스탬프로, 1970년 1월 1일 00:00:00 UTC 이후 경과된 밀리초를 나타냅니다.
    • 즉, 해당 경과된 밀리초를 사용하여 DateTime으로 데이터를 반환합니다.

  factory Chat.fromJson(Map<String, dynamic> json) => _$ChatFromJson(json);
  Map<String, dynamic> toJson() => _$ChatToJson(this);

 

dart의 factory를 사용하여 생성자를 만든다.

 

각각 Chat 객체를 JSON 데이터로 변환하거나 JSON 데이터를 Chat 객체로 변환할 때 사용한다.


마찬가지로 Friend Model 부분도 Chat Model 처럼 변경해준다.

 

import 'package:json_annotation/json_annotation.dart';
part 'friend.g.dart';

@JsonSerializable()
class Friend {
  final String id;
  final String name;
  String message;
  String profileImgPath;
  int me;

  Friend({
    required this.id,
    required this.name,
    this.message = "",
    this.profileImgPath = Strings.defaultProfileImgPath,
    this.me = 0
  });

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'name': name,
      'message': message,
      'profileImgPath': profileImgPath,
      'me': me
    };
  }

  factory Friend.fromMap(Map<String, dynamic> map) {
    return Friend(
      id: map['id'],
      name: map['name'],
      message: map['message'],
      profileImgPath: map['profileImgPath'],
      me: map['me']
    );
  }
  @override
  String toString() {
    return "Friend(id: $id, name: $name, message: $message, profileImgPath: $profileImgPath, me: $me)";
  }

  factory Friend.fromJson(Map<String, dynamic> json) => _$FriendFromJson(json);
  Map<String, dynamic> toJson() => _$FriendToJson(this);
}

 


다음 포스팅에서는 위에서 생성한 코드를 사용하여

 

간단하게 JSON 데이터를 생성하고 JSON에서 데이터를 가져오는 방법에 대해 알아보겠습니다.

 

 

반응형