'Project/졸업프로젝트'에 해당되는 글 1건

  1. [경성대 배달학과] 포트폴리오

프로젝트 진행 기간 : 2015.03.01 ~ 2015.06.08

개발 환경 :

  - Android 4.4 Kitkat 기준 (Min Version : Android 4.0.3 IceCreamSandWich)

  - 개발 도구 : 안드로이드 스튜디오 1.3.2 (Gradle), mySQL, Eclipse EE(PHP)

  - 사용 언어 : 자바(Android), PHP (백엔드)

  - 서버 정보 : Ubuntu Linux 환경 Apache Server


4학년 1학기에 들은 필수과목 종합설계 프로젝트라는 캡스톤 디자인 과목에서 진행한 프로젝트 입니다.


01234567891011121314


(기획발표 프레젠테이션)


경성대의 공대는 학교 가장 꼭대기에 위치하여 쉬이 무언가를 먹으려 내려가기 힘든 환경입니다. 

그래서 연구실 생활을 하는 동안 무언가를 시켜먹는 일이 잦았습니다.

항상 비슷한 것들만 먹게 되다보니 좀 더 맛있는 집을 찾게 되었고, 여러 유명한 배달업체를 찾아봤지만 대연동이라는 검색범주 안에서는 제외되는 업체도 많고, 숨겨진 맛집을 찾기에는 힘이 들었습니다.

또한, 배달을 올때마다 뿌리고 가는 전단지들 때문에 교내 환경이 전단지로 몸살을 앓기 시작했습니다.

이러한 점들을 개선하고자 경성대만의 배달업체 정보제공 안드로이드 어플리케이션, 경성대 배달학과를 만들자는 생각을 하게 되었습니다.



종합설계 프로젝트는 강의이니 만큼 교수님의 지도 하에 프로젝트가 진행되었는데, 소프트웨어 공학에 대해 공부하면서

DFD(Data Flow Diagram), HIFO(Hierachy Plus Input Process Output) Diagram을 작성하며 프로젝트의 상세 설계를 해나갔습니다.

이러한 Diagram은 처음 그려보는 것이라 그리면서도 이게 맞나..하며 그렸지만, 교수님의 질타를 예상했던 것보단 좋은 반응을 받을 수 있었습니다.


종설 DFD.hwp종설 HIPO.hwp

(작성한 Diagram)



이때 프로젝트를 진행했던 인원은 본인 포함 2명이었는데, 다른 팀원 한명이 DB를 포함한 백엔드 서비스를 담당하고 저는 안드로이드 프로그래밍을 맡았습니다. 당시 사용한 서버는 연구실에서 사용하는 서버로, 이전의 프로젝트들로 서버 환경은 모두 구축되어 있었기에 DB와 PHP만 만들면 되는 상황이었습니다.

안드로이드에서 제가 구현을 맡은 것은 UI구성과 UI에 들어갈 이미지들 작성, SNS연동 기능, 서버와 http 통신을 통해 데이터를 교환하는 기능, 그 데이터들을 바탕으로 안드로이드 상에 출력해 주는 일 등 이었습니다.

따라서 여태 프로젝트를 진행할 때 그래왔듯이, 먼저 화면 구성을 프로토타입을 통해 짜게 되었습니다.


https://ovenapp.io/view/wFN7m1FXelKmy4mhgAtno1WGmAxH4m0y/T3RVd

(프로토타입 툴 oven을 사용해 만든 경성대 배달학과 프로토타입)



그리고 두번째로는 앱 내부에 들어갈 이미지들을 제작하였습니다. 

버튼 이미지 또한 나인패치로 제작하였습니다.



-App Icon



-Main Logo



-Categories



-Buttons(Nine Patch)


    



(제작 및 편집한 이미지들)



마지막으로 안드로이드 내부에서는 SNS연동과 백엔드와의 통신 등의 어플리케이션을 기능을 구현하였습니다.


