happy cat image

everdevel

우리 모두의 웹 입문, 에버디벨

UI 변경

회원가입 페이지 만들기

이번시간에는 회원가입 페이지를 만들어 보겠습니다.
필자는 웹디자인에 대해서 전혀 아는게 없기 때문에 디자인을 신경쓰지 않도록 합니다. ^^;
이 프로젝트 디자인이 워낙 안좋아서요 ^^ 미리 쉴드를
홈페이지에는 아이디 중복 확인 기능도 포함하겠습니다.
일단 소스는 아래와 같습니다.

htdocs/myProject/member/signUpForm.php

<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>에버디벨 :: 회원가입 폼</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.1.0.min.js" ></script>
<script type="text/javascript" src="../js/mySignupForm.js"></script>
<link rel="stylesheet" href="../css/mySignupForm.css" />
</head>
<body>
<div id="wrap">
    <div id="container">
        <h1 class="title">회원가입</h1>
        <form name="signUp" action="./memberSave.php" method="post" onsubmit="return checkSubmit()">
            <div class="line">
                <p>아이디</p>
                <div class="inputArea">
                    <input type="text" name="memberId" class="memberId" />
                </div>
                <div class="memberIdCheck">중복 확인</div>
                <div class="memberIdComment comment"></div>
            </div>
            <div class="line">
                <p>이름</p>
                <div class="inputArea">
                    <input type="text" name="memberName" class="memberName" />
                </div>
            </div>
            <div class="line">
                <p>비밀번호</p>
                <div class="inputArea">
                    <input type="password" name="memberPw" class="memberPw" />
                </div>
            </div>
            <div class="line">
                <p>비밀번호 확인</p>
                <div class="inputArea">
                    <input type="password" name="memberPw2" class="memberPw2"  />
                    <div class="memberPw2Comment comment"></div>
                </div>
            </div>
            <div class="line">
                <p>닉네임</p>
                <div class="inputArea">
                    <input type="text" name="memberNickName" class="memberNickName"  />
                    <div class="memberNickNameComment comment"></div>
                </div>
            </div>
            <div class="line">
                <p>이메일</p>
                <div class="inputArea">
                    <input type="text" name="memberEmailAddress" class="memberEmailAddress" />
                    <div class="memberEmailAddressComment comment"></div>
                </div>
            </div>
            <div class="line">
                <p>생일</p>
                <div class="inputArea">
                    <input type="text" name="memberBirthDay" class="memberBirthDay" />
                    <div class="memberBirthDayComment comment"></div>
                </div>
            </div>
            <div class="line">
                <input type="submit" value="가입하기" class="submit" />
            </div>
        </form>

        <div class="formCheck">
            <input type="hidden" name="idCheck" class="idCheck" />
            <input type="hidden" name="pw2Check" class="pwCheck2" />
            <input type="hidden" name="eMailCheck" class="eMailCheck" />
        </div>
    </div>
</div>
</body>
</html>

위의 소스는 회원가입 폼 입니다.
그냥 단순히 폼이죠.
7 라인 "../js/mySignupForm.js"은 아이디 중복 검사를 위한 db소스에 요청을 하는 기능 및 다른 값들이 입력이 되어있는지 이메일이 정확히 들어가있는지를 검사합니다.

htdocs/myProject/js/mySignupForm.js

