서버 & DB

AWS EC2 MySQL 서버와 안드로이드 스튜디오 연동

마루설아 2022. 5. 11. 12:31

https://maruseol-a.tistory.com/6

 

AWS EC2 서버 구축 및 연동 - 4

https://maruseol-a.tistory.com/5 AWS EC2 서버 구축 및 연동 - 3 https://maruseol-a.tistory.com/4 AWS EC2 서버 구축 및 연동 - 2 https://maruseol-a.tistory.com/3 AWS EC2 서버 구축 및 연동 - 1 https://a..

maruseol-a.tistory.com

 

이전 포스트에서는 AWS EC2 서버를 구현하고 MySQL 연동까지 진행하였다.

이번 포스트에서는 구축된 MySQL 서버와 안드로이드 스튜디오 연동 및

데이터 전달까지 다뤄보려고 한다.

 

=======================================

 

필자는 현재 앱 작동이 정상적으로 되지 않고 있다.

.php파일을 웹 사이트에서 접속하면 504 Gateway Timeout 오류가 뜨고있다.

처음으로 구축했던 서버와 앱은 이상없이 잘 작동하고 있으나

이번 포스팅에서 새로 만들고 있는 서버에서는 이 현상이 생기고 있다.

우선 작성하던 포스팅은 미리 올려두고 해당 오류가 수정되면 원인 및 수정사항을 재업하도록 하겠다.

 

=======================================

 

=======================================

 

504 Gateway Timeout 원인을 발견했다.

AWS EC2 서버 내 인바운드 규칙에 MySQL을 추가해줘야 했다.

인바운드 규칙을 추가하는 방법은 아래 포스팅에서 확인해보아라.

 

https://maruseol-a.tistory.com/4

 

AWS EC2 서버 구축 및 연동 - 2

https://maruseol-a.tistory.com/3 AWS EC2 서버 구축 및 연동 - 1 https://aws.amazon.com/ko/console/ AWS Management Console AWS Support 플랜은 AWS로 성공하는 데 도움이 되는 다양한 도구, 프로그램 및 전..

maruseol-a.tistory.com

 

 

=======================================

 

 

안드로이드 스튜디오 프로젝트를 작성하기에 앞서

이전에 구현했던 데이터베이스에 테스트용 테이블을 하나 추가해주자.

 

phpMyAdmin이나 putty를 사용하여 테이블을 추가하면 된다.

이 포스트에서는 phpMyAdmin에서 진행하겠다.

 

이전에 만든 데이터베이스인 testDB에 들어가서 테이블을 만들어보자.

이름에 User, 컬럼수 2를 적고 실행을 누른다.

 

간단하게 10자리 ID 필드와 20자리 Password 필드를 가진 User 테이블을 만들 것이다.

위와 같이 작성해도 되고 아래 콘솔창에서 직접 쿼리문을 넣어도 된다.

모두 완료되면 저장을 누르고 정상적으로 잘 되었는지 확인하려면

좌측 testDB - User에 들어간 후 상단에 구조 버튼을 눌러서 확인한다.

 

위와 같이 테이블이 완성되었다.

 

다음으로 로그인 및 회원가입을 위한 2개의 php 파일을 생성해야 한다.

우선은 텍스트 편집기를 실행한다.

본인이 편한 텍스트 편집기를 사용하면 될 듯 하다.

필자는 Sublime Text를 사용하겠다.

 

signup_test.php

<?php

	error_reporting(E_ALL);
	ini_set("display_errors", 1);

	$con = mysqli_connect("54.180.145.229", "Maru", "maru1234", "testDB");
	mysqli_query($con, 'SET NAMES utf8');

	$ID = $_POST["ID"];
	$Password = $_POST["Password"];

	$statement = mysqli_prepare($con, "insert into User values (?,?)");
	mysqli_stmt_bind_param($statement, "ss", $ID, $Password);
	mysqli_stmt_execute($statement);

	$response = array();
	$response["success"] = true;

	echo json_encode($response);

	mysqli_close($con);

?>

signup_test.php
0.00MB

 

 

회원가입을 위한 php이다.

 

가장 위에 보이는 error_reportings, ini_set 구분은

앱 연동 과정에서 작동이 되지 않을때 웹 사이트로 php문을 열어 확인하면

쿼리문 Syntax 오류 등의 내용을 파악할 수 있어 추가했다.

 

mysqli_connect 구문은 연결할 아이피, MySQL ID, Password, 그리고 접근할 데이터베이스 이름을 적는다.

ID, Password, DB 이름은 대소문자를 구분하니 유의하자.

 

$_POST 방식으로 값을 서버에서 받고,

