반응형
SpringBoot에서 JPA Repository 를 활용해 CRUD를 구현했습니다.
https://kakaroo.tistory.com/49
이제, Android UI에서 input 을 서버에 주고 서버의 결과를 화면에 출력하는 것을 만들어 보겠습니다.
기본적인 UI는 아래처럼 JPA repository 데이터를 Post/Put/Get/Delete 할 수 있게 간단한 UI를 생성합니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">
<EditText
android:id="@+id/et_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:inputType="text"
android:hint="Title"
app:layout_constraintBottom_toTopOf="@+id/et_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:inputType="text"
android:hint="Content"
app:layout_constraintBottom_toTopOf="@+id/et_author"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_title" />
<EditText
android:id="@+id/et_author"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:inputType="text"
android:hint="Author"
app:layout_constraintBottom_toTopOf="@+id/radio_post"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_content" />
<RadioButton
android:id="@+id/radio_post"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="Post"
app:layout_constraintBottom_toTopOf="@+id/et_getId"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_author" />
<RadioButton
android:id="@+id/radio_put"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="Put"
app:layout_constraintStart_toEndOf="@+id/radio_post"
app:layout_constraintTop_toBottomOf="@+id/et_author" />
<Button
android:id="@+id/bt_post_put"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:text="POST/PUT"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_author" />
<EditText
android:id="@+id/et_getId"
android:layout_width="64dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:inputType="number"
android:hint="ID"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/radio_post" />
<Button
android:id="@+id/bt_get"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:layout_marginStart="8dp"
android:text="Get"
app:layout_constraintBottom_toBottomOf="@+id/et_getId"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="@+id/et_getId"
app:layout_constraintTop_toTopOf="@+id/et_getId"
app:layout_constraintVertical_bias="0.0" />
<Button
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintHorizontal_weight="1"
android:layout_marginHorizontal="12dp"
android:id="@+id/bt_delete"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Delete"
app:layout_constraintBottom_toBottomOf="@+id/bt_get"
app:layout_constraintStart_toEndOf="@+id/bt_get"
app:layout_constraintTop_toTopOf="@+id/bt_get" />
<Button
android:id="@+id/bt_getall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:text="GET ALL"
app:layout_constraintBottom_toBottomOf="@+id/bt_get"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="@+id/bt_delete"
app:layout_constraintTop_toTopOf="@+id/bt_get"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/tv_result"
android:layout_width="51dp"
android:layout_height="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="48dp"
android:layout_marginEnd="16dp"
android:text="Result"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_getId" />
</androidx.constraintlayout.widget.ConstraintLayout>
Layout View에 action을 주기위해 View binding을 설정합니다.
<build.gradle>
viewBinding {
enabled = true
}
import com.kakaroo.jpatestkotlin.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
//전역변수로 binding 객체선언
private var mBinding: ActivityMainBinding? = null
// 매번 null 체크를 할 필요 없이 편의성을 위해 바인딩 변수 재 선언
private val binding get() = mBinding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_main)
mBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}
View Binding?
안드로이드 개발 초기에는 findViewById를 이용해서 xml의 뷰와 변수를 연결시켜주는 그런 작업을 해야 했습니다.
한 두 개 정도는 상관없지만, 복잡한 UI (여기서는 간단하지만...)에는 한 페이지에 들어가는 뷰가 아주 많게 됩니다.
view binding은 이 findViewById를 대체할 수 있는 기능이다.
Failed to connect to localhost/127.0.0.1:8080
이미 JPA 를 이용하기 위해 서버를 local 로 열었으므로 안드로이드로 동일 IP로 연결시 위 error가 발생합니다.
이 때는 localhost가 아니라 10.0.2.2 를 써보시면 될 것 같습니다.
< Post >
< Get >
< Get All >
< Put >
requestbody를 넣지 않았더니 400 Bad Request 가 발생했습니다.
수정한 결과 정상적으로 처리됩니다.
< Delete >
URL connection, request, response 처리하는 코드
// URL 객체 생성
val url = URL(page)
// 연결 객체 생성
val httpConn: HttpURLConnection = url.openConnection() as HttpURLConnection
// Post 파라미터
//val params = ("param=1"
// + "¶m2=2" + "sale")
// 결과값 저장 문자열
val sb = StringBuilder()
// 연결되면
if (httpConn != null) {
Log.i(Common.LOG_TAG, page + " connection succesfully")
result += "Connection successfully!" + "\n"
// 응답 타임아웃 설정
httpConn.setRequestProperty("Accept", "application/json")
httpConn.setRequestProperty("Content-type", "application/json; utf-8");
httpConn.setConnectTimeout(Common.HTTP_CONNECT_TIMEOUT)
// POST 요청방식
httpConn.setRequestMethod(Common.HTTP_REQ_METHOD_LIST[method])
// 포스트 파라미터 전달
//httpConn.getOutputStream().write(params.toByteArray(charset("utf-8")))
//--------------------------
// 서버로 값 전송
//--------------------------
if(bNeedRequestParam) {
var json : String = ""
// build jsonObject
val jsonObject = JSONObject()
jsonObject.accumulate("title", binding.etTitle.text.toString())
jsonObject.accumulate("content", binding.etContent.text.toString())
jsonObject.accumulate("author", binding.etAuthor.text.toString())
// convert JSONObject to JSON to String
json = jsonObject.toString()
// OutputStream으로 POST 데이터를 넘겨주겠다는 옵션.
httpConn.doOutput = true
// InputStream으로 서버로 부터 응답을 받겠다는 옵션.
httpConn.doInput = true
val os : OutputStream = httpConn.outputStream
os.write(json.toByteArray(Charsets.UTF_8))
os.flush()
os.close()
}
// url에 접속 성공하면 (200)
var status : Int = try {
httpConn.responseCode
} catch (e: IOException) {
// HttpUrlConnection will throw an IOException if any 4XX
// response is sent. If we request the status again, this
// time the internal status will be properly set, and we'll be
// able to retrieve it.
Log.e(Common.LOG_TAG, "URL responseCode error :$e")
httpConn.responseCode
}
result += "Respose code:" + status + "\n"
if(status == HttpURLConnection.HTTP_OK) {
// 결과 값 읽어오는 부분
val br = BufferedReader(
InputStreamReader(
httpConn.inputStream, "utf-8"
)
)
var line: String?
while (br.readLine().also { line = it } != null) {
sb.append(line)
}
// 버퍼리더 종료
br.close()
Log.i(Common.LOG_TAG, "결과 문자열 :$sb")
if(!bJsonResponseParam) {
result + sb.toString()
} else { //return 값이 JSON 이다.
//{"id":2,"title":"Title1","content":"Content1","author":"Author1"}
// 안드로이드에서 기본적으로 제공하는 JSONObject로 JSON을 파싱
// getAll인 경우 JsonArray 형태이므로
if(method == Common.HTTP_GET_ALL) {
val jsonArray = JSONTokener(sb.toString()).nextValue() as JSONArray
for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i)
val title = jsonObject.getString("title")
val content = jsonObject.getString("content")
val author = jsonObject.getString("author")
result += "title: "+ title + "\ncontent: " + content + "\nauthor: " + author +"\n"
}
} else {
val jsonObject = JSONObject(sb.toString())
val title = jsonObject.getString("title")
val content = jsonObject.getString("content")
val author = jsonObject.getString("author")
result += "title: "+ title + "\ncontent: " + content + "\nauthor: " + author +"\n"
}
}
}
// 연결 끊기
httpConn.disconnect()
}
//백그라운드 스레드에서는 메인화면을 변경 할 수 없음
// runOnUiThread(메인 스레드영역)
runOnUiThread {
Toast.makeText(applicationContext, "응답$sb", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Log.e(Common.LOG_TAG, "HttpURLConnection error :$e")
result += "HttpURLConnection error! $e"
} finally {
binding.tvResult.setText(result)
}
}
th.start()
Android에서 json parsing 방법은 아래를 참조하였습니다.
ref : https://devsnote.com/writings/2338
Source : https://github.com/kakarooJ/JPA-Android-byKotlin
반응형
'Web' 카테고리의 다른 글
1. AWS 서버 환경 구축 (AWS EC2) (0) | 2022.03.04 |
---|---|
1. SpringBoot - JPA server using MySQL (0) | 2022.02.18 |
Spring Boot - Eclipse Maven으로 Spring Web Layer 실습 (0) | 2022.02.14 |
3 - Spring Boot - 웹화면 구성 with JPA, Mustache (0) | 2022.02.11 |
Spring Web Layer (공사중...) (0) | 2022.02.07 |