Android(Kotlin) / PHP / Mysql을 이용한 회원가입 구현하기

김현지·2023년 12월 28일
0
post-thumbnail
post-custom-banner

Tools : Android Studio / Vscode
Version Control : GitHub
Language : Kotlin / PHP / Mysql

고등학생이라 코드가 깔끔하진 못하지만
거두절미하고 바로 가보겠습니다.

쉬운 설명을 위해 많은 부분을 삭제했습니다.
자세한 코드는 깃허브 참고 부탁드립니다. (2024 6월까지 개발 진행중)
👉android kotlin code
👉php server code

- 대략적인 단계

  • res/layout/activity_signup.xml 생성 및 ui 개발
  • SignupActivity.kt에 POST 코드 작성
  • signup.php 코드 작성 및 데이터베이스 접근

- 1. UI개발

기능만 성공하면 되기 때문에 일단 대충 만들어보겠습니다.
res/layout/activity_signup.xml을 생성하여 코드를 작성합니다.

아래 코드는 밑을 포함합니다.

  • edittext를 이용하여 사용자의 이름, 아이디, 비밀번호를 입력받습니다.
    - android:hint는 edittext의 placeholder입니다.
    - android:singleLine에 true를 줌으로써 줄바꿈이 불가피해집니다.

activity_signup.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <!--이름 입력-->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:text="이름을 입력해 주세요."
        android:textSize="20dp" />

    <EditText
        android:id="@+id/signUpEditTextName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="이름을 입력해 주세요."
        android:singleLine="true"
        android:maxLength="20"
        android:padding="15dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"/>

    <!--아이디 입력-->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="30dp"
        android:text="아이디를 입력해 주세요."         
        android:textSize="20dp" />

    <EditText
        android:id="@+id/signUpEditTextID"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:hint="아이디를 입력해 주세요."
        android:singleLine="true"
        android:maxLength="20"
        android:padding="15dp"
        android:layout_marginTop="15dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginBottom="30dp"/>

    <!--비밀번호 입력-->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:text="비밀번호를 입력해 주세요."
        android:textSize="20dp" />

    <EditText
        android:id="@+id/signUpEditTextPW"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="비밀번호를 입력해 주세요."
        android:inputType="textPassword"
        android:singleLine="true"
        android:maxLength="20"
        android:padding="15dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"/>

    <!--다음 버튼-->
    <Button
        android:id="@+id/go_nextBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="회원가입 하기"
        android:textColor="@color/white"
        android:textStyle="bold"
        android:textSize="16dp"
        android:layout_margin="15dp"
        android:padding="17dp"/>

</LinearLayout>

- 2. SignupActivty에 기능구현

저는 Volley라는 안드로이드 http 통신 라이브러리를 사용하였습니다.

volley 세팅 방법

  • AndroidMenifest.xml에 아래 코드를 붙여넣습니다.
<uses-permission android:name="android.permission.INTERNET" />
  • build.gradle속 dependencies 밑에 아래 문장을 붙여넣습니다.
implementation 'com.android.volley:volley:1.1.1'

참고로 저는 데이터베이스에 값은 잘 들어가지만
json parsing error 때문에
success후 기능들을 JSONException에 넣었습니다.

SignupActivity.kt

package kr.hs.emirim.dreamorreality

import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.EditText
import android.widget.Spinner
import androidx.activity.ComponentActivity
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import org.json.JSONException
import org.json.JSONObject

class SignUpActivity : ComponentActivity() {

	//localhost 안돼요!
    //전 제 컴퓨터 아이피 사용했습니다.
    private val serverUrl = "http://본인컴퓨터ip or dothome등의 서버/본인 프로젝트 디렉토리/signup.php"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_signup)

		//activity_signup.xml에서 버튼에 부여한 id를 가져온다.
        val nextButton = findViewById<Button>(R.id.go_nextBtn)
        nextButton.setOnClickListener {
            handleNextButtonClick() //버튼을 클릭했을때, 이 메소드를 호출합니다.
        }
    }

    //error dialog를 띄우는 메소드
    private fun showErrorDialog(message: String) {
        val builder = AlertDialog.Builder(this)
        builder.setTitle("Error")
        builder.setMessage(message)
        builder.setPositiveButton("확인", null)
        val dialog = builder.create()
        dialog.show()
    }

	//success dialog를 띄우는 메소드
    private fun showSuccessDialog(message: String) {
        val builder = AlertDialog.Builder(this)
        builder.setTitle("Success")
        builder.setMessage(message)
        builder.setPositiveButton("확인", null)
        val dialog = builder.create()
        dialog.show()
    }

	// 다음 회원가입 버튼을 눌렀을 때 동작하는 메소드
    private fun handleNextButtonClick() {
        //필요 필드 값을 가져옴.
        val username = findViewById<EditText>(R.id.signUpEditTextName).text.toString()
        val userid = findViewById<EditText>(R.id.signUpEditTextID).text.toString()
        val userpw = findViewById<EditText>(R.id.signUpEditTextPW).text.toString()    

        //필드가 하나라도 비었다면 Error Dialog 발생
        if(username.isEmpty() || userid.isEmpty() || userpw.isEmpty() )
            showErrorDialog("모든 필드를 입력해주세요.")

        //JSON 객체를 생성하여 데이터를 저장
        val json = JSONObject()
        json.put("username", username)
        json.put("userid", userid)
        json.put("userpw", userpw)

        // Volley를 사용하여 서버로 POST 요청 보내기
        sendPostRequest(json.toString())
    }

	// 서버로 POST 요청을 보내는 메소드
    private fun sendPostRequest(data: String) {
        val requestQueue = Volley.newRequestQueue(this)

        val stringRequest = object : StringRequest(
            Request.Method.POST,
            serverUrl,
            Response.Listener { response ->
                try {
                    val jsonResponse = JSONObject(response)
                    val error = jsonResponse.getBoolean("error")

                    if (error) {
                        val errorMessage = jsonResponse.getString("message")
                        showErrorDialog(errorMessage)

                        // 에러 상세 정보를 출력할 경우
                        if (jsonResponse.has("errorDetails")) {
                            val errorDetails = jsonResponse.getString("errorDetails")
                            Log.e("ServerError", errorDetails)
                        }
                    } else {
                        val successMessage = jsonResponse.getString("message")
                        // 성공 메시지 처리
                        Log.d("ServerResponse", successMessage)
                    }
                } catch (e: JSONException) {
                    Log.e("JSONError", "Error parsing JSON: $response")
                    //json parsing error가 해결될때까지 성공 메세지코드는 여기 위치합니다.
                    showSuccessDialog("성공적으로 회원가입 되었습니다.")
                    //실질적으론 확인 버튼을 누르면 넘어가는게 아닌 2초 대기 후 넘어가는 코드
                    Handler().postDelayed({
                        val intent = Intent(this, MainActivity::class.java)
                        startActivity(intent)
                    }, 2000) // 2초 대기
                }
            },
            Response.ErrorListener { error ->
                // 오류 처리
                Log.e("VolleyError", "Volley Error: ${error.networkResponse?.statusCode}, ${error.message}")
                showErrorDialog("서버 오류가 발생했습니다.")
            }
        ) {
            override fun getBodyContentType(): String {
                return "application/json; charset=utf-8"
            }

            override fun getBody(): ByteArray {
                return data.toByteArray()
            }
        }

        requestQueue.add(stringRequest)
    }


}

