DevBoi

[Flutter] S3이미지 + 데이터 Listview 세팅 (백엔드 서버 통신) 본문

[Mobile]/[Flutter]

[Flutter] S3이미지 + 데이터 Listview 세팅 (백엔드 서버 통신)

HiSmith 2023. 8. 12. 22:35
반응형

1. S3에 이미지를 올린다.

https://devboi.tistory.com/564 참고하여, S3 구성

테스트 이미지 세팅

 

2.플러터 S3이미지 호출 방법

assets가 아닌 외부 Url로 이미지를 세팅하는 방법은 이렇다.

Image.network(
              "s3주소/image/3126993.png",
              height: 170,
              width: MediaQuery.of(context).size.width,
              fit: BoxFit.cover,
            ),

 

3. 확인

4. 데모 백엔드 서버 구성

Docker-compose + Spring Hibernate + Mariadb (비즈니스 로직에 따라 querydsl 옵셔널)

 

5. 플러터에서 데모 백엔드 호출 

 

라이브러리 추가 + http 통신 api 개발

http: ^0.13.5
Future<List<PostItem>> getApiGet(Map<String, dynamic>? param) async{
  print('get Api get 호출');
  Iterable l;
  late List<PostItem> posts ;
  var url = Uri.http(backendHost, 'content',param);
  var response = await http.get(url).then((value) =>
  {
        l = json.decode(value.body),
       posts = List<PostItem>.from(l.map((model)=> PostItem.fromJson(model)))
  }
  );
  return  posts;
}

api를 호출하는 Widget 소스이다

class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text("Feeds"),
        centerTitle: true,
        actions: <Widget>[
          IconButton(
            icon: Icon(
              Icons.filter_list,
            ),
            onPressed: () {},
          ),
        ],
      ),

      body: Container(
        child: FutureBuilder(
          future: getApiGet({'asfa':'asfas'}),
          builder: (context,AsyncSnapshot snapshot){
          if (snapshot.hasData) {
            print(snapshot);
            return ListView.builder(
              padding: EdgeInsets.symmetric(horizontal: 20),
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, int index) {
                PostItem item = snapshot.data[index];
                return PostItem(dp: item.dp,name: item.name,img: item.img,time: item.time,);
              },
            );
          }
          else
            {
              return Container(
                child: Center(
                  child: Text("Loading..."),
                ),
              );
            }
          }
        )
      ),
class PostItem extends StatefulWidget {
  var dp;
  var name;
  var time;
  var img;

  PostItem({
    super.key,
    required this.dp,
    required this.name,
    required this.time,
    required this.img,
  });
  factory PostItem.fromJson(dynamic? json){
    PostItem item =  PostItem(dp: json?['dp'],name: json?['name'],time: json?['time'],img: json?['img']);
    return item;
  }
  @override
  _PostItemState createState() => _PostItemState();
}

class _PostItemState extends State<PostItem> {

위는 게시글에 대한 모델 소스이다.

리스트 뷰에 부를때는 FutureBuilder를 사용한다. 그러면 초기화에 대한 이슈가 자동으로 해결된다.

 

이렇게 목록들이 리스트 뷰로 그려준다.

 

전체 소스는 이렇다.

import 'package:flutter/material.dart';

class PostItem extends StatefulWidget {
  var dp;
  var name;
  var time;
  var img;

  PostItem({
    super.key,
    required this.dp,
    required this.name,
    required this.time,
    required this.img,
  });
  factory PostItem.fromJson(dynamic? json){
    PostItem item =  PostItem(dp: json?['dp'],name: json?['name'],time: json?['time'],img: json?['img']);
    return item;
  }
  @override
  _PostItemState createState() => _PostItemState();
}

class _PostItemState extends State<PostItem> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 5),
      child: InkWell(
        child: Column(
          children: <Widget>[
            ListTile(
              leading: CircleAvatar(
                backgroundImage: AssetImage(
                  "${widget.dp}",
                ),
              ),
              contentPadding: EdgeInsets.all(0),
              title: Text(
                "${widget.name}",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                ),
              ),
              trailing: Text(
                "${widget.time}",
                style: TextStyle(
                  fontWeight: FontWeight.w300,
                  fontSize: 11,
                ),
              ),
            ),
            Image.network(
              "https://gshotbucket.s3.ap-northeast-2.amazonaws.com/image/3126993.png",
              height: 170,
              width: MediaQuery.of(context).size.width,
              fit: BoxFit.cover,
            ),
          ],
        ),
        onTap: () {},
      ),
    );
  }
}
import 'dart:convert';

import 'package:boilerflutterapp/view/widget/post/post_item.dart';
import 'package:http/http.dart' as http;


const String backendHost = "localhost:8080";
const String imageS3Host = "https://gshotbucket.s3.ap-northeast-2.amazonaws.com/image";

Future<List<PostItem>> getApiGet(Map<String, dynamic>? param) async{
  Iterable l;
  late List<PostItem> posts ;
  var url = Uri.http(backendHost, 'content',param);
  await http.get(url).then((value) =>
  {
        l = json.decode(value.body),
       posts = List<PostItem>.from(l.map((model)=> PostItem.fromJson(model)))
  }
  );
  return  posts;
}
import 'package:boilerflutterapp/http/httpApi.dart';
import 'package:flutter/material.dart';
import '../../widget/post/post_item.dart';


class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text("Feeds"),
        centerTitle: true,
        actions: <Widget>[
          IconButton(
            icon: Icon(
              Icons.filter_list,
            ),
            onPressed: () {},
          ),
        ],
      ),

      body: Container(
        child: FutureBuilder(
          future: getApiGet({'asfa':'asfas'}),
          builder: (context,AsyncSnapshot snapshot){
          if (snapshot.hasData) {
            print(snapshot);
            return ListView.builder(
              padding: EdgeInsets.symmetric(horizontal: 20),
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, int index) {
                PostItem item = snapshot.data[index];
                return PostItem(dp: item.dp,name: item.name,img: item.img,time: item.time,);
              },
            );
          }
          else
            {
              return Container(
                child: Center(
                  child: Text("Loading..."),
                ),
              );
            }
          }
        )
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(
          Icons.add,
          color: Colors.white,
        ),
        onPressed: () {},
      ),
    );
  }
}

이러면 무한으로 Listview Builder가 무한 리스트뷰를 그려준다.

반응형