C#/수업내용

2020.07.29. 수업내용 - DB 서버와 유니티 연동 ( MySQL, Nodejs, Unity)(2)

dev_sr 2020. 7. 29. 14:48

1. 비밀번호 암호화

node.js route의 member.js에서 

crypto 모듈을 사용해서 비밀번호를 암호화 해줌

 

비밀번호를 암호화하는 function을 만들어준다.

 

post부분에 추가해준다

 

암호화된 비밀번호가 길어져서 안 들어올 수 도 있으므로 비밀번호 문자열데이터 길이를 늘려준다.

DB에서 테이블을 수정해주고

 

자바스크립트에서 member.js에서 password type을 수정해줌

 

DB에 비밀번호가 암호화 되어서 들어옴

 

 

 

2. 등록

 

등록 UI를 만들어준다.

 

SignUp 클래스를 만들어주고

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UISignUp : MonoBehaviour
{
    public InputField inputMemberName;
    public InputField inputPassword;
    public Button btnSubmit;

    public void Init()
    {

    }

 
}

 

test 클래스 start 부분에 init( )하고 작성해줌

this.uISignUp.btnSubmit.onClick.AddListener(() =>
        {
            var memberName = this.uISignUp.inputMemberName.text;
            var password = this.uISignUp.inputPassword.text;
            Debug.LogFormat("{0},{1}", memberName, password);

            var req = new Protocols.req_member_post();
            req.username = memberName;
            req.password = password;
            this.SignUp(req);

        });

 

public void SignUp(Protocols.req_member_post req)
    {
        //로딩바 켜줌
        this.loading.SetActive(true);
        StartCoroutine(this.Post1("/member", req, (responseCode) =>
        {
            //로딩바 꺼줌
            this.loading.SetActive(false);
            if (responseCode == 200)
            {
                Debug.Log("가입 완료");
            }
        }));
    }

 

//form으로 보내기 
    //body로 보내는 방법도 있음
    private IEnumerator Post1(string uri, Protocols.req_member_post req, System.Action<long> onComplete)
    {
        //List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
        var form = new WWWForm();
        form.AddField("username", req.username);
        form.AddField("password", req.password);
        var url = string.Format("{0}:{1}{2}", host, port, uri);
        var www = UnityWebRequest.Post(url, form);
        yield return www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log(www.responseCode);
            onComplete(www.responseCode);
        }
    }

 

 

3. 수정

 

 

팝업 창을 보여줄 prompt 오브젝트를 만들고 스크립트도 만듦

비활성화 해놨다가 멤버 리스트의 수정 버튼을 누르면 나타나고

변경한 이름 적고 등록 버튼을 누르거나 취소 버튼을 누르면 사라지게 함

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

public class UIPopUpPrompt : MonoBehaviour
{
    public InputField inputNewMemberIndexName;
    public Button btnOkay;
    public Button btnCancel;
    public UnityAction<int, string> OnClickOk;


    private int id;

    public void Init()
    {
        this.btnOkay.onClick.AddListener(() =>
        {
            this.OnClickOk(this.id, this.inputNewMemberIndexName.text);
        });
    }

    public void Close()
    {
        this.gameObject.SetActive(false);
    }

    public void Open(int id)
    {
        this.id = id;
        this.gameObject.SetActive(true);
    }
}

 

멤버 리스트의 수정 버튼을 눌렀을 때 대리자를 호출함

UIMembers 의 Refresh 메서드의 멤버들을 생성하는 foreach문에 써준다.

    	listItem.btnUpdata.onClick.AddListener(() =>
            {
                this.OnUpdateClick(member.id, member.username);
            });

 

test 의 start 부분에 대리자 정의를 써줌

팝업이 열림

 	//수정
        this.uiMembers.OnUpdateClick = (id, username) =>
        {
            Debug.LogFormat("{0},{1}", id, username);
            this.uiPopUpPrompt.Open(id);
        };

        

 

UIPopUpPrompt 를 start 에서 init 해주고

