안녕하세요.

버전 관리하는 방법을 설명하기 전에 그동안 제가 개발을 해왔던 내용 중 백업과 버전 관리 부분을 어떻게 해왔는지 공유해 보겠습니다.

1. 백업, 버전관리를 전혀 하지 않았음

1-1. 1대의 컴퓨터에서 작업

처음 개발을 할떄는 버전 관리를 전혀 하지 않았습니다. 처음에는 로컬에 작업 공간을 만들어서 개발을 진행했습니다. 저는 대부분 혼자서 개발을 해 왔고 한대의 컴퓨터에서만 작업할 때에는 별 문제점이 없었습니다.

1-2. 여러대 컴퓨터에서 작업할 때 - 외장 스토리지 사용

여러 컴퓨터에서 왔다 갔다 하면서 작업하기 위해서 USB나 외장하드를 이용해서 작업하곤 했었죠.

USB에서 직접 작업할 경우 속도도 문제이지만
(센디스크의 경우?) USB가 잠겨버려서 포맷도 안 되는 경우를 몇 번 경험했습니다.

외장 하드의 경우 휴대성이 약간 떨어지긴 하지만 직접 작업하는 데는 지장이 없었습니다.
잠겨버리는 경우도 아직 경험하진 못했고요.
선과 외장하드를 케이스에 넣고 빼기가 생각보다 귀찮습니다. 가끔 작업해야 되는데 두고 온 적도 종종 있습니다.

1-3. 나스(NAS) 구매

나스를 구매한 뒤로 원격에서도 해당 공간에 바로 접속해서 작업도 해봤습니다. (제가 구매한 나스는 시놀로지사의 DS218에 4TB HDD를 장착했습니다.) 내부 네트워크에서는 속도가 빨라서 문제점을 찾지 못했는데 원격으로 할 때는 인터넷 상태에 따라서 속도가 많이 느려지는 단점이 있습니다.


1의 방법들은 각각의 휴대/원격 공간에서 직접 작업하는 방법으로 작업공간은 어떻게든 하나만 존재합니다. 이제부터 작업공간이 2개 이상 생겨서 백업을 한다고 볼 수 있습니다.

2. 백업, 버전관리 초보 - 동기화, 버전 별 압축하기

2-1. 동기화 프로그램 - 백업은 되지만 버전 관리는 안됨

로컬에서 작업을 한 뒤에 동기화 프로그램으로 동기화 해서 최신 버전을 유지하는 방법도 사용해 봤습니다.
무료 프로그램 중에서 FreeFileSync가 있는데 유용하게 잘 썼습니다.

 

FreeFileSync

Download the latest FreeFileSync 10.12. FreeFileSync is a free open source data backup software that helps you synchronize files and folders on Windows, Linux and macOS.

freefilesync.org

하지만 여러 프로젝트를 진행하게 되면 스캔하고 동기화 할 때마다 적지 않은 시간이 소요됩니다. 그리고 항상 최신 버전으로 백업하기 때문에 버전 관리를 수동으로 해줘야 합니다.

2-2. 백업할 때마다 압축해서 날짜 적어놓기

백업 저장소에도 생각날 때 마다 압축파일을 만들어 날짜를 포함해서 다른 공간에 차곡차곡 쌓아두었습니다.

압축할 때마다 전체 프로젝트를 저장하게 되면 용량이 쓸데없이 많아집니다. 압축할 때마다 새로 고친 파일만 저장하게 되면 나중에 해당 버전을 쓸 때 추가로 작업할 내용이 많아 귀찮아집니다.


3. 드디어 버전관리도 시작? GIT 입문! 두둥

그러다가 최극 작업물부터 git을 활용해서 버전을 관리하기 시작했습니다.
아직 협업까지는 진행해 보지 않았지만 위에서 발생하는 문제점들을 잘 해결해 줬습니다.
아직 적응을 못해서 가끔 리모트 저장소에 push를 안 해놓고 가서 다른 장소에서 작업을 못 한 적이 있긴 하지만
작업 전 후 버전관리에 습관을 들인다면 이런 실수도 줄어들겠죠?

git도 관련 서비스가 엄청 많습니다. 저는 우선 git, git-server, github, TortoiseGit 정도 사용해 봤습니다.

 

Git

 

git-scm.com

 

Build software better, together

GitHub is where people build software. More than 36 million people use GitHub to discover, fork, and contribute to over 100 million projects.

github.com

 

TortoiseGit – Windows Shell Interface to Git

Support Manuals, FAQ, bug reporting, mailing list, and more…

tortoisegit.org

다음번에는 제가 git으로 버전 관리하는 방법을 알려드리겠습니다.

감사합니다.

이번에는 파일을 분석해서 이 파일이 어느 종류의 파일인지를 알 수 있는 방법에 대해 알아보겠습니다.

사실 대부분의 경우 확장자가 잘 되어 있기 때문에 이 과정이 필요 없을 수 있습니다.
확장자가 jpg, png bmp 인 경우 그림파일, mp3 wav 인 경우 오디오 파일 avi mp4 인 경우 동영상 파일 등...
컴퓨터를 사용하다 보면 자연스럽게 알게 되는 정보이기 때문이죠.

그런데 흔하지는 않지만 실수 또는 잘못된 방법으로 파일의 확장자가 마음대로 변경된 경우를 경험하신 적 있으신가요?
저도 거의 없었지만 이전 휴대폰의 파일을 백업하고 오랜 기간이 지난 후에 보니 그림과 동영상 파일의 확장자가 001 002 같이 마음대로 바껴있더라고요.

물론 대략 폴더의 위치를 보고 확장자를 jpg 나 mp4로 바꿔서 실행해 보는 방법이 있습니다만
요즘 프로그래밍을 공부하다 보니 근본적으로 이 파일이 무슨 파일인지 알아내는 방법이 있는지, 이를 프로그래밍 할 수 있는 방법이 있을 지 궁금해 졌습니다.

그래서 구글로 검색을 해 본 결과 다음과 같은 프로그램을 찾았습니다.

TrID - File Identifier
http://mark0.net/soft-trid-e.html

위 프로그램은 파일의 내부를 분석해서 파일의 확장자가 무엇인지와 무슨 파일인지를 찾아주는 프로그램입니다. 실행 방식은 윈도우 cmd에서 실행해서 결과를 텍스트로 뿌려줍니다. 내 컴퓨터에서 실행하기 위해서는 아래 다운로드 링크 중에서 실행 파일과 TrIDDefs.TRD package 2개를 다운받은 후 압축을 풀면 됩니다.

