본문 바로가기
Programando/Android

[Android/Kotlin] Retrofit2 PHP MySQL 통신

0. 종속성 추가

Retrofit2를 사용하기 위해서는 먼저 app 모듈의 build.gradle에 종속성을 추가해야 합니다. Retrofit2의 최신 버전은 https://github.com/square/retrofit에서 확인할 수 있습니다.

    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'

 

1. Manifest에 권한 추가

RestAPI를 통해 데이터를 받아오기 위해서는 인터넷이 필요하므로 manifest 파일에 Internet 권한을 추가해야 합니다.

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

 

2. RetrofitClient Object 생성

통신할 baseUrl을 설정하고 데이터 파싱 및 객체 정보를 반환할 수 있는 Retrofit 객체와 Json을 Kotlin Object로 변환시켜줄 Gson 객체를 생성하는 부분을 싱글톤(Object)으로 만들어줍니다.

먼저, baseUrl은 고정된 주소로 지정합니다. 저는 "http://IP_주소/UserInsert.php", "http://IP_주소/UserSelect.php" 등 여러 PHP과 통신을 해야하기 때문에 "http://IP_주소/"를 baseUrl로 지정했습니다. 중요한 점은 baseUrl은 꼭 ‘/’로 끝나야 오류가 생기지 않는다는 점입니다.

그리고 addConverterFactory(GsonConverterFactory.create(gson))은 Json 데이터를 POJO Class 형식으로 자동변환하기 위해 필요합니다.

import com.google.gson.GsonBuilder
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory

object RetrofitClient {
    private var instance : Retrofit? = null
    private val gson = GsonBuilder().setLenient().create()

    fun getInstance() : Retrofit {
        if(instance == null){
            instance = Retrofit.Builder()
                .baseUrl("http://${IP_ADDRESS}/")
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build()
        }
        return instance!!
    }
}

 

3. POJO Class 생성

제가 생성한 PHP 파일에서는 아래와 같은 Json 데이터를 반환합니다.

// UserSelect.php
// 로그인 성공 시
echo json_encode(array(
    "status" => "true",
    "message" => "로그인 성공"
    "email"=>$row["email"],
    "password"=>$row["password"],
    "username"=>$row["username"],
    "picture"=>$row["picture"],
), JSON_UNESCAPED_UNICODE);

// 로그인 실패 시
echo json_encode(array(
    "status" => "false",
    "message" => "로그인 실패"
), JSON_UNESCAPED_UNICODE);
// 로그인 성공 시
{
    "status" => "true",
    "message" => "로그인 성공"
    "email":"rit@abc.com",
    "password":"123456",
    "username":"RIT",
    "picture":"rit@abc.com/profile.JPG"
}

// 로그인 실패 시
{
    "status" => "false",
    "message" => "로그인 실패"
}

 

위와 같은 Json 데이터를 받을 POJO Class는 아래와 같습니다. PHP에서 반환되는 Json의 Key 값과 Data Class의 속성명과 변수명 + 타입(ex String,Int,Boolean) 일치는 필수입니다. 혹은 @SerializedName 어노테이션을 통해 Json의 Key 값과 같도록 만들어줘야 합니다.

data class User (
    val email : String?,
    val user_name : String?,
    val gender : String?,
    val picture : String?,
    val status : String?,
    val message : String?    
)

 

반응형

 

4. API Interface 생성

저는 POST 방식으로 PHP로 데이터를 보내고, 가져오는 것을 선택했습니다. @POST는 위에서 지정해둔 baseUrl의 뒤에 오는 "UserInsert.php"이나 "UserSelect.php" 같은 상세 주소를 지정하고, 동적으로 변경해야 하는 파라미터는 @Field 어노테이션을 이용해서 PHP에 보낼 데이터의 형식을 정해줍니다. 마지막으로 PHP로부터 Json을 반환받는다면 POJO Class로 받을 수 있도록 Call을 return type으로 정해줍니다.

import retrofit2.Call
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST

interface UserAPI {
    @FormUrlEncoded
    @POST("UserSelect.php")
    fun getUser(
        @Field("email") email: String
    ): Call<User>
}

 

5. Request 보내기

처음에 만들었던 RetrofitClient를 통해 생성한 Retrofit 객체를 받아오고, 해당 객체를 이용해 Interface를 구현합니다. 통신 방법에는 enqueue를 이용하는 비동기 작업과 execute를 이용하는 동기 작업이 있습니다.

비동기 작업으로 실행한다면 통신 종료 후 이벤트 처리를 위해 Callback을 등록해야 하고, 동기 작업으로 실행한다면 AsyncTask 등을 통해 받아온 데이터를 가지고 UI 작업을 할 수 있습니다.

저는 비동기 작업으로 실행할 것이므로 enqueue를 이용하였습니다. email로 요청을 보내고 난 다음 결과는 두 가지로 나뉩니다. 통신에 성공했을 경우에는 onResponse, 통신에 실패했을 경우에는 onFailure로 나뉘는데 실패했을 경우에는 그에 따른 처리를 해주어야 합니다.

  • SigninActivity.kt
    val retrofit = RetrofitClient.getInstance()

    val server = retrofit.create(UserAPI::class.java)

    server.getUser(email).enqueue(object : Callback<User> {
        override fun onResponse(
            call: Call<User>,
            response: Response<User>
        ) {
            Log.d(TAG, "성공 : ${response.body()}")
        }

        override fun onFailure(call: Call<User>, t: Throwable) {
            Log.d(TAG, "실패 : ${t.localizedMessage}")
        }
    })

 

  • UserSelect.php
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    include("dbcon.php");

    $email = $_POST['email'];

    if($email == '') {
        echo json_encode(array(
            "status" => "false",
            "message" => "필수 인자가 부족합니다"),
            JSON_UNESCAPED_UNICODE
        );
    } else {

        try {

            $sql="select * from user_tb where U.email like '$email'";
            $stmt = $con->prepare($sql);
            $stmt->execute();

            if ($stmt->rowCount() == 0) {
                echo json_encode(
                    array(
                        "status" => "false",
                        "message" => "로그인 실패"
                        ), JSON_UNESCAPED_UNICODE
                    );

            } else {

                while($row=$stmt->fetch(PDO::FETCH_ASSOC)) {

                    extract($row);

                    echo json_encode(array(
                        "status" => "true",
                        "message" => "로그인 성공",
                        "email"=>$row["email"],
                        "password"=>$row["password"],
                        "user_name"=>$row["user_name"],
                        "picture"=>$row["picture"]
                    ), JSON_UNESCAPED_UNICODE);
                }

            }

        } catch(PDOException $e) {
            die("Database error: " . $e->getMessage());
        }
    }
}
?>

 

6. 통신 결과

반응형