[ Toy Project ] 강남 맛집 50곳 위치 찍기 (with Kakao Map API)

ma.caron_g·2022년 11월 4일
0

Toy Project

목록 보기
3/3
post-thumbnail

강남 맛집 50곳 위치 찍기

[ 1. 데이터 수집 📝 ]

강남 맛집 50곳의 정보를 정리해줍니다.

맛집 검색 사이트에서 50곳을 가져와 엑셀 파일로 정리해줬습니다.
그러나 맛집이 30개만 보여주어서 제가 좋아하는 카페도 20곳을 넣어줬습니다.

[ 1-1. 📃 강남_맛집.xlsx ]

다음과 같이 총 50개의 데이터를 뽑아 정리했습니다.

[ 2. 데이터베이스에 저장하기 ]

[ 2-1. 데이터를 저장할 테이블 생성 ]

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | NO   | PRI | NULL    | auto_increment |
| store_name | varchar(30)  | YES  |     | NULL    |                |
| address    | varchar(255) | NO   |     | NULL    |                |
| x          | varchar(255) | YES  |     | NULL    |                |
| y          | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
Field NameValue
id가게들의 구분 번호
store_name가게 이름
address가게 주소
x지도상에 가게의 x좌표
y지도상에 가게의 y좌표

테이블에 값을 추가해주기 위해 SQL문으로 변경해주겠습니다.
SQL문으로 변경해주기 위해

엑셀에 새로운 필드에 값을 추가해준다.
="INSERT INTO [테이블명] (필드1, 필드2, 필드3 ...) VALUES (값1("&레이블&, &레이블&, &레이블& ...)";
을 추가하여 드래그를 해주면

자동으로 레이블에 위치한 값들이 들어갑니다.

이를 복사하여 값을 넣어줍니다.

다음과 같이 레코들이 저장됩니다.

[ 2-2. Geocoder를 이용한 좌표값 저장 ]

데이터베이스를 연결하여 address를 읽고 그 값을 geocoder에 넣어 좌표 값을 얻어오겠습니다.

php는 공통으로 사용되는 코드를 미리 정의해놓고 include를 통해 작성된 코드를 불러올 수 있습니다.

예를 들어,

  • hsy.php

    하세요.

가 작성 돼 있으면

  • hi.php

안녕
include "hsy.php";

안녕하세요.

와 같은 값이 나타납니다.

이를 이용하여

데이터베이스에 연결하는 코드를 공통 코드로 작성해주기 위해 다음과 같이 작성해줍니다.

[ 📄 db.conn.php ]

<?php
$server = "localhost";
    $user = "[데이터베이스 유저 이름]";
    $password = "데이터베이스 비밀번호";
    $dbname = "[테이블명]";

    $connect = mysqli_connect($server, $user, $password);
    $db_conn = mysqli_select_db($connect, "[데이터베이스명]");

?>

[ 📄 convert_geo.php ]

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- PHP 작성 -->
    <?php
    include "db_conn.php";

    $sql = "SELECT * FROM store WHERE x is null order by id asc";
    $result = mysqli_query($connect, $sql);

    if($result) {
        ?>

        <script> alert("연결에 성공했습니다.");</script>

    <?php
    }
    else{
    ?>

        <script> alert("연결에 실패했습니다.");</script>

    <?php

    }

    ?>

    <?php
    // SQL을 설정하여 좌표값이 비어있는 id를 순차적으로 조회
    while ($row = mysqli_fetch_array($result)) {

        echo $row['address']."<br>";
    ?>

        <script>
            var geocoder = new kakao.maps.services.Geocoder();
        // 주소-좌표 변환 객체를 생성합니다

        // 주소로 좌표를 검색합니다
        geocoder.addressSearch('<?= $row['address'] ?>', function(result, status) {

        // 정상적으로 검색이 완료됐으면 
        if (status === kakao.maps.services.Status.OK) {
      
            var coords = new kakao.maps.LatLng(result[0].y, result[0].x);

            console.log(result[0].y + " / " + result[0].x);
          
            save_geo(result[0].y, result[0].x, <?=$row['id'] ?>);
                    
        }
        else {

        }
    });
    </script>

    <?php 
    }

    mysqli_close($connect);
    ?>
