Contents
통신시 파싱하는 방법통신시 파싱하는 방법
플러터는 통신으로 json 정보를 받으면 개발자가 직접 jsonDecode() 같은 코드를 사용해서 json을 map으로 파싱해서 사용해야 되지만
통신시
dio
라는 라이브러리를 사용하면 json으로 받은 것을 dart의 Map 타입으로 편하게 파싱해줄 수 있다.response로 응답을 받은 것을 dio 라이브러리를 통해 response.data로 바로 map으로 파싱하고 map에서 키값으로 밸류를 꺼내는 것처럼 response.data[’body’]를 사용해서 body를 꺼내서 사용하는 것이었다.
통신을 하는 부분은 따로 repository 폴더에 화면 구조와 똑같이 해서 만들어 놨다
lend_tab.vm.dart에서 통신요청을 할 때는 lend_repository.dart를 사용한다.

lend_tab_vm.dart에서
대여중 리스트를 뽑기 위해서 통신을 통해 list를 받아 오고 싶다.
lend_repository.dart 에서 findAll을 통해 json을 map으로 파싱한 정보를 그대로 리턴하고 vm에서 list로 받고 있다.

lend_repository.dart의 findAll

dio를 사용해서 주소를 적고 요청을 하는데
core/utils에 my_http.dart에 있다.
import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:intl/intl.dart';
final baseUrl = "http://192.168.0.58:8080";
//로그인 되면, dio에 jwt 추가하기
//dio.options.headers['Authorization'] = 'Bearer $_accessToken';
final dio = Dio(
BaseOptions(
baseUrl: baseUrl, // 내 IP 입력
contentType: "application/json; charset=utf-8",
//응답코드가 200이 아니면 다 터지는데 그러면 에러 메시지를 못 받는다.
//그렇기 때문에 아래의 설정을 해줘야 응답 코드가 200이 아니어도(실패했어도) 서버가 터지지 않고 에러메시지를 받는다.
//그래야 에러 메시지를 받아서 alert를 띄워줄 수 있을 것이다.
validateStatus: (status) => true, // 200 이 아니어도 예외 발생안하게 설정
),
);
api 주소 요청시 앞에 붙이는 ip주소는 서버 ip주소를 넣으면 되는데
내가 내 컴퓨터에서 할 때는 시작 → cmd → ipconfig를 쳐서 IPv4주소 사용
이러고 my_http.dart에서 baseUrl에 넣어줘야 가능하다.
(참고로 내가 내 컴에서 할 때는 어플은 바로 가능하지만 웹으로 할 때는 CORS 설정 필요)
서버 CORS 설정
이렇게 맵으로 파싱된 정보를 뽑아서 그대로 리턴시킨다.
repository에서는 들어오는 json 데이터를 map으로 파싱하면서 받고 그대로 vm에 리턴해주면 된다.
그런데 map으로 어떻게 파싱해야될 지는 들어오는 데이터의 모양에 따라 다르다.
데이터에서 body를 빼고 그 안에서 또 books를 뺀 것은 들어오는 데이터의 모양이 아래처럼 body에 books라는 배열에 정보가 들어 있기 때문이다.

일단 List<dynamic> 타입으로 리턴해주고
vm에서 List<dynamic>타입으로 받아서 우리가 필요한 Lend타입인
List<Lend> 타입으로 변환 해준다. 이 작업은 repository의 책임이 아니기 때문에 vm에서 해줘야 한다.
참고로 map을 꺼내는 것은 2줄의 단계를 [’a’][’b’] 이런 식으로 한 번에 꺼낼 수 있다.

다시 vm으로 돌아가보면
ui/main/library/lend_tab의 lend_tab.vm

받아온 list를 map으로 돌리면서 Lend.fromMap(map) 생성자에 넣으면서 List<Lend>로 변환해줬다.
이 newList를 LendTabVm의 Model인 LendListModel에
객체를 새로 생성하면서 전달하면 상태 변경을 감지하고 이를 보고 있던 view들이 한 번에 바뀌게 되는 것이다.
아래는 library에서 사용중인 Lend 클래스이다. 공통적으로 항상 사용되는 필드는 ?를 안 붙였다.
import 'package:bookbox/core/utils/date_format.dart';
class Lend {
int? lendId;
String? lendDate;
String returnDate;
bool? returnStatus;
String isbn13;
String title;
String cover;
Lend({
this.lendId,
this.lendDate,
required this.returnDate,
this.returnStatus,
required this.isbn13,
required this.title,
required this.cover,
});
Lend.fromMap(map)
: this.lendId = map['lendId'],
this.lendDate = DateUtil.format(map['lendDate']),
this.returnDate = DateUtil.format(map['returnDate']),
this.returnStatus = map['returnStatus'],
this.isbn13 = map['isbn13'],
this.title = map['title'],
this.cover = map['cover'];
}
참고로 lendDate는 core/utils에 date_format.dart의 DateUtil을 사용해서 시간 파싱을 해주고 있는데 이때 null이 들어오면 null포인터 예외가 터지므로 null 처리를 해줘야 한다. 위에 공용 클래스 만들기에서 설명한 것처럼 이런 null 처리를 하고 싶지 않다면 화면별로 언더바 ( _ ) 를 붙여서 개별 클래스를 사용한다.
date_format.dart
import 'package:intl/intl.dart';
class DateUtil {
static String format(String? date) {
if (date == null) {
return "";
}
DateTime dt = DateTime.parse(date);
String formatDt = DateFormat("yy-MM-dd").format(dt);
return formatDt;
}
}
null이 들어올 수도 있으므로 String? date 를 해줬다.
Share article