프로젝트를 진행하면서 백엔드 Spring boot 서버와 통신이 필요하게 됩니다. 수많은 데이터를 로컬에 저장하기엔 너무 무거우니까요.

우리는 서버 컴퓨터에 저장된 데이터 가져온 후 화면에 나타내려고 합니다. 

서버에서 데이터를 가져오는 방법은 많지만, 가장 쉽고 대표적인 방법으로 HTTP 통신을 사용하려 합니다.

 

Flutter 에서 사용하기 위해서는 http package 가 필요하므로 설치해줍시다.

pubspec.yaml 파일에 아래 내용을 넣고, pub get 을 해줍시다!

  http: ^1.1.0

 

먼저 대략적인 순서는 이렇습니다.

1. post, get method 를 통하여 데이터를 요청한다. (Front)

2. 백엔드에서 요청을 받은 후, 쿼리를 통해 백엔드 데이터베이스에서 데이터를 가져온다. (Backend)

3. 백엔드에서 request에 대한 response로 데이터를 반환한다. (Backend)

4. 반환한 데이터를 상황에 맞게 자료구조에 저장한 뒤, 화면에 나타낸다. (Front)

 

2,3 은 Spring boot에서 다루므로 오늘 글에서는 알아보지는 않지만 순서가 이렇게 진행된다는 것은 반드시 숙지해야합니다. (모르면 백엔드와 소통이 안됨..ㅜㅜ)

 

1. post, get method를 통해 데이터를 요청한다

우리는, 데이터를 '가져오는' 입장이기 때문에 GET 메서드를 사용합니다. (POST를 사용해도 무방합니다. 보안성을 고려한다면 POST로!)

프로젝트에서 가져오려는 데이터는 마커를 클릭했을 때 마커가 나타내는 Location의 이름과 Location의 이미지 List 입니다.

해당 내용을 가져오기 위해서 백엔드는 고민에 빠지고, 우리에게 한마디 통보하게 됩니다.

 

"어디에 있는 Location이지? 위도와 경도를 적어놓을 공간을 줄테니까, 여기에 꼭좀 적어줘. 그럼 안줄거임 ㅅㄱ"

 

백엔드의 요청에 답하기 위해 우리는 get 메서드에 필요한 parameter를 기재해줘야 합니다.

 

형식은 이렇습니다.

"http://{ServerAddress}/API../../information?latitude={}&longitude={}"

우리는 중괄호로 감싸진 공간에 답하여야만, 요청을 할 수 있고 백엔드에서 중괄호에 넣은 내용을보고 데이터베이스에서 우리가 원하는 데이터를 찾습니다.

이제, 1번 항목의 코드는 대략 다음과 같습니다. (parameter에 category 같은경우 빼셔도 무방)

final response = await http.get(
        Uri.parse("http://${ServerConf.url}/location/search/information?latitude=$latitude&longitude=$longitude&category=$category"),
        headers: <String, String>{
          'Content-Type': 'application/json',
        }
    );

 

4. 백엔드에 반환해준 데이터를 상황에 맞게 자료구조에 저장한다.

글로 설명하는 것보다 코드를 먼저 보면서 설명해보겠습니다. 

 if (response.statusCode == 200) {
      var data = jsonDecode(utf8.decode(response.bodyBytes));
      String title = data["title"];

      List<dynamic> imageBlobs = data["images"];

      // Blob 데이터를 Uint8List로 변환합니다.
      List<Uint8List> images = imageBlobs.map<Uint8List>((imageData) {
        return base64Decode(imageData["image"]);
      }).toList();
      // 결과를 title과 이미지 리스트로 반환합니다.
      return {
        "title": title,
        "images": images
      };
    } else {
      // 오류 처리
      throw Exception("Failed to load location data");
    }

 

http 요청은 response를 통해 반환이 되는데, response마다 statuscode로 그 결과의 형태가 어떤 것인지 알 수 있다.

보통 response.status 값이 200이라면, 정상적으로 반환했다는 의미이다.

여러가지 status code가 존재하니 아래 링크를 통해 한번 눈으로 훑어봤으면 좋겠습니다.

https://developer.mozilla.org/ko/docs/Web/HTTP/Status

 

백엔드에서 데이터를 전달할 때 response.body를 통해 그 데이터가 전달되고, 컨텐츠 타입을 JSON 형태로 지정했다.

만약, 데이터에 한글이 포함되어 있다면 json을 Decode 할 때 utf8을 사용해야 한다.

 

image는 db에 바이트코드로 저장이 되어있으며, 백엔드와 base64 방식으로 인코딩/디코딩 하기로 약속했다.

Flutter에서 이를 받아왔을 때 실제로 사용하기 위해서는 base64로 다시 디코딩 해줘야 한다. 

 

다시 정리해보면

백엔드가 원하는 데이터

  • latitude(위도)
  • longitude(경도)

프론트엔드가 원하는 데이터

  • Location 관련 image 리스트
  • Location Name

프론트 입장에서는 항상 백엔드가 원하는 데이터가 무엇인지 post, get 메서드를 통해 이를 명시해줘야 합니다.

 

전체코드는 다음과 같습니다.

 

import 'dart:convert';
import 'dart:typed_data';
import 'package:mapdesign_flutter/APIs/backend_server.dart';
import 'package:http/http.dart' as http;

class LocationClicked{
  static clickLocation(double latitude, double longitude, String category) async {
    final response = await http.get(
        Uri.parse("http://${ServerConf.url}/location/search/information?latitude=$latitude&longitude=$longitude&category=$category"),
        headers: <String, String>{
          'Content-Type': 'application/json',
        }
    );
    if (response.statusCode == 200) {
      var data = jsonDecode(utf8.decode(response.bodyBytes));
      String title = data["title"];

      List<dynamic> imageBlobs = data["images"];

      // Blob 데이터를 Uint8List로 변환합니다.
      List<Uint8List> images = imageBlobs.map<Uint8List>((imageData) {
        return base64Decode(imageData["image"]);
      }).toList();
      // 결과를 title과 이미지 리스트로 반환합니다.
      return {
        "title": title,
        "images": images
      };
    } else {
      // 오류 처리
      throw Exception("Failed to load location data");
    }
  }
}