<script>
    function save_geo(x, y, id) {
        var form = document.createElement('form');
        form.setAttribute('method', 'post');
        form.setAttribute('target', '_blank');
        form.setAttribute('action', 'save_geo.php');
        document.charset = "UTF-8";

        var hiddenField1 = document.createElement('input');
        hiddenField1.setAttribute('type', 'hidden');
        hiddenField1.setAttribute('name', 'id');
        hiddenField1.setAttribute('value', id);
        var hiddenField2 = document.createElement('input');
        hiddenField2.setAttribute('type', 'hidden');
        hiddenField2.setAttribute('name', 'x');
        hiddenField2.setAttribute('value', x);
        var hiddenField3 = document.createElement('input');
        hiddenField3.setAttribute('type', 'hidden');
        hiddenField3.setAttribute('name', 'y');
        hiddenField3.setAttribute('value', y);

        document.body.appendChild(form);
        form.appendChild(hiddenField1);
        form.appendChild(hiddenField2);
        form.appendChild(hiddenField3);

        form.submit();
    }

</script>
</body>
</html>

가져온 값을 폼에 넣은 후, 좌표를 저장하는 기능을 가진📄 save_geo.php에 값을 넘겨 데이터베이스에 저장합니다.

[ 📄 save_geo.php ]

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

<?php
    include "db_conn.php";

    $id = $_POST['id'];
    $x = $_POST['x'];
    $y = $_POST['y'];

    echo "id : ".$id."    =      ";
    echo "x : ".$x."     /     ";
    echo "y : ".$y;

    $sql = "UPDATE store SET x=$x, y=$y WHERE id=$id";

    $result = mysqli_query($connect, $sql);

    mysqli_close($connect);
?>
</body>
</html>

다음과 같은 코드를 이용해서 페이지를 실행시키면
자동으로 값들이 넘어가고

console.log()를 통해 얻어진 값들을 확인할 수 있습니다.

