[캡스톤_front] flutter api 값을 넘기고, request 받아서 화면 navigator 하기

피용희·2024년 4월 14일
0

2024 캡스톤

목록 보기
18/19

귀찮아서 정리는 아직 안했지만..
사실 어제까지 화면 전체적으로 다듬기 및 qr 가운데에 이미지 넣기 등
전체적인 꾸밈요소 넣기는 전부 끝났다!

그래서 오늘은, api로 보내기 위한 새로운 싱글톤 클래스를 생성하고
그 클래스의 data 정보를 api로 보내서, 성공 요청을 받으면 다음 화면인 "송금 완료" 화면으로 넘기는 것까지의 작업을 해보았다.

일단 현재까지 완성된 결과물을 살펴보자!


업로드중..


오늘 추가한 것은, 여기서 201이라는 create request를 받을시 다음 화면으로 넘어가도록 한 것이다.(왜인지 사이트에는 put 시행시 정상 request가 200이라고 나와 있던데, 201이 날라오드라...create시 201 request가 날라온다고 하는데 이 부분은 수정이 필요할시 수정 진행할 예정이다.)

class SendApi {
  late String sendAccountId;
  late String receiveAccountId;
  late int amount;

  // 싱글톤 인스턴스 생성
  static final SendApi _instance = SendApi._internal();

  factory SendApi() => _instance;

  // 내부 생성자 (임시)
  SendApi._internal() {
    sendAccountId = '김철수'; //로그인 세션에서 받아올 예정
    receiveAccountId = ''; //api에서 받아오기
    amount = 0;
  }

  Map<String, dynamic> toJson() {
    return {
      'sendAccountId': sendAccountId,
      'receiveAccountId': receiveAccountId,
      'amount': amount,
    };
  }
}

우선 보내기 위한 api data를 저장하는 클래스를 새로 생성했다.
원래는 sendAccountId의 경우, 로그인 세션에서 받아와야 하는데 아직 로그인 부분은 완전 구현이 안 된 상태라 임의의 이름을 넣었다.
receiveAccountId와 amount는 qr에서 읽어온 데이터를 넣을 예정이다.

싱글톤 인스턴스 생성하는 방법은 예전에 다뤘으니 넘어가고..
toJson()은 put 데이터로 보낼때 Map<String, dynamic> 데이터를 보내야 해서 만든 것이다. 여기에 각 요소들이 map 형태로 담겨져 전송될 예정이다.

import 'package:http/http.dart' as http;
import 'dart:convert';

import 'package:flutter/cupertino.dart';

Future<int> httpPut({required String path, Map? data}) async {
  String baseUrl = 'https://reqres.in$path';
  var body = jsonEncode(data);
  try {
    http.Response response =
    await http.post(Uri.parse(baseUrl), body: body, headers: {
      "accept": "application/json",
      "Content-Type": "application/json",
    });
    return response.statusCode; //200
  } catch (e) {
    debugPrint("httpPut error: $e");
    return 503;
  }
}

put을 처리할 코드이다.
https://nuridal-class.tistory.com/entry/%ED%8C%A8%ED%82%A4%EC%A7%80-http%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-API-%ED%98%B8%EC%B6%9C%ED%95%B4%EB%B3%B4%EA%B8%B0

이 분의 http api 호출법을 참고했다. 감사합니다!!

https://reqres.in$path라는 baseUrl에 각 요청에 따라 뒤 url을 붙여서 백 서버로 보낼 수 있는 기능이고, headers를 통해서 헤더를 같이 보낸다.
에러가 발생할시 503등의 서버 에러를 발생시킬 수 있도록 했다. 서버 에러 발생시 화면을 어떻게 할지도 정해야 할 것 같긴한데...이 부분은 논의가 필요할 것 같아서 우선 보류중이다.