나타난 팝업에서 변경한 이름을 적고 등록버튼(btnOkay)를 누르면 호출되는 대리자를 정의해줌

	this.uiPopUpPrompt.Init();
        this.uiPopUpPrompt.OnClickOk = (id, newMemberName) =>
        {
            //test 에서 id를 전역변수로 갖고 값을 저장해서 보내는 것보다
            //이 방법이 낫다!
            //id와 membername을 서버에 보냄
            Debug.LogFormat("{0},{1}", id, newMemberName);
            var req = new Protocols.req_member_put();
            req.username = newMemberName;
            this.UpdateMemberName(id, req);
        };

 

UpdateMemberName 메서드에서 변경할 id를 담은 uri를 만들고 put 코루틴 시작

  public void UpdateMemberName(int id, Protocols.req_member_put req)
    {
        var uri = string.Format("/member/{0}", id);
        StartCoroutine(this.Put(uri, req, (responseCode) =>
         {
             Debug.Log(responseCode);
         }));
        this.uiPopUpPrompt.Close();
    }

 

서버로 url과 req를 보냄

직렬화하고 01010001로 인코딩해서 보냄

유니티에서는 patch의 기능을 put이 하는데

www.method ="PATCH"; 

하면 member.js의 patch로 보낼 수 있음

//Unity에서는 Patch의 기능을 Put이 함
    private IEnumerator Put(string uri, Protocols.req_member_put req, System.Action<long> onComplete)
    {
        var url = string.Format("{0}:{1}{2}", host, port, uri);
        var json = JsonConvert.SerializeObject(req);
        var data = Encoding.UTF8.GetBytes(json);
        var www = UnityWebRequest.Put(url, data);
        www.SetRequestHeader("Content-Type", "application/json");
        //www.method = "PATCH"; //=> node.js에 patch로 들어간다.
        yield return www.SendWebRequest();


        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log(www.responseCode);
            onComplete(www.responseCode);
        }
    }

 

route 의 member.js에서 put 기능을 추가해줌

 

취소 버튼 누르면 닫기

	this.uiPopUpPrompt.btnCancel.onClick.AddListener(() =>
        {
            this.uiPopUpPrompt.Close();
        });

 

 

4. 삭제

 

멤버리스트에서 삭제버튼을 누르면 멤버를 삭제시킬 거임

UIMember 클래스의 Refresh메서드 멤버들 접근하는 foreach부분에

삭제버튼을 누르면 id를 넘겨주는 대리자를 호출하게 함

 	listItem.btnDelete.onClick.AddListener(() =>
            {
                this.OnDeleteClick(member.id);
            });

 

test의 start부분에서 정의해줌

	//삭제
        this.uiMembers.OnDeleteClick = (id) =>
        {
            this.DeleteMember(id);
        };

 

멤버 uri만들고 코루틴으로 넘겨줌

 //삭제
    public void DeleteMember(int id)
    {
        var uri = string.Format("/member/{0}", id);
        StartCoroutine(this.Delete(uri, (responseCode) =>
        {
            Debug.Log(responseCode);
        }));
    }
private IEnumerator Delete(string uri, System.Action<long> onComplete)
    {
        var url = string.Format("{0}:{1}{2}", host, port, uri);
        var www = UnityWebRequest.Delete(url);
        yield return www.SendWebRequest();
        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log(www.responseCode);
            onComplete(www.responseCode);
        }
    }

 

결과

 

 

 

 

전체 코드

 

Test

