MySQL을 사용해서 아주 간단한 로그인, 회원가입, 유저정보 리스트 보기 기능을 구현했다.
안드로이드는 MySQL 직접 연결이 불가능해서 서버가 필요하다. 그래서 Node.js로 api 서버를 만들고 연동해서 사용했다.
로그인, 회원가입, 유저리스트 가져오기 기능만 구현 해보기 위해서 최소한으로 만들었다.
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
}
);
}
});
});
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]);
});
}
});
});
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 사용법에 대한 자세한 내용은 이미 이전에 작성한 게시물이 있기 때문에 생략하겠습니다...
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
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())
}
})
}
}
}
로그인 성공시 다음 액티비티로 화면이 전환됩니다.
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 님 안녕하세요."
}
}
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
}
}
}
}
모든 유저 보기 버튼 클릭시 해당 액티비티로 전환됩니다.
서버로부터 모든 회원정보를 가져와서 리스트 형태로 보여줍니다.
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)
}
}