본문 바로가기
AndroidStudio

웹 서비스 HTTP통신 : 이미지만 올리기*

by EUN-JI 2023. 9. 6.

EX68

VSC > 05Retrofit> aaa.php

<?php
    header('Content-Type:text/plain; charset=utf-8');

    //파일데이터 임시저장소에 있고 파일에 대한 정보만 이 php로 전달됨
    $file= $_FILES['img'];  //img ==안드로이드에서 저장한 것
   
    $srcName= $file['name'];  //원본파일명
    $size= $file['size']; //파일크기
    $type= $file['type'];  //파일타입
    $tmpName= $file['tmp_name']; //임시저장소의 위치 ==이름이 정해져있음

    //임시저장소에 있는 파일을 원하는 위치로 이동
    $dstName= "./image/" . date('YmdHis') . $srcName;
    move_uploaded_file($tmpName,$dstName);

    //잘 받았는지 확인
    echo $srcName . "<\n>";
    echo $size . "<\n>";
    echo $type . "<\n>";
    echo $tmpName . "<\n>";
    echo $dstName;


?>

Gradle>

android{

buildFeatures{
    viewBinding true

}

dependencies{ 5개 무조건 하기

implementation 'com.github.bumptech.glide:glide:4.16.0'//image load library
implementation 'com.squareup.retrofit2:retrofit:2.9.0'   //retrofit library
implementation 'com.google.code.gson:gson:2.10.1'   //retrofit library
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'   //retrofit library
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'//retrofit library

}

 

manifest>퍼미션

<uses-permission android:name="android.permission.INTERNET"/>
android:usesCleartextTraffic="true"

xml. mainac

<?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:orientation="vertical"
    android:padding="16dp"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_select"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="select image"/>
    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:text="image path"/>
    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="300dp"/>
    <Button
        android:id="@+id/btn_upload"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:backgroundTint="@color/black"
        android:text="upload image"/>

RetrofitService.java

package com.eunji0118.ex68retrofitimageupload;

import okhttp3.MultipartBody;
import retrofit2.Call;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
//컴퓨터가 볼수있는 주석 @
public interface RetrofitService {
    //같이 써야함.. @Multipart //이미지를 담는 박스
    @Multipart
    @POST("05Retrofit/aaa.php")
    Call<String> uploadImage(@Part MultipartBody.Part file);


}

mainAC.JAVA

package com.eunji0118.ex68retrofitimageupload;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.loader.content.CursorLoader;

import android.Manifest;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.eunji0118.ex68retrofitimageupload.databinding.ActivityMainBinding;

import java.io.File;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;

public class MainActivity extends AppCompatActivity {
    ActivityMainBinding binding;

    String imagePath;  //이미지의 실제경로 6

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding= ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        binding.btnSelect.setOnClickListener(view -> clickSelect());
        binding.btnUpload.setOnClickListener(view -> clickUpload());

    }

    void clickSelect(){
        Intent intent=new Intent(MediaStore.ACTION_PICK_IMAGES);
        //3.
        resultLauncher.launch(intent);
    }
    //대행사2
    ActivityResultLauncher<Intent> resultLauncher=registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),result -> {
        //4
        if (result.getResultCode()==RESULT_CANCELED) return;

        Intent intent=result.getData();
        Uri uri=intent.getData();
        //문자열로 출력해
        binding.tv.setText(uri.toString());
        //글라이드 싱크 후 사용.
        Glide.with(this).load(uri).into(binding.iv);
        //uri는 파일의 실제 경로가 아님. 미디어 저장소의 DB경로임.
        //http 통신으로 파일을 전송하려면 DB주소가 아니라.. 실제 파일의 경로가 필요함.
        //7. 이경로 확인 후 업로드해야함. !!
        imagePath=getRealPathFromUri(uri);
        binding.tv.setText(imagePath);

    });

    //Uri -- > 절대경로로 바꿔서 리턴시켜주는 메소드  /메모장 복사 5
    String getRealPathFromUri(Uri uri){
        String[] proj= {MediaStore.Images.Media.DATA};
        CursorLoader loader= new CursorLoader(this, uri, proj, null, null, null);
        Cursor cursor= loader.loadInBackground();
        int column_index= cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String result= cursor.getString(column_index);
        cursor.close();
        return  result;
    }

    void clickUpload(){
        if (imagePath==null){
            Toast.makeText(this, "이미지를 선택하세요.", Toast.LENGTH_SHORT).show();
            return;  //업로드 못하게 리턴
        }
        //레트로핏 라이브러리를 이용하여 이미지파일 업로드하기
        //1. 레트로핏 객체 생성
        Retrofit.Builder builder=new Retrofit.Builder();
        builder.baseUrl("http://lej0118.dothome.co.kr");
        builder.addConverterFactory(ScalarsConverterFactory.create());
        Retrofit retrofit=builder.build();

        //2. 원하는 작업에 대한 명세서를 작성하는 인터페이스와 추상메소드를 설계 -레트로핏서비스.JAVA/ uploadImage() 추상메소드

        //3. 인터페이스를 객체로 생성
        RetrofitService retrofitService=retrofit.create(RetrofitService.class);

        //4. 원하는 작업명세를 호출  - 이떄 통신안됨. 업로드하는 코드를 가진 call객체를 리턴해줌.

        //이미지 파일을 http통신용 파일 택배박스로 포장하기
        File file=new File(imagePath);
        RequestBody requestBody= RequestBody.create(MediaType.parse("image/*"),file); //진공팩같은 객체
        MultipartBody.Part part=MultipartBody.Part.createFormData("img",file.getName(),requestBody);
        //위세줄이면 파일 보냄.
        Call<String> call =retrofitService.uploadImage(part);

        //5.네트워크 작업 실행 //enqueue 활주로에 들어가
        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {

                String s=response.body();
                new AlertDialog.Builder(MainActivity.this).setMessage(s).create().show();
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Toast.makeText(MainActivity.this, "error"+t.getMessage(), Toast.LENGTH_SHORT).show();

            }
        });



    }


}