$(function(){

    //아이디 중복 확인 소스
    var memberIdCheck = $('.memberIdCheck');
    var memberId = $('.memberId');
    var memberIdComment = $('.memberIdComment');
    var memberPw = $('.memberPw');
    var memberPw2 = $('.memberPw2');
    var memberPw2Comment = $('.memberPw2Comment');
    var memberNickName = $('.memberNickName');
    var memberNickNameComment = $('.memberNickNameComment');
    var memberEmailAddress = $('.memberEmailAddress');
    var memberEmailAddressComment = $('.memberEmailAddressComment');
    var memberBirthDay = $('.memberBirthDay');
    var memberBirthDayComment = $('.memberBirthDayComment');
    var idCheck = $('.idCheck');
    var pwCheck2 = $('.pwCheck2');
    var eMailCheck = $('.eMailCheck');

    memberIdCheck.click(function(){
        console.log(memberId.val());
        $.ajax({
            type: 'post',
            dataType: 'json',
            url: '../member/memberIdCheck.php',
            data: {memberId: memberId.val()},

            success: function (json) {
                if(json.res == 'good') {
                    console.log(json.res);
                    memberIdComment.text('사용가능한 아이디 입니다.');
                    idCheck.val('1');
                }else{
                    memberIdComment.text('다른 아이디를 입력해 주세요.');
                    memberId.focus();
                }
            },

            error: function(){
              console.log('failed');

            }
        })
    });

    //비밀번호 동일 한지 체크
    memberPw2.blur(function(){
       if(memberPw.val() == memberPw2.val()){
           memberPw2Comment.text('비밀번호가 일치합니다.');
           pwCheck2.val('1');
       }else{
           memberPw2Comment.text('비밀번호가 일치하지 않습니다.');

       }
    });

    //이메일 유효성 검사
    memberEmailAddress.blur(function(){
        var regex=/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/;
        if(regex.test(memberEmailAddress.val()) === false){
            memberEmailAddressComment.text('이메일이 유효성에 맞지 않습니다.');
            eMailCheck.val('1');
        }else{
            memberEmailAddressComment.text('올바른 이메일 입니다.');
        }
    });

});

function checkSubmit(){
    var idCheck = $('.idCheck');
    var pwCheck2 = $('.pwCheck2');
    var eMailCheck = $('.eMailCheck');
    var memberBirthDay = $('.memberBirthDay');
    var memberNickName = $('.memberNickName');
    var memberName = $('.memberName');


    if(idCheck.val() == '1'){
        res = true;
    }else{
        res = false;
    }
    if(pwCheck2.val() == '1'){
        res = true;
    }else{
        res = false;
    }
    if(eMailCheck.val() == '1'){
        res = true;
    }else{
        res = false;
    }

    if(memberName.val() != ''){
        res = true;
    }else{
        res = false;
    }
    if(memberBirthDay.val() != ''){
        res = true;
    }else{
        res = false;
    }
    if(memberNickName.val() != ''){
        res = true;
    }else{
        res = false;
    }

    if(res == false){
        alert('회원가입 폼을 정확히 채워 주세요.');
    }
    return res;

}

위의 소스는 회원가입 버튼을 누르기전 사용자가 제대로 입력을 했는지 확인하는 소스 입니다.
라인 4부터 라인 18까지는 해당 엘리먼트를 변수에 담는 작업 입니다.

var memberIdCheck = $('.memberIdCheck');
    var memberId = $('.memberId');
    var memberIdComment = $('.memberIdComment');
    var memberPw = $('.memberPw');
    var memberPw2 = $('.memberPw2');
    var memberPw2Comment = $('.memberPw2Comment');
    var memberNickName = $('.memberNickName');
    var memberNickNameComment = $('.memberNickNameComment');
    var memberEmailAddress = $('.memberEmailAddress');
    var memberEmailAddressComment = $('.memberEmailAddressComment');
    var memberBirthDay = $('.memberBirthDay');
    var memberBirthDayComment = $('.memberBirthDayComment');
    var idCheck = $('.idCheck');
    var pwCheck2 = $('.pwCheck2');
    var eMailCheck = $('.eMailCheck');

