[Android+MySQL] 로그인, 회원가입 구현하기

LeeEunJae·2022년 8월 30일
1

Kotlin Project

목록 보기
6/10

📌 실행 결과

MySQL을 사용해서 아주 간단한 로그인, 회원가입, 유저정보 리스트 보기 기능을 구현했다.
안드로이드는 MySQL 직접 연결이 불가능해서 서버가 필요하다. 그래서 Node.js로 api 서버를 만들고 연동해서 사용했다.

📌 데이터베이스 테이블 구조

로그인, 회원가입, 유저리스트 가져오기 기능만 구현 해보기 위해서 최소한으로 만들었다.

📌 Node.js 서버

  1. 회원가입

select * from User where id=? 구문을 통해서 현재 클라이언트에게 전달 받은 id가 데이터베이스에 이미 존재하는지 확인하고, 존재하지 않으면 insert into.. 구문을 통해 데이터를 삽입한 후, 결과를 클라이언트에게 전송한다.


router.post('/register', (req, res) =>{
  const body = req.body;
  const id = body.id;
  const pw = body.pw;

  connection.query('select * from User where id=?',[id],(err,data)=>{
    if(data.length == 0){
        console.log('회원가입 성공');
        connection.query('insert into User(id, password) values(?,?)',[id,pw]);
        res.status(200).json(
          {
            "message" : true
          }
        );
    }else{
        console.log('회원가입 실패');
        res.status(200).json(
          {
            "message" : false
          }
        );
        
    }
    
  });
});
  1. 로그인

select id, password from User where id=? and password=? 구문을 통해 클라이언트에게 전달받은 아이디, 비밀번호와 데이터 베이스 상에 존재하는 아이디, 비밀번호를 비교한다.
로그인에 실패하면 UID 값으로 -1을 전달하고, 성공시 select UID from User where id=? 구문을 통해 해당 유저의 UID 값을 전달한다.

router.post('/login', (req, res)=>{
  const body = req.body;
  const id = body.id;
  const pw = body.pw;
  
  connection.query('select id, password from User where id=? and password=?', [id,pw], (err, data)=>{
    if(data.length == 0){ // 로그인 실패
      console.log('로그인 실패');
      res.status(200).json(
        {
          "UID" : -1
        }
      )
    }
    else{
      // 로그인 성공
      console.log('로그인 성공');
      connection.query('select UID from User where id=?',[id],(err,data)=>{
        res.status(200).send(data[0]); 
      });
      
    }
  });

});
  1. 모든 회원정보 가져오기
router.get('/users_info', (req, res) => {
  connection.query('SELECT * FROM User', (error, rows) => {
    if(error) throw error;
    console.log('user info is : ', rows);
    
    res.status(200).send(rows)
    
  });
});

여기까지 했으면, 이제 안드로이드에서 서버와 연동을 시켜주면 된다.
Retrofit2 사용법에 대한 자세한 내용은 이미 이전에 작성한 게시물이 있기 때문에 생략하겠습니다...

📌 RetroInterface.kt

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.POST

interface RetroInterface{
    @POST("/register")
    @Headers("accept: application/json",
        "content-type: application/json")
    fun register(
        @Body jsonparams: RegisterModel
    ) : Call<RegisterResult>

    @POST("/login")
    fun login(
        @Body jsonparams: LoginModel
    ) : Call<LoginResult>

    @GET("/users_info")
    fun allUser(): Call<ArrayList<User>>

    companion object { // static 처럼 공유객체로 사용가능함. 모든 인스턴스가 공유하는 객체로서 동작함.
        private const val BASE_URL = "http://본인 컴퓨터 IP 주소:포트번호" //

        fun create(): RetroInterface {
            val gson : Gson =   GsonBuilder().setLenient().create();

            return Retrofit.Builder()
                .baseUrl(BASE_URL)
//                .client(client)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build()
                .create(RetroInterface::class.java)
        }
    }
}

📌 데이터 클래스


import java.io.Serializable

data class RegisterModel(
    var id: String,
    var pw: String
)


data class RegisterResult(
    var message: Boolean
)

data class LoginModel(
    var id: String,
    var pw: String
)

data class LoginResult(
    var UID: Int
)

data class User(
    val UID: Int,
    val id: String,
    val password: String
): Serializable

