본문 바로가기
ICIA 수업일지

2021.10.01 수업일지 (안드로이드 기초, MySQL, Web Server)

by 주성씨 2021. 10. 1.

- 지금까지 DB연결을 위한 Tomcat Servlet, Node.js 등을 이용해봤었다.

- MySQL과 안드로이드는 다이렉트로 연결이 안되서 웹서버(웹프로그램)를 중간에 만들어 연결해줘야한다. 앱 - 웹 - DB의 연결 구조라고 생각하면 된다.

 

- 주소관리 앱을 만들어서 사진까지 등록해보도록 하겠다.

 

- DB Table을 만들도록 하겠다.

 

- MySQL

- db는 어떤걸 사용해도 상관없다. 해당 db에 table을 만들겠다.

#2021.10.01
# 주소록 테이블을 만들겠다.
use sys;
create table users(
	id int auto_increment primary key,
    name nvarchar(20),
    tel nvarchar(20),
    address nvarchar(200)
);

 

확인

 

- table에 data를 insert 해주겠다.

photo.zip
0.24MB

insert into users(name,tel,address,photo) values('송중기','010-0101-0101','인천시 미추홀구 주안동','img01.png');
insert into users(name,tel,address,photo) values('조승우','010-0202-0202','인천시 중구 신포동','img02.png');
insert into users(name,tel,address,photo) values('지성','010-0303-0303','인천시 부평구 부평동','img03.png');
insert into users(name,tel,address,photo) values('조인성','010-0404-0404','인천시 계양구 계양동','img04.png');
insert into users(name,tel,address,photo) values('현빈','010-0505-0505','인천시 강화군 강화면','img05.png');

select * from users;

 

insert 확인

 

- Node.js 작업을 위해 VSC Open

- Terminal open - 프로젝트 생성

C:\data\node>express -e ex10

 

- npm install - 라이브러리 설치

C:\data\node\ex10>npm install

 

- nodemon 설치

C:\data\node\ex10>npm install nodemon -g

 

- Mysql 설치

C:\data\node\ex10>npm install mysql

 

- C:\data\node\ex10\package.json

{
  "name": "ex10",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "ejs": "~2.6.1",
    "express": "~4.16.1",
    "http-errors": "~1.6.3",
    "morgan": "~1.9.1",
    "mysql": "^2.18.1" <<<---
  }
}

 

확인

 

- C:\data\node\ex10\routes\users.js

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  // send로 해당 데이터 출력
  res.send('respond with a resource');
});

module.exports = router;

 

- C:\data\node\ex10\routes\users.js

var express = require('express');
var router = express.Router();
var mysql = require('mysql');

var db = mysql.createConnection({
  host:'localhost',
  user:'root',
  password:'1111',
  database:'sys'
})

/* GET users listing. */
router.get('/', function(req, res, next) {

  var sql = "select * from users";
  db.query(sql,function(err,rows){
    // send로 해당 데이터 출력
    res.send(rows);
  });
});

module.exports = router;

 

확인

 

- 이미지를 담을 폴더를 생성하겠다. 해당 폴더에 photo 폴더에 담은 이미지를 넣는다. 이미지를 넣은 후 서버를 재시작한다.

- C:\data\node\ex10\public\(new)upload - folder

확인

 

확인

 

- localhost 로 접속 가능하지만 ip로도 가능하다.

ip 확인

 

확인

 

 

- 이제 안드로이드 앱 작업을 하도록 하겠다.

 

- ex07이라는 새로운 프로젝트를 생성하겠다.