SNS 연동 같은 경우 페이스북과 카카오 연동 두가지 방식을 사용했는데, 결과 발표 당시에는 페이스북만 구현했지만 완성 이후에 카카오톡 연동 또한 구현하였습니다.


구현 시에는 페이스북 로그인 SDK와 카카오 로그인 SDK를 사용하여 사용자의 고유 카카오/페이스북 id와 이름, 프로필 사진 url 등을 받아 최초 로그인 시에 서버 DB에 저장하고, 어플리케이션 내에서는 세션을 유지시켜서 로그인을 유지할 수 있게 하였습니다.


세션을 유지하는 기능은 이전 프로젝트에서 구현했던 기능을 활용하여서 쉽게 구현할 수 있었습니다.




-LoginActivity.java

 :  Splash Activity 겸 세션 체크 후 로그인 상태가 아닐 때 로그인 기능이 나타나는 액티비티. 

페이스북/카카오 연동 로그인 기능 및 InsertUser 객체를 통해 서버의 DB유저정보를 삽입하거나 수정한다. 

연동 과정에서 액티비티가 사라지는 현상이 있어서 BaseActivity를 밑에 깔아 주었다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
package com.miclab.ksbaedal.login;
 
import android.content.Context;
import android.content.Intent;
 
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.os.Handler;
 
import android.util.Log;
 
import android.view.KeyEvent;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.Toast;
 
import com.facebook.*;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
 
import com.kakao.auth.ApiResponseCallback;
import com.kakao.auth.AuthType;
import com.kakao.auth.ErrorResult;
import com.kakao.auth.ISessionCallback;
import com.kakao.auth.KakaoSDK;
import com.kakao.auth.Session;
import com.kakao.usermgmt.UserManagement;
import com.kakao.usermgmt.callback.MeResponseCallback;
 
import com.kakao.usermgmt.response.model.UserProfile;
import com.kakao.util.exception.KakaoException;
import com.kakao.util.helper.log.Logger;
import com.miclab.ksbaedal.R;
import com.miclab.ksbaedal.kakao.KakaoSDKAdapter;
import com.miclab.ksbaedal.main.MainActivity;
 
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
 
 
public class LoginActivity extends FragmentActivity {
    CallbackManager callbackManager;
    ProfileTracker profileTracker;
    AccessTokenTracker accessTokenTracker;
 
    SessionCallback callback;
 
    Context con, basecon;
    Intent i, intent;
    Boolean isFirst;
    SessionManager session;
 
    Button fbloginButton, kakaologinButton;
    int delaySec;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FacebookSdk.sdkInitialize(getApplicationContext());
        try{
            KakaoSDK.init(new KakaoSDKAdapter(this));
        }
        catch (KakaoSDK.AlreadyInitializedException ex){;}
        setContentView(com.miclab.ksbaedal.R.layout.activity_login);
        final Handler handler = new Handler();
        con=this;
 
        i = new Intent(LoginActivity.this, MainActivity.class);
        intent = getIntent();
 
        delaySec = 1500;
        Boolean isDelay = intent.getBooleanExtra("startAnimation"true);
        if(!isDelay) {
            delaySec=0;
        }
        isFirst = intent.getBooleanExtra("ExistBase",false);
 
        session = new SessionManager(this.getApplicationContext());
 
        //facebook sdk 설정
        callbackManager = CallbackManager.Factory.create();
        accessTokenTracker = new AccessTokenTracker() {
            @Override
            protected void onCurrentAccessTokenChanged(
                    AccessToken oldAccessToken,
                    AccessToken currentAccessToken) {
                // On AccessToken changes fetch the new profile which fires the event on
                // the ProfileTracker if the profile is different
                //Profile.fetchProfileForCurrentAccessToken();
            }
        };
        profileTracker = new ProfileTracker() {
            @Override
            protected void onCurrentProfileChanged(Profile oldProfile, Profile newProfile) {
                setProfile(newProfile.getId(), newProfile.getName(), "f""");
            }
        };
 
        accessTokenTracker.startTracking();
        profileTracker.startTracking();
 
