API 문서

1. 게시글목록 (Get)
<http://10.0.0.171:8080/api/post>

2. 게시글상세 (Get)
<http://10.0.0.171:8080/api/post/1>

3. 게시글쓰기 (Post)
<http://10.0.0.171:8080/api/post>
application/json
{"title": "제목입니다", "content":"내용입니다"}

4. 게시글삭제 (Delete)
<http://10.0.0.171:8080/api/post/1>

5. 게시글수정 (Put)
<http://10.0.0.171:8080/api/post/1>
application/json
{"title": "제목입니다", "content":"내용입니다"}

post_list_page

import 'package:blog/ui/components/custom_appbar.dart';
import 'package:blog/ui/list/components/post_list_body.dart';
import 'package:blog/ui/list/post_list_page_vm.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class PostListPage extends ConsumerWidget {

  final refreshKey = GlobalKey<RefreshIndicatorState>();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: CustomAppBar(title: "Post List Page"),
      body: RefreshIndicator(
        key: refreshKey,
        onRefresh: () async {
          ref.read(postListProvider.notifier).notifyInit();
        },
        child: PostListBody(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          Navigator.pushNamed(context, "/write");
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

post_list_body

import 'package:blog/data/post.dart';
import 'package:blog/ui/detail/post_detail_page.dart';
import 'package:blog/ui/list/post_list_page_vm.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class PostListBody extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    List<Post>? models = ref.watch(postListProvider);

    if (models == null) {
      return Center(child: CircularProgressIndicator());
    } else {
      return Padding(
        padding: const EdgeInsets.symmetric(horizontal: 16),
        child: ListView.separated(
          itemCount: models.length,
          itemBuilder: (context, index) {
            return ListTile(
              leading: Text("${models[index].id}"),
              title: Text("${models[index].title}"),
              trailing: IconButton(
                icon: Icon(Icons.arrow_forward_ios),
                onPressed: () {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => PostDetailPage(),
                      ));
                },
              ),
            );
          },
          separatorBuilder: (context, index) => Divider(),
        ),
      );
    }
  }
}

post_repository

import 'package:blog/core/utils.dart';
import 'package:blog/data/post.dart';
import 'package:dio/dio.dart';

class PostRepository {
  // 1. 게시글목록
  Future<List<Post>> findAll() async {
    Response response = await dio.get("/api/post");
    List<dynamic> list = response.data["body"];
    List<Post> posts = list.map((e) => Post.fromJson(e)).toList();
    return posts;
  }

  // 2. 게시글상세보기
  Future<Post> findById(int id) async {
    Response response = await dio.get("/api/post/$id");
    Post post = Post.fromJson(response.data["body"]);
    return post;
  }

  // 3. 게시글쓰기
  Future<void> write(String title, String content) async {
    try {
      Response response = await dio.post(
        "/api/post",
        data: {
          "title":title,
          "content":content
        },
      );
    } catch (error) {
      throw Exception(error);
    }
  }

  // 4. 게시글삭제
  Future<void> deleteById(int id) async {
    try {
      Response response = await dio.delete("/api/post/$id");
    } catch (error) {
      throw Exception(error);
    }
  }
}

post_list_page_vm

import 'package:blog/data/post.dart';
import 'package:blog/data/post_repository.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// 창고
class PostListVM extends StateNotifier<List<Post>?>{
  PostListVM(super.state);

  Future<void> notifyInit() async {
    List<Post> posts = await PostRepository().findAll();
    state = posts;
  }

}

// 창고 관리자
final postListProvider = StateNotifierProvider<PostListVM, List<Post>?>((ref) {
  return PostListVM(null)..notifyInit();
});

post_detail_page_vm

import 'package:blog/data/post.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// 창고
class PostDetailVM extends StateNotifier<Post?>{
  PostDetailVM(super.state);

  Future<void> notifyInit() async {
    // PostRepository().findById(1);
  }
}

// 창고 관리자
final postDetailProvider = StateNotifierProvider<PostDetailVM, Post?>((ref) {
  return PostDetailVM(null)..notifyInit();
});

post

class Post {
  int id;
  String title;
  String content;
  String createdAt;
  String updateAt;

  Post(this.id, this.title, this.content, this.createdAt, this.updateAt);

  // Get 요청시 사용
  Post.fromJson(Map<String, dynamic> json)
      : id = json["id"] ?? "",
        title = json["title"] ?? "",
        content = json["content"] ?? "",
        createdAt = json["createdAt"] ?? "",
        updateAt = json["updateAt"] ?? "";

}