저는 아래 그림과 같이 "C:\trid_w32" 폴더에 trid.exe, triddefs.trd 파일을 복사했습니다. 그리고 테스트를 위해 그림파일을 하나 가져와서 파일 이름을 unknownfile 이라고 하고 확장자를 지워버렸습니다.

그럼 cmd에서 실행해 볼까요? 윈도우키+R을 누르면 실행창이 뜨는데요 "cmd"라고 입력한 후에 확인을 클릭하면 됩니다. "C:\trid_w32" 폴더로 이동해서 명령어를 "trid unknownfile"라고 입력하면 아래 그림과 파일 분석 후에 결과가 나오게 됩니다.

이 프로그램의 결과를 visual studio 로 가져와서 원하는 형식으로 출력할 수 있을까요? 검색을 해 본 결과 가능한 것을 확인했습니다.

Process.start: how to get the output?
https://stackoverflow.com/questions/4291912/process-start-how-to-get-the-output

이제 프로그래밍을 해보겠습니다.

Visual Studio에서 새로운 프로젝트를 아래 그림과 같이 생성합니다. 프로젝트 이름은 "WindowsFormFileIdentifier" 로 지정하였습니다.

그리고 폼을 꾸며보겠습니다. 우선 기본 폼의 속성을 몇가지 변경합니다.

(Name): Form1 - Text: 파일형식 찾기 / Size: 400, 400

이제 도구들을 추가하고 속성을 변경하겠습니다.

라벨(Label) - (Name): label1 / Location: 20, 20 / AutoSize: True / Size: 137, 12(자동으로 설정됨) / Text: 파일 형식 찾기 프로그램
라벨(Label) - (Name): label2 / Location: 20, 60 / AutoSize: True / Size: 231, 12(자동으로 설정됨) / Text: 1. 오른쪽 버튼을 눌러 파일을 선택합니다.
버튼(Button) - (Name): button1 / Location: 260, 60 / AutoSize: False / Size: 75, 23 / Text: 파일 선택
라벨(Label) - (Name): label3 / Location: 20, 100 / AutoSize: True / Size: 73, 12(자동으로 설정됨) / Text: 선택한 파일:
라벨(Label) - (Name): label4 / Location: 100, 100 / AutoSize: True / Size: 29, 12(자동으로 설정됨) / Text: 없음
라벨(Label) - (Name): label5 / Location: 20, 140 / AutoSize: True / Size: 109, 12(자동으로 설정됨) / Text: 선택한 파일의 정보
자료보기창(DataGridView) - (Name): dataGridView1 / Location: 20, 180 / AutoSize: False / Size: 350, 160

꾸며진 결과는 아래 그림과 같습니다.

외형을 완성했으면 이제 프로그래밍을 해보겠습니다.
파일 선택 버튼을 더블클릭하면 자동으로 이벤트가 추가되고 코드보기 화면으로 전환됩니다.

코드를 작성하기 전에 bin\debug 폴더에 위에서 실행했던 trid.exe, triddefs.trd 2개의 파일을 붙여넣기 해야 합니다.
코드 왼쪽에 있는 솔루션 탐색기 메뉴에서 아이콘 중 모든파일 표시 아이콘을 클릭합니다. 기존에는 프로젝트와 관련이 없는 폴더나 파일은 숨겨져 있는데 이 아이콘을 클릭하면 모든 파일이 나타납니다. bin 폴더 안에 있는 debug 폴더에 커서를 놓고 오른쪽 마우스 버튼을 클릭한 후에 "파일 탐색기에서 폴더 열기" 메뉴를 클릭하면 해당 폴더 파일 탐색기가 열리게 됩니다.

이제 위에서 설명한 2개의 파일을 붙여넣기 하면 아래 그림과 같이 파일이 복사된 것을 확인할 수 있습니다.

이제 프로그래밍으 해보겠습니다. 매서드를 2개 만들겠습니다.

매서드1. 실행파일과 분석할 파일 경로를 활용하여 cmd에서 나왔던 정보를 datatable 형식으로 변환하여 출력해 주는 매서드 입니다.

        /// <summary>
        /// 선택한 파일에 대한 정보를 DataTable 형식으로 내보냅니다.
        /// </summary>
        /// <param name="FileName">선택한 파일의 전체 경로</param>
        /// <returns></returns>
        private DataTable GetResultsFromTridCMDStrings(string FileName)
        {
            // executableLocation 은 프로젝트 폴더\bin\debug 까지의 폴더입니다.
            string executableLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            // exefileLocation 는 executableLocation 안에 있는 실행파일 trid.exe 의 전체 경로입니다.
            string exefileLocation = Path.Combine(executableLocation, "trid.exe");

            // cmd에서 실행했던 것 처럼 프로세스를 실행하기 위한 설정값이 들어간 process 클래스를 proc라는 변수명으로 생성합니다.
            var proc = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = exefileLocation,
                    Arguments = FileName,
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    CreateNoWindow = true
                }
            };

            // 출력을 위한 datatable을 생성합니다.
            DataTable dt = new DataTable();
            dt.Columns.Add("%", typeof(string)); // 확률
            dt.Columns.Add("Ext", typeof(string)); // 확장자
            dt.Columns.Add("Desc", typeof(string)); // 설명

            proc.Start(); // 위에서 생성한 proc를 실행합니다.
            while (!proc.StandardOutput.EndOfStream)
            {
                string line1 = proc.StandardOutput.ReadLine(); // cmd에서 나왔던 결과를 1줄씩 가져옵니다.

                if (line1.Contains("%")) // 라인에 %가 있을 경우에만 동작하게 했습니다.
                {
                    string dtcol1 = line1.Split('%')[0]; // 확률정보만 가져옵니다.
                    dtcol1 += "%";
                    string dtcol2 = line1.Split('(')[1]; // 확장자(점포함) 정보만 가져옵니다.
                    dtcol2 = dtcol2.Split(')')[0];
                    string dtcol3 = line1.Split(')')[1]; // 설명부분만 가져옵니다.
                    dtcol3 = dtcol3.Split('(')[0];

                    dt.Rows.Add(dtcol1, dtcol2, dtcol3); // 위의 3가지 정보가 포함된 DataRow를 추가합니다.
                }
            }

            return dt;
        }