insert into User values(?,?) 는 각 컬럼에 데이터를 입력하겠다는 의미이다.

 

그 외 아래 구문들에 대한 자세한 정보는 아직 배우지 않아서, 직접 찾아보도록 하자.

 

 

login_test.php

<?php

	error_reporting(E_ALL);
	ini_set("display_errors", 1);

	$con = mysqli_connect("54.180.145.22", "Maru", "maru1234", "testDB");
	mysqli_query($con, 'SET NAMES utf8');

	$ID = $_POST["ID"];
	$Password = $_POST["Password"];

	$statement = mysqli_prepare($con, "select * from User where ID = ? AND Password = ?");
	mysqli_stmt_bind_param($statement, "ss", $ID, $Password);
	mysqli_stmt_execute($statement);

	mysqli_stmt_store_result($statement);
	mysqli_stmt_bind_result($statement, $ID, $Password);

	$response = array();
	$response["success"] = false;

	while(mysqli_stmt_fetch($statement)) 
	{
		$response["success"] = true;
		$response["ID"] = $ID;
		$response["Password"] = $Password;
	}

	echo json_encode($response);

	mysqli_close($con);

?>

login_test.php
0.00MB

 

 

로그인을 위한 php도 회원가입과 비슷하다.

 

이 2개의 php파일을 파일질라를 이용해서 /var/www/html 경로에 넣어준다.

 

 

완료되었으면 안드로이드 스튜디오로 넘어간다.

필자는 Empty Activity, Java, API 28 : Android 9.0(Pie)를 사용한다.

프로젝트명은 testEC2로 해줬다.

 

우선 AndroidManifest.xml에 인터넷 권한을 허용하는 아래 코드를 입력한다.

<uses-permission android:name="android.permission.INTERNET" 

<application

	...
	android:usesCleartextTraffic="true">
	...
    
</application>

 

다음은 서버로부터 JSON 데이터를 주고 받기 위해 volley 라이브러리를 사용할 것이다.

bulid.gradle (Module: .app)에 볼리 라이브러리를 추가해준다.

추가하면 Sync Now를 해주는 것을 잊지말자.

dependencies {
	...
    //볼리 라이브러리
    implementation 'com.android.volley:volley:1.2.1'
}

 

다음은 activity_main.xml, MainAcitivty.java 두 파일로 로그인 화면을 구현할 것이다.

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout_editor_absoluteX="-137dp"
        tools:layout_editor_absoluteY="-189dp">

        <EditText
            android:id="@+id/idInput"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="220dp"
            android:autofillHints="아이디"
            android:hint="아이디"/>

        <EditText
            android:id="@+id/pwInput"
            android:layout_width="300dp"
            android:layout_height="70dp"
            android:layout_below="@+id/idInput"
            android:layout_centerHorizontal="true"
            android:autofillHints="비밀번호"
            android:hint="비밀번호"/>

        <Button
            android:id="@+id/loginButton"
            android:layout_width="150dp"
            android:layout_height="55dp"
            android:layout_below="@+id/pwInput"
            android:layout_alignParentStart="true"
            android:layout_marginStart="128dp"
            android:layout_marginTop="30dp"
            android:text="로그인"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/signupButton"
            android:layout_width="150dp"
            android:layout_height="55dp"
            android:layout_below="@+id/pwInput"
            android:layout_alignParentStart="true"
            android:layout_marginStart="128dp"
            android:layout_marginTop="100dp"
            android:text="회원가입"
            android:textAllCaps="false" />

        <TextView
            android:id="@+id/textView"
            android:layout_width="150dp"
            android:layout_height="47dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="128dp"
            android:layout_marginTop="73dp"
            android:gravity="center"
            android:text="로그인"
            android:textSize="15pt" />

    </RelativeLayout>


</androidx.constraintlayout.widget.ConstraintLayout>

activity_main.xml
0.00MB

 

 

로그인 화면이다.

아이디, 비밀번호를 입력할 수 있는 EditText

로그인, 회원가입을 누를 수 있는 Button을 만들어주었다.

 

 

MainActivity.java

package com.example.testec2;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.Volley;

import org.json.JSONException;
import org.json.JSONObject;

public class MainActivity extends AppCompatActivity {

    EditText ID, Password;
    Button Login, Signup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ID = findViewById(R.id.idInput);
        Password = findViewById(R.id.pwInput);
        Login = findViewById(R.id.loginButton);
        Signup = findViewById(R.id.signupButton);

        //로그인 버튼 이벤트
        Login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String id = ID.getText().toString();
                String pw = Password.getText().toString();