+----+------------------------------------+-------------------------------------------------------------------------------------------+------------------+------------------+
| id | store_name                         | address                                                                                   | x                | y                |
+----+------------------------------------+-------------------------------------------------------------------------------------------+------------------+------------------+
|  1 | 고메램                             | 서울특별시 강남구 삼성로9615 송영빌딩                                                  | 37.5090904790547 | 127.057075333082 |
|  2 | 육전식당                           | 서울특별시 강남구 테헤란로811-4 신도빌딩 1F                                            | 37.4980495536809 | 127.031990525034 |
|  3 | 묵전                               | 서울특별시 강남구 언주로16822                                                          | 37.5260905512061 | 127.035349303391 |
|  4 | 대우부대찌개                       | 서울특별시 강남구 테헤란로2534                                                         | 37.5027507897379 | 127.035271910674 |
|  5 | 뽕나무쟁이                         | 서울특별시 강남구 역삼로6531 1F                                                        | 37.5031995277517 | 127.052001164203 |
|  6 | 고갯마루집                         | 서울특별시 강남구 테헤란로2827                                                         | 37.4993986379075 | 127.03941842768  |
|  7 | 리북집                             | 서울특별시 강남구 학동로245                                                            | 37.5087080835741 | 127.023588823983 |
|  8 | 돝고기506                          | 서울특별시 강남구 역삼로1753                                                           | 37.4982482701982 | 127.036206152949 |
|  9 | 땅코참숯구이                       | 서울특별시 강남구 도곡로728                                                            | 37.4925710310399 | 127.034381266758 |
| 10 | 카브루브루펍                       | 서울특별시 강남구 압구정로7919 레인애비뉴 101| 37.5253737056184 | 127.048780188752 |
| 11 | 명인등심                           | 서울특별시 강남구 도산대로10013                                                        | 37.5238228613413 | 127.052038439495 |
| 12 | 모범갈빗살                         | 서울특별시 서초구 서초대로7340                                                         | 37.5009272542176 | 127.024557940948 |
| 13 | 송쉐프                             | 서울특별시 강남구 도산대로140                                                          | 37.5193386747828 | 127.019615704918 |
| 14 | 일일향                             | 서울특별시 서초구 서초대로7822                                                         | 37.4958057253368 | 127.027547429997 |
| 15 | 홍백                               | 서울특별시 강남구 삼성로 571                                                              | 37.5123480626965 | 127.053210303682 |
| 16 | 구스아일랜드 브루하우스            | 서울특별시 강남구 역삼로 118                                                              | 37.4934315723756 | 127.032179999229 |
| 17 | 제주몬트락                         | 서울특별시 강남구 강남대로7816                                                         | 37.4949414141627 | 127.030734893816 |
| 18 | 초선과여포                         | 서울특별시 서초구 서초대로7844                                                         | 37.493807077575  | 127.028452355866 |
| 19 | 삼육가                             | 서울특별시 강남구 강남대로1148                                                         | 37.5056918554336 | 127.025018227907 |
| 20 | 셰막                               | 서울특별시 강남구 강남대로 442                                                            | 37.5020628314474 | 127.026055773707 |
| 21 | 호남마을                           | 서울특별시 강남구 역삼로72                                                             | 37.4943456433573 | 127.033479240817 |
| 22 | 파크루안                           | 서울특별시 강남구 논현로 430                                                              | 37.499001193592  | 127.038355416717 |
| 23 | 문어앤치킨                         | 서울특별시 강남구 삼성로10424                                                          | 37.5111425206875 | 127.056692899298 |
| 24 | 온돌더프라임                       | 서울특별시 강남구 테헤란로 129                                                            | 37.4999326440603 | 127.032367803374 |
| 25 | 천미미                             | 서울특별시 강남구 강남대로15211                                                        | 37.517382475711  | 127.020330650586 |
| 26 | 신동궁감자탕                       | 서울특별시 강남구 테헤란로1011                                                         | 37.4976452465943 | 127.032741357124 |
| 27 | 육시리                             | 서울특별시 강남구 논현로 420                                                              | 37.4978572977128 | 127.038840424582 |
| 28 | 삼미숯불갈비                       | 서울특별시 강남구 학동로230                                                            | 37.5094736193094 | 127.022917114554 |
| 29 | 창고43                             | 서울특별시 강남구 강남대로 362                                                            | 37.4953055764745 | 127.029416048324 |
| 30 | 성북동청국장                       | 서울특별시 강남구 봉은사로1046                                                         | 37.5139610210377 | 127.061937258246 |
| 31 | 장꼬방                             | 서울특별시 서초구 강남대로6127                                                         | 37.4983360267419 | 127.023793980532 |
| 32 | 어퍼앤언더                         | 서울특별시 강남구 강남대로10228 B1-2F                                                  | 37.5027388377688 | 127.027719504577 |
| 33 | 썸띵어바웃커피                     | 서울특별시 강남구 강남대로10230 1-3F                                                   | 37.5028324298668 | 127.027814764233 |
| 34 | 원아베뉴                           | 서울특별시 강남구 테헤란로711                                                          | 37.4998890201223 | 127.03038996316  |
| 35 | 타짜도르                           | 서울특별시 서초구 서초대로7761 SG타워 1F                                               | 37.5024331030407 | 127.023686484894 |
| 36 | 마키아티                           | 서울특별시 강남구 강남대로8415 효성해링턴타워 더 퍼스트 106| 37.4970034183304 | 127.02983569457  |
| 37 | 겟썸커피 다운스테어                | 서울특별시 강남구 봉은사로630                                                          | 37.5030771832102 | 127.027255717013 |
| 38 | 스크렘                             | 서울특별시 강남구 봉은사로417                                                          | 37.5037271673496 | 127.026468923524 |
| 39 | 리퍼크                             | 서울특별시 강남구 강남대로 382 메리츠타워 1F                                              | 37.4970486776201 | 127.028627058312 |
| 40 | 트리오드                           | 서울특별시 강남구 강남대로9428 유니언타운 LF                                           | 37.4996425246433 | 127.029602310921 |
| 41 | 밀도                               | 서울특별시 서초구 강남대로 419 1F                                                         | 37.4998007315864 | 127.026210824749 |
| 42 | 커먼위켄드                         | 서울특별시 강남구 봉은사로634 스타제이빌딩 1F                                          | 37.5028323549489 | 127.027363971961 |
| 43 | 꽃을피우고                         | 서울특별시 강남구 봉은사로1880                                                         | 37.5016033846107 | 127.027357416481 |
| 44 | IFMT                               | 서울특별시 강남구 역삼로 121                                                              | 37.4940648495544 | 127.032656566707 |
| 45 | 베이커리로컬                       | 서울특별시 강남구 강남대로10215                                                        | 37.5022103870338 | 127.026988276372 |
| 46 | 정월                               | 서울특별시 강남구 강남대로10246 1F                                                     | 37.5036597194557 | 127.028626641848 |
| 47 | 브릭샌드                           | 서울특별시 강남구 강남대로 374-2 강남역 신분당선 B1 4| 37.4962880387828 | 127.028664424942 |
| 48 | 알베르                             | 서울특별시 강남구 강남대로10234                                                        | 37.5030565318496 | 127.028103011462 |
| 49 | 가배도                             | 서울특별시 강남구 강남대로11013 2-3F                                                   | 37.504032006687  | 127.02593114799  |
| 50 | 카페마마스                         | 서울특별시 서초구 서운로 138                                                              | 37.495994185     | 127.025267395048 |
+----+------------------------------------+-------------------------------------------------------------------------------------------+------------------+------------------+