- build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 30 <<<---
    buildToolsVersion "30.0.0" <<<---

    defaultConfig {
        applicationId "com.example.ex07"
        minSdkVersion 26 <<<---
        targetSdkVersion 30 <<<---
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {  <<<---
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    implementation 'com.android.support:design:30.0.0'  <<<---
    implementation 'com.squareup.retrofit2:retrofit:2.2.0'  <<<---
    implementation 'com.squareup.retrofit2:converter-gson:2.2.0'  <<<---
    implementation 'com.squareup.picasso:picasso:2.5.2'  <<<---
    implementation 'de.hdodenhof:circleimageview:3.1.0'  <<<---

}

 

확인

 

 

- src/main/res/drawable/(new)ic_person.xml - 사람 이미지가 없을때 기본값 이미지

- src/main/java/com/example/ex07/MainActivity.java

package com.example.ex07;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportActionBar().setTitle("사용자관리");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_person);
    }

//    @Override
//    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
//        return super.onOptionsItemSelected(item);
//    }
}

 

- src/main/res/layout/activity_main.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=".MainActivity">

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

 

- 메인에 들어갈 아이템 xml 생성

- src/main/res/layout/(new)item_user.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#03A9F4"
    android:padding="10sp">
    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/photo"
        android:layout_width="70sp"
        android:layout_height="70sp"
        android:src="@drawable/ic_person"
        android:layout_marginRight="20sp"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ffffff"
        android:text="아무개"
        android:textSize="20sp"
        android:layout_toRightOf="@id/photo"
        android:textStyle="bold"/>
    <TextView
        android:id="@+id/tel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ffffff"
        android:text="010-0000-0000"
        android:textSize="15sp"
        android:layout_toRightOf="@id/photo"
        android:layout_below="@id/name"/>
    <TextView
        android:id="@+id/address"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ffffff"
        android:text="뉴욕주 뉴욕시 뉴욕면"
        android:textSize="15sp"
        android:layout_toRightOf="@id/photo"
        android:layout_below="@id/tel"/>
</RelativeLayout>

 

- db 연결을 위한 인터넷 권한 설정

- src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ex07">
    <uses-permission android:name="android.permission.INTERNET" />
.....
</manifest>

 

- src/main/java/com/example/ex07/(new)User.java - java class

package com.example.ex07;

public class User {
    private int id;
    private String name;
    private String tel;
    private String address;
    private String photo;
    
    // generate getters and setters and toString

 

- src/main/java/com/example/ex07/MainActivity.java

package com.example.ex07;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    ArrayList<User> array = new ArrayList<>();
    ListView list;
    UserAdapter userAdapter = new UserAdapter();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportActionBar().setTitle("사용자관리");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_person);

        list = findViewById(R.id.list);
        list.setAdapter(userAdapter);

    }

    class UserAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return 5;
        }

        @Override
        public Object getItem(int i) {
            return null;
        }

        @Override
        public long getItemId(int i) {
            return 0;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            view = getLayoutInflater().inflate(R.layout.item_user,viewGroup,false);
            return view;
        }
    }
}

 

확인

 

- 네트워크 접속을 위한 인터페이스 생성

- src/main/java/com/example/ex07/(new)Remote.java - Interface

package com.example.ex07;

import java.util.List;

import retrofit2.Call;
import retrofit2.http.GET;

public interface Remote {
    public static final String URL="http://192.168.0.27:3000/";

    //사용자목록
    @GET("users")
    Call<List<User>> listUser();
}

 

- src/main/java/com/example/ex07/MainActivity.java

package com.example.ex07;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;


import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import static com.example.ex07.Remote.URL;


public class MainActivity extends AppCompatActivity {
    List<User> array=new ArrayList<>();
    ListView list;
    UserAdapter userAdapter = new UserAdapter();