위의 소스는 에버디벨에 있는 제이쿼리 강좌를 보셨을 거라 생각하고 넘어가겠습니다.
아래의 소스는 AJAX라는 것을 이용해서 사용자가 입력한 아이디를 아이디 중복검사를 하는 php소스에 전달하는 소스 입니다.
여기서 에이잭스(AJAX)에 대해서 궁금해 하시는 분들이 계실것입니다.
에버디벨에서 한번도 언급한적이 없기 때문이지요.
페이스북의 좋아요 수나 네이버 댓글의 찬성, 반대 수를 보신적이 있죠?
클릭을 한번 하는것 만으로 찬성 한 사람의 수가 갱신됩니다.
보통의 예전 웹들은 무언가 DB의 갱신된 값을 보기 위해서는 페이지 전체를 새로 고침 해야 했습니다.
하지만 페이스북의 좋아요 수나 네이버 댓글의 찬성 반대 버튼은 버튼만 누르면 해당하는 수만 새로고침이 됩니다.
그렇게 페이지 새로고침 없이 값을 갱신하는 것을 AJAX라고 합니다.
그럼 이 기술을 이용하여 페이지 새로 고침 없이 해당하는 아이디를 DB에서 찾아 존재 유무에 따라 사용자가 사용가능한지 불가능한지를 알아보는 기능을 만들어 봅시다.
어렵게 생각하실 필요는 없습니다.
정말 간단하기 때문이죠.

 memberIdCheck.click(function(){
        console.log(memberId.val());
        $.ajax({
            type: 'post',
            dataType: 'json',
            url: '../member/memberIdCheck.php',
            data: {memberId: memberId.val()},

            success: function (json) {
                if(json.res == 'good') {
                    console.log(json.res);
                    memberIdComment.text('사용가능한 아이디 입니다.');
                    idCheck.val('1');
                }else{
                    memberIdComment.text('다른 아이디를 입력해 주세요.');
                    memberId.focus();
                }
            },

            error: function(){
              console.log('failed');

            }
        })
    });