매서드2. 위에서 제공된 결과를 DataGridView 컨트롤에서 볼 수 있도록 가져옵니다.

        /// <summary>
        /// 선택한 폴더의 파일 목록을 가져와서 DataGridView 도구에 보여줍니다.
        /// </summary>
        /// <param name="dt1">선택한 폴더의 파일 목록이 들어있는 DataTable을 입력합니다.</param>
        /// <param name="dgv1">결과를 출력할 DataGridView를 선택합니다.</param>
        private void ShowDataFromDataTableToDataGridView(DataTable dt1, DataGridView dgv1)
        {
            dgv1.Rows.Clear(); // 이전 정보가 있을 경우, 모든 행을 삭제합니다.
            dgv1.Columns.Clear(); // 이전 정보가 있을 경우, 모든 열을 삭제합니다.

            foreach (DataColumn dc1 in dt1.Columns) // 선택한 파일 목록이 들어있는 DataTable의 모든 열을 스캔합니다.
            {
                dgv1.Columns.Add(dc1.ColumnName, dc1.ColumnName); // 출력할 DataGridView에 열을 추가합니다.
            }

            int row_index = 0; // 행 인덱스 번호(초기 값)
            foreach (DataRow dr1 in dt1.Rows) // 선택한 파일 목록이 들어있는 DataTable의 모든 행을 스캔합니다.
            {
                dgv1.Rows.Add(); // 빈 행을 하나 추가합니다.
                foreach (DataColumn dc1 in dt1.Columns) // 선택한 파일 목록이 들어있는 DataTable의 모든 열을 스캔합니다.
                {
                    dgv1.Rows[row_index].Cells[dc1.ColumnName].Value = dr1[dc1.ColumnName]; // 선택 행 별로, 스캔하는 열에 해당하는 셀 값을 입력합니다.
                }
                row_index++; // 다음 행 인덱스를 선택하기 위해 1을 더해줍니다.
            }

            foreach (DataGridViewColumn drvc1 in dgv1.Columns) // 결과를 출력할 DataGridView의 모든 열을 스캔합니다.
            {
                drvc1.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; // 선택 열의 너비를 자동으로 설정합니다.
            }
        }

위에서 만든 2개의 매서드를 활용하여 버튼클릭 이벤트를 아래와 같이 수정합니다.

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog(); // OpenFileDialog 생성합니다.
            openFileDialog1.Multiselect = false; // 여러개 선택 못하게 합니다.
            if (openFileDialog1.ShowDialog() == DialogResult.OK) // 파일이 선택된 경우에만 실행되게 합니다.
            {
                label4.Text = openFileDialog1.FileName; // 선택한 폴더 이름을 label4에 출력합니다.
                DataTable dt_filelistinfo = GetResultsFromTridCMDStrings(openFileDialog1.FileName);
                ShowDataFromDataTableToDataGridView(dt_filelistinfo, dataGridView1);
            }
        }

전체 코드는 다음과 같습니다.

using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System; using System.Windows.Forms; using System.Data; // DataTable 사용 using System.IO; // Path 사용 using System.Reflection; // Assembly 사용 using System.Diagnostics; // Process 사용 namespace WindowsFormFileIdentifier { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); // OpenFileDialog 생성합니다. openFileDialog1.Multiselect = false; // 여러개 선택 못하게 합니다. if (openFileDialog1.ShowDialog() == DialogResult.OK) // 파일이 선택된 경우에만 실행되게 합니다. { label4.Text = openFileDialog1.FileName; // 선택한 폴더 이름을 label4에 출력합니다. DataTable dt_filelistinfo = GetResultsFromTridCMDStrings(openFileDialog1.FileName); ShowDataFromDataTableToDataGridView(dt_filelistinfo, dataGridView1); } } private DataTable GetResultsFromTridCMDStrings(string FileName) {             생략(매서드1) } private void ShowDataFromDataTableToDataGridView(DataTable dt1, DataGridView dgv1) {             생략(매서드2) } } }

이제 실행해 보겠습니다.
실행하면 다음과 같이 나타납니다.

파일 선택 버튼을 클릭하고 예제 파일에 있던 "unknownfile" 을 선택하면 다음과 같이 결과가 출력됩니다.

이제 위의 내용을 활용해서 확장자가 변경되었거나 확실하지 않은 파일이 있다면 이 프로그램으로 찾아서 바꿔주는 프로그래밍을 할 수 있습니다.

감사합니다.

주) 현재 동작하지 않습니다.

이 글을 읽기 전에 다음 3개의 글을 읽어주세요.
"안드로이드 DB CRUD(쓰기, 읽기, 수정, 삭제) 1 - 프로세스" - http://ilbbang.tistory.com/34
"안드로이드 DB CRUD(쓰기, 읽기, 수정, 삭제) 2 - MariaDB 설정하기" - http://ilbbang.tistory.com/45
"안드로이드 DB CRUD(쓰기, 읽기, 수정, 삭제) 3 - PHP로 MySQL에 접근하기" - http://ilbbang.tistory.com/47
제가 따라해 볼 원문을 다시 확인해 보겠습니다.(출처)
http://freeprojectcode.com/android/android-mysql-basic-crud-operation-tutorial-for-android-studio-project/
(글 게시자가 홈페이지를 초기화 해서 해당 글을 더이상 볼 수 없습니다.)
이제 안드로이드에서 화면 및 구동이 가능하도록 프로그래밍을 해보겠습니다.
화면은 3개를 만들 예정입니다.
1. 쓰기 - 이름, 직책, 급여 입력란에 값을 입력하고 버튼을 클릭하면 DB에 작성 후에 "2. 읽기"으로 이동합니다. 입력하지 않아도 "2. 읽기" 화면으로 이동할 수도 있습니다.
2. 읽기 - 전체 목록을 출력합니다. 특정 목록을 클릭하면 "3.수정 및 삭제" 화면으로 이동합니다. "1. 쓰기" 화면으로 이동할 수도 있습니다.
3. 수정 및 삭제 - "2. 읽기"에서 출력된 목록 중 선택된 항목에 대한 정보를 수정할 수 있는 페이지 입니다. 내용을 변경 후에 버튼을 클릭하면 수정된 내용으로 DB를 update한 후에 "2. 읽기" 화면으로 이동합니다.. 수정하지 않고 "2. 읽기" 화면으로 이동할 수도 있습니다. 삭제 버튼을 클릭하면 선택된 항목을 삭제할 수도 있습니다.
그리고 구동에 필요한 별도의 자바 클래스를 4개 만들 예정입니다.
1. Constant - PHP 파일 주소 목록을 설정합니다.
2. PostRequestHandler - Post 방식의 Requset를 보내기 위한 클래스 입니다. 네트워크 관련 처리기 때문에 별도의 스래드(3. BackgroundWorker)를 생성하여 수행합니다.
3. BackgroundWorker - Background 에서 수행할 매서드가 있는 클래스입니다. Post로 보내기 및 받기 매서드가 있습니다.
4. JsonParser - Json으로 받은 내용을 안드로이드 화면에 출력하기 위해 변환하는 매서드가 있습니다.
안드로이드 스튜디오에서 새로운 프로젝트를
우선 클래스 부터 만들어 보겠습니다. 클래스를 만드는 방법은 아래 그림과 같이 탐색기에서 app 폴더에 마우스를 올린 후에 오른쪽 마우스 버튼을 클릭하고 New - Java Class를 클릭하고 클래스 이름을 입력하고 OK 버튼을 클릭하면 됩니다. 그럼 파일 별 코드를 보겠습니다.