📌 MainActivity.kt

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.dldmswo1209.servertest.databinding.ActivityMainBinding
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    val api = RetroInterface.create()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.registerButton.setOnClickListener {
            binding.apply {
                val id = inputID.text.toString()
                val pw = inputPw.text.toString()

                if(id == "" || pw == "") {
                    Toast.makeText(applicationContext, "입력하지 않은 정보가 있습니다.", Toast.LENGTH_SHORT).show()
                    return@setOnClickListener
                }
            }
            val newUser = RegisterModel(binding.inputID.text.toString(), binding.inputPw.text.toString())
            api.register(newUser).enqueue(object: retrofit2.Callback<RegisterResult>{
                override fun onResponse(call: Call<RegisterResult>, response: Response<RegisterResult>) {
                    val result = response.body()?.message ?: return
                    if(result)
                        Toast.makeText(applicationContext, "회원가입 성공", Toast.LENGTH_SHORT).show()
                    else
                        Toast.makeText(applicationContext, "회원가입 실패, 이미 존재하는 아이디 입니다.", Toast.LENGTH_SHORT).show()
                }

                override fun onFailure(call: Call<RegisterResult>, t: Throwable) {
                    Log.d("testt", t.message.toString())
                }
            })
        }
        binding.loginButton.setOnClickListener {
            binding.apply {
                val id = inputID.text.toString()
                val pw = inputPw.text.toString()

                if(id == "" || pw == "") {
                    Toast.makeText(applicationContext, "입력하지 않은 정보가 있습니다.", Toast.LENGTH_SHORT).show()
                    return@setOnClickListener
                }
            }

            val loginUser = LoginModel(binding.inputID.text.toString(), binding.inputPw.text.toString())
            api.login(loginUser).enqueue(object: Callback<LoginResult>{
                override fun onResponse(call: Call<LoginResult>, response: Response<LoginResult>) {
                    val user_uid = response.body()?.UID ?: return
                    if(user_uid != -1) {
                        Toast.makeText(applicationContext, "로그인 성공", Toast.LENGTH_SHORT).show()
                        val intent = Intent(this@MainActivity, SecondActivity::class.java)
                        intent.putExtra("id", binding.inputID.text.toString())
                        startActivity(intent)

                        Log.d("testt", user_uid.toString())
                    }
                    else{
                        Toast.makeText(applicationContext, "로그인 실패, 아이디 또는 비밀번호를 확인해주세요.", Toast.LENGTH_SHORT).show()
                    }

                }

                override fun onFailure(call: Call<LoginResult>, t: Throwable) {
                    Log.d("testt", t.message.toString())
                }
            })
        }
        binding.allUserButton.setOnClickListener {
            api.allUser().enqueue(object:Callback<ArrayList<User>>{
                override fun onResponse(
                    call: Call<ArrayList<User>>,
                    response: Response<ArrayList<User>>
                ) {
                    val userList = response.body() ?: return
                    val intent = Intent(this@MainActivity, AllUserActivity::class.java)
                    intent.putExtra("userList", userList)
                    startActivity(intent)
                }

                override fun onFailure(call: Call<ArrayList<User>>, t: Throwable) {
                    Log.d("testt",t.message.toString())
                }
            })
        }

    }
}

📌 SecondActivity.kt

로그인 성공시 다음 액티비티로 화면이 전환됩니다.
intent 로 id 를 전달 받아서 화면에 띄워줍니다.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.dldmswo1209.servertest.databinding.ActivityMainBinding
import com.dldmswo1209.servertest.databinding.ActivitySecondBinding

class SecondActivity : AppCompatActivity() {
    private lateinit var binding: ActivitySecondBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivitySecondBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val intent = intent
        val id = intent.getStringExtra("id")
        binding.textView.text = "$id 님 안녕하세요."

    }
}

📌 Adater.kt

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.dldmswo1209.servertest.databinding.UserItemBinding


class Adapter: ListAdapter<User, Adapter.ViewHolder>(diffUtil) {
    inner class ViewHolder(private val binding: UserItemBinding): RecyclerView.ViewHolder(binding.root){
        fun bind(user: User){
            binding.idTextView.text = user.id
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(UserItemBinding.inflate(LayoutInflater.from(parent.context),parent,false))
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(currentList[position])
    }

    companion object{
        private val diffUtil = object: DiffUtil.ItemCallback<User>(){
            override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
                return oldItem.UID == newItem.UID
            }

            override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
                return oldItem == newItem
            }
        }
    }
}

📌 AllUserActivity.kt

모든 유저 보기 버튼 클릭시 해당 액티비티로 전환됩니다.
서버로부터 모든 회원정보를 가져와서 리스트 형태로 보여줍니다.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.dldmswo1209.servertest.databinding.ActivityAllUserBinding

class AllUserActivity : AppCompatActivity() {
    private lateinit var binding: ActivityAllUserBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityAllUserBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val intent = intent
        val users = intent.getSerializableExtra("userList") as ArrayList<User>
        val adapter = Adapter()
        binding.recyclerView.adapter = adapter
        adapter.submitList(users)

    }
}
profile
매일 조금씩이라도 성장하자

0개의 댓글