[ 3.카카오 맵 API ]

이제 이 좌표값들을 갖고 카카오 맵 API를 이용하여 카카오 지도를 띄우고 지도에 해당 가게들의 위치를 저장해보겠습니다.

카카오 API 사용을 위한 KEY값을 발급해주고,

지도를 생성합니다.

그 후, 데이터베이스를 연결해 좌표값을 가져와 각 마커에 넣어주고 뿌려줍니다.

[ 3-1. 📄 PHP 파일 ]

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=c3f57535868ce6095b1eccaba9087bf2&libraries=services"></script>
    <link rel="stylesheet" href="macarong_Toy.css">
    <script src="macarong_Toy.js"></script>
</head>

<body>

<div >
    <div id='map' class="display:inline-block" style="width: 100%; height: 100%;"></div>
    <div id="btnSection">
    <button onclick="makeMarker()" id="btnViewAll">전체보기</button>
</div>
    <!-- <div class="display:inline-block" style="background-color:blue; width:10%; height:200px; margin-left:600px" ></div> -->
    <div id="listView">

    </div>
  
    <script>
        var mapContainer = document.getElementById('map'), // 지도를 표시할 div 
            mapOption = {
                center: new kakao.maps.LatLng(37.496486063, 127.028361548), // 지도의 중심좌표
                level: 4 // 지도의 확대 레벨
            };

        // 지도를 표시할 div와  지도 옵션으로  지도를 생성합니다
        var map = new kakao.maps.Map(mapContainer, mapOption);
    </script>
    <p id="result"></p>
    <?php
    include "db_conn.php";

    $sql = "SELECT * FROM store";

    $result = mysqli_query($connect, $sql);
    ?>

    <script>
        var positions = [];
    </script>

    <?php
    while ($row = mysqli_fetch_array($result)) {
        // echo $row['store_name'] . "<br>";
        // echo $row[' x'] . "<br>";
        // echo $row['y'] . "<br>";
    ?>
        <script>
            positions.push({
                title: '<?= $row['store_name'] ?>',
                content: '<?= $row['store_name'] ?>',
                latlng: new kakao.maps.LatLng(<?= $row['x'] ?>, <?= $row['y'] ?>,
                    coords = new kakao.maps.Coords(<?= $row['x'] ?>, <?= $row['y'] ?>))
            });
        </script>

    <?php
    }
    ?>

    <script>
        var markers = [];

        var storeMarkers = [];
        var cafeMarkers = [];

        var cafeImageSrc = 'images/markers/markerCoffee.png', // 마커이미지의 주소입니다    
            imageSize = new kakao.maps.Size(31, 35), // 마커이미지의 크기입니다
            imageOption = {offset: new kakao.maps.Point(27, 69)}; // 마커이미지의 옵션입니다. 마커의 좌표와 일치시킬 이미지 안에서의 좌표를 설정합니다.

        var cafeImage = new kakao.maps.MarkerImage(cafeImageSrc, imageSize, imageOption);
      
        var storeImageSrc = 'images/markers/markerStore.png', // 마커이미지의 주소입니다    
            imageSize = new kakao.maps.Size(31, 35), // 마커이미지의 크기입니다
            imageOption = {offset: new kakao.maps.Point(27, 69)}; // 마커이미지의 옵션입니다. 마커의 좌표와 일치시킬 이미지 안에서의 좌표를 설정합니다.

        var storeImage = new kakao.maps.MarkerImage(storeImageSrc, imageSize, imageOption);
      
        // 마커가 표시될 위치입니다 
        for (var i = 0; i < 36; i++) {
            // 마커를 생성합니다
            var marker = new kakao.maps.Marker({
                // map: map, // 마커를 표시할 지도
                position: positions[i].latlng, // 마커의 위치
                image : storeImage
            });

            // marker.title = positions[i].title;

            // 마커에 표시할 인포윈도우를 생성합니다 
            var infowindow = new kakao.maps.InfoWindow({
                content: positions[i].content, // 인포윈도우에 표시할 내용
            });

            markers.push(marker);
            cafeMarkers.push(marker);

            kakao.maps.event.addListener(marker, 'mouseover', makeOverListener(map, marker, infowindow));
            kakao.maps.event.addListener(marker, 'mouseout', makeOutListener(infowindow));
            kakao.maps.event.addListener(marker, 'mouseover', markerCircle(map, marker));
            kakao.maps.event.addListener(marker, 'mouseout', clearCircle(map, marker));
            kakao.maps.event.addListener(marker, 'click', circleInMarker(marker, circle));
            kakao.maps.event.addListener(marker, 'click', testClick(marker));

            // 마커가 지도 위에 표시되도록 설정합니다
            marker.setMap(map);
        }

        for (var i = 36; i < positions.length; i++) {
            // 마커를 생성합니다
            var marker = new kakao.maps.Marker({
                // map: map, // 마커를 표시할 지도
                position: positions[i].latlng, // 마커의 위치
                image : cafeImage
            });

            // marker.title = positions[i].title;

            // 마커에 표시할 인포윈도우를 생성합니다 
            var infowindow = new kakao.maps.InfoWindow({
                content: positions[i].content, // 인포윈도우에 표시할 내용
            });

            markers.push(marker);
            storeMarkers.push(marker);

            kakao.maps.event.addListener(marker, 'mouseover', makeOverListener(map, marker, infowindow));
            kakao.maps.event.addListener(marker, 'mouseout', makeOutListener(infowindow));
            kakao.maps.event.addListener(marker, 'mouseover', markerCircle(map, marker));
            kakao.maps.event.addListener(marker, 'mouseout', clearCircle(map, marker));
            kakao.maps.event.addListener(marker, 'click', circleInMarker(marker, circle));
            kakao.maps.event.addListener(marker, 'click', testClick(marker));

            // 마커가 지도 위에 표시되도록 설정합니다
            marker.setMap(map);
        }

        function testClick(marker) {
            return function() {
           
            }
        }

        // 인포윈도우를 표시하는 클로저를 만드는 함수입니다 
        function makeOverListener(map, marker, infowindow) {
            return function() {
                infowindow.open(map, marker);
            };
        }

        // 인포윈도우를 닫는 클로저를 만드는 함수입니다 
        function makeOutListener(infowindow) {
            return function() {
                infowindow.close();
            };
        }

        var circle;

        kakao.maps.event.addListener(map, 'click', function(mouseEvent) {
            var latlng = mouseEvent.latLng;
            if (circle) {
                circle.setMap(null);
            }
            circle = new kakao.maps.Circle({
                center: new kakao.maps.LatLng(latlng.getLat(), latlng.getLng()), // 원의 중심좌표 입니다
                radius: 1000, // 미터 단위의 원의 반지름입니다 
                strokeWeight: 1, // 선의 두께입니다 
                strokeColor: '#75B8FA', // 선의 색깔입니다
                strokeOpacity: 1, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
                strokeStyle: 'line', // 선의 스타일 입니다
                fillColor: '#CFE7FF', // 채우기 색깔입니다
                fillOpacity: 0.7, // 채우기 불투명도 입니다   
            });
            circle.setMap(map)
        });

        var circleInMarker = [];
        function circleInMarker(marker, circle) {
            return function() {
                circleInMarker = [];
                var center = marker.getPosition();
                var radius = 1000;
                var line = new kakao.maps.Polyline();

                markers.forEach(function(marker) {
                    var path = [marker.getPosition(), center];
                    line.setPath(path);

                    var dist = line.getLength();

                    if (dist < 1000) {
                        marker.setMap(map)
                        circleInMarker.push(marker);
                    } else {
                        marker.setMap(null);
                    }

                });
            }

        }

        function clearCircle(map, marker) {
            return function() {
                if (clearCircle) {
                    circle.setMap(null)
                }
            }
        }

        function markerCircle(map, marker) {
            return function() {
                if (circle) {
                    circle.setMap(null);
                }
                circle = new kakao.maps.Circle({
                    center: new kakao.maps.LatLng(marker.getPosition().getLat(), marker.getPosition().getLng()), // 원의 중심좌표 입니다
                    radius: 1000, // 미터 단위의 원의 반지름입니다 dd
                    strokeWeight: 1, // 선의 두께입니다 
                    strokeColor: '#75B8FA', // 선의 색깔입니다
                    strokeOpacity: 1, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
                    strokeStyle: 'line', // 선의 스타일 입니다
                    fillColor: '#CFE7FF', // 채우기 색깔입니다
                    fillOpacity: 0.7, // 채우기 불투명도 입니다   
                });
                circle.setMap(map)
            }
        }
    </script>


    <!-- <script>
        function makeMarker() {
            markers.forEach(function(marker) {
                marker.setMap(map);
            });
        }
    </script> -->


    <script>
        function showStore() {

        }
    </script>
