Android 클라이언트에서 서버로 로그인 정보 전송

안드로이드 앱에서 사용자 이름과 비밀번호를 입력받아 서버에서 MySQL 데이터베이스를 통해 유효성을 검사하는 로그인 기능을 구현하는 방법을 공유합니다. 핵심은 안드로이드 클라이언트에서 서버로 데이터를 안전하게 전송하는 것입니다.

서버 측 구현 (Java Servlet)

먼저, 클라이언트로부터 요청을 받아 처리하는 간단한 서블릿을 작성합니다. 이 예제에서는 요청된 사용자 이름과 비밀번호를 콘솔에 출력하는 기능만 포함합니다. 실제 구현에서는 이 정보를 데이터베이스와 비교하여 인증을 수행합니다.


import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AuthServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        String userId = request.getParameter("userId");
        String userPass = request.getParameter("userPass");

        System.out.println("수신된 사용자 ID: " + userId);
        System.out.println("수신된 비밀번호: " + userPass);

        // TODO: 여기서 데이터베이스와 비교하여 인증 로직 추가
        // 예: User user = userService.findByCredentials(userId, userPass);
        // if (user != null) { response.setStatus(HttpServletResponse.SC_OK); } else { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // POST 요청 처리는 필요에 따라 구현
    }
}

위 서블릿은 클라이언트가 GET 요청으로 전달하는 `userId`와 `userPass` 파라미터를 받습니다. 데이터베이스 인증 로직은 주석으로 표시되어 있으며, 실제 프로젝트에서는 해당 부분을 채워야 합니다.

안드로이드 클라이언트 측 구현

1. MainActivity.java

로그인 화면의 UI 요소를 관리하고, 사용자가 입력한 정보를 가져와 네트워크 요청을 시작하는 액티비티입니다.


import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.UnsupportedEncodingException;

public class MainActivity extends Activity {

    private EditText usernameInput;
    private EditText passwordInput;
    private Button loginButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login); // 레이아웃 파일 이름 변경

        usernameInput = findViewById(R.id.editTextUsername); // ID 변경
        passwordInput = findViewById(R.id.editTextPassword); // ID 변경
        loginButton = findViewById(R.id.buttonLogin);       // ID 변경

        loginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String enteredUsername = usernameInput.getText().toString();
                String enteredPassword = passwordInput.getText().toString();

                // 입력값 유효성 검사 (간단하게)
                if (enteredUsername.isEmpty() || enteredPassword.isEmpty()) {
                    Toast.makeText(MainActivity.this, "아이디와 비밀번호를 모두 입력해주세요.", Toast.LENGTH_SHORT).show();
                    return;
                }

                // 네트워크 요청 수행 (별도의 스레드 또는 AsyncTask 사용 권장)
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        boolean loginSuccess = false;
                        try {
                            // 서버 통신을 위한 서비스 호출
                            loginSuccess = AuthService.authenticateUser(enteredUsername, enteredPassword);
                        } catch (Exception e) {
                            e.printStackTrace();
                            // 네트워크 오류 처리
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    Toast.makeText(MainActivity.this, "네트워크 오류 발생", Toast.LENGTH_SHORT).show();
                                }
                            });
                        }

                        final boolean finalLoginSuccess = loginSuccess;
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                if (finalLoginSuccess) {
                                    Toast.makeText(MainActivity.this, "로그인 성공!", Toast.LENGTH_SHORT).show();
                                } else {
                                    Toast.makeText(MainActivity.this, "로그인 실패. 아이디 또는 비밀번호를 확인하세요.", Toast.LENGTH_SHORT).show();
                                }
                            }
                        });
                    }
                }).start();
            }
        });
    }
}

UI 요소의 ID를 변경했으며, 입력값 검증 로직을 추가했습니다. 또한, 네트워크 요청은 UI 스레드를 차단하지 않도록 별도의 스레드 내에서 실행되도록 수정했습니다. 성공/실패 메시지 표시는 `runOnUiThread`를 사용하여 메인 스레드에서 처리합니다.

2. activity_login.xml (레이아웃 파일)

로그인 화면의 구성을 정의하는 XML 레이아웃입니다. 입력 필드와 버튼의 ID를 위 Java 코드와 일치시킵니다.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="아이디" />

    <EditText
        android:id="@+id/editTextUsername"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="아이디를 입력하세요"
        android:inputType="text"
        android:singleLine="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="비밀번호" />

    <EditText
        android:id="@+id/editTextPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="비밀번호를 입력하세요"
        android:inputType="textPassword"
        android:singleLine="true" />

    <Button
        android:id="@+id/buttonLogin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="로그인" />

</LinearLayout>

3. AuthService.java (네트워크 통신 서비스)

서버와 통신하여 로그인 인증을 처리하는 클래스입니다. GET 요청을 사용하여 파라미터를 전송합니다.


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;

public class AuthService {

    // 실제 서버 IP 주소와 포트로 변경해야 합니다.
    private static final String SERVER_URL = "http://192.168.0.100:8080/YourApp/AuthServlet"; // 서버 URL 수정

    /**
     * 사용자 인증을 위해 서버에 요청을 보냅니다.
     * @param userId 사용자 ID
     * @param userPass 비밀번호
     * @return 인증 성공 여부
     * @throws Exception 네트워크 통신 또는 인코딩 오류
     */
    public static boolean authenticateUser(String userId, String userPass) throws Exception {
        // 파라미터를 URL에 안전하게 포함시키기 위해 UTF-8로 인코딩
        String encodedUserId = URLEncoder.encode(userId, "UTF-8");
        String encodedUserPass = URLEncoder.encode(userPass, "UTF-8");

        // GET 요청 URL 생성
        String requestUrl = String.format("%s?userId=%s&userPass=%s", SERVER_URL, encodedUserId, encodedUserPass);

        HttpURLConnection connection = null;
        try {
            URL url = new URL(requestUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(15000); // 연결 타임아웃 설정
            connection.setRequestMethod("GET"); // GET 메소드 사용

            // 서버 응답 코드 확인
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 성공적으로 응답받은 경우 (서버에서 200 OK 반환 시)
                // 실제로는 서버 응답 내용을 읽어 인증 성공 여부를 판단할 수도 있습니다.
                // 여기서는 단순히 HTTP 상태 코드만으로 판단합니다.
                return true;
            } else {
                // 오류 응답 처리
                return false;
            }
        } finally {
            if (connection != null) {
                connection.disconnect(); // 연결 종료
            }
        }
    }

    // 필요하다면 POST 요청을 위한 메서드 추가
    // public static boolean postRequest(...) { ... }
}

`SERVER_URL`은 실제 운영 환경에 맞게 수정해야 합니다. `HttpURLConnection`을 사용하여 GET 요청을 보내고, 서버의 HTTP 상태 코드를 확인하여 인증 성공 여부를 반환합니다. 파라미터는 `URLEncoder`를 사용하여 URL 인코딩 처리합니다.

네트워크 권한 설정

안드로이드 앱이 인터넷에 접속하려면 `AndroidManifest.xml` 파일에 인터넷 사용 권한을 추가해야 합니다.


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

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

    <application
        ...>
        <activity android:name=".MainActivity" ...>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- 다른 컴포넌트들 -->
    </application>
</manifest>

위 코드는 안드로이드 애플리케이션에서 서버로 로그인 정보를 전송하고 검증하는 기본적인 과정을 보여줍니다. 실제 서비스에서는 비밀번호 암호화, HTTPS 사용, 더 견고한 오류 처리 및 응답 파싱 등이 필요합니다.

태그: Android java Servlet MySQL HTTP

6월 4일 18:41에 게시됨