- 3. php server code 작성하기

저같은 경우에는 초기에 html을 이용해서 db에 값이 잘 들어가는지 확인 후
안드로이드 연결 작업을 시행하였습니다.

mysqli table 쿼리문입니다.

create table user(
	id int auto_increment primary key,
    username varchar(10) not null,
    userid varchar(35) not null unique,
    userpw varchar(35) not null);

db_conn.php 파일에 데이터베이스 정보를 넣고
signup.php파일 상단에 include('db_conn.php'); 추가해주세요.

db_conn.php

<?php
    $dbhost = 'host이름';
    $dbid ='사용자이름';
    $dbpw = '비밀번호';
    $db = '데이터베이스 이름';

    $conn = mysqli_connect($dbhost, $dbid, $dbpw, $db);
?>

가끔 안되시는분들 있는거같은데 밑 코드처럼 수정해보세요.

$port = '3307'; //추가
$conn = mysqli_connect(기존유지... , $port);

signup.php

<?php
    //모든 에러의 표시 설정
    error_reporting(E_ALL);
    ini_set('display_errors', 1);

    include('db_conn.php');

    // 사용자 에이전트에서 안드로이드를 찾는다.
    $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");

    // POST 요청이거나 안드로이드에서 요청일 경우
    if (($_SERVER['REQUEST_METHOD'] == 'POST') || $android) {

        // POST 요청으로 전달된 JSON 데이터 수집
        $data = json_decode(file_get_contents("php://input"), true);

        // 입력값이 비어있는지 확인하고 오류 메시지 설정
        if (empty($data['username'])) $errMSG = "이름";
        else if (empty($data['userid'])) $errMSG = "아이디";
        else if (empty($data['userpw'])) $errMSG = "비밀번호";

    	// 에러가 없으면 데이터베이스에 삽입
    	if (!isset($errMSG)) {
        	// 입력값이 비어있는지 확인하고 오류 메시지 설정
        	$userName = $data['username'];
        	$userId = $data['userid'];
        	$userPw = $data['userpw'];
            
        	try {
            	$stmt = $conn->prepare("INSERT INTO user(username, userid, userpw) 
                                    VALUES('$userName', '$userId', '$userPw')");

            // 쿼리 실행에 실패하면 예외 발생
            if (!$stmt) throw new Exception('Prepare statement failed: ' . $conn->error);
            

            // 쿼리 실행
            if ($stmt->execute()) $successMSG = "가입 성공";
            else $errMSG = "가입 실패";
                
            } catch (PDOException $e) {
                // 데이터베이스 오류 시 예외 처리
                die("데이터베이스 오류: " . $e->getMessage());
            } catch (Exception $e) {
                // 일반적인 오류 예외 처리
                die("오류: " . $e->getMessage());
            }
        }
    }
?>

<?php
    // 에러 메시지 및 성공 메시지 출력
    if (isset($errMSG)) echo $errMSG;
    if (isset($successMSG)) echo $successMSG;
 
    // 안드로이드에서 요청이 아니면 HTML 폼 출력
    $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");
 
    if (!$android) {
?>
    <html>
        <body>
            <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST"> <br>
                이름: <input type="text" name="username" /> <br>
                아이디: <input type="text" name="userid" /> <br>
                비밀번호: <input type="text" name="userpw" /> <br>
                <input type="submit" name="submit" />
            </form>
        </body>
    </html>
<?php
    }
?>

이렇게 작업하시면 json parsing error는 발생하지만
데이터베이스에 값은 잘 들어갈겁니다..
profile
모두가 따라할 수 있는 쉬운 글을 작성하자!
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 12월 28일

현지야!!!! 글 잘 보고 가
너무 잘 썼다~~

답글 달기