    Remote remote;
    Retrofit retrofit;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportActionBar().setTitle("사용관리");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_person);

        list = findViewById(R.id.list);
        list.setAdapter(userAdapter);

        retrofit=new Retrofit.Builder()
                .baseUrl(URL)
                .addConverterFactory(GsonConverterFactory.create()).build();
        remote = retrofit.create(Remote.class);

        Call<List<User>> call=remote.listUser();
        call.enqueue(new Callback<List<User>>() {
            @Override
            public void onResponse(Call<List<User>> call, Response<List<User>> response) {
                array = response.body();
                userAdapter.notifyDataSetChanged();
                System.out.println("...................." +array.size());
            }

            @Override
            public void onFailure(Call<List<User>> call, Throwable t) {
                System.out.println("error............." + t.toString());
            }
        });
    }

    class UserAdapter extends BaseAdapter{
        @Override
        public int getCount() {
            return array.size();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            convertView = getLayoutInflater().inflate(R.layout.item_user, parent, false);
            User user=array.get(position);
            TextView name=convertView.findViewById(R.id.name);
            name.setText(user.getName());
            TextView tel=convertView.findViewById(R.id.tel);
            tel.setText(user.getTel());
            TextView address=convertView.findViewById(R.id.address);
            address.setText(user.getAddress());
            CircleImageView photo=convertView.findViewById(R.id.photo);
            Picasso.with(MainActivity.this).load(URL+"/upload/" + user.getPhoto()).into(photo);
            return convertView;
        }
    }
}

 

- src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ex07">
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true"> <<<---
        .....

 

확인

 

- 만약 이미지가 없다면

.....
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
.....
            CircleImageView photo=convertView.findViewById(R.id.photo);
            if(user.getPhoto()==null || user.getPhoto().equals("")){
                photo.setImageResource(R.drawable.ic_person);
            }else {
                Picasso.with(MainActivity.this).load(URL+"/upload/" + user.getPhoto()).into(photo);
            }
            return convertView;
        }
.....

 

- 이제 회원 item을 클릭시 해당 정보로 이동할 수 있도록 하겠다. 우선 기본 액티비티를 만들겠다.

- src/main/java/com/example/ex07/(new)ReadActivity.java

package com.example.ex07;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;

public class ReadActivity extends AppCompatActivity {
    int id;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read);

        Intent intent = getIntent();
        id = intent.getIntExtra("id",0);

        getSupportActionBar().setTitle("사용자정보");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
            finish();
        }
        return super.onOptionsItemSelected(item);
    }
}

 

- src/main/res/layout/item_user.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#03A9F4"
    android:padding="10sp"
    android:id="@+id/item">
.....

 

- src/main/java/com/example/ex07/MainActivity.java

.....
		@Override
        public View getView(int position, View convertView, ViewGroup parent) {
            convertView = getLayoutInflater().inflate(R.layout.item_user, parent, false);
            User user=array.get(position);
            TextView name=convertView.findViewById(R.id.name);
            name.setText(user.getName());
            TextView tel=convertView.findViewById(R.id.tel);
            tel.setText(user.getTel());
            TextView address=convertView.findViewById(R.id.address);
            address.setText(user.getAddress());
            CircleImageView photo=convertView.findViewById(R.id.photo);
            if(user.getPhoto()==null || user.getPhoto().equals("")){
                photo.setImageResource(R.drawable.ic_person);
            }else {
                Picasso.with(MainActivity.this).load(URL+"/upload/" + user.getPhoto()).into(photo);
            }

            RelativeLayout item = convertView.findViewById(R.id.item); <<<---
            item.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this,ReadActivity.class);
                    intent.putExtra("id",user.getId());
                    startActivity(intent);
                }
            });
            return convertView;
        }
    }
}

 

- src/main/res/layout/(new)activity_read.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=".ReadActivity"
    android:background="#CE000000"
    android:padding="20sp">
    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/photo"
        android:layout_width="250sp"
        android:layout_height="250sp"
        android:src="@drawable/ic_person_250"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="20sp"
        android:layout_marginTop="50sp"/>
    <EditText
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="이름"
        android:textColorHint="#ffffff"
        android:textColor="#ffffff"
        android:layout_below="@id/photo"
        android:layout_marginBottom="20sp"
        android:padding="10sp"/>
    <EditText
        android:id="@+id/tel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="전화번호"
        android:textColorHint="#ffffff"
        android:textColor="#ffffff"
        android:layout_below="@id/name"
        android:layout_marginBottom="20sp"
        android:padding="10sp"/>
    <EditText
        android:id="@+id/address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="주소"
        android:textColorHint="#ffffff"
        android:textColor="#ffffff"
        android:layout_below="@id/tel"
        android:layout_marginBottom="20sp"
        android:padding="10sp"/>
