** 해야 할 일
1. select from DB => show Android ()
2. input Android => insert data to DB
** use DataBase : MySQL
** Setting ("xampp\htdocts" 에서 php 파일 보관)
use DataBase(DBMS) |
MySQL(PHPMyAdmin) |
Environment |
Windows10 |
web Server |
Apatch(localhost, 개이IP) |
etc |
통합 환경 XAMPP 사용 |
여러번 삽질을 해본 결과... 사실 연동이라 함은 깔끔하게 데이터만 뽑아서 가져올법 하지만, 그건 모두 개발자의 몫이다.. 따라서 원하는 데이터가 있다면 먼저 DB에서 php 화면에 데이터를 불러와서 띄운다음에, 그 띄운 글자를 안드로이드에 배열 형태로 가져온다. 그리고 배열에서 '[' 같은 문자를 파싱하고 출력하면 내가 처음에 원하는 것이 나온다...
주로 이런 값 전달은 php의 echo "전달할값" 과 $변수명 으로 통한다. 안드로이드에서 쓴 글씨를 DB에 넣지 않고 php 상에서 본다는건... 사실상 좀 까다로운 일 같다.., 될 수 있는지도 모르겠다..
"안드로이드에서 받은 값을 DB에서 넣지 않고 php 상에 띄운다" 는 "안드로이드에서 입력한 값을 php로 보내서 echo로 출력하면 그 출력 데이터가 다시 돌아와 안드로이드에서 출력된다" 와 같은 의미였다... 하긴, 동적인 값을 어떻게 php에서 받아서 바로바로 출력해줄 수 있겠어...
** 1. select from DB => show Android
1) Select from DB - PHP
안드로이드에서 DB의 값을 출력하고싶다면, 먼저 DB에서 값을 가져와 PHP에 출력하는 작업이 필요하다. 사실상 출력이라기보다는 값전달에 가깝다. PHP 화면상에 DB의 값이 출력되는건 echo 함수로 값을 전달 할 수 밖에 없기 때문에 보여질 수 밖에 없는 것이다..
다음은 DB에서 값을 읽어와 php에 출력하는 코드.
- insertData.php
<?php
// DB 연동을 시작합니다.
$con=mysqli_connect("호스트명", "DB ID", "DB PW", "DB 이름");
// mysqli_connect()에 대한 마지막 호출에 대한 오류 코드 값을 반환한다.
// echo mysqli_connect() 에서 0은 오류가 발생하지 않았음을 의미한다
if (mysqli_connect_errno($con)) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
/* select data */
// 1. 실행할 쿼리문을 작성합니다.
$selectSQL = "select * from ttest";
$result = mysqli_query($con, $selectSQL);
// 출력할 데이터를 저장할 배열변수 선언
// 데이터는 json-array 형식으로 출력할 것임 (일반적으로 이렇게 함)
$data = array();
if ($result) {
while ($row=mysqli_fetch_array($result)) {
array_push($data,array('컬럼명'=>$row[0],'컬럼명'=>$row[1]));
}
header('Content-Type: application/json; charset=utf8');
$json = json_encode(array("테이블이름"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);
echo $json; // => 출력되는 값이 이 코드로 하여금 android로 전송된다..
} else {
echo "SQL문 처리중 에러 발생 : ";
echo mysqli_error($con);
}
// DB 연동을 종료 합니다
mysqli_close($con);
?>
여기서, if 문을 살펴보자
array_push($data,array('컬럼명'=>$row[0],'컬럼명'=>$row[1])); |
배열로 선언한 data 변수에 첫번째 컬럼명(row[0]), 두번째 컬럼명(row[1]) 을 연관배열의 형태로 저장한다. 이 부분은 필요하다면 for을 사용해서 더 깔끔하게 코딩할 수 있다.. 나는 그냥 필요한 만큼만 했다.. 여기서 '컬럼명'은 연관배열로 지정해줄 이름일뿐, 굳이 컬럼명을 적지 않아도 된다!!! 대신 컬럼명이 아닌데 컬럼 값을 가지고 있으면, 다른 사람이 볼 때 어떤 값인지.. 잘 알아볼 수 있을까..ㅎ
$json = json_encode(array("테이블이름"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE); |
json이라는 변수를 선언하고 아까 data 배열 변수를 json 코드로 인코딩해서 저장했다. 뒤에 있는건 추가적으로 json 배열이 더 예쁘게 내보이고 싶다면 사용하는 옵션이다. 더 필요한 옵션이 있다면 구글링을 하시도록!
2) Show Android - Android Programming
- activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:layout_margin="40dp"
android:gravity="center"
tools:context=".MainActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/edtText1"
android:hint="ID"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/edtText2"
android:hint="PW"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:gravity="center"
android:layout_marginTop="20dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/insertBtn"
android:text="insert"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_marginTop="80dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/txtView"
android:text="test txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
- MainActivity.java
public class MainActivity extends AppCompatActivity {
private TextView txtView;
private EditText editText1, editText2;
Button insertBtn;
private static String IP = ""; //서버 없이 사용하는 IP가 있다면 저장해서 사용하면 된다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 사용할 액티비티 선언
editText1 = findViewById(R.id.edtText1);
editText2 = findViewById(R.id.edtText2);
insertBtn = findViewById(R.id.insertBtn);
// String url = "http://" + IP + "/php파일명.php";
String url = "http://" + IP + "/InsertData.php";
selectDatabase selectDatabase = new selectDatabase(url, null);
selectDatabase.execute(); // AsyncTask는 .excute()로 실행된다.
}
class selectDatabase extends AsyncTask<Void, Void, String> {
private String url1;
private ContentValues values1;
String result1; // 요청 결과를 저장할 변수.
public selectDatabase(String url, ContentValues contentValues) {
this.url1 = url;
this.values1 = contentValues;
}
@Override
protected String doInBackground(Void... params) {
RequestHttpURLConnection requestHttpURLConnection = new RequestHttpURLConnection();
result1 = requestHttpURLConnection.request(url1, values1); // 해당 URL로 부터 결과물을 얻어온다.
return result1; // 여기서 당장 실행 X, onPostExcute에서 실행
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//txtView.setText(s); // 파서 없이 전체 출력
doJSONParser(s); // 파서로 전체 출력
}
}
// 받아온 json 데이터를 파싱합니다..
public void doJSONParser(String string) {
try {
String result = "";
JSONObject jsonObject = new JSONObject(string);
JSONArray jsonArray = jsonObject.getJSONArray("ttest");
for (int i=0; i < jsonArray.length(); i++) {
JSONObject output = jsonArray.getJSONObject(i);
result += output.getString("ed1txt")
+ " / "
+ output.getString("ed2txt")
+ "\n";
}
txtView = findViewById(R.id.txtView);
txtView.setText(result);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
- RequestHttpURLConnection.java
public class RequestHttpURLConnection {
public String request(String _url, ContentValues _params){
// HttpURLConnection 참조 변수.
HttpURLConnection urlConn = null;
// URL 뒤에 붙여서 보낼 파라미터.
StringBuffer sbParams = new StringBuffer();
/**
* 1. StringBuffer에 파라미터 연결
* */
// 보낼 데이터가 없으면 파라미터를 비운다.
if (_params == null)
sbParams.append("");
// 보낼 데이터가 있으면 파라미터를 채운다.
else {
// 파라미터가 2개 이상이면 파라미터 연결에 &가 필요하므로 스위칭할 변수 생성.
boolean isAnd = false;
// 파라미터 키와 값.
String key;
String value;
for(Map.Entry<String, Object> parameter : _params.valueSet()){
key = parameter.getKey();
value = parameter.getValue().toString();
// 파라미터가 두개 이상일때, 파라미터 사이에 &를 붙인다.
if (isAnd)
sbParams.append("&");
sbParams.append(key).append("=").append(value);
// 파라미터가 2개 이상이면 isAnd를 true로 바꾸고 다음 루프부터 &를 붙인다.
if (!isAnd)
if (_params.size() >= 2)
isAnd = true;
}
}
/**
* 2. HttpURLConnection을 통해 web의 데이터를 가져온다.
* */
try{
URL url = new URL(_url);
urlConn = (HttpURLConnection) url.openConnection();
// [2-1]. urlConn 설정.
urlConn.setRequestMethod("POST"); // URL 요청에 대한 메소드 설정 : POST.
urlConn.setRequestProperty("Accept-Charset", "UTF-8"); // Accept-Charset 설정.
urlConn.setRequestProperty("Context_Type", "application/x-www-form-urlencoded;cahrset=UTF-8");
// [2-2]. parameter 전달 및 데이터 읽어오기.
String strParams = sbParams.toString(); //sbParams에 정리한 파라미터들을 스트링으로 저장. 예)id=id1&pw=123;
OutputStream os = urlConn.getOutputStream();
os.write(strParams.getBytes("UTF-8")); // 출력 스트림에 출력.
os.flush(); // 출력 스트림을 플러시(비운다)하고 버퍼링 된 모든 출력 바이트를 강제 실행.
os.close(); // 출력 스트림을 닫고 모든 시스템 자원을 해제.
// [2-3]. 연결 요청 확인.
// 실패 시 null을 리턴하고 메서드를 종료.
if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK)
return null;
// [2-4]. 읽어온 결과물 리턴.
// 요청한 URL의 출력물을 BufferedReader로 받는다.
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), "UTF-8"));
// 출력물의 라인과 그 합에 대한 변수.
String line;
String page = "";
// 라인을 받아와 합친다.
while ((line = reader.readLine()) != null){
page += line;
}
return page;
} catch (MalformedURLException e) { // for URL.
e.printStackTrace();
} catch (IOException e) { // for openConnection().
e.printStackTrace();
} finally {
if (urlConn != null)
urlConn.disconnect();
}
return null;
}
}
- NetworkTask.java
public class NetworkTask extends AsyncTask<Void, Void, String> {
private String url;
private ContentValues values;
public NetworkTask(String url, ContentValues values) {
this.url = url;
this.values = values;
}
@Override
protected String doInBackground(Void... params) {
String result; // 요청 결과를 저장할 변수.
RequestHttpURLConnection requestHttpURLConnection = new RequestHttpURLConnection();
result = requestHttpURLConnection.request(url, values); // 해당 URL로 부터 결과물을 얻어온다.
return result;
}
}
insert도 비슷하니까 설명 생략하고 그냥 코드 복붙..
** 2. input Android => insert data to DB
1) Type input data - Android
- insertData.php (코드 추가함)
<?php
/* insert data */
// 1. 안드로이드에서 post로 날린 값을 받아 변수에 저장합니다
$ed1txt = $_POST['ed1txt'];
$ed2txt = $_POST['ed2txt'];
// 2. 실행할 쿼리문을 작성합니다. => mysqli_query(실행할 Db, 실행할 query)
$insertSQL = "insert into ttest (ed1txt,ed2txt) values ('$ed1txt','$ed2txt')";
$result1 = mysqli_query($con, $insertSQL);
if ($result1) {
echo "Success!!";
} else {
echo "Fail insert data to Database...";
}
?>
2) Insert data to DB - PHP
- MainActivity.java (코드 추가함)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
insertBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
insertoToDatabase(editText1.getText().toString(),editText2.getText().toString());
}
});
}
private void insertoToDatabase(final String ed1, String ed2) {
class InsertData extends AsyncTask<String, Void, String> {
ProgressDialog loading;
@Override
protected void onPreExecute() {
super.onPreExecute();
loading = ProgressDialog.show(MainActivity.this, "Please Wait", null, true, true);
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
loading.dismiss();
//Log.d("Tag : ", s); // php에서 가져온 값을 최종 출력함
Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
}
@Override
protected String doInBackground(String... params) {
try {
String edt1Text = (String) params[0];
String edt2Text = (String) params[1];
String link = "http://"+cafeIP+"/InsertData.php";
String data = URLEncoder.encode("ed1txt", "UTF-8") + "=" + URLEncoder.encode(edt1Text, "UTF-8");
data += "&" + URLEncoder.encode("ed2txt", "UTF-8") + "=" + URLEncoder.encode(edt2Text, "UTF-8");
URL url = new URL(link);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(conn.getOutputStream());
outputStreamWriter.write(data);
outputStreamWriter.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
// Read Server Response
while ((line = reader.readLine()) != null) {
sb.append(line);
break;
}
Log.d("tag : ", sb.toString()); // php에서 결과값을 리턴
return sb.toString();
} catch (Exception e) {
return new String("Exception: " + e.getMessage());
}
}
}
InsertData task = new InsertData();
task.execute(ed1,ed2);
}
** 헉 대박 이거 잊으면 안됨 꼭 해야함
** manifest 셋팅
- AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:usesCleartextTraffic="true">
</application>
</manifest>
1. 인터넷 퍼미션
2. thread 오류가 나도 계속 진행하게함.