https://github.com/youngmoon97/flutter
파일 이름 : flutter_http_1 / flutter_http_2 / flutter_boxoffice / flutter_attr_busan
//테이블 용
class PostDTOTable {
//Post가 게시판을 뜻하는것임
int userId; //유저번호
int id; //글 번호
String title; //제목
PostDTOTable({required this.userId, required this.id, required this.title});
//팩토리:생성자를 통해서 객체를 만들려고 하는데 처리가 번거로울 경우 사용함
//어떠한 타입을 받아서 클래스 내부에서 객체를 생성해서 리턴 해주기 위함
factory PostDTOTable.fromJson(dynamic json) => PostDTOTable(
userId: json["userId"],
id: json["id"],
title: json["title"],
);
//모양은 화살표 함수와 비슷, 기능과 역할은 다르다.
//팩토리 아님, 일반 함수임
//JSON은 JSON인데 LIST타입의 데이터를 받는 JSON
static List<PostDTOTable> fromJsonList(List jsonList) {
return jsonList
.map((json) => PostDTOTable.fromJson(json))
.toList(); //괄호안에 e를 그대로 써도되고 json으로 바꿔도되고..
}
}
//상세 페이지용
class PostDTODetail {
int userId; //유저번호
int id; //글 번호
String title; //제목
String body; //내용
PostDTODetail(
{required this.userId,
required this.id,
required this.title,
required this.body});
factory PostDTODetail.fromJson(dynamic json) => PostDTODetail(
userId: json["userId"],
id: json["id"],
title: json["title"],
body: json["body"],
);
}
//post_repository.dart
import 'dart:convert';
import 'package:flutter_http_1/post/model/dto/post_dto.dart';
import 'package:http/http.dart' as http;
class PostRepository{
//싱글톤 - 해당 타입의 객체가 프로그램에서 단 한개만 존재
//스태틱 변수 선언
static PostRepository? _instance;
//첨에는 null이니까 ? 붙임. 지금은 인스턴스가 아니라 오브젝트 상태임
//public 생성자 제거(public 생성자가 있으면 여러개 만들수 있어서 막아야됨)
//dart에서 private는 맨 앞에 언더바(_)를 붙인다.
PostRepository._canAnyName(){
// count++;
// print(count);
} //생성자 이름은 아무거나 만들어도 상관없음 앞에다가 언더바 붙이기
// static int count = 0;
//변수 ?? 대체값
//?? 뒤에는 변수가 null일 경우 대체값으로 들어가는(리턴되는) 내용
//String str = [null일수도 있는 String]; 이면 에러나는데 String str = [null일수도 있는 String] ?? "값없음";은 가능
//String str = "값없음";
//계속 null이라서 부를때마다 새 객체가 호출됨
//--------------------------------------------------------------------
//변수 ??= 대입값
//변수가 null일 경우 변수에 대입값을 넣고 리턴한다.
//String str = [null일수도 있는 String] ??= "값이 없음";
//String str = ["값이 없음"라는 값이 들어간 null일수도 있는 String];
//위 단계에서 값이 들어가기 때문에 다음번 호출할때는 null 아님(새 객체는 한번만 생기고 다음부터는 원래 객체 불러져서 싱글톤 동작)
//싱글톤 객체 getter
static PostRepository get instance => _instance ??= PostRepository._canAnyName();
//값을 넘겨주는 함수. 통신은 실패할 수 있으므로 nullable임
Future<List<PostDTOTable>?> getDTOList() async{
String url = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(Uri.parse(url));
if(response.statusCode==200){ //http 상태 코드. 200은 정상 진행
return PostDTOTable.fromJsonList(jsonDecode(response.body));
}else{
return null;
}
}
}
Future<PostDTODetail?> getDTO(int postId) async{
String url="https://jsonplaceholder.typicode.com/posts/$postId";
http.Response response = await http.get(Uri.parse(url));
}
void main() {
//PostRepository.instance; //생성자를 불러서 1 출력
//PostRepository.instance; //생성자를 불러서 2 출력
//PostRepository.instance; //생성자를 불러서 3 출력
// (??대신 ??=이면 싱글톤이 적용되어서 여러번 불러도 1 한번만 출력됨)
}
import 'package:flutter/material.dart';
class DetailPage extends StatelessWidget {
const DetailPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Text("디테일 페이지");
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_http_1/post/controller/post_table_controller.dart';
import 'package:flutter_http_1/post/model/dto/post_dto.dart';
import 'package:flutter_http_1/post/model/repository/post_repository.dart';
import 'package:flutter_http_1/routes.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
class ListPage extends HookWidget {
const ListPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//더미 데이터
//PostDTOTable postDTOTable = PostDTOTable(userId: 0, id: 0, title: "테스트 제목");
//실제 데이터
//통신은 실패할 수 있다 = nullable
//controller 생성으로 주석처리댐
//final listState = useState<List<PostDTOTable>?>(null);
final controller = context.watch<PostTableController>();
//final jsonState = useState<String?>(null);
//useEffect(작동함수, 관찰할 상태 리스트);
//빌드가 완료되면 작동한다
//관찰하는 상태가 변경되면 작동한다
//관찰하는 상태가 없으면 빌드시 한번 작동한다.
useEffect((){
controller.setPostDTOTableList();
},[]);
return Scaffold(
body: SafeArea(
child: ListView(
children: controller.postDTOTableList?.map((e) => ListItem(postDTOTable: e)).toList()?? [],
),
),
);
}
}
class ListItem extends StatelessWidget {
PostDTOTable postDTOTable;
ListItem({Key? key, required this.postDTOTable}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
context.pushNamed(Routes.detail);
},
child: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black)),
child: Column(
children: [
Text("유저번호 : ${postDTOTable.userId}"),
Divider(),
Text("글 번호 : ${postDTOTable.id}"),
Divider(),
Text("글 제목 : ${postDTOTable.title}"),
],
),
),
);
}
}
import 'package:flutter/foundation.dart';
import 'package:flutter_http_1/post/model/dto/post_dto.dart';
import 'package:flutter_http_1/post/model/repository/post_repository.dart';
class PostTableController extends ChangeNotifier{
List<PostDTOTable>? _postDTOTableList;
List<PostDTOTable>? get postDTOTableList => _postDTOTableList;
void setPostDTOTableList(){
PostRepository.instance.getDTOList().then((value){
_postDTOTableList = value;
notifyListeners();
});
}
}
import 'package:flutter/material.dart';
import 'package:flutter_http_1/post/controller/post_table_controller.dart';
import 'package:flutter_http_1/post/view/pages/list_page.dart';
import 'package:flutter_http_1/routes.dart';
import 'package:provider/provider.dart';
void main(){
// controller는 사용하기 전에 주입을 해줘야한다.
// 프로젝트가 커지면 하나의 controller로만 사용하기 어렵다.
// 주입을 해주는 ChangeNotifierProvider를 여러 개 사용하고 싶다. ->
// MultiProvider를 사용한다.
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (BuildContext context)=>PostTableController()),
],
child: MyApp(),
)
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: Routes.goRouter,
);
}
}
import 'package:flutter_http_1/post/view/pages/detail_page.dart';
import 'package:flutter_http_1/post/view/pages/list_page.dart';
import 'package:go_router/go_router.dart';
class Routes {
static const String table = 'table';
static const String detail = 'detail';
static final GoRouter goRouter = GoRouter(
initialLocation: '/table',
routes: [
GoRoute(
name: Routes.table,
path: '/table',
builder: (context, state) => ListPage(),
),
GoRoute(
name: Routes.detail,
path: '/detail',
builder: (context, state) => DetailPage(),
),
],
);
}
import 'package:flutter/foundation.dart';
import 'package:flutter_http_2/model/dto/user_dto.dart';
import 'package:flutter_http_2/model/repository/user_repository.dart';
class UserTableController extends ChangeNotifier{
List<UserDTOTable>? _userDTOTableList;
List<UserDTOTable>? get userDTOTableList => _userDTOTableList;
void setUserDTOTableList(){
UserRepository.instance.getDTOList().then((value){
_userDTOTableList=value;
notifyListeners();
});
}
}
class UserDTOTable {
int id;
String name;
String email;
UserDTOTable({required this.id, required this.name, required this.email});
factory UserDTOTable.fromJson(dynamic json) => UserDTOTable(
id: json["id"],
name: json["name"],
email: json["email"],
);
static List<UserDTOTable> fromJsonList(List jsonList){
return jsonList.map((json) => UserDTOTable.fromJson(json)).toList();
}
}
class UserDTODetaiil{
int id;
String name;
String email;
String body;
UserDTODetaiil({required this.id, required this.name,
required this.email, required this.body});
}
import 'dart:convert';
import 'package:flutter_http_2/model/dto/user_dto.dart';
import 'package:http/http.dart' as http;
class UserRepository{
static UserRepository? _instance;
UserRepository._canAnyName(){
}// 생성자
static UserRepository get instance => _instance ??= UserRepository._canAnyName();
Future<List<UserDTOTable>?> getDTOList() async{
String url = "https://jsonplaceholder.typicode.com/users";
http.Response response = await http.get(Uri.parse(url));
if(response.statusCode == 200){
return UserDTOTable.fromJsonList(jsonDecode(response.body));
}else{
return null;
}
}
}
void main(){
//
}
import 'package:flutter/material.dart';
class UserDetail extends StatelessWidget {
const UserDetail({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Text("유저 디테일 페이지");
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_http_2/controller/user_controller.dart';
import 'package:flutter_http_2/model/dto/user_dto.dart';
import 'package:flutter_http_2/model/repository/user_repository.dart';
import 'package:flutter_http_2/routes.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
class UserPage extends HookWidget {
const UserPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final controller = context.watch<UserTableController>();
useEffect(() {
controller.setUserDTOTableList();
}, []);
return Scaffold(
body: SafeArea(
child: ListView(
children: controller.userDTOTableList?.map((e) => UserItem(postDTOTable: e)).toList()?? [],
),
),
);
}
}
class UserItem extends StatelessWidget {
UserDTOTable postDTOTable;
UserItem({Key? key, required this.postDTOTable}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
context.pushNamed(Routes.detail);
},
child: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black),
),
child: Column(
children: [
Text("아이디 : ${postDTOTable.id}"),
Divider(),
Text("이름 : ${postDTOTable.name}"),
Divider(),
Text("이메일 : ${postDTOTable.email}"),
],
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_http_2/controller/user_controller.dart';
import 'package:flutter_http_2/routes.dart';
import 'package:flutter_http_2/view/pages/user_page.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (BuildContext context) => UserTableController()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: Routes.goRouter,
);
}
}
import 'package:flutter_http_2/view/pages/user_detail.dart';
import 'package:flutter_http_2/view/pages/user_page.dart';
import 'package:go_router/go_router.dart';
class Routes {
static const String table = 'table';
static const String detail = 'detail';
static final GoRouter goRouter = GoRouter(
initialLocation: '/table',
routes: [
GoRoute(
name: Routes.table,
path: '/table',
builder: (context, state) => UserPage(),
),
GoRoute(
name: Routes.detail,
path: '/detail',
builder: (context, state) => UserDetail(),
),
],
);
}
class BoxofficeDTOTable {
String rank;
String audiCnt;
String movieNm;
String openDt;
BoxofficeDTOTable({
required this.rank,
required this.audiCnt,
required this.movieNm,
required this.openDt,});
factory BoxofficeDTOTable.fromJson(dynamic json) =>
BoxofficeDTOTable(
rank: json["rank"],
audiCnt: json["audiCnt"],
movieNm: json["movieNm"],
openDt: json["openDt"],
);
static List<BoxofficeDTOTable> fromJsonList(List jsonList) {
return jsonList.map((json) => BoxofficeDTOTable.fromJson(json)).toList();
}
}
class BoxofficeResult {
String boxofficeType;
String showRange;
List<BoxofficeDTOTable> dailyBoxOfficeList;
BoxofficeResult({
required this.boxofficeType,
required this.showRange,
required this.dailyBoxOfficeList,
});
factory BoxofficeResult.fromJson(dynamic json) =>
BoxofficeResult(
boxofficeType: json["boxofficeType"],
showRange: json["showRange"],
dailyBoxOfficeList: BoxofficeDTOTable.fromJsonList(json["dailyBoxOfficeList"]),
);
}
import 'dart:convert';
import 'package:flutter_boxoffiice/post/dto/boxoffice_dto.dart';
import 'package:http/http.dart' as http;
class BoxofficeRepository{
static BoxofficeRepository? _instance;
BoxofficeRepository._canAnyName(){
}
static BoxofficeRepository get instance => _instance ??= BoxofficeRepository._canAnyName();
Future<BoxofficeResult?> getDTOList() async{
String url="http://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=f5eef3421c602c6cb7ea224104795888&targetDt=20120101";
http.Response response = await http.get(Uri.parse(url));
if(response.statusCode==200){
var json = jsonDecode(response.body);
//print(response.body);
return BoxofficeResult.fromJson(json["boxOfficeResult"]);
}else{
return null;
}
}
}
void main(){
}
import 'package:flutter/material.dart';
import 'package:flutter_boxoffiice/post/dto/boxoffice_dto.dart';
import 'package:flutter_boxoffiice/post/repository/boxoffice_repository.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class ListPage extends HookWidget {
const ListPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final listState = useState<BoxofficeResult?>(null);
useEffect(() {
BoxofficeRepository.instance.getDTOList().then((value) {
listState.value = value;
});
}, []);
return Scaffold(
body: SafeArea(
child: Column(
children: [
Text(listState.value?.boxofficeType ?? ""),
Divider(height: 1.0,color: Colors.black,thickness: 1.0),
Text(listState.value?.showRange ?? ""),
Expanded(
child: ListView(
children: listState.value?.dailyBoxOfficeList.map((e) => ListItem(boxofficeDTOTable: e)).toList() ?? [],
),
),
],
)
),
);
}
}
class ListItem extends StatelessWidget {
BoxofficeDTOTable boxofficeDTOTable;
ListItem({Key? key, required this.boxofficeDTOTable}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black)),
child: Column(
children: [
Divider(),
Text("랭킹 : ${boxofficeDTOTable.rank}"),
Divider(),
Text("관객 수 : ${boxofficeDTOTable.audiCnt}"),
Divider(),
Text("영화 이름 : ${boxofficeDTOTable.movieNm}"),
Divider(),
Text("개봉 일 : ${boxofficeDTOTable.openDt}"),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_boxoffiice/view/pages/boxoffice_list_page.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ListPage(),
);
}
}
class AttrDTO {
// MAIN_TITLE
// CNTCT_TEL
// MAIN_IMG_THUMB
String mainTitle;
String cntctTel;
String mainImgThumb;
AttrDTO({
required this.mainTitle,
required this.cntctTel,
required this.mainImgThumb,
});
factory AttrDTO.fromJson(dynamic json) => AttrDTO(
mainTitle: json["MAIN_TITLE"],
cntctTel: json["CNTCT_TEL"],
mainImgThumb: json["MAIN_IMG_THUMB"],
);
static List<AttrDTO> fromJsonList(List jsonList){
return jsonList.map((e) => AttrDTO.fromJson(e)).toList();
}
}
import 'package:flutter/material.dart';
import 'package:flutter_attr_busan/attr_dto.dart';
class AttrItem extends StatelessWidget {
final AttrDTO attrDTO;
const AttrItem({Key? key, required this.attrDTO}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10),
child: Column(
children: [
Image.network(attrDTO.mainImgThumb),
Text(attrDTO.mainTitle),
Text(attrDTO.cntctTel),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_attr_busan/attr_dto.dart';
import 'package:flutter_attr_busan/attr_item.dart';
import 'package:flutter_attr_busan/attr_repository.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class AttrPage extends HookWidget {
const AttrPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final listState = useState<List<AttrDTO>>([]);
useEffect(() {
AttrRepository.getDTO().then((value) {
listState.value = value ?? [];
});
}, []);
return Scaffold(
body: SafeArea(
child: ListView(
children: listState.value.map((e) => AttrItem(attrDTO: e)).toList(),
),
),
);
}
}
import 'dart:convert';
import 'package:flutter_attr_busan/attr_dto.dart';
import 'package:http/http.dart' as http;
class AttrRepository {
static Future<List<AttrDTO>?> getDTO() async {
final String url = "https://apis.data.go.kr/6260000/AttractionService/getAttractionKr?serviceKey=L4O6Jd5locofQV0Sa674EwMQ4GyHi380DNlzkWVMQLw8O2LvzNMvBKe1RxTj4jssgmQKPrDvinJFtSOIs9KmbA%3D%3D&pageNo=1&numOfRows=10&resultType=json";
http.Response response = await http.get(Uri.parse(url));
if(response.statusCode == 200){
dynamic json = jsonDecode(response.body);
return AttrDTO.fromJsonList(json["getAttractionKr"]["item"]);
} else {
return null;
}
}
}
import 'package:flutter/material.dart';
import 'package:flutter_attr_busan/attr_page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: AttrPage(),
);
}
}