</RelativeLayout>

 

확인

 

- 이제 read 결과를 해당 액티비티에 출력하도록 하겠다.

- VSC

- C:\data\node\ex10\routes\users.js

.....
// 사용자 정보 가지고 오기
router.get('/read', function(req,res){
  var id = parseInt(req.query.id);
  var sql = "select * from users where id=?";
  db.query(sql,[id],function(err,rows){
    res.send(rows[0]);
  });
});

module.exports = router;

확인

 

 

- 안드로이드 스튜디오

- 서버로 부터 정보 읽어오기

- src/main/java/com/example/ex07/Remote.java

.....
    //사용자정보
    @GET("users/read")
    Call<User> readUser(@Query("id") int id);
}

 

- src/main/java/com/example/ex07/ReadActivity.java

.....
public class ReadActivity extends AppCompatActivity {
    int id;

    EditText name,tel,address; <<<---
    CircleImageView photo; <<<---
    Remote remote; <<<---
    Retrofit retrofit; <<<---

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read);

        Intent intent = getIntent();
        id = intent.getIntExtra("id",0);

        getSupportActionBar().setTitle("사용자정보");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        name = findViewById(R.id.name); <<<---
        tel = findViewById(R.id.tel); <<<---
        address = findViewById(R.id.address); <<<---
        photo = findViewById(R.id.photo); <<<---
		// 이하  <<<---
        retrofit = new Retrofit.Builder().baseUrl(URL).addConverterFactory(GsonConverterFactory.create()).build();
        remote = retrofit.create(Remote.class);
        Call<User> call = remote.readUser(id);
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                System.out.println("............."+response.body());
                User user = response.body();
                name.setText(user.getName());
                tel.setText(user.getTel());
                address.setText(user.getAddress());
                Picasso.with(ReadActivity.this).load(URL+"/upload/"+user.getPhoto()).into(photo);
            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
                System.out.println("............."+t.toString());
            }
        });

    }

.....

 

확인

 

 

- 이제 입력, 수정, 삭제 작업을 해보도록 하겠다.

 

- update - VSC

- C:\data\node\ex10\routes\users.js

.....
// post user update
router.post('/update', function(req,res){
  var id = parseInt(req.query.id);
  var name = req.query.name;
  var tel = req.query.tel;
  var address = req.query.address;
  var sql = "update users set name=?,tel=?,address=? where id=?";

  db.query(sql,[name,tel,address,id], function(err,rows){
    res.send(rows);
  })

})

module.exports = router;

 

- 안드로이드 스튜디오

- src/main/res/drawable/(new)ic_baseline_update_24.xml

- src/main/res/layout/activity_read.xml

.....
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/update"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_baseline_update_24"
        android:backgroundTint="#3F51B5"
        android:layout_marginBottom="20sp"
        android:layout_marginRight="20sp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"/>
</RelativeLayout>

 

- src/main/java/com/example/ex07/Remote.java

.....
    //사용자정보 수정
    @POST("users/update")
    Call<Void> updateUser(@Query("id") int id,
                          @Query("name") String name,
                          @Query("tel") String tel,
                          @Query("address") String address);
}

 

- src/main/java/com/example/ex07/MainActivity.java

.....
public class MainActivity extends AppCompatActivity {
    List<User> array=new ArrayList<>();
    ListView list;
    UserAdapter userAdapter = new UserAdapter();