        //kakao sdk 설정
        callback = new SessionCallback();
        Session.getCurrentSession().addCallback(callback);
        if(session.isLogin()) Session.getCurrentSession().checkAndImplicitOpen();
 
        fbloginButton = (Button) findViewById(R.id.fb_Login_button);
        kakaologinButton = (Button) findViewById(R.id.kakao_Login_button);
 
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //세션체크
                        if (session.isLogin()) {
                            System.out.println("login");
                            startActivity(i);
                            overridePendingTransition(R.animator.in, R.animator.out);
                            finish();
                            if(isFirst) BaseActivity.base.finish();
                        } else {
                            Animation ani = new AlphaAnimation(01);
                            ani.setDuration(400);
                            fbloginButton.setAnimation(ani);
                            kakaologinButton.setAnimation(ani);
                            fbloginButton.setVisibility(View.VISIBLE);
                            kakaologinButton.setVisibility(View.VISIBLE);
                        }
                    }
                }, delaySec);
            }
        });
 
        //페이스북 로그인
        //fbloginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
        LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
            @Override
            public void onSuccess(LoginResult loginResult) {
                AccessToken accessToken = loginResult.getAccessToken();
                Profile profile = Profile.getCurrentProfile();
                //Profile.fetchProfileForCurrentAccessToken();
                //setProfile(Profile.getCurrentProfile());
                setProfile(profile.getId(), profile.getName(), "f""");
                startActivity(i);
                overridePendingTransition(R.animator.in, R.animator.out);
                if(isFirst) BaseActivity.base.finish();
                finish();
                // }
            }
 
            @Override
            public void onCancel() {
                Log.d("FacebookLogin""Canceled");
            }
 
            @Override
            public void onError(FacebookException error) {
                Log.d("FacebookLogin"String.format("Error: %s", error.toString()));
                String title = "Facebook 로그인 에러";
                String alertMessage = error.getMessage();
                Toast.makeText(con, title+" : "+alertMessage, Toast.LENGTH_SHORT).show();
            }
        });
 
        fbloginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                fbButtonOnClick();
            }
        });
 
        //카톡 로그인 부분
        kakaologinButton.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View view) {
                kakaoButtonOnClick();
            }
        });
    }
 
    void fbButtonOnClick(){
        LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile"));
    }
 
    void kakaoButtonOnClick(){
        Session.getCurrentSession().open(AuthType.KAKAO_TALK_EXCLUDE_NATIVE_LOGIN, this);
    }
 
    void kakaoLogin(){
        UserManagement.requestMe(new MeResponseCallback() {
            @Override
            public void onFailure(ErrorResult errorResult) {
                String message = "failed to get user info. msg=" + errorResult;
                Logger.d(message);
            }
 
            @Override
            public void onSessionClosed(ErrorResult errorResult) {
                String message = "failed to get user info. msg=" + errorResult;
                Logger.d(message);
            }
 
            @Override
            public void onSuccess(UserProfile userProfile) {
                if (userProfile != null) {
                    userProfile.saveUserToCache();
                    Logger.d("UserProfile : " + userProfile);
                    setProfile(String.valueOf(userProfile.getId()), userProfile.getNickname(), "k", userProfile.getThumbnailImagePath());
                    startActivity(i);
                    overridePendingTransition(R.animator.in, R.animator.out);
                    if (isFirst) BaseActivity.base.finish();
                    finish();
                }
            }
 
            @Override
            public void onNotSignedUp() {
                session.logout();
            }
        });
    }
 
    void kakaoUpdate(){
        final Map<StringString> properties = new HashMap<StringString>();
        properties.put("nickname", session.getValue("userName"));
        properties.put("profile_image", session.getValue("profilePicture"));
 
        UserManagement.requestUpdateProfile(new ApiResponseCallback<Long>() {
            @Override
            public void onSuccess(Long userId) {
                UserProfile profile = UserProfile.loadFromCache();
                profile.updateUserProfile(properties).saveUserToCache();
                Logger.d("succeeded to update user profile" + profile);
                setProfile(String.valueOf(session.getLoginID()), profile.getNickname(), "k", profile.getThumbnailImagePath());
            }
 
            @Override
            public void onNotSignedUp() {
                session.logout();
            }
 
            @Override
            public void onFailure(ErrorResult errorResult) {
                String message = "failed to get user info. msg=" + errorResult;
                Logger.e(message);
            }
 
            @Override
            public void onSessionClosed(ErrorResult errorResult) {
                String message = "failed to get user info. msg=" + errorResult;
                Logger.e(message);
            }
        }, properties);
    }
 
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Handler handler = new Handler();
        if(event.getAction()==KeyEvent.ACTION_DOWN){
            if(keyCode==KeyEvent.KEYCODE_BACK){
                if (isFirst) BaseActivity.base.finish();
                return super.onKeyDown(keyCode, event);
            }
        }
        return true;
    }
 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 
        if (Session.getCurrentSession().handleActivityResult(requestCode, resultCode, data)) {
            return;
        }
        callbackManager.onActivityResult(requestCode, resultCode, data);
        super.onActivityResult(requestCode, resultCode, data);
    }
 
    @Override
    public void onDestroy() {
        Session.getCurrentSession().removeCallback(callback);
        profileTracker.stopTracking();
        accessTokenTracker.stopTracking();
        super.onDestroy();
    }
 
 
 
    private void setProfile(String id, String name, String type, String picture) {
        Log.i("login info""id : " + id + " name : " + name + " type : " + type);
        if(type=="f") {
            session.login(id, type, name, "https://graph.facebook.com/" + id + "/picture?type=large");
        }
        else if(type=="k"){
            session.login(id, type, name, picture);
        }
 
        InsertUser iu = new InsertUser(LoginActivity.this, session.getLoginID(), session.getLoginType(), session.getValue("userName"), session.getValue("profilePicture"), session);
        try {
            iu.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    private class SessionCallback implements ISessionCallback {
        @Override
        public void onSessionOpened() {
            if(session.isLogin()){if(session.getLoginType()=="k")
                LoginActivity.this.kakaoUpdate();
            }
            else {
                LoginActivity.this.kakaoLogin();
            }
        }
 
        @Override
        public void onSessionOpenFailed(KakaoException exception) {
            if(exception != null) {
                Logger.e(exception);
            }
        }
    }
}
 
cs



-SessionManager.java

 : 어플리케이션 내의 앱 데이터, 세션을 설정하는 부분. 

SharedPreferences를 사용해서 현재 로그인 된 정보를 저장하고 호출시 정보를 로드한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.miclab.ksbaedal.login;
 
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
 
public class SessionManager {
    SharedPreferences pref;
    Editor edit;
 
    public static final String IS_LOGIN = "isLogin";
    public static final String USER_ID = "userID";
    public static final String USER_TYPE = "userType";
    public static final String USER_NAME = "userName";
    public static final String USER_NICKNAME = "nickName";
    public static final String PROFILE_PICTURE = "profilePicture";
 
    public SessionManager(Context con){
        pref=con.getSharedPreferences("LoginSession", Activity.MODE_PRIVATE);
        edit=pref.edit();
    }
 
    public void login(String id, String type, String name, String picture){
        edit.putBoolean(IS_LOGIN, true);
        edit.putString(USER_ID, id);
        edit.putString(USER_TYPE, type);
        edit.putString(USER_NAME, name);
        edit.putString(PROFILE_PICTURE, picture);
        edit.commit();
    }
 
    public void logout(){
        if(isLogin()){
            edit.putBoolean(IS_LOGIN, false);
            edit.putString(USER_ID, null);
            edit.putString(USER_TYPE, null);
            edit.putString(USER_NAME, null);
            edit.putString(USER_NICKNAME, null);
            edit.putString(PROFILE_PICTURE, null);
            edit.commit();
        }
    }
 
    public String getLoginID(){
        if(isLogin()){
            return pref.getString(USER_ID, null);
        }
        return null;
    }
 
    public String getLoginType(){
        if(isLogin()){
            return pref.getString(USER_TYPE, null);
        }
        return null;
    }
 
    public String getValue(String key){
        if(isLogin()){
            return pref.getString(key, "");
        }
        return null;
    }
 
    public boolean isLogin(){
        return pref.getBoolean(IS_LOGIN, false);
    }
 
 
 
}
 
cs



(SNS 연동 로그인 기능)



이외에 나머지 기능은 대부분 커스텀 리스트뷰와 http 통신을 하는 것으로 생략하겠습니다.


수정한 실제 액티비티의 구성은 이렇습니다.




-kakao : kakaoSDK 관련 파일

-login : splash 포함 로그인 기능 액티비티, 세션관리 매니저

-main : http 통신을 통해 json 데이터를 파싱하는 기능, 메인 액티비티를 중심으로 가게 카테고리 리스트, 메뉴 추천 액티비티 포함 (FavoriteAcitivity 파일은 개인의 즐겨찾기 가게를 보여주는 액티비티로 미구현 기능)

-pasing : 교내 식당 페이지 데이터 파싱 기능, 파싱한 데이터(학식 메뉴)를 표시해주는 액티비티

-store : 가게 상세 페이지 관련 액티비티/어댑터. 리뷰 작성 기능

-CTextView.java : 글자가 잘리지 않고 줄넘김이 되는 텍스트뷰 사용을 위한 파일




다음은 백엔드 서비스 구조입니다.

서버 내에 php 언어를 사용해서 json 데이터를 송출하고, 안드로이드에서는 json데이터가 있는 해당 페이지에서 파싱을 통해 데이터를 가져옵니다.




리뷰 삽입/로드

-insert_review.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php
header("Content-Type: application/json; charset=UTF-8");
header("Accept: application/json");
header("Cache-control: No-Cache");
header("Pragma: No-Cache");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
 
$mysql_hostname="";
$mysql_user="";
$mysql_password="";
$mysql_database="";
 
$dbc = mysql_connect($mysql_hostname,$mysql_user,$mysql_password)
or die("db connect error: ".mysql_error());
mysql_select_db($mysql_database,$dbc)
or die("db connect error: ".mysql_error());
 
mysql_query("SET NAMES UTF8");
 
$idx = $_POST["idx"]; 
$score = $_POST["score"];
$userid = $_POST["userid"];
$usertype = $_POST["usertype"];
$storeid = $_POST["storeid"];
$content = $_POST["content"];
$image = $_POST["image"];
 
if($userid!=null&&$usertype!=null&&$storeid!=null){
    //index - null : insert new review
    if($idx==null){
        $result = mysql_query("INSERT INTO baedal.review (score, userid, usertype, storeid, content, image) values (".$score.",'".$userid."','".$usertype."','".$storeid."','".$content."','".$image."')");
        if($result)
            echo "review insert success. ";
        else
            die("review insert fail:".mysql_error());
    }
    
    //index - not null : update review
    else{
        //review check
        $result = mysql_query("SELECT * FROM review WHERE idx = ".$idx);
        if(!$result)
            die("review query fail:".mysql_error());
        $numrow = mysql_num_rows($result);
        
        if($numrow!=null){
            $result = mysql_query("UPDATE review SET score=".$score.", userid='".$userid."',usertype='".$usertype."',storeid='".$storeid."',content='".$content."',image='".$image."' WHERE idx=".$idx);
            if($result)
                echo "review update success. ";
            else
                die("review update fail:".mysql_error());
        }
        else die("not exist review index");
    }    
}
 
//exception
else{
    echo "error - foreign key null";
}
 
//score update
$result = mysql_query("SELECT sum(score), count(score) FROM review WHERE storeid='".$storeid."'");
if($result)
    echo "review select success. ";
else
    die("review select fail".mysql_error());
    
$row = mysql_fetch_row($result);
$avg_score = $row[0]/$row[1];
$result = mysql_query("UPDATE store SET score=".$avg_score." WHERE storeid='".$storeid."'");
 
if($result)
    echo "score update success";
else
    die("score update fail".mysql_error());
 
 
mysql_close($dbc);
?>
 
cs


-load_review.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php
header("Content-Type: application/json; charset=UTF-8");
header("Accept: application/json");
header("Cache-control: No-Cache");
header("Pragma: No-Cache");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
 
$mysql_hostname="";
$mysql_user="";
$mysql_password="";
$mysql_database="";
 
$dbc = mysql_connect($mysql_hostname,$mysql_user,$mysql_password)
or die("db connect error: ".mysql_error());
mysql_select_db($mysql_database,$dbc)
or die("db connect error: ".mysql_error());
 
mysql_query("SET NAMES UTF8");
 
$type = $_POST["type"];
$userid = $_POST["userid"];
$usertype = $_POST["usertype"];
$storeid = $_POST["storeid"];
 
if($type=='u')
    $selectquery = "SELECT * FROM review WHERE userid='".$userid."' AND usertype='".$usertype."'";
 
else if($type='s')
    $selectquery = "SELECT * FROM review WHERE storeid='".$storeid."'";
 
else
    die("type is null or incorrect (only u or s)");
 
$result = mysql_query($selectquery);
if(!$result)
    die("review select fail:".mysql_error());
 
if(mysql_num_rows($result)>0){
 
    $response = array();
echo "{\"android\":";
    while($row = mysql_fetch_array($result)){
        $main["idx"= $row[0];
        $main["score"= $row[1];
        $main["username"= mysql_fetch_array(mysql_query("SELECT name FROM user WHERE userid='".$row[2]."' AND type='".$row[3]."'"))[0];
        $main["storeid"= $row[4];
        $main["content"= $row[5];
        $main["datetime"= $row[6];
        $main["image"= $row[7];
 
        array_push($response$main);
    }
    echo json_encode($response, JSON_UNESCAPED_UNICODE);
    echo "}";
}
 
else {
    //not found
    $response["success"= 0;
    $response["message"= "Can't load or is not any review";
 
    //echo no user JSON
    echo json_encode($response, JSON_UNESCAPED_UNICODE);
}
 
mysql_close($dbc);
?>
 
cs



데이터베이스의 경우, 함께 프로젝트를 진행했던 팀원이 설계를 담당했었는데 가게마다 각각의 메뉴 테이블을 가지고 있는 아주 비효율적인 구조를 가지고 있었습니다. 그래서 최종발표 이후 데이터베이스를 갈아엎는 수정을 거치게 됩니다.


데이터베이스는 User 테이블, Review 테이블, Store 테이블로 구성되어 있으며 

store테이블안에는 가게정보와 메뉴정보가 함께 들어있습니다.

메뉴같은 경우 parent id라는 컬럼을 추가한 메뉴와 가게 테이블을 join한 형태인데 parent id에 값이 있냐 없냐에 따라 가게항목과 메뉴항목을 구분하였습니다. 메뉴의 경우 해당 가게의 id값을 parent id로 조회하여 쿼리 결과로 나타내었는데, 데이터베이스에 설계가 미숙할 때 수정했던 것이라 지금에 와서는 메뉴만을 모아놓은 테이블과 가게테이블을 1대다 관계로 설정하면 되지 않을까 하는 생각이 듭니다. 

수정한 데이터베이스는 서버가 열려있을 때 (지금은 닫혀있는 상태) DB 구성을 캡쳐하지 못하여 관련 자료가 없습니다.


이렇게 만들어진 베타 버전의 경성대 배달학과는 야침찬 부가기능 개발계획을 가지고 있었지만, 이 후의 일정에 밀려 더 이상 발전시키지 못해서 아쉬움이 많은 프로젝트입니다.

구글 플레이스토어에 등록까지 했지만, 언젠가 완성시켜서 이미 졸업한 학교이지만 후배들에게 편의를 제공해 주는 것이 목표입니다.


마지막으로 실제 실행 화면이 포함된 어플리케이션 사용설명서를 첨부합니다.

사용설명서.hwp