using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class Test : MonoBehaviour
{
    public UIMembers uiMembers;
    public UISignUp uISignUp;
    public GameObject loading;
    public UIPopUpPrompt uiPopUpPrompt;

    private string host = "http://localhost";
    private int port = 3000;

    void Start()
    {
        this.uISignUp.Init();
        this.uiPopUpPrompt.Init();
        this.uiPopUpPrompt.OnClickOk = (id, newMemberName) =>
        {
            //test 에서 id를 전역변수로 갖고 값을 저장해서 보내는 것보다
            //이 방법이 낫다!
            //id와 membername을 서버에 보냄
            Debug.LogFormat("{0},{1}", id, newMemberName);
            var req = new Protocols.req_member_put();
            req.username = newMemberName;
            this.UpdateMemberName(id, req);
        };

        this.uiPopUpPrompt.btnCancel.onClick.AddListener(() =>
        {
            this.uiPopUpPrompt.Close();
        });

        this.uISignUp.btnSubmit.onClick.AddListener(() =>
        {
            var memberName = this.uISignUp.inputMemberName.text;
            var password = this.uISignUp.inputPassword.text;
            Debug.LogFormat("{0},{1}", memberName, password);

            var req = new Protocols.req_member_post();
            req.username = memberName;
            req.password = password;
            this.SignUp(req);

        });


        this.uiMembers.Init();

        //수정
        this.uiMembers.OnUpdateClick = (id, username) =>
        {
            Debug.LogFormat("{0},{1}", id, username);
            this.uiPopUpPrompt.Open(id);
        };

        //삭제
        this.uiMembers.OnDeleteClick = (id) =>
        {
            this.DeleteMember(id);
        };


        //새로고침
        this.uiMembers.btnRefresh.onClick.AddListener(() =>
        {
            this.GetMembers();
        });


        this.GetMembers();
    }
    public void SignUp(Protocols.req_member_post req)
    {
        //로딩바 켜줌
        this.loading.SetActive(true);
        StartCoroutine(this.Post1("/member", req, (responseCode) =>
        {
            //로딩바 꺼줌
            this.loading.SetActive(false);
            if (responseCode == 200)
            {
                Debug.Log("가입 완료");
            }
        }));
    }


    public void GetMembers()
    {
        //로딩바 껴줌
        this.loading.SetActive(true);
        StartCoroutine(this.Get("/member", (res) =>
        {
            if (res.status == 200)
            {
                this.uiMembers.Refresh(res.members);
            }
            else
            {
                Debug.LogFormat("{0}", res.status);
            }
            //로딩바 꺼줌
            this.loading.SetActive(false);
        }));
    }


    //수정
    public void UpdateMemberName(int id, Protocols.req_member_put req)
    {
        var uri = string.Format("/member/{0}", id);
        StartCoroutine(this.Put(uri, req, (responseCode) =>
         {
             Debug.Log(responseCode);
         }));
        this.uiPopUpPrompt.Close();
    }

    //삭제
    public void DeleteMember(int id)
    {
        var uri = string.Format("/member/{0}", id);
        StartCoroutine(this.Delete(uri, (responseCode) =>
        {
            Debug.Log(responseCode);
        }));
    }


    //처음 실행할때 조회
    private IEnumerator Get(string uri, System.Action<Protocols.res_member_get> onComplete)
    {
        var url = string.Format("{0}:{1}{2}", host, port, uri);
        Debug.Log(url);
        UnityWebRequest www = UnityWebRequest.Get(url);
        yield return www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError)
        {
            Debug.LogFormat("{0}", www.error);  //보통 밖에서 에러 처리 해주는게 좋음
        }
        else
        {
            var result = www.downloadHandler.data;
            var json = Encoding.UTF8.GetString(result);
            Protocols.res_member_get res = JsonConvert.DeserializeObject<Protocols.res_member_get>(json);
            Debug.LogFormat("status: {0}, member cnt: {1}", res.status, res.members.Count());
            onComplete(res);

        }
    }

    //form으로 보내기 
    //body로 보내는 방법도 있음
    private IEnumerator Post1(string uri, Protocols.req_member_post req, System.Action<long> onComplete)
    {
        //List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
        var form = new WWWForm();
        form.AddField("username", req.username);
        form.AddField("password", req.password);
        var url = string.Format("{0}:{1}{2}", host, port, uri);
        var www = UnityWebRequest.Post(url, form);
        yield return www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log(www.responseCode);
            onComplete(www.responseCode);
        }
    }

    //Unity에서는 Patch의 기능을 Put이 함
    private IEnumerator Put(string uri, Protocols.req_member_put req, System.Action<long> onComplete)
    {
        var url = string.Format("{0}:{1}{2}", host, port, uri);
        var json = JsonConvert.SerializeObject(req);
        var data = Encoding.UTF8.GetBytes(json);
        var www = UnityWebRequest.Put(url, data);
        www.SetRequestHeader("Content-Type", "application/json");
        //www.method = "PATCH"; //=> node.js에 patch로 들어간다.
        yield return www.SendWebRequest();


        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log(www.responseCode);
            onComplete(www.responseCode);
        }
    }

    private IEnumerator Delete(string uri, System.Action<long> onComplete)
    {
        var url = string.Format("{0}:{1}{2}", host, port, uri);
        var www = UnityWebRequest.Delete(url);
        yield return www.SendWebRequest();
        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log(www.responseCode);
            onComplete(www.responseCode);
        }
    }

}

 