라인 1에 있는 이 소스
memberIdCheck.click(function(){ 는 memberIdCheck를 누르면 이 함수를 실행해라 라는 명령입니다.
$.ajax({ 이부분 부터 ajax의 시작이죠,
type: 'post', 이부분은 post타입으로 데이터를 전송한다는 의미 입니다. 여기에서 말하는 데이터는 중복 확인을 할 아이디 겠죠?
dataType: 'json', 이부분은 데이터타입을 뭘로 할것 이냐는 것인데 json으로 한다는 뜻입니다.
json이란 무엇일까요?
이세상에는 수많은 프로그래밍 언어가 있습니다. 또 그러한 만큼 서로 다른 프로그래밍 언어간에 데이터를 전송해야 하는 일도 필요하죠,
그래서 서로 다른 프로그래밍간에 데이터를 전달하는 표준화된 방법이 필요했습니다.
그래서 개발된 언어는 json과 xml이 있죠.
json은 다음과 같은 형식으로 이루어집니다.
{'kidsName':'tony'} 이러한 형식입니다. kidsName를 키값으로 값이 tony가 들어 가죠. xml은 html방식처럼 태그방식입니다.
이 강좌에서는 json을 방식으로 전달합니다.
그럼 다음으로
url: '../member/memberIdCheck.php', 가 있습니다. 우리는 중복검사할 아이디를 어딘가에 보내서 요청을 해야 하죠.
그 아이디를 중복검사 해줄 페이지를 url에 입력합니다.
우리는 ../member/memberIdCheck.php 이 파일을 아직 작성하지 않았습니다. 나중에 작성할 것입니다. ^^;
그리고 데이터는 이렇게
data: {memberId: memberId.val()}, memberId를 변수로 값을 memberId.val()로 합니다.
제이쿼리 강좌에서 보셨겠지만 그래도 모르시는 분을 위해서 설명을 해보겠습니다.
아이디를 적는 엘리먼트의 클래스를 memberId를 지정했고 해당 엘리먼트를 memberId변수에 담았습니다.
memberId.val()은 $('.memberId').val()을 의미하죠 즉, 아이디 적는 공간에 있는 값을 의미 합니다.
즉 그 값을 데이터 전송하겠다는 의미 입니다.
그 변수는 memberId이구요.
그리고 해당하는 값을 보내고 받을때 성공 유무에 따라 행동을 나눌수 있죠?
성공시 이렇게

success: function (json) {
                if(json.res == 'good') {
                    console.log(json.res);
                    memberIdComment.text('사용가능한 아이디 입니다.');
                    idCheck.val('1');
                }else{
                    memberIdComment.text('다른 아이디를 입력해 주세요.');
                    memberId.focus();
                }
            },

실패시 이렇게

error: function(){
              console.log('failed');
 }

그럼 이번엔 아이디를 받아서 중복검사를 해 줄 기능을 만들어 봅시다.

htdocs/myProject/member/memberIdCheck.php

<?php

    include "../include/dbConnect.php";

    $memberId = $_POST['memberId'];

    $sql = "SELECT * FROM member WHERE memberId = '{$memberId}'";

    $res = $dbConnect->query($sql);


    if($res->num_rows >= 1){
        echo json_encode(array('res'=>'bad'));
    }else{
        echo json_encode(array('res'=>'good'));
    }

?>

디비 접속 소스를 include를 했으며,
memberId 변수를 선언해서 post 방식으로 ajax에서 선언한 memberId 변수를 받습니다.
그리고 바로 그 값을 select문을 작성하여 검사 합니다.
해당하는 쿼리수는 num_rows함수를 통해서 확인할 수 있죠?
해당하는 아이디로 검색된 레코드 수가 0개 여야만 그 아이디를 사용할 수 있죠.
그래서 0개 인 경우는 res값으로 good를 반환합니다.
echo json_encode(array('res'=>'good'));가 그 의미죠.
echo문으로 json_encode를 선언하고 자기만의 변수를 사용하면 됩니다. 꼭 res로 사용할 필요는 없습니다.
그러면 끝!!이죠

그 값을 ajax소스에서 아래와 같이 json.res == 'good'면 어떤것 아니면 어떤것에 따라 실행합니다.

success: function (json) {
                if(json.res == 'good') {
                    console.log(json.res);
                    memberIdComment.text('사용가능한 아이디 입니다.');
                    idCheck.val('1');
                }else{
                    memberIdComment.text('다른 아이디를 입력해 주세요.');
                    memberId.focus();
                }
            },
//비밀번호 동일 한지 체크
    memberPw2.blur(function(){
       if(memberPw.val() == memberPw2.val()){
           memberPw2Comment.text('비밀번호가 일치합니다.');
           pwCheck2.val('1');
       }else{
           memberPw2Comment.text('비밀번호가 일치하지 않습니다.');

       }
    });

그 외에도 비밀번호 체크 동일 하는 소스 입니다. 비밀번호가 일치 한지 일치 하지 않은지를 체크 합니다.
이것또한 매우 간단하죠
memberPw2.blur(function(){ 이 뜻은, 비밀번호 확인란을 입력후 그 확인란을 떠날때 함수가 작동 한다는 뜻입니다.
그래서 비밀번호 입력란과 비밀번호 입력 확인란의 값이 일치 하냐 안하냐를 확인 하죠.

//이메일 유효성 검사
    memberEmailAddress.blur(function(){
        var regex=/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/;
        if(regex.test(memberEmailAddress.val()) === false){
            memberEmailAddressComment.text('이메일이 유효성에 맞지 않습니다.');
            eMailCheck.val('1');
        }else{
            memberEmailAddressComment.text('올바른 이메일 입니다.');
        }
    });

위 소스는 이메일 유효성을 검사합니다. 이메일 주소를 제대로 작성했는지 하지 않았는지를 검사하죠.
memberEmailAddress.blur(function(){ 는 위와 같이 이메일 입력란을 떠났을때 함수를 실행한다는 의미이죠.
var regex=/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/;
이것은 정규식을 이용하여 이메일을 제대로 입력했는지 안했는지 검사하는 식입니다.
저도 정규식을 공부해야 하는데 아직 안하고 있죠, 필요할때 마다 구글링해서 이용하고 있습니다.
회원가입폼에서 가입하기 버튼을 누르면 action에 설정된 페이지로 이동을 하게 되는데요.
그 전에 값들이 제대로 입력되었는지 확인하는 함수를 작동하게 하기 위해서는 form태그에 다음을 작성해 주어야 합니다.
onsubmit="return checkSubmit()" 이렇게 하면 checkSubmit() 함수를 작동해서 반환된 값이 true이냐 false이냐에 따라서 달라집니다.
true면 action에 있는 주소로 이동할 것 이며, false면 이동하지 않죠.
checkSubmit()함수는 아래와 같습니다.

function checkSubmit(){
    var idCheck = $('.idCheck');
    var pwCheck2 = $('.pwCheck2');
    var eMailCheck = $('.eMailCheck');
    var memberBirthDay = $('.memberBirthDay');
    var memberNickName = $('.memberNickName');
    var memberName = $('.memberName');


    if(idCheck.val() == '1'){
        res = true;
    }else{
        res = false;
    }
    if(pwCheck2.val() == '1'){
        res = true;
    }else{
        res = false;
    }
    if(eMailCheck.val() == '1'){
        res = true;
    }else{
        res = false;
    }

    if(memberName.val() != ''){
        res = true;
    }else{
        res = false;
    }
    if(memberBirthDay.val() != ''){
        res = true;
    }else{
        res = false;
    }
    if(memberNickName.val() != ''){
        res = true;
    }else{
        res = false;
    }

    if(res == false){
        alert('회원가입 폼을 정확히 채워 주세요.');
    }
    return res;

위와 같이 검사를 해봅니다. 간편화 하기 위해서 어떠한 항목들은 값이 비었는지 아닌지만 확인해 봅니다.
그리고 마지막으로 허접한 디자인을 입히기 위해 css파일을 작성합니다.

htdocs/myProject/css/mySignupForm.css

@charset "utf-8";

/* css reset */
div,span,body{margin:0;padding:0}

#wrap{clear:both;float:left;width:100%;background:hotpink}
#container{clear:both;width:800px;_border:1px solid #fff;margin:3% auto}
#container h1{clear:both;float:left;width:100%;text-align:center;color:#fff}
#container h1 a{color:#fff;text-decoration:none}
.line{clear:both;float:left;width:100%;border:1px solid #fff;margin-bottom:3%}
.line p{float:left;min-width:100px;margin-left:3%;color:#fff}
.line .inputArea{float:left;}
.line .inputArea input{float:left;width:370px;height:30px;margin:10px 0 0 0;padding-left:10px}
.submit{clear:both;float:left;width:100%;height:50px;background:#fff;border:0;font-size:20px;color:hotpink}

그럼 다음 강좌는 회원정보를 저장하는 프로그램을 만들어 봅시다.

에버디벨의 완성 :: 웹코딩 시작하기

안녕하세요.
에버디벨 운영자입니다.
여러분이 늘 이용해 주셔서 하루 5명 오는 사이트가 1000명이 오는 사이트가 되었고,
또 그 이유로 사이트를 운영을 멈추지 않아 저같은 평범한 사람이 책까지 쓸 수 있게 되었습니다.
여러분이 찾지 않았다면 진작 사이트 접었습니다.
저의 웹개발 경력 2년을 쏟아내어서 6개월의 집필, 8개월의 교정기간을 거쳐 [웹코딩 시작하기]가 출간했습니다.
웹코딩 시작하기는 HTML5를 시작으로 CSS3 -> jQuery를 학습합니다.
그리고 앞에서 배운 내용으로 간단한 소통사이트를 반응형으로 제작합니다.
보통의 책은 HTML5 + CSS3로 끝나고 혹은 HTML5 + CSS3 + jQery로 끝나지만 웹코딩 시작하기는 여기서 끝내지 않았습니다.
그 다음 바로 데이터베이스중 하나인 MySQL를 학습하고, 그 이후 PHP를 학습니다. 그리고 앞에서 만든 소통사이트에 회원가입, 로그인 기능은 기본으로 진행하며, 스크롤이벤트를 이용하여 스크롤을 내리면 AJAX를 작동시켜 게시물을 더 불러오는 기능을 구현하고 자기의 로그기록을 파일에 쓰기, 그 밖에 자신의 프로필사진, 커버사진 등록, 댓글 쓰기등의 기능을 적용합니다.
본서는 웹코딩을 처음하는 사람이 하나에서 끝나지 않고 처음부터 시작해 프로젝트까지 완성해가며 전체적으로 시스템이 어떻게 작동하는지 전반적으로 알게하기 위해 태어났습니다.
적어도 지구에서 가장 친절한 웹 입문서라고 생각하는 책입니다.
에버디벨로 부족하셨다면 웹코딩 시작하기를 추천합니다.

어제보다 나은 나, 오늘 보다 나을 내일의 나를 만드는 :: 웹코딩 시작하기

목차보기

종이책 구입하기

전자책 구입하기

PART 1. 프론트엔드 HTML5 + CSS3 + jQuery

CHAPTER 1. HTML5

1. HTML5 소개

2. 메타 태그

3. 텍스트 태그

4. 이미지 태그

5. 하이퍼링크 태그(a 태그)

6. 리스트 태그

7. form 태그

8. 공간 태그

9. video 태그

11. svg와 canvas

12. table 태그

CHAPTER 2. CSS3

1. CSS 소개

2. CSS를 적용하는 세 가지 방법

3. 선택자(selector)

4. 텍스트를 꾸미는 CSS 요소

5. 가로 길이와 세로 길이 조정하기

6. 텍스트가 영역을 벗어날 때

7. HTML 엘리먼트의 위치 변경하기

8. 배경 꾸미기

9. 외곽선 긋기

10. float와 clear

11. 박스의 바깥 여백 설정하기

12. 박스의 안쪽 여백 설정하기

13. CSS 리셋

14. 애니메이션

15. transform

16. transition

17. display

18. 반응형 웹

19. 반응형으로 간단한 레이아웃 만들기

20. SVG 태그

CHAPTER 3. jQuery

1. jQuery 시작하기

2. 셀렉터

3. 엘리먼트 보이기와 숨기기

4. 클릭했을 때 무언가 하기

5. 마우스 포인터를 요소 위에 올릴 때 무언가 하기

6. 제이쿼리로 CSS 적용하기

7. 변수 사용하기

8. HTML 엘리먼트에 있는 텍스트 변경하기

9. HTML 태그 제어하기

10. 애니메이션 기능

11. 엘리먼트에 클래스 추가, 삭제하기

12. 엘리먼트의 이동

13. 폼 태그의 값 조정

14. 포커스

15. this 사용하기

16. 연산자

17. 함수 만들기

18. 변수에 대해서

19. 글로벌 변수와 로컬 변수

20. 조건문

21. 반복문

22. 스크롤 이벤트

23. AJAX

24. canvas 태그(HTML5)

project 나의 첫 웹서비스 만들기

CHAPTER 1. 나의 첫 웹서비스 프로젝트 소개

CHAPTER 2. 나의 첫 웹서비스 만들기 프로젝트 - front end

1. 메인 페이지 만들기(index.html)

2. 나의 페이지 만들기(me.html)

3. 모두의 페이지 만들기(all.html)

PART 2. 백엔드 MySQL + PHP

CHAPTER 1. MySQL

1. 데이터베이스란?

2. MySQL 시작하기

3. 데이터베이스 만들기

4. 테이블

5. 필드의 데이터 크기와 데이터형 지정하기

6. 테이블 생성하기

7. 필드의 추가, 수정, 삭제

8. 테이블 삭제하기

9. 테이블에 데이터 입력하기

10. 데이터 불러오기

11. 데이터의 값을 변경, 삭제하기

12. 테이블 초기화

13. 2개 이상의 테이블 사용하기(JOIN)

14. 집계함수

15. 그룹별 집계

16. 출력 결과의 정렬

17. 불러올 레코드 수 지정하기

18. 2개 이상의 테이블을 묶어 사용하기

19. 쿼리문 안의 쿼리문 서브쿼리

20. 특정 필드에 같은 값을 넣지 않는 방법

21. 서로 다른 필드의 값을 합쳐서 출력하기

22. 검색을 더욱 빠르게 하는 인덱스

CHAPTER 2. PHP

1. PHP 소개

2. 출력문

3. 주석

4. 변수

5. 연산자

6. 배열>

7. 데이터형

8. 조건문

9. 반복문

10. 함수

11. 함수 만들기

12. POST와 GET

13. 기능의 사물화

14. 코드의 재활용

15. PHP와 MySQL의 연동

16. 상수

17. 정규 표현식

18. 파일 업로드

19. 디렉터리 함수

20. 파일 함수

21. Anchor 태그의 ping 속성과 AJAX

22. 쿠키와 세션

23. 객체지향 프로그래밍

project 나의 첫 웹서비스 만들기

CHAPTER 3. 나의 첫 웹서비스 만들기 프로젝트 - back end

3-1. 회원가입 기능

3-2. 로그인, 로그아웃 기능

3-3. 게시물 등록하기

3-4. 게시물 불러오기

3-5. 댓글 등록하기

3-6. 댓글 불러오기

3-7. 게시물 공감하기

3-8. 모두의 페이지

3-9. 포토 업로드 기능

3-10. 나의 로그 만들기

강좌로 돌아가기