ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 32일차
    카테고리 없음 2023. 3. 12. 21:11
    • Getx AuthController 강의를 보고 따라서 제작하시오.

     

    • AuthController에는 User의 정보만을 담고있다. 로그인을 하면 유저를 식별할 수 있는 Token 값도 함께 받아볼 수 있는데, 해당 Token 값을 AuthController 내에 저장할 수 있도록 하고, 코드를 제시하시오.
      • 해당 API의 정보는 다음과 같다
        • API URL
        • // <http://52.79.115.43:8090/api/collections/users/auth-with-password>
        • API Request
        • // Method : POST // data : identity(String), password(String) // Teddy/sfac12341234
        • API Response
    {
      "token": "JWT_TOKEN",
      "record": {
        "id": "RECORD_ID",
        "collectionId": "_pb_users_auth_",
        "collectionName": "users",
        "created": "2022-01-01 01:00:00Z",
        "updated": "2022-01-01 23:59:59Z",
        "username": "username123",
        "verified": false,
        "emailVisibility": true,
        "email": "test@example.com",
        "name": "test",
        "avatar": "filename.jpg"
      }
    }

     

     

    • MainController에는 readDocuments라는 멤버 함수(메서드)를 제작하시오.
      • 해당 API의 정보는 다음과 같다 이 때, AuthController를 find하여 Token값이 존재하면 (로그인 되었다면) 실행할 수 있도록 한다.
        • API URL
        • // <http://52.79.115.43:8090/api/collections/documents/records>
        • API Request (필수)
      • // Method: GET
        // 해당 API는 인증된 사용자만 사용할 수 있기 때문에
        // 로그인 시 획득한 Token을 반드시 Request 헤더에 Authorization을 포함시켜야만합니다.

        • API Response (성공시) 
    • 위 API 정보를 토대로 응답 데이터형식에 맞게 Document 커스텀 클래스를 제작하고, MainPage의 Home이 다음과 같이 출력되도록 한다.

    • 아래 FAB를 누르면 readDocuments를 실행하고 결과를 화면에 출력한다.
      • document리스트는 MainController 멤버변수로 저장한다.
    • 다음의 제공되는 코드를 사용할 수 있도록 한다.
      • /lib/model/document.dart
    // ignore_for_file: public_member_api_docs, sort_constructors_first, non_constant_identifier_names
    
    class Document {
      String title;
      String content;
      String sec_level;
      String? attachment_url;
      Document({
        required this.title,
        required this.content,
        required this.sec_level,
        this.attachment_url,
      });
    
      factory Document.fromMap(Map<String, dynamic> map) {
        return Document(
          title: map['title'] as String,
          content: map['content'] as String,
          sec_level: map['sec_level'] as String,
          attachment_url:
              map['attachment_url'] != '' ? map['attachment_url'] : null,
        );
      }
    }

     

     

     

     

    lib/controller/auth_controller.dart

    import 'package:dio/dio.dart';
    import 'package:get/get.dart';
    import 'package:myapp32/model/user.dart';
    import 'package:myapp32/util/api_routes.dart';
    import 'package:myapp32/util/app_routes.dart';
    
    class AuthController extends GetxController {
      final Rxn<User> _user = Rxn();
      Dio dio = Dio();
      String? _token;
    
      User? get user => _user.value; //user를 불러오면 _user의 value를 전달해
      String? get token => _token; //토큰 전달
    
      login(String id, String pw) async {
        try {
          var res = await dio.post(
              'http://52.79.115.43:8090${ApiRoutes.authWithPassword}',
              data: {'identity': id, 'password': pw}); //데이터따로관리해준
          if (res.statusCode == 200) {
            var user = User.fromMap(res.data['record']);
            _user(user); //유저정보 저장
            _token = res.data['token']; //토큰저장
          }
        } on DioError catch (e) {
          print(e.message);
        }
      }
    
      logout() {
        _user.value = null;
      }
    
      _handleAuthChanged(User? data) {
        if (data != null) {
          //메인페이지 이동
          Get.toNamed(AppRoutes.main);
          return;
        }
        //로그인페이지 이동
        Get.toNamed(AppRoutes.login);
        return;
      }
    
      @override
      void onInit() {
        super.onInit();
        ever(_user, _handleAuthChanged);
      }
    }

    token...어케하지 눈치것 썼는데..

     

    lib/controller/login_controller.dart

    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:myapp32/controller/auth_controller.dart';
    
    class Logincontroller extends GetxController {
      var idController = TextEditingController();
      var pwController = TextEditingController();
    
      login() {
        Get.find<AuthController>().login(idController.text, pwController.text);
        //Authcontroller는 전역에서 사용가능하기 때문에 find할수있게됨
      }
    }

    lib/controller/main_controller.dart

    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:myapp32/controller/auth_controller.dart';
    import 'package:myapp32/model/document.dart';
    import 'package:myapp32/util/api_routes.dart';
    
    class MainController extends GetxController {
      var pageController = PageController();
      RxInt curPage = 0.obs;
      RxList<Document> documents = RxList();
      Dio dio = Dio();
    
      onPageTapped(int v) {
        pageController.jumpToPage(v);
        curPage(v);
      }
    
      logout() {
        Get.find<AuthController>().logout();
      }
    
      readDocuments() async {
        dio.options.baseUrl = 'http://52.79.115.43:8090';
        var token = Get.find<AuthController>().token;
        try {
          documents.clear();
          var res = await dio.get(ApiRoutes.documents,
              options: Options(headers: {'authorization': token}),
              data: {token: token});
          if (res.statusCode == 200) {
            List<Map<String, dynamic>> data =
                List<Map<String, dynamic>>.from(res.data['items']);
            documents.addAll(data.map((e) => Document.fromMap(e)).toList().obs);
          }
        } on DioError catch (e) {
          print(e.message);
        }
      }
    }

    lib/model/document.dart 고대로 사용함

    // ignore_for_file: public_member_api_docs, sort_constructors_first, non_constant_identifier_names
    
    class Document {
      String title;
      String content;
      String sec_level;
      String? attachment_url;
      Document({
        required this.title,
        required this.content,
        required this.sec_level,
        this.attachment_url,
      });
    
      factory Document.fromMap(Map<String, dynamic> map) {
        return Document(
          title: map['title'] as String,
          content: map['content'] as String,
          sec_level: map['sec_level'] as String,
          attachment_url:
              map['attachment_url'] != '' ? map['attachment_url'] : null,
        );
      }
    }

    lib/model/user.dart

    // ignore_for_file: public_member_api_docs, sort_constructors_first, non_constant_identifier_names
    
    class Document {
      String title;
      String content;
      String sec_level;
      String? attachment_url;
      Document({
        required this.title,
        required this.content,
        required this.sec_level,
        this.attachment_url,
      });
    
      factory Document.fromMap(Map<String, dynamic> map) {
        return Document(
          title: map['title'] as String,
          content: map['content'] as String,
          sec_level: map['sec_level'] as String,
          attachment_url:
              map['attachment_url'] != '' ? map['attachment_url'] : null,
        );
      }
    }

    lib/util/api_routes.dart

    //Api가 계속 늘어날수도 있기때문에 따로 관리해줌
    
    class ApiRoutes {
      static const String authWithPassword =
          '/api/collections/users/auth-with-password';
      static const String documents = '/api/collections/documents/records';
    }

    lib/util/app_routes.dart

    import 'package:myapp32/view/login_page.dart';
    import 'package:myapp32/view/main_page.dart';
    
    class AppRoutes {
      static const main = MainPage.route; //메인 페이지 라우트
      static const login = LoginPage.route; //로그인 페이지 라우트
    }

    lib/util/apppages.dart

    import 'package:get/get.dart';
    import 'package:myapp32/util/app_routes.dart';
    import 'package:myapp32/view/login_page.dart';
    import 'package:myapp32/view/main_page.dart';
    
    class AppPages {
      static final pages = [
        GetPage(name: AppRoutes.main, page: () => const MainPage()),
        GetPage(name: AppRoutes.login, page: () => const LoginPage()),
      ];
    }

    lib/view/main_page.dart

    // ignore_for_file: prefer_const_constructors
    
    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:myapp32/controller/auth_controller.dart';
    import 'package:myapp32/controller/main_controller.dart';
    import 'package:myapp32/view/homescreen.dart';
    import 'package:myapp32/view/myscreen.dart';
    
    class MainPage extends GetView<MainController> {
      const MainPage({super.key});
      static const String route = '/main';
    
      @override
      Widget build(BuildContext context) {
        var user = Get.find<AuthController>().user;
        return Scaffold(
          body: SafeArea(
              child: PageView(
            controller: controller.pageController,
            children: [
              //Home페이지
              Obx(() =>
                  HomeScreen(document: controller.documents.toList(), user: user!)),
              //My페이지
              MyScreen(user: user!, onTap: controller.logout)
            ],
          )),
          bottomNavigationBar: Obx(
            () => BottomNavigationBar(
                currentIndex: controller.curPage.value,
                onTap: controller.onPageTapped,
                items: [
                  BottomNavigationBarItem(
                      icon: Icon(
                        Icons.home,
                      ),
                      label: 'Home'),
                  BottomNavigationBarItem(
                      icon: Icon(
                        Icons.person,
                      ),
                      label: 'My')
                ]),
          ),
          floatingActionButton: Obx((() {
            if (controller.curPage.value == 0) {
              return FloatingActionButton(
                onPressed: controller.readDocuments,
                child: Icon(Icons.refresh),
              );
            }
            return SizedBox();
          })),
        );
      }
    }

    lib/view/login_page.dart

    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:myapp32/controller/login_controller.dart';
    
    class LoginPage extends GetView<Logincontroller> {
      const LoginPage({super.key});
      static const String route = '/login';
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                TextField(
                  controller: controller.idController,
                ),
                TextField(
                  controller: controller.pwController,
                ),
                ElevatedButton(onPressed: controller.login, child: Text('로그인하기'))
              ],
            ),
          ),
        );
      }
    }

    lib/view/homescreen

    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:myapp32/controller/login_controller.dart';
    
    class LoginPage extends GetView<Logincontroller> {
      const LoginPage({super.key});
      static const String route = '/login';
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                TextField(
                  controller: controller.idController,
                ),
                TextField(
                  controller: controller.pwController,
                ),
                ElevatedButton(onPressed: controller.login, child: Text('로그인하기'))
              ],
            ),
          ),
        );
      }
    }

    lib/view/myscreen

    import 'package:flutter/material.dart';
    import 'package:flutter/src/widgets/container.dart';
    import 'package:flutter/src/widgets/framework.dart';
    import 'package:get/get.dart';
    import 'package:myapp32/controller/auth_controller.dart';
    import 'package:myapp32/model/user.dart';
    
    class MyScreen extends StatelessWidget {
      const MyScreen({
        super.key,
        required this.user,
        required this.onTap,
      });
    
      final User user;
      final VoidCallback onTap; //입력 인자가 없는 함수를 호출할 수 있는 타입
    
      @override
      Widget build(BuildContext context) {
        var user = Get.find<AuthController>().user!;
        return Scaffold(
            body: //My페이지
                Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          ListTile(
            title: Text(user.username),
            subtitle: Text(user.name),
          ),
          ListTile(
            title: Text('로그아웃'),
            leading: Icon(Icons.logout),
            onTap: onTap,
          ),
        ]));
      }
    }

    main.dart

    // ignore_for_file: prefer_const_constructors
    
    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:myapp32/controller/auth_controller.dart';
    import 'package:myapp32/controller/login_controller.dart';
    import 'package:myapp32/controller/main_controller.dart';
    import 'package:myapp32/util/app_routes.dart';
    import 'package:myapp32/util/apppages.dart';
    import 'package:myapp32/view/login_page.dart';
    import 'package:myapp32/view/main_page.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return GetMaterialApp(
          initialBinding: BindingsBuilder(() {
            Get.put(AuthController()); //initialBinding이 실행되면서 Get.put이실행됨
            Get.lazyPut(() => Logincontroller());
            Get.lazyPut(
              () => MainController(),
            );
          }),
          getPages: AppPages.pages,
          home: Scaffold(
            body: Center(
              child: TextButton(
                onPressed: () => Get.toNamed(AppRoutes.login),
                child: Text('로그인페이지로 가실?'),
              ),
            ),
          ),
        );
      }
    }

    결과가 나왔당

    어려운데 할만한거 같기도 하고...

    내용정리를 아직못해서  시간이 더 걸릴거다..

Designed by Tistory.