                Response.Listener<String> responseListener = new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        try
                        {
                            JSONObject jsonObject = new JSONObject(response);
                            boolean success = jsonObject.getBoolean("success");

                            if (success)
                            {
                                String msg = jsonObject.getString("ID");
                                Toast.makeText(getApplicationContext(), "로그인 성공. ID :" + msg, Toast.LENGTH_SHORT).show();
                            }

                            else
                            {
                                Toast.makeText(getApplicationContext(), "실패", Toast.LENGTH_SHORT).show();
                                return;
                            }
                        }

                        catch (JSONException e)
                        {
                            e.printStackTrace();
                            Toast.makeText(getApplicationContext(), "예외 1", Toast.LENGTH_SHORT).show();
                            return;
                        }

                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                };

                LoginRequestActivity loginRequestActivity = new LoginRequestActivity(id, pw, responseListener);
                RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
                queue.add(loginRequestActivity);
            }
        });


        //회원가입 버튼 이벤트
        Signup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(getApplicationContext(), SignupActivity.class);
                startActivity(intent);
            }
        });
    }
}

MainActivity.java
0.00MB

 

 

아이디와 비밀번호를 입력하고 로그인 버튼을 누르면

DB 내 아이디 및 비밀번호가 있는지 검사한 후 로그인이 성공되면 로그인이 성공됐다는 토스트 메세지를 출력하고

로그인이 실패하거나 예외처리가 되면 오류 토스트 메세지를 출력한다.

 

 

LoginRequestActivity.java

package com.example.testec2;

import com.android.volley.AuthFailureError;
import com.android.volley.Response;
import com.android.volley.toolbox.StringRequest;

import java.util.HashMap;
import java.util.Map;

public class LoginRequestActivity extends StringRequest {

    final static private String URL = "http://54.180.145.22/login_test.php";
    private Map<String, String> map;

    public LoginRequestActivity(String ID, String Password, Response.Listener<String> listener)
    {
        super(Method.POST, URL, listener, null);

        map = new HashMap<>();
        map.put("ID", ID);
        map.put("Password", Password);
    }

    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        return map;
    }
}

LoginRequestActivity.java
0.00MB

 

 

MainActivity.java에서 요청을 받아 처리한다.

URL에는 http://본인의 IPv4주소/login_test.php를 적자.

 

 

activity_signup.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/textView"
            android:layout_width="150dp"
            android:layout_height="47dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="121dp"
            android:layout_marginTop="51dp"
            android:gravity="center"
            android:text="회원가입"
            android:textSize="15pt" />

        <TextView
            android:id="@+id/textview2"
            android:layout_width="120dp"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="45dp"
            android:layout_marginTop="145dp"
            android:gravity="left"
            android:text="아이디"
            android:textSize="11pt" />

        <EditText
            android:id="@+id/signup_idInput"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="45dp"
            android:layout_marginTop="180dp"
            android:autofillHints="아이디"
            android:hint="아이디를 입력해 주십시오" />

        <TextView
            android:id="@+id/textview3"
            android:layout_width="120dp"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="45dp"
            android:layout_marginTop="235dp"
            android:gravity="left"
            android:text="비밀번호"
            android:textSize="11pt" />

        <EditText
            android:id="@+id/signup_pwInput"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="45dp"
            android:layout_marginTop="268dp"
            android:autofillHints="비밀번호"
            android:hint="비밀번호를 입력해 주십시오" />

        <Button
            android:id="@+id/signupButton"
            android:layout_width="150dp"
            android:layout_height="55dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="118dp"
            android:layout_marginTop="486dp"
            android:text="회원가입"
            android:textAllCaps="false" />

    </RelativeLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

activity_signup.xml
0.00MB

 

 

회원가입 화면이다.

아이디, 비밀번호를 입력할 수 있는 EditText

회원가입을 누를 수 있는 Button을 만들어주었다.

 

 

SignupActivity.java

package com.example.testec2;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.Volley;

import org.json.JSONException;
import org.json.JSONObject;

public class SignupActivity extends AppCompatActivity {