1. Constant.java

public class Constant {      private static final String BASE_PATH = "php파일이있는폴더(마지막에/으로끝냄)";      public static final String CREATE_URL = BASE_PATH + "addEmp.php";     public static final String READ = BASE_PATH + "getAllEmp.php";     public static final String UPDATE = BASE_PATH + "updateEmp.php";     public static final String DELETE = BASE_PATH + "deleteEmp.php";      public static final String GET_METHOD = "GET";     static final String POST_METHOD = "POST"; } 

2. PostRequestHandler.java

import android.os.AsyncTask;  import java.io.UnsupportedEncodingException; import java.util.HashMap;  public class PostRequestHandler extends AsyncTask<Void, Void, String> {     // php URL 주소     String url;     // Key, Value 값     HashMap<String, String> requestedParams;      PostRequestHandler(String url, HashMap<String, String> params){         this.url = url;         this.requestedParams = params;     }      @Override     protected void onPreExecute() {         super.onPreExecute();     }      @Override     protected String doInBackground(Void... voids) {          // post request 보냄         BackgroundWorker backgroundWorker = new BackgroundWorker();         try {             String s = backgroundWorker.postRequestHandler(url, requestedParams);             return s.toString();         } catch (UnsupportedEncodingException e) {             e.printStackTrace();         }          return null;     }      @Override     protected void onPostExecute(String s) {         super.onPostExecute(s);     } } 

3. BackgroundWorker.java

import android.util.Log;  import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map;  public class BackgroundWorker {      // Make a POST Request Handler     public String postRequestHandler(String requestUrl, HashMap<String, String> requestedDataParams) throws UnsupportedEncodingException {          // Set an Empty URL obj in system         URL url;           // Set a String Builder to store result as string         StringBuilder stringBuilder = new StringBuilder();          try {             // Now Initialize URL             url = new URL(requestUrl);              // Make a HTTP url connection             HttpURLConnection connection = (HttpURLConnection) url.openConnection();              // Set Method Type             connection.setRequestMethod(Constant.POST_METHOD);             // Set Connection Time             connection.setConnectTimeout(10000);             connection.setReadTimeout(10000);             // set Input output ok             connection.setDoInput(true);             connection.setDoOutput(true);             // Remove Caches             //connection.setUseCaches(false);             //connection.setDefaultUseCaches(false);               // Creating a url as String with params             StringBuilder url_string = new StringBuilder();              boolean ampersand = false;             for (Map.Entry<String, String> params : requestedDataParams.entrySet() ){                 if (ampersand)                     url_string.append("&");                 else                     ampersand = true;                  url_string.append(URLEncoder.encode(params.getKey(), "UTF-8"));                 url_string.append("=");                 url_string.append(URLEncoder.encode(params.getValue(), "UTF-8"));             }             Log.d("Final Url===", url_string.toString());                //Creating an output stream             OutputStream outputStream = connection.getOutputStream();              // Write Output Steam             BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));             bufferedWriter.write(url_string.toString());              bufferedWriter.flush();             bufferedWriter.close();             outputStream.close();              //        Log.d("Response===", connection.getResponseMessage());              if (connection.getResponseCode() == HttpURLConnection.HTTP_OK){                 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));                  // Local String                 String result;                 while ((result = bufferedReader.readLine()) != null) {                     stringBuilder.append(result);                 }                 //            Log.d("Result===", result);              }         } catch (MalformedURLException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         }          return stringBuilder.toString();     }      // Get Request Handler     public String getRequestHandler(String requestUrl){         // To Store response         StringBuilder stringBuilder = new StringBuilder();          try {             URL url = new URL(requestUrl);             // Open Connection             HttpURLConnection connection = (HttpURLConnection) url.openConnection();             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));              // Local             String result;             while ((result = bufferedReader.readLine()) != null) {                 stringBuilder.append(result + "\n");             }          } catch (MalformedURLException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         }          return null;     }  } 

4. JsonParser.java

import android.util.Log;  import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL;  public class JsonParser {     private static final String TAG = JsonParser.class.getSimpleName();      public String convertJson(String reqUrl) {         String response = null;         try {             URL url = new URL(reqUrl);             HttpURLConnection conn = (HttpURLConnection) url.openConnection();             conn.setRequestMethod("GET");             // read the response             InputStream in = new BufferedInputStream(conn.getInputStream());             response = convertStreamToString(in);         } catch (MalformedURLException e) {             Log.e(TAG, "MalformedURLException: " + e.getMessage());         } catch (ProtocolException e) {             Log.e(TAG, "ProtocolException: " + e.getMessage());         } catch (IOException e) {             Log.e(TAG, "IOException: " + e.getMessage());         } catch (Exception e) {             Log.e(TAG, "Exception: " + e.getMessage());         }         return response;     }      private String convertStreamToString(InputStream is) {         BufferedReader reader = new BufferedReader(new InputStreamReader(is));         StringBuilder sb = new StringBuilder();          String line;         try {             while ((line = reader.readLine()) != null) {                 sb.append(line).append('\n');             }         } catch (IOException e) {             e.printStackTrace();         } finally {             try {                 is.close();             } catch (IOException e) {                 e.printStackTrace();             }         }         return sb.toString();     } } 

이제 위 클래스를 포함한 화면을 만들어 보겠습니다. 추가 화면을를 만드는 방법은 아래 그림과 같이 탐색기에서 app 폴더에 마우스를 올린 후에 오른쪽 마우스 버튼을 클릭하고 New - Java Class를 클릭하고 클래스 이름을 입력하고 OK 버튼을 클릭하면 됩니다. 그럼 파일 별 코드를 보겠습니다.

위 방법으로 "ViewActivity"와 "EditActivity"를 프로젝트에 추가합니다.
이제부터 Activity의 외형 및 코드를 아래와 같이 작성합니다.
화면1. activity_main.xml

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:padding="22dp"     tools:context=".MainActivity">      <LinearLayout         android:layout_width="match_parent"         android:layout_height="match_parent"         android:orientation="vertical"         android:padding="11dp">          <TextView             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:text="Android PHP MySQL CRUD"             android:textAlignment="center"             android:textColor="#e21ace41"             android:textSize="22dp" />          <TextView             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:text="FreeProjectCode.com"             android:textAlignment="center"             android:textColor="#e2f209df"             android:textSize="20dp" />          <EditText             android:id="@+id/name"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:hint="Name" />          <EditText             android:id="@+id/designation"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:hint="Designation" />          <EditText             android:id="@+id/salary"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:hint="Salary" />          <Button             android:id="@+id/btn_add"             android:onClick="createEmployee"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:textColor="#fff"             android:background="#e21ace41"             android:text="Add Employee"/>         <Button             android:id="@+id/btn_list"             android:onClick="employeeList"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:textColor="#fff"             android:layout_marginTop="11dp"             android:background="#e2152099"             android:text="Employee List"/>     </LinearLayout>  </android.support.constraint.ConstraintLayout> 

java코드1. MainActivity.java

import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast;  import java.util.HashMap;  public class MainActivity extends AppCompatActivity {      private EditText mName, mDesignation, mSalary;     private Button mBtnAdd;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          // Initialize EditText View         mName = (EditText) findViewById(R.id.name);         mDesignation = (EditText) findViewById(R.id.designation);         mSalary = (EditText) findViewById(R.id.salary);          mBtnAdd = (Button) findViewById(R.id.btn_add);     }      // Create     public void createEmployee(View view){          String name = mName.getText().toString();         String designation = mDesignation.getText().toString();         String salary = mSalary.getText().toString();          HashMap<String, String> requestedParams = new HashMap<>();         requestedParams.put("name", name);         requestedParams.put("designation", designation);         requestedParams.put("salary", salary);         Log.d("HashMap", requestedParams.get("name"));         Toast.makeText(getApplicationContext(), "Success!!! Employee Added Name: " + requestedParams.get("name"), Toast.LENGTH_LONG).show();          PostRequestHandler postRequestHandler = new PostRequestHandler(Constant.CREATE_URL, requestedParams);         postRequestHandler.execute();          employeeList(view);     }      public void employeeList(View view) {         Intent intent = new Intent(MainActivity.this, ViewActivity.class);         startActivity(intent);     }  } 

화면2. activity_view.xml

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ViewActivity">  <RelativeLayout     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical">     <Button         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_marginBottom="11dp"         android:layout_marginTop="11dp"         android:background="#e21bd721"         android:onClick="addEmployee"         android:text="Add New Employee"         android:layout_alignParentBottom="true"         android:textColor="#fff" />      <ListView         android:id="@+id/list"         android:layout_width="match_parent"         android:layout_height="wrap_content" />  </RelativeLayout>  </RelativeLayout > 

여기서 ListView에 단순하게 택스트로 보여줄 수도 있지만 보기 좋은 형식으로 보여주려면 별도의 레이아웃 xml 파일을 만들어 줘야 합니다. 레이아웃을 만드는 방법은 아래 그림과 같이 탐색기에서 app 폴더에 마우스를 올린 후에 오른쪽 마우스 버튼을 클릭하고 New - Android Resource File을 클릭하고 Resource type를 Layout으로 선택한 다음 파일이름, Root element 등을 입력하고 OK 버튼을 클릭하면 됩니다.

위 방법으로 list_item.xml 파일를 프로젝트에 추가합니다.

화면2-1. list_item.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical" android:layout_width="match_parent"     android:layout_height="match_parent">      <TextView         android:id="@+id/id"         android:layout_width="0dp"         android:layout_height="0dp"         android:visibility="invisible"/>      <TextView         android:id="@+id/name"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:paddingBottom="2dip"         android:paddingTop="6dip"         android:textColor="@color/colorPrimaryDark"         android:textSize="16sp"         android:textStyle="bold" />      <TextView         android:id="@+id/designation"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:paddingBottom="2dip"         android:textColor="@color/colorAccent" />      <TextView         android:id="@+id/salary"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:textColor="#5d5d5d"         android:textStyle="bold" />  </LinearLayout> 

java코드2. ViewActivity.java

import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast;  import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject;  import java.util.ArrayList; import java.util.HashMap;  public class ViewActivity extends AppCompatActivity {      private String TAG = MainActivity.class.getSimpleName();      private ProgressDialog pDialog;     private ListView lv;      // URL to get contacts JSON     //private static String url = "http://shapon.website/android/CRUD/getAllEmp.php";      ArrayList<HashMap<String, String>> contactList;      private String id, name, designation, salary;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_view);          contactList = new ArrayList<>();          lv = (ListView) findViewById(R.id.list);          new Handler().execute();          // OnItem Click         lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {             @Override             public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {                 //Employee employee = (Employee) adapterView.getItemAtPosition(i);                 Intent intent = new Intent(ViewActivity.this, EditActivity.class);                  id = ((TextView) view.findViewById(R.id.id)).getText().toString();                 name = ((TextView) view.findViewById(R.id.name)).getText().toString();                 designation = ((TextView) view.findViewById(R.id.designation)).getText().toString();                 salary = ((TextView) view.findViewById(R.id.salary)).getText().toString();     //                String id = employee.getId(); //                String name = employee.getName(); //                String designation = employee.getDesignation(); //                String salary = employee.getSalary();                  intent.putExtra("ID", id);                 intent.putExtra("NAME", name);                 intent.putExtra("DESIGNATION", designation);                 intent.putExtra("SALARY", salary);                  startActivity(intent);             }         });     }      public void addEmployee(View view) {         Intent intent = new Intent(ViewActivity.this, MainActivity.class);         startActivity(intent);     }      /**      * Async task class to get json by making HTTP call      */     private class Handler extends AsyncTask<Void, Void, Void> {          private ListAdapter adapter;          @Override         protected void onPreExecute() {             super.onPreExecute();             // Showing progress dialog             pDialog = new ProgressDialog(ViewActivity.this);             pDialog.setMessage("Please wait...");             pDialog.setCancelable(false);             pDialog.show();          }          @Override         protected Void doInBackground(Void... arg0) {             JsonParser sh = new JsonParser();              // Making a request to url and getting response             String jsonStr = sh.convertJson(Constant.READ);              Log.e(TAG, "Response from url: " + jsonStr);              if (jsonStr != null) {                 try {                     JSONObject jsonObj = new JSONObject(jsonStr);                      // Getting JSON Array node                     JSONArray employeeArray = jsonObj.getJSONArray("result");                      // looping through All Contacts                     for (int i = 0; i < employeeArray.length(); i++) {                         JSONObject c = employeeArray.getJSONObject(i);                          String id = c.getString("id");                         String name = c.getString("name");                         String designation = c.getString("designation");                         String salary = c.getString("salary");                          // Phone node is JSON Object //                        JSONObject phone = c.getJSONObject("phone"); //                        String mobile = phone.getString("mobile"); //                        String home = phone.getString("home"); //                        String office = phone.getString("office");                          // tmp hash map for single contact                         HashMap<String, String> employee = new HashMap<>();                          // adding each child node to HashMap key => value                         employee.put("id", id);                         employee.put("name", name);                         employee.put("designation", designation);                         employee.put("salary", salary);                          // adding contact to contact list                         contactList.add(employee);                     }                 } catch (final JSONException e) {                     Log.e(TAG, "Json parsing error: " + e.getMessage());                     runOnUiThread(new Runnable() {                         @Override                         public void run() {                             Toast.makeText(getApplicationContext(),                                     "Json parsing error: " + e.getMessage(),                                     Toast.LENGTH_LONG)                                     .show();                         }                     });                  }             } else {                 Log.e(TAG, "Couldn't get json from server.");                 runOnUiThread(new Runnable() {                     @Override                     public void run() {                         Toast.makeText(getApplicationContext(),                                 "Couldn't get json from server. Check LogCat for possible errors!",                                 Toast.LENGTH_LONG)                                 .show();                     }                 });              }              return null;         }          @Override         protected void onPostExecute(Void result) {             super.onPostExecute(result);             // Dismiss the progress dialog             if (pDialog.isShowing())                 pDialog.dismiss();             /**              * Updating parsed JSON data into ListView              * */             ListAdapter adapter = new SimpleAdapter(                     ViewActivity.this, contactList,                     R.layout.list_item, new String[]{"id", "name", "designation",                     "salary"}, new int[]{R.id.id, R.id.name,                     R.id.designation, R.id.salary});              lv.setAdapter(adapter);           }      }  } 

화면3. activity_edit.xml

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     tools:context=".EditActivity">      <LinearLayout         android:layout_width="match_parent"         android:layout_height="match_parent"         android:orientation="vertical"         android:padding="11dp">          <TextView             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:text="Android PHP MySQL CRUD"             android:textAlignment="center"             android:textColor="#e21ace41"             android:textSize="22dp" />          <TextView             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:text="FreeProjectCode.com"             android:textAlignment="center"             android:textColor="#e2f209df"             android:textSize="20dp" />           <EditText             android:id="@+id/id"             android:layout_width="0dp"             android:layout_height="0dp"             android:hint="Id"             android:visibility="invisible" />          <EditText             android:id="@+id/name"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:hint="Name" />          <EditText             android:id="@+id/designation"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:hint="Designation" />          <EditText             android:id="@+id/salary"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:hint="Salary" />          <Button             android:id="@+id/btn_update"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:background="#e21ace41"             android:onClick="updateEmployee"             android:text="Edit Employee"             android:textColor="#fff" />          <Button             android:id="@+id/btn_list"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_marginTop="11dp"             android:background="#c28c27a6"             android:onClick="listEmployee"             android:text="Show Employee List"             android:textColor="#fff" />          <Button             android:id="@+id/btn_delete"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_marginTop="11dp"             android:background="#e2d11527"             android:onClick="deleteEmployee"             android:text="Delete Employee"             android:textColor="#fff" />        </LinearLayout>  </android.support.constraint.ConstraintLayout> 

java코드3. EditActivity.java

import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast;


import java.util.HashMap; public class EditActivity extends AppCompatActivity { private EditText mId, mName, mDesignation, mSalary; private Button mBtnAdd; //private String mId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_edit); // Initialize EditText View mId = (EditText) findViewById(R.id.id); mName = (EditText) findViewById(R.id.name); mDesignation = (EditText) findViewById(R.id.designation); mSalary = (EditText) findViewById(R.id.salary); mBtnAdd = (Button) findViewById(R.id.btn_add); Intent intent = getIntent(); Bundle bundle = intent.getExtras(); if (bundle != null){ mId.setText(bundle.getString("ID")); mName.setText(bundle.getString("NAME")); mDesignation.setText(bundle.getString("DESIGNATION")); mSalary.setText(bundle.getString("SALARY")); } } public void updateEmployee(View view) { String id = mId.getText().toString(); String name = mName.getText().toString(); String designation = mDesignation.getText().toString(); String salary = mSalary.getText().toString(); HashMap<String, String> requestedParams = new HashMap<>(); requestedParams.put("id", id); requestedParams.put("name", name); requestedParams.put("designation", designation); requestedParams.put("salary", salary); Log.d("HashMap", requestedParams.get("id")); Toast.makeText(getApplicationContext(), "Success!! Employee Updated ID : " + requestedParams.get("id"), Toast.LENGTH_LONG).show(); PostRequestHandler postRequestHandler = new PostRequestHandler(Constant.UPDATE, requestedParams); postRequestHandler.execute(); listEmployee(view); } public void deleteEmployee(View view) { String id = mId.getText().toString(); // String name = mName.getText().toString(); // String designation = mDesignation.getText().toString(); // String salary = mSalary.getText().toString(); HashMap<String, String> requestedParams = new HashMap<>(); requestedParams.put("id", id); // requestedParams.put("name", name); // requestedParams.put("designation", designation); // requestedParams.put("salary", salary); Log.d("HashMap", requestedParams.get("id")); Toast.makeText(getApplicationContext(), "Success!! Employee Deleted ID : " + requestedParams.get("id"), Toast.LENGTH_LONG).show(); PostRequestHandler postRequestHandler = new PostRequestHandler(Constant.DELETE, requestedParams); postRequestHandler.execute(); listEmployee(view); } public void listEmployee(View view) { Intent intent = new Intent(EditActivity.this, ViewActivity.class); startActivity(intent); } }

이제 빌드 후 앱을 실행해 보겠습니다.
안드로이드 DB CRUD 1 - 쓰기
앱을 실행하면 처음 화면이 나타납니다. 이름. 직책, 급여를 입력하고 ADD EMPLOYEE 버튼을 클릭하면 DB에 저장되고 전체 목록을 보여줍니다.

 

안드로이드 DB CRUD 2 - 읽기
DB에 저장된 전체 목록을 불러온 화면입니다. 항목을 클릭하면 해당 항목만 불러와 수정, 삭제를 할 수 있습니다.

안드로이드 DB CRUD 3 - 수정
알바생의 급여를 수정한 후에 EDIT EMPLOYEE 버튼을 클릭하면 DB에 내용이 수정되고 수정된 내용이 포함된 전체 목록을 출력합니다.

 

안드로이드 DB CRUD 4 - 삭제
알바생을 선택한 후에 DELETE EMPLOYEE 버튼을 클릭하면 DB에서 알바생을 삭제하고 업데이트 된 전체 목록을 출력합니다.

 

감사합니다.



이 글을 읽기 전에 다음 2개의 글을 읽어주세요.

"안드로이드 DB CRUD(쓰기, 읽기, 수정, 삭제) 1 - 프로세스" - http://ilbbang.tistory.com/34
"안드로이드 DB CRUD(쓰기, 읽기, 수정, 삭제) 2 - MariaDB 설정하기" - http://ilbbang.tistory.com/45

제가 따라해 볼 원문을 다시 확인해 보겠습니다.(출처)
http://freeprojectcode.com/android/android-mysql-basic-crud-operation-tutorial-for-android-studio-project/

이전단계에서 MariaDB 설정을 완료했으면 다음 단계는 PHP 서버 프로그래밍으로 쿼리문을 실행할 수 있게 하겠습니다. 안드로이드에서는 서비스DB에 직접 접근할 수 없습니다. 이전에는 Mysql에서 제공하는 dbconnector를 import 해서 접근이 가능했지만 이 기능은 더이상 사용이 불가능하다고 합니다. 그래서 중간에 PHP 또는 Node.js 와 같은 서버 프로그래밍을 활용하여 간접적으로 DB에 접근이 가능합니다. Node.js가 더 신기술이긴 소규모 서비스를 위한 비용을 고려했을 때 PHP가 더 저렴하다고 판단하였기 때문에 PHP를 선택하였습니다.

저는 cafe24 사이드를 사용중입니다. node.js가 더 저렴한 곳이 있다면 댓글 남겨주세요.

이번 단계에서 만들 php 파일은 총 6개 입니다. (테스트용 파일 제외)

파일1. db_config.php
파일2. addEmp.php
파일3. getEmp.php
파일4. getAllEmp.php
파일5. updateEmp.php
파일6. deleteEmp.php

파일 별 설명 및 코드를 살펴보겠습니다.

파일1은 Maria DB를 접속하기 위한 파일입니다. 이 파일이 없다면 나머지 파일에 동일하게 접속할 수 있는 코드를 만들면 되지만, 이 경우 정보가 변경되었을 때 번거롭기 때문에 하나의 파일로 관리합니다.

파일1. db_config.php
<?php

 //DB 정보를 입력합니다
 define('HOST','IP또는HOSTNAME:PORT(생략시3306)');
 define('USER','사용자ID');
 define('PASS','암호');
 define('DB','DB이름');
 
 //DB에 접속합니다.
 $con = mysqli_connect(HOST,USER,PASS,DB) or die('DB에 연결할 수 없습니다.');
?>
이 파일을 다른 파일에서 require_once 명령어로 불러오면 $con 변수에 접속 스크립트가 실행되여 DB에 접속이 가능합니다. 접속이 안 될 경우에는 'DB에 연결할 수 없습니다.' 문구를 출력하고 접속이 되지 않습니다.

파일2는 DB에 자료를 입력하기 위한 파일입니다. 이름(name), 직함(designation), 급여(salary) 정보를 post 방식으로 보내면 이 파일에서 쿼리문을 실행해 DB에 입력합니다.

파일2. addEmp.php
<?php 
        // POST 방식일 경우에만 코드가 실행됩니다.
	if($_SERVER['REQUEST_METHOD']=='POST'){
		
		//POST로 보낸 값을 받아서 변수에 입력합니다.
		$name = $_POST['name'];
		$desg = $_POST['designation'];
		$sal = $_POST['salary'];
		
		//받아온 값을 입력 값으로 지정한 INSERT 쿼리문을 작성합니다.
		$sql = "INSERT INTO employee (name, designation, salary) VALUES ('$name','$desg','$sal')";
		
		//DB 접속 스크립트를 불러옵니다.
		require_once('db_config.php');
		
		//쿼리문을 실행합니다.
		if(mysqli_query($con,$sql)){

// 입력 성공 시 아래 내용을 출력합니다. echo '종업원 정보가 성공적으로 입력되었습니다.';

}else{

// 입력 실패 시 아래 내용을 출력합니다. echo '종업원 정보를 입력할 수 없습니다.'; } //접속을 종료합니다. mysqli_close($con); }else{

// POST 방식이 아니면 아래 내용을 출력합니다. echo 'Post Request 가 아닙니다.'; } ?>

파일3과 파일4는 DB의 자료를 읽어오기 위한 파일입니다. 읽어온 자료를 json 형식으로 변환해서 화면에 출력해 줍니다.
파일3은 단일 레코드의 정보를 가져옵니다. 검색 조건은 id 입니다. 파일4는 모든 레코드의 정보를 가져옵니다.

파일3. getEmp.php

<?php 
	
	//POST로 보낸 id 값을 받아서 변수에 입력합니다.
	$id = $_POST['id'];
	
	//DB 접속 스크립트를 불러옵니다.
	require_once('db_config.php');
	
	//받아온 id를 검색 조건으로 특정 종업원의 정보를 불러오는 쿼리문을 작성합니다.
	$sql = "SELECT * FROM employee WHERE id=$id";
	
	//쿼리문을 실행합니다. 결과를 r 변수에 저장합니다.
	$r = mysqli_query($con,$sql);
	
	// r 변수의 내용을 array 형식으로 내보내 result 변수에 저장합니다.
	$result = array();
	$row = mysqli_fetch_array($r);
	array_push($result,array(
			"id"=>$row['id'],
			"name"=>$row['name'],
			"desg"=>$row['designation'],
			"salary"=>$row['salary']
		));

	//저장된 result 변수를 json 형식으로 출력합니다.
	echo json_encode(array('result'=>$result), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);
	

//접속을 종료합니다. mysqli_close($con); ?>

파일4. getAllEmp.php

<?php 
	//DB 접속 스크립트를 불러옵니다.
	require_once('db_config.php');
	
	//전체 종업원의 정보를 불러오는 쿼리문을 작성합니다.
	$sql = "SELECT * FROM employee";
	
	//쿼리문을 실행합니다. 결과를 r 변수에 저장합니다.
	$r = mysqli_query($con,$sql);
	
	// result 변수의 유형을 array 로 정의합니다.
	$result = array();
	
	// 모든 레코드에 대하여 while 문으로 반복 처리를 수행합니다.
	while($row = mysqli_fetch_array($r)){
		
		// r 변수의 내용을 array 형식으로 내보내 result 변수에 저장합니다.
		array_push($result,array(
			"id"=>$row['id'],
			"name"=>$row['name'],
                        "designation"=>$row['designation'],
                        "salary"=>$row['salary']
		));
	}
	
	//저장된 result 변수를 json 형식으로 출력합니다.
	echo json_encode(array('result'=>$result), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);
	

//접속을 종료합니다. mysqli_close($con); ?>

파일5는 DB의 자료를 수정하기 위한 파일입니다. 검색 조건은 id 입니다. id, 이름(name), 직함(designation), 급여(salary) 정보를 post 방식으로 보내면 이 파일에서 쿼리문을 실행해 자료를 수정합니다.

파일5. updateEmp.php

<?php 
	if($_SERVER['REQUEST_METHOD']=='POST'){
		//POST로 보낸 값을 받아서 변수에 입력합니다.
		$id = $_POST['id'];
		$name = $_POST['name'];
		$desg = $_POST['designation'];
$sal = $_POST['salary']; //DB 접속 스크립트를 불러옵니다. require_once('db_config.php'); //특정 종업원의 정보를 수정하는 쿼리문을 작성합니다. $sql = "UPDATE employee SET name = '$name', designation = '$desg', salary = '$sal' WHERE id = $id;"; //Updating database table if(mysqli_query($con,$sql)){ // 수정 성공 시 아래 내용을 출력합니다. echo '종업원 정보가 성공적으로 수정되었습니다.'; }else{ // 수정 실패 시 아래 내용을 출력합니다. echo '종업원 정보를 수정할 수 없습니다.'; } //접속을 종료합니다. mysqli_close($con); } ?>

파일6은 DB의 자료를 삭제하기 위한 파일입니다. 검색조건은 id 입니다. id 정보를 post 파일로 보내면 이 파일에서 쿼리문을 실행해 해당 자료를 삭제합니다.

파일6. deleteEmp.php

<?php 
   // POST 방식일 경우에만 코드가 실행됩니다.
   if(isset($_POST['id'])){
	//POST로 보낸 id 값을 받아서 변수에 입력합니다.
	$id = $_POST['id'];
	
	//DB 접속 스크립트를 불러옵니다.
	require_once('db_config.php');
	
	//특정 종업원의 정보를 삭제하는 쿼리문을 작성합니다.
	$sql = "DELETE FROM employee WHERE id=$id;";
	
	//쿼리문을 실행합니다.
	if(mysqli_query($con,$sql)){
                // 삭제 성공 시 아래 내용을 출력합니다. 
		echo '종업원 정보가 성공적으로 삭제되었습니다.';
	}else{
                // 삭제 실패 시 아래 내용을 출력합니다. 
		echo '종업원 정보를 삭제할 수 없습니다.';
	}
	
	//접속을 종료합니다.
	mysqli_close($con);
   }else{
        // POST 방식이 아니면 아래 내용을 출력합니다.
        echo 'Post Request 가 아닙니다.';
   }
?>

예제 파일이어서 그대로 진행하지만 post 로 보낼때 변수 값을 더 지정한다면 파일을 여러개 만들 필요가 없다고 생각합니다.
시간이 되신다면 dbconfig.php, crudEmp.php 파일 두개로 진행할 수 있는 방법을 생각해 보세요.

이제 안드로이드에서 php 파일에 접속하여 MariaDB에 CRUD(쓰기, 읽기, 수정, 삭제)를 수행해 보겠습니다. 아래 링크를 클릭해 주세요

"안드로이드 DB CRUD(쓰기, 읽기, 수정, 삭제) 4 - Android 화면 및 구현하기" - http://ilbbang.tistory.com/52

감사합니다.

이 글을 읽기 전에 "안드로이드 DB CRUD(쓰기, 읽기, 수정, 삭제) 1 - 프로세스" 글을 먼저 읽어주세요.
http://ilbbang.tistory.com/34?category=823124

프로세스를 파악했으니 첫 번째 단계로 MySQL에서 DB를 설정하도록 하겠습니다.

제가 따라해 볼 원문을 다시 확인해 보겠습니다.
http://freeprojectcode.com/android/android-mysql-basic-crud-operation-tutorial-for-android-studio-project/

제가 따라할 부분은 DB 1개 생성, Table 1개 생성하는 것입니다.
그 중에서 DB는 이전에 만들어 놓은 Test DB에 테이블을 추가할 것이기 때문에 생략되고 Table 1개만 생성하면 됩니다.

할 일도 간단합니다. 아래의 Create Table 문을 복사해서 SQL 프로그램의 쿼리문에 붙여넣기 한 후 실행만 하면 됩니다.
본문에 제공한 SQL 문은 아래와 같습니다.

CREATE TABLE IF NOT EXISTS employee(
	id int(11) primary key auto_increment,
	name varchar(100) not null,
	designation varchar(50) not null,
	salary int(50) not null,
	created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
);

실행될까요? 안됩니다.
아무래도 DB 버전이 달라서 안되는거 같습니다. 제가 사용하는 환경은 Synolygy NAS에서 패키지로 설치한 Maria DB 10.0 버전입니다.
접속은 HeidiSQL을 설치했으며, 개인 도메인 및 포트 설정으로 외부에서도 접속 가능하도록 했습니다.

구글 검색등을 통해 코드를 수정해서 실행된 코드는 다음과 같습니다.

CREATE TABLE IF NOT EXISTS 'employee' (
	'id' INT(11) NOT NULL AUTO_INCREMENT,
	'name' VARCHAR(100) NOT NULL,
	'designation' VARCHAR(50) NOT NULL,
	'salary' INT(50) NOT NULL,
	'created_at' DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`)
);

생성되는 열 별로 속성을 살펴보면 다음과 같습니다.

1열 - 열 이름: id, 형식: 11자리 정수, 기본키(중복허용안함, Null 값 허용 안함), 자동 증가
2열 - 열 이름: name, 형식: 100자 글씨, Null 값 허용 안함
3열 - 열 이름: designation, 형식: 50자 글씨, Null 값 허용 안함
4열 - 열 이름: salary, 형식: 50자 정수, Null 값 허용 안함
5열 - 열 이름: create_at, 형식: 날짜, Null 값 허용 안함, 기본값은 현재시간

이렇게 테이블을 만들면 자료 입력 시 name, designation, salary 3개만 입력하면 id, create_at 열은 조건에 맞는 값이 자동으로 입력됩니다.

DB 설정은 이렇게 간단하게 끝났습니다. 설명이 길어졌지만 실행은 SQL 쿼리문 1개입니다.
(독립적인 DB를 생성했다면 원문에 있는 CREATE DATABASE 문으로 새로운 DB도 생성해야 합니다.)

다음은 php를 활용해서 쿼리문을 수행할 수 있도록 하겠습니다. 아래 링크를 클릭해 주세요.

"안드로이드 DB CRUD(쓰기, 읽기, 수정, 삭제) 3 - PHP로 MySQL에 접근하기" - http://ilbbang.tistory.com/47

감사합니다.

'프로그래밍 > SQL' 카테고리의 다른 글

mysql 명령어 완전 기초  (0) 2018.06.07

+ Recent posts