    Remote remote;
    Retrofit retrofit;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportActionBar().setTitle("사용자관리");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_person);

        list = findViewById(R.id.list);
        list.setAdapter(userAdapter);

        retrofit=new Retrofit.Builder()
                .baseUrl(URL)
                .addConverterFactory(GsonConverterFactory.create()).build();
        remote = retrofit.create(Remote.class);

        readUsers();  <<<---
    }

    class UserAdapter extends BaseAdapter{
        @Override
        public int getCount() {
            return array.size();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            convertView = getLayoutInflater().inflate(R.layout.item_user, parent, false);
            User user=array.get(position);
            TextView name=convertView.findViewById(R.id.name);
            name.setText(user.getName());
            TextView tel=convertView.findViewById(R.id.tel);
            tel.setText(user.getTel());
            TextView address=convertView.findViewById(R.id.address);
            address.setText(user.getAddress());
            CircleImageView photo=convertView.findViewById(R.id.photo);
            if(user.getPhoto()==null || user.getPhoto().equals("")){
                photo.setImageResource(R.drawable.ic_person);
            }else {
                Picasso.with(MainActivity.this).load(URL+"/upload/" + user.getPhoto()).into(photo);
            }

            RelativeLayout item = convertView.findViewById(R.id.item);
            item.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this,ReadActivity.class);
                    intent.putExtra("id",user.getId());
                    startActivity(intent);
                }
            });
            return convertView;
        }
    }

    // read method 만들기 <<<---
    public void readUsers(){
        Call<List<User>> call=remote.listUser();
        call.enqueue(new Callback<List<User>>() {
            @Override
            public void onResponse(Call<List<User>> call, Response<List<User>> response) {
                array = response.body();
                userAdapter.notifyDataSetChanged();
                System.out.println("...................." +array.size());
            }

            @Override
            public void onFailure(Call<List<User>> call, Throwable t) {
                System.out.println("error............." + t.toString());
            }
        });
    }

    @Override  <<<---
    protected void onRestart() {
        super.onRestart();
        readUsers();
    }
}

 

 

- 이제 수정을 할 수 있도록 하겠다.

- src/main/java/com/example/ex07/ReadActivity.java

.....
        });

        FloatingActionButton update = findViewById(R.id.update);
        update.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AlertDialog.Builder box = new AlertDialog.Builder(ReadActivity.this);
                box.setMessage("수정하시겠습니까?");
                box.setNegativeButton("아니오",null);
                box.setPositiveButton("예",null);
                box.show();
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
            finish();
        }
        return super.onOptionsItemSelected(item);
    }
}

 

확인

 

        });

        FloatingActionButton update = findViewById(R.id.update);
        update.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AlertDialog.Builder box = new AlertDialog.Builder(ReadActivity.this);
                box.setMessage("수정하시겠습니까?");
                box.setNegativeButton("아니오",null);
                box.setPositiveButton("예", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        String strName = name.getText().toString();
                        String strTel = tel.getText().toString();
                        String strAddress = address.getText().toString();
                        Call<Void> call = remote.updateUser(id,strName,strTel,strAddress);
                        call.enqueue(new Callback<Void>() {
                            @Override
                            public void onResponse(Call<Void> call, Response<Void> response) {
                                finish();
                            }

                            @Override
                            public void onFailure(Call<Void> call, Throwable t) {
                                System.out.println("........."+t.toString());
                            }
                        });
                    }
                });
                box.show();
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
            finish();
        }
        return super.onOptionsItemSelected(item);
    }
}

 

- src/main/res/drawable/(new)ic_baseline_delete_24.xml

- src/main/res/(new)menu/(new)read.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:title="삭제"
        android:id="@+id/delete"
        android:icon="@drawable/ic_baseline_delete_24"
        app:showAsAction="always"/>
</menu>

 

- src/main/java/com/example/ex07/ReadActivity.java