    EditText ID, Password;
    Button Signup;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signup);

        Signup = (Button) findViewById(R.id.signupButton);
        ID = (EditText) findViewById(R.id.signup_idInput);
        Password = (EditText) findViewById(R.id.signup_pwInput);

        //회원가입 버튼 이벤트
        Signup.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                String id = ID.getText().toString();
                String pw = Password.getText().toString();

                Response.Listener<String> responseListener = new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        try
                        {
                            JSONObject jsonObject = new JSONObject(response);
                            boolean success = jsonObject.getBoolean("success");

                            if (success)
                            {
                                Toast.makeText(getApplicationContext(), "성공", Toast.LENGTH_SHORT).show();
                                Intent intent = new Intent(SignupActivity.this, MainActivity.class);
                                startActivity(intent);
                            }

                            else
                            {
                                Toast.makeText(getApplicationContext(), "실패", Toast.LENGTH_SHORT).show();
                                return;
                            }
                        }

                        catch(JSONException e)
                        {
                            e.printStackTrace();
                            Toast.makeText(getApplicationContext(), "예외 1", Toast.LENGTH_SHORT).show();
                            return;
                        }

                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                };

                SignupRequestActivity signupRequestActivity = new SignupRequestActivity(id, pw, responseListener);
                RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
                queue.add(signupRequestActivity);
            }
        });
    }
}

SignupActivity.java
0.00MB

 

 

아이디와 비밀번호를 입력하고 회원가입 버튼을 누르면

입력한 아이디 및 비밀번호가 DB 내에 insert 되고

성공했다는 토스트 메세지 출력과 함께 로그인 화면으로 넘어간다.

실패와 예외 처리 또한 해두었다.

 

 

SignupRequestActivity.java

package com.example.testec2;

import com.android.volley.AuthFailureError;
import com.android.volley.Response;
import com.android.volley.toolbox.StringRequest;

import java.util.HashMap;
import java.util.Map;

public class SignupRequestActivity extends StringRequest {

    final static private String URL = "http://54.180.145.22/signup_test.php";
    private Map<String, String> map;

    public SignupRequestActivity(String ID, String Password, Response.Listener<String> listener)
    {
        super(Method.POST, URL, listener, null);

        map = new HashMap<>();
        map.put("ID", ID);
        map.put("Password", Password);
    }

    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        return map;
    }
}

SignupRequestActivity.java
0.00MB

 

 

SignupActivity.java에서 요청을 받아 처리한다.

URL에는 http://본인의 IPv4주소/login_test.php를 적자.

 

 

로그인 화면에서 회원가입 버튼을 눌렀을 때 앱이 강제종료 된다면

AndroidManifest.xml 내 application 태그 안에 다음의 코드를 넣어준다.

MainActivity.java에서 SignupActivity.java로 넘어가기 위해 해주는 작업이다.

<application>

...
	<activity
		android:name=".SignupActivity"
		android:exported="true" >
	</activity>
...

</application>

 

 

마지막 과정에서 앱 작동을 하면 아무 토스트메시지가 출력되지 않을 수도 있다.

그러면 다음 방법을 따라해보자.

 

우선 putty 에서 아래 명령어를 입력하고 비밀번호를 임의로 설정해준다.

sudo passwd root

 

그 다음은 아래 명령어를 입력하여 root 권한으로 접근한다.

패스워드 입력메세지가 뜨면 방금 입력한 패스워드를 입력한다.

su root

 

아래 명령어를 입력하고 편집기를 열어준다.

vi /etc/mysql/mysql.conf.d.mysqld.cnf

 

그러면 31번, 32번 라인에

bind-address, mysqlx-bind-address 앞부분에 #을 기입하여 주석처리를 해주고

ESC, :wq!를 입력하여 저장해준다.

 

아래 명령어를 입력하고 앱에서 다시 작동해본다.

sudo service mysql restart

 

 

앱 예뮬레이터로 정상 작동하는지 확인해보자.

 

 

첫 화면이 뜨면 회원가입을 눌러서

아이디는 test, 비밀번호는 test1234로 회원가입을 했다.

 

그 후 로그인 화면에서 가입했던 정보와 틀린 정보를 입력하면

실패라는 토스트 메세지가 표시되고,

맞는 정보를 입력하면 성공 메세지와 함께 아이디가 표시된다.

 

 

이후 phpmyadmin에 접속하여 User 테이블을 조회해보면

정상적으로 데이터가 입력이 된 것을 확인할 수 있다.

 

 

지금까지 AWS EC2 서버 구축과 Android Studio 연동까지 알아보았다.

 

필자는 중간중간 상당히 많은 오류를 경험했고

하나씩 수정하는 작업에서도 꽤나 많은 시간이 지체되었다.

앞으로 또 다른 프로젝트를 하게 된다면

한번에 성공할 거라는 기대는 안 해야할듯하다..

'서버 & DB' 카테고리의 다른 글

AWS EC2 서버 구축 및 연동 - 4  (0) 2022.05.09
AWS EC2 서버 구축 및 연동 - 3  (0) 2022.05.09
AWS EC2 서버 구축 및 연동 - 2  (0) 2022.05.09
AWS EC2 서버 구축 및 연동 - 1  (0) 2022.05.09