Protocols

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Protocols 
{
    public class member
    {
        public int id;
        public string username;
        public string password;
        public string created_at;
    }


    public class res_memeber
    {
        public int status;
    }

    //멤버 조회
    public class res_member_get:res_memeber
    {
        public member[] members;
    }

    //멤버 삭제
    public class res_member_delete : res_memeber
    {
        
    }

    //멤버 등록
    public class req_member_post
    {
        public string username;
        public string password;
    }

    public class res_member_post : res_memeber
    {

    }

    //멤버 이름 수정(patch)

    public class req_member_put
    {
        public string username;
    }

    public class res_member_put : res_memeber
    {

    }
}

 

UIMembers

using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

public class UIMembers : MonoBehaviour
{
    public Button btnRefresh;
    public Transform contentsTrans;
    public UIlistItem uiListItemPrefabs;
    public UnityAction<int, string> OnUpdateClick;
    public UnityAction<int> OnDeleteClick;


    public void Init()
    {
        
    }

    public void Refresh(Protocols.member[] members)
    {
        foreach(Transform child in this.contentsTrans)
        {
            Destroy(child.gameObject);
        }


        foreach(var member in members)
        {
            var go = Instantiate<GameObject>(this.uiListItemPrefabs.gameObject, this.contentsTrans);
            var listItem = go.GetComponent<UIlistItem>();
            listItem.Init(member.id, member.username);
            listItem.btnUpdata.onClick.AddListener(() =>
            {
                this.OnUpdateClick(member.id, member.username);
            });

            listItem.btnDelete.onClick.AddListener(() =>
            {
                this.OnDeleteClick(member.id);
            });
        }
    }

}

 

UIlistItem

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIlistItem : MonoBehaviour
{
    public Text txtId;
    public Text txtMemeberName;
    public Button btnUpdata;
    public Button btnDelete;

    private int id;
    private string memberName;

    public void Init(int id, string memberName)
    {
        this.id = id;
        this.memberName = memberName;

        this.txtId.text = this.id.ToString();
        this.txtMemeberName.text = this.memberName.ToString();

    }


   
}

 

UISignUp

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UISignUp : MonoBehaviour
{
    public InputField inputMemberName;
    public InputField inputPassword;
    public Button btnSubmit;

    public void Init()
    {

    }

 
}

 

UIPopUpPrompt

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

public class UIPopUpPrompt : MonoBehaviour
{
    public InputField inputNewMemberIndexName;
    public Button btnOkay;
    public Button btnCancel;
    public UnityAction<int, string> OnClickOk;


    private int id;

    public void Init()
    {
        this.btnOkay.onClick.AddListener(() =>
        {
            this.OnClickOk(this.id, this.inputNewMemberIndexName.text);
        });
    }

    public void Close()
    {
        this.gameObject.SetActive(false);
    }

    public void Open(int id)
    {
        this.id = id;
        this.gameObject.SetActive(true);
    }
}