.....
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.delete:
                AlertDialog.Builder box = new AlertDialog.Builder(this);
                box.setMessage("삭제하시겠습니까?");
                box.setNegativeButton("아니오", null);
                box.setPositiveButton("예", null);
                box.show();
                break;
            case android.R.id.home:
            finish();
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.read,menu);
        return super.onCreateOptionsMenu(menu);
    }
}

 

 

- VSC

- C:\data\node\ex10\routes\users.js

.....
// post user delete
router.post('/delete',function(req,res){
  var id = parseInt(req.query.id);
  var sql = "delete from users where id=?";
  db.query(sql,[id],function(err,rows){
    res.send(rows);
  })
})


module.exports = router;

 

- 안드로이드 스튜디오

- src/main/java/com/example/ex07/Remote.java

.....
    //사용자 삭제
    @POST("users/delete")
    Call<Void> deleteUser(@Query("id") int id);
}

 

- src/main/java/com/example/ex07/ReadActivity.java

.....
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.delete:
                AlertDialog.Builder box = new AlertDialog.Builder(this);
                box.setMessage("삭제하시겠습니까?");
                box.setNegativeButton("아니오", null);
                box.setPositiveButton("예", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Call<Void> call = remote.deleteUser(id);
                        call.enqueue(new Callback<Void>() {
                            @Override
                            public void onResponse(Call<Void> call, Response<Void> response) {
                                finish();
                            }

                            @Override
                            public void onFailure(Call<Void> call, Throwable t) {
                                System.out.println("삭제 오류 : " +t.toString());
                            }
                        });
                    }
                });
                box.show();
                break;
            case android.R.id.home:
            finish();
        }
        return super.onOptionsItemSelected(item);
    }
.....

 

확인

 

 

- 이제 Insert하는 작업을 해보겠다.

- VSC

- C:\data\node\ex10\routes\users.js

.....
// post user insert
router.post('/insert',function(req,res){
  var name = req.query.name;
  var tel = req.query.tel;
  var address = req.query.address;
  var sql = "insert into users(name,tel,address) values(?,?,?)"
  db.query(sql,[name,tel,address],function(err,rows){
    res.send(rows);
  })
})

module.exports = router;

 

- AndStu

- src/main/java/com/example/ex07/Remote.java

.....
    //사용자 등록
    @POST("users/insert")
    Call<Void> insertUser(@Query("name") String name,
                          @Query("tel") String tel,
                          @Query("address") String address);
}

 

- MainActivity에 insert 버튼 추가

- src/main/res/drawable/(new)ic_baseline_add_24.xml

- src/main/res/layout/activity_main.xml

.....
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/insert"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:backgroundTint="#3F51B5"
        android:src="@drawable/ic_baseline_add_24"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="20sp"
        android:layout_marginRight="20sp"/>
</RelativeLayout>

 

- src/main/java/com/example/ex07/(new)InsertActivity.java

package com.example.ex07;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MenuItem;

public class InsertActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read);

        getSupportActionBar().setTitle("사용자등록");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
                finish();

        }
        return super.onOptionsItemSelected(item);
    }
}

 

- src/main/java/com/example/ex07/MainActivity.java

.....
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportActionBar().setTitle("사용자관리");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_person);

        list = findViewById(R.id.list);
        list.setAdapter(userAdapter);

        retrofit=new Retrofit.Builder()
                .baseUrl(URL)
                .addConverterFactory(GsonConverterFactory.create()).build();
        remote = retrofit.create(Remote.class);
        readUsers();

        FloatingActionButton insert = findViewById(R.id.insert); <<<---
        insert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, InsertActivity.class);
                startActivity(intent);
            }
        });
    }
.....

 

확인

 

- src/main/java/com/example/ex07/InsertActivity.java

.....
public class InsertActivity extends AppCompatActivity {