@override
  void initState() {
    super.initState();
    // 데이터를 가져오는 함수 호출. init 부분에서 시행한다.
    fetchData();
  }

  Future<void> fetchData() async {
    try {
      // API 요청을 보냅니다.
      final value = await httpPut(path: '/api/users/2', data: sendApi.toJson());

      if (value == 201) { //put
        // 성공적으로 응답을 받았을 때 FinishExchange 화면으로 이동합니다.
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => FinishExchange()),
        );
      } else {
        print(value);
        debugPrint('서버 에러입니다. 다시 시도해주세요');
        // 에러가 발생하면 에러 메시지를 출력합니다.
        // 이 경우에는 화면 전환이 필요하지 않으므로 setState()는 호출하지 않습니다.
      }
    } catch (e) {
      debugPrint('API 요청 중 오류가 발생했습니다: $e');
      // 에러가 발생하면 에러 메시지를 출력합니다.
      // 이 경우에는 화면 전환이 필요하지 않으므로 setState()는 호출하지 않습니다.
    }
  }

로딩 화면에서는 init 부분에 fetchData() 라는 api 요청 비동기 함수를 넣어주었다.

굳이 초기화 작업에서 api 요청을 진행하는 이유가 뭘지 궁금해서 찾아본 결과는 다음과 같다.

  • initState() 메서드는 StatefulWidget이 생성될 때 한 번만 호출되는 특별한 메서드이다. 이곳에서는 주로 초기화 작업을 진행하는 이유는 다음과 같다.
    • 한 번만 호출되도록 보장: initState()는 StatefulWidget이 처음 생성될 때 한 번만 호출되므로, 데이터를 가져오는 함수를 여기서 호출하면 화면이 처음 렌더링될 때 한 번만 데이터를 가져온다. 이는 중복 요청을 방지하고 성능을 향상시킨다.
    • 화면이 렌더링되기 전에 데이터를 준비할 수 있음: initState()는 화면이 실제로 빌드되기 전에 호출되므로, 데이터를 가져오는 함수를 이곳에서 호출하면 화면이 빌드되기 전에 데이터를 가져와서 화면에 표시할 준비를 할 수 있다.
    • 에러 처리: 데이터 가져오기 함수는 비동기적일 수 있으므로, initState() 내에서 예외를 캐치하고 적절히 처리할 수 있다.

또한, 정상적으로 송금이 완료되면 FinishExchange() 화면으로 이동할 수 있도록 했다.

++ 추가

spacer()와 expended로 버튼을 아래에 고정할때 주의할 점이 있다..

Expanded(
                flex: 50,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.end,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Text(
                      '보내기 성공!',
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        color: Color(0xFF4B4A48),
                        fontSize: 30,
                        fontFamily: 'Noto Sans KR',
                        fontWeight: FontWeight.w300,
                        height: 0,
                      ),
                    ),
                    const SizedBox(height: 20),
                    Text(
                      '매듭 보내기가',
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        color: Color(0xFFFF8D4D),
                        fontSize: 40,
                        fontFamily: 'Noto Sans KR',
                        fontWeight: FontWeight.w500,
                        height: 0,
                      ),
                    ),
                    Row(
                      mainAxisSize: MainAxisSize.min,
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: [
                        Text(
                          '완료',
                          textAlign: TextAlign.center,
                          style: TextStyle(
                            color: Color(0xFFFF8D4D),
                            fontSize: 40,
                            fontFamily: 'Noto Sans KR',
                            fontWeight: FontWeight.w500,
                            height: 0,
                          ),
                        ),
                        const SizedBox(width: 10),
                        Text(
                          '되었습니다.',
                          textAlign: TextAlign.center,
                          style: TextStyle(
                            color: Colors.black,
                            fontSize: 30,
                            fontFamily: 'Noto Sans KR',
                            fontWeight: FontWeight.w500,
                            height: 0,
                          ),
                        ),
                      ],
                    ),
                    Padding(
                      padding: const EdgeInsets.symmetric(vertical: 20.0),
                      // 패딩 설정
                      child: SizedBox(
                        height: 250,
                        width: 250,
                        child: Lottie.asset("assets/lottie/handshake.json"),
                      ),
                    ),
                    Text(
                      '추가로 보낼까요?',
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        color: Color(0xFF4B4A48),
                        fontSize: 30,
                        fontFamily: 'Noto Sans KR',
                        fontWeight: FontWeight.w300,
                        height: 0,
                      ),
                    ),
                  ],
                ),
              ),
              Spacer(),

이렇게 가운데로 정렬하기 위한 mainAxis, crossAxis를 expended 안에 정의해야 한다!!
부모 컬럼 안에 정의하면 말짱 도루묵이라는거

profile
코린이

0개의 댓글

관련 채용 정보