</div>
</body>

</html>

버튼을 추가하여 마커를 클릭하여 1km 근방의 매장들을 보여주었을 때, 다시 전체매장을 보기 위해 버튼을 따로 추가해주었습니다.

[ 3-2. 📄 css파일 ]

#btnSection {
    position: absolute;
    top:50;
    left:50;
    z-index: 2;
}

button {
    width: 120px;
    height: 40px;
    border: 0px solid rgb(200, 200, 200);
    border-radius: 5px;
    background-color: rgb(255, 157, 0);
    color: white;
    font-size: 15px;
    font-weight: 500;
    box-shadow: 0px 1px 10px rgb(50, 50, 50);
}

카카오에서 맵 위에 컴포넌트를 띄우기 위해 여러가지 방법이 있지만, z-index값을 주어 맵 위에 올리는게 편리해서 다음과 같이 적용했습니다.

[ 3-3. 🛠 js파일 ]

//기존의 모든 마커들을 보여주는 기능 구현
function makeMarker() {
    markers.forEach(function (marker) {
        marker.setMap(map);
    });
}





[ 4. 결과물 ]

매장마다의 marker들을 생성하여 데이터와 마커 이미지를 적용하여 카카오맵에 설정해줍니다.

[ 4-1. 마커 클릭시 ]

클릭 마커 기준 반지름 1km 근방의 매장만을 보여줍니다. (총 2km 반경)

[ 4-2. 전체보기 클릭 시 ]

안 보이는 매장을 다시 모두 set 해주어 매장 위치의 마커를 모두 표시하여줍니다.

[ 4-3. 맵 클릭 시 ]

마커가 아닌 맵을 클릭했을 시 맵에서 클릭한 좌표를 중심으로 1km의 원을 그려줍니다.


profile
다른 사람이 만든 것을 소비하는 활동보다, 내가 생산적인 활동을 하는 시간이 더 많도록 생활화 하자.

0개의 댓글