    // 입력값 변수 설정
    EditText name, tel, address;
    Remote remote;
    Retrofit retrofit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read);

        getSupportActionBar().setTitle("사용자등록");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        name = findViewById(R.id.name);
        tel = findViewById(R.id.tel);
        address = findViewById(R.id.address);

        retrofit = new Retrofit.Builder().baseUrl(URL).addConverterFactory(GsonConverterFactory.create()).build();
        remote = retrofit.create(Remote.class);

        FloatingActionButton insert = findViewById(R.id.update);
        insert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String strName = name.getText().toString();
                String strTel = tel.getText().toString();
                String strAddress = address.getText().toString();
                if(strName.equals("") || strTel.equals("") || strAddress.equals("")){
                    Toast.makeText(InsertActivity.this,"내용을 입력하세요.",Toast.LENGTH_SHORT).show();
                }else{
                    AlertDialog.Builder box = new AlertDialog.Builder(InsertActivity.this);
                    box.setMessage("사용자를 등록하시겠습니까?");
                    box.setNegativeButton("아니오",null);
                    box.setPositiveButton("예", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            Call<Void> call = remote.insertUser(strName,strTel,strAddress);
                            call.enqueue(new Callback<Void>() {
                                @Override
                                public void onResponse(Call<Void> call, Response<Void> response) {
                                    finish();
                                }

                                @Override
                                public void onFailure(Call<Void> call, Throwable t) {
                                    System.out.println("insert 오류"+t.toString());
                                }
                            });
                        }
                    });
                    box.show();
                }
            }
        });
    }
.....

 

확인

 

- 이미지 업로드를 해보겠다.

- 엘범에 있는 데이터를 가지고와서 업로드 해보겠다.

- src/main/java/com/example/ex07/InsertActivity.java

.....
public class InsertActivity extends AppCompatActivity {

    // 입력값 변수 설정
    EditText name, tel, address;
    Remote remote;
    Retrofit retrofit;

    // 이미지 저장을 위한 변수
    CircleImageView photo; <<<---

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read);

        getSupportActionBar().setTitle("사용자등록");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        name = findViewById(R.id.name);
        tel = findViewById(R.id.tel);
        address = findViewById(R.id.address);

        photo = findViewById(R.id.photo);  <<<---
        photo.setOnClickListener(new View.OnClickListener() { // InsertActivity의 이미지 클릭시
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                startActivityForResult(intent, 0);
            }
        });
.....

 

확인

 

 

- 엘범에서 가지고온 이미지 파일을 업로드하기 위한 권한설정을 해주겠다.

- src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ex07">

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

 

- 최초 실행시 스토리지 접근 권한 여부를 물어보도록 하겠다.

- src/main/java/com/example/ex07/MainActivity.java

public class MainActivity extends AppCompatActivity {
    List<User> array=new ArrayList<>();
    ListView list;
    UserAdapter userAdapter = new UserAdapter();

    Remote remote;
    Retrofit retrofit;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 최초실행시 권한 여부 물음
        permissionCheck(); <<<---

.....
    @Override
    protected void onRestart() {
        super.onRestart();
        readUsers();
    }

    public void permissionCheck(){
        String[] permissions= {Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA };
        ArrayList<String> checkPermission=new ArrayList<>();

        for(String permission:permissions){
            if(ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){
                checkPermission.add(permission);
            }
        }
        if(checkPermission.size() > 0){
            String[] reqPermission=checkPermission.toArray(new String[checkPermission.size()]);
            ActivityCompat.requestPermissions(this, reqPermission,100);
        }
    }
}

 

- src/main/java/com/example/ex07/InsertActivity.java

.....

public class InsertActivity extends AppCompatActivity {

    // 입력값 변수 설정
    EditText name, tel, address;
    Remote remote;
    Retrofit retrofit;

    // 이미지 저장을 위한 변수
    CircleImageView photo;
    String strFile;

.....

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if(requestCode==0){
//            photo.setImageURI(data.getData());
            try {
                String[] projection = {MediaStore.Images.Media.DATA};
                Cursor cursor = getContentResolver().query(data.getData(),projection,null,null,null);
                cursor.moveToNext();
                strFile = cursor.getString(cursor.getColumnIndex(projection[0]));
                // 안드로이드는 비트맺으로 읽어봐야 업로드가 가능하다.
                photo.setImageBitmap(BitmapFactory.decodeFile(strFile));
                cursor.close();
            }catch (Exception e){
                System.out.println("error : "+e.toString());
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
                finish();

        }
        return super.onOptionsItemSelected(item);
    }
}

 

확인

 

- 이제 사진을 DB 업로드 하는 작업을 하도록 하겠다.

- VSC

 

- 이미지 업로드를 위한 라이브러리 multer를 터미널에서 설치해주겠다.

C:\data\node\ex10> npm install multer

 

 

- C:\data\node\ex10\routes\users.js

.....

// 이미지 업로드 및 파일명 설정
var multer = require('multer');
var upload = multer({
  storage: multer.diskStorage({
    destination:(req,file,done) =>{
      done(null, './public/upload');
    },
    filename:(req,file,done) =>{
      done(null, Date.now()+'_'+file.originalname);
    }
  })
});

// post user insert
router.post('/insert',upload.single('photo'), function(req,res){
  var name = req.body.name;
  var tel = req.body.tel;
  var address = req.body.address;
  var photo = req.file.filename;
  var sql = "insert into users(name,tel,address,photo) values(?,?,?,?)"
  db.query(sql,[name,tel,address,photo],function(err,rows){
    res.send(rows);
  })
})

module.exports = router;

 

- AndStu

- src/main/java/com/example/ex07/Remote.java

.....
	// insert 수정하여 아래와 같이 한다.
    //사용자 등록 + 이미지 업로드
    @POST("users/insert")
    Call<Void> uploadUser(@Part("name") RequestBody name,
                          @Part("tel") RequestBody tel,
                          @Part("address") RequestBody address,
                          @Part MultipartBody.Part photo);
}

 

- src/main/java/com/example/ex07/InsertActivity.java

.....
        FloatingActionButton insert = findViewById(R.id.update);
        insert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String strName = name.getText().toString();
                String strTel = tel.getText().toString();
                String strAddress = address.getText().toString();
                if(strName.equals("") || strTel.equals("") || strAddress.equals("")){
                    Toast.makeText(InsertActivity.this,"내용을 입력하세요.",Toast.LENGTH_SHORT).show();
                }else{
                    AlertDialog.Builder box = new AlertDialog.Builder(InsertActivity.this);
                    box.setMessage("사용자를 등록하시겠습니까?");
                    box.setNegativeButton("아니오",null);
                    box.setPositiveButton("예", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            File file=new File(strFile);
                            System.out.println("strFile................." + strFile);
                            RequestBody reqFile=RequestBody.create(MediaType.parse("multipart/form-data"), file);
                            MultipartBody.Part partFile=MultipartBody.Part.createFormData("photo", file.getName(), reqFile);

                            RequestBody reqName=RequestBody.create(MediaType.parse("multipart/form-data"),strName);
                            RequestBody reqTel=RequestBody.create(MediaType.parse("multipart/form-data"),strTel);
                            RequestBody reqAddress=RequestBody.create(MediaType.parse("multipart/form-data"),strAddress);

                            Call<Void> call = remote.uploadUser(reqName,reqTel,reqAddress,partFile);
                            call.enqueue(new Callback<Void>() {
                                @Override
                                public void onResponse(Call<Void> call, Response<Void> response) {
                                    finish();
                                }

                                @Override
                                public void onFailure(Call<Void> call, Throwable t) {
                                    System.out.println("insert 오류"+t.toString());
                                }
                            });
                        }
                    });
                    box.show();
                }
            }
        });
.....

 

확인