달달한 스토리

728x90
반응형

 

오늘은 아쉬운 점이 있던 부분을 보안하여

 

새로운 방법을 알아냈기에 글을 써본다.

 

금연 앱도 거의 마무리했고, 현재 금연일기를 만드는 중이다.

 

사실 저번 글에서 mysql에 blob을 통해 이미지를 저장하는 법을 올렸는데,

 

디비에 저장하는 법을 알았지만, 그 저장된 것을 가져오는 부분을 공부하던 중,

 

커뮤니티에서 그런 방법보다는 서버에 이미지를 올려서 그 url를 연동하는 법이나,

 

파이어 베이스에 스토리지를 올리는 편이 간단하고, 효율이 좋다는 이야기를 듣게 되었다.

 

마침 잘 안 풀리기도 했고, 그래도 끝까지 blob으로 이미지를 가져오게 하는 법을 알고,

 

마무리하고 싶었지만, 뜻대로 된 것 같지는 않다. ㅠㅠ

 

그래서 이 blob은 이 정도 까지만 알고(언젠가 배울 날이 올 것이다.)

 

더 효율적이라는 파이어 베이스 스토리지에 대해 배워 보았다.

 

이번 프로젝트에서는 mysql만 사용하려 했는데,

 

파이어 베이스를 사용하게 될 줄 몰랐다.

 

파이어 베이스에 처음 계정을 만들고, 앱에 연동하는 부분은

 

인터넷에 많이 즐비하니 이 부분을 생략하고,

 

제일 중요한 이미지를 업로드하고, 다운로드하는 법을 기술하겠다.

 


해결법

 

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if true;
    }
  }
}

우선 프로젝트 권한은 이렇게 설정해준다.

 

모든 사용자가 읽고 쓰는 게 가능하다는 뜻이다.

 

이 보안에 대해서는 상황에 따라 다르지만, 현재는 예제를 보여주므로,

 

이런 식으로 입력해준다.

 

홈페이지에 나와있는 필수로 입력해줘야 하는 라이브러리도 입력을 해준다

 

(파이어 베이스 계정을 만들 때, 다 설명이 나와있다.)

 

만약 못 봤다면, 여기서 보도록 하자

 

https://firebase.google.com/docs/android/setup?authuser=0

 

Android 프로젝트에 Firebase 추가

기본 요건 Android 프로젝트가 준비되지 않았다면 빠른 시작 샘플 중 하나를 다운로드하여 Firebase 제품을 사용해 볼 수 있습니다. 다음 옵션 중 하나를 사용하여 Android 앱을 Firebase에 연결할 수 있

firebase.google.com

dependencies {
    // Import the BoM for the Firebase platform
    implementation platform('com.google.firebase:firebase-bom:26.5.0')

    // Declare the dependency for the Cloud Storage library
    // When using the BoM, you don't specify versions in Firebase library dependencies
    implementation 'com.google.firebase:firebase-storage'
}

그리고 스토리지 라이브러리를 사용하려면 이 두 가지 라이브러리는 필수로 넣어줘야 한다.

 

 

간단하게 3가지 방법으로 보여주고, 응용법을 보여주겠다.

(참고로 여러 가지 방법이 있지만, 나 같은 경우는 "로컬 파일에서 업로드 및 다운로드"

방법을 사용했다는 점을 참고 주길 바란다.)

 

이미지 저장하는 법(이미지 업로드)

 		//storage 객체 만들고 참조
        FirebaseStorage storage = FirebaseStorage.getInstance(); //스토리지 인스턴스를 만들고,
        StorageReference storageRef = storage.getReference();//스토리지를 참조한다
        //파일명을 만들자.
        String filename = "profile" + num + ".jpg";  //ex) profile1.jpg 로그인하는 사람에 따라 그에 식별값에 맞는 프로필 사진 가져오기
        Uri file = uri;
        Log.d("유알", String.valueOf(file));
        //여기서 원하는 이름 넣어준다. (filename 넣어주기)
        StorageReference riversRef = storageRef.child("profile_img/" + filename);
        UploadTask uploadTask = riversRef.putFile(file);
        
        // 새로운 프로필 이미지 저장
        // Register observers to listen for when the download is done or if it fails
        uploadTask.addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception exception) {
            }
        }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                Toast.makeText(getContext(), "프로필 이미지가 변경되었습니다.", Toast.LENGTH_SHORT).show();
            }
        });

첫 번째는 이미지를 스토리지에 저장하는 법이다.

 

스토리지 객체를 만들고, 참조를 한다.

 

그러고 나서 참조한 곳에 child메서드 안에 경로와 그 안에 어떤 이름으로 이미지를 저장할 것인지 입력해준다.

 

위와 같이 진행된다면, 성공할 시에,

 

스토리지 안에 profile_img1.jpg로 저장되게 된다.

 

 

이미지 삭제하는 법 (이미지 삭제)

 //storage
        FirebaseStorage storage = FirebaseStorage.getInstance(); //스토리지 인스턴스를 만들고,
        StorageReference storageRef = storage.getReference();//스토리지를 참조한다

        // TODO: 2021-03-17 기존 이미지 삭제
        // Create a reference to the file to delete
        StorageReference desertRef = storageRef.child("profile_img/" + "profile" + num + ".jpg"); //삭제할 프로필이미지 명
        // Delete the file
        desertRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception exception) {
            }
        });

이건 이미지를 삭제하는 방법이다.

 

저장과 똑같이 객체를 만들고, 참조를 해준 다음,

 

child메서드를 호출해 삭제를 할 이미지의 경로를 입력하여,

 

진행이 완료되면, 이미지의 삭제가 이루어진다.

 

이미지 가져오기, 불러오기(다운로드)

 /**이미지 (파이어베이스 스토리지에서 가져오기) */
    private void getFireBaseProfileImage(int num) {
        //우선 디렉토리 파일 하나만든다.
        File file = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES + "/profile_img"); //이미지를 저장할 수 있는 디렉토리
        //구분할 수 있게 /toolbar_images폴더에 넣어준다.
        //이 파일안에 저 디렉토리가 있는지 확인
        if (!file.isDirectory()) { //디렉토리가 없으면,
            file.mkdir(); //디렉토리를 만든다.
        }
        downloadImg(num); //이미지 다운로드해서 가져오기 메서드
    }

    /**이미지 다운로드해서 가져오기 메서드 */
    private void downloadImg(int num) {
        FirebaseStorage storage = FirebaseStorage.getInstance(); //스토리지 인스턴스를 만들고, //다운로드는 주소를 넣는다.
        StorageReference storageRef = storage.getReference();//스토리지를 참조한다
        storageRef.child("profile_img/" + "profile" + num + ".jpg").getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
            @Override
            public void onSuccess(Uri uri) {
               //성공시
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception exception) {
            //실패시
            }
        });
    }

마지막 이미지를 가져오는 법이다.

 

우선 두 가지 메서드를 임의로 지정한다.

 

파일 객체를 만들어, 스토리지에 디렉터리를 만드는 메서드를 호출한다.

 

File file = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES + "/profile_img"); //이미지를 저장할 수 있는 디렉토리
        //구분할 수 있게 /toolbar_images폴더에 넣어준다.
        //이 파일안에 저 디렉토리가 있는지 확인
        if (!file.isDirectory()) { //디렉토리가 없으면,
            file.mkdir(); //디렉토리를 만든다.
        }

이 부분을 보면 만약 /profile_img라는 폴더가 존재하지 않으면,

 

자동으로 /profile_img폴더를 만들어주는 코드라고 할 수 있다.

 

이 폴더를 만드는 메서드는 다른 곳에서 잘 활용하길 바란다.

 

그러고 나서, downloadImg 메서드를 호출한다.

 

이 메서드가 이미지를 가져오는 메서드라고 할 수 있다.

 

private void downloadImg(int num) {
        FirebaseStorage storage = FirebaseStorage.getInstance(); //스토리지 인스턴스를 만들고, //다운로드는 주소를 넣는다.
        StorageReference storageRef = storage.getReference();//스토리지를 참조한다
        storageRef.child("profile_img/" + "profile" + num + ".jpg").getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
            @Override
            public void onSuccess(Uri uri) {
               //성공시
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception exception) {
            //실패시
            }
        });

이미지 삭제와 비슷한 형태라고 할 수 있다.

 

객체를 만들고, 참조하여,

 

해당 파일에 경로와 가져올 이미지의 이름을 입력해주고,

 

성공 시에 uri로 그 값을 받아.

 

보통은 Glide라이브러리로 그 값을 받고,

 

uri값을 넣어 이미지 뷰에 넣는다.

 

혹시 모르니 글라이드 라이브러리도 남겨두겠다.

 

 dependencies {
 implementation 'com.github.bumptech.glide:glide:3.7.0' //글라이드 이미지(프로필 사진)
 ....
 }

 

 

이런 식으로 하면 이렇게 내가 원하는 경로에 이미지를 저장하고 불러올 수 있게 되는 것이다.

 

 

그렇다면 마지막으로 응용법을 알려주겠다.

 

상황을 하나 줘 보자.

 

만약에 사용자가 프로필 사진을 바꾸는 상황이다.

 

프로필을 바꿀 때마다 사진을 저장소에 저장한다?

 

너무 비효율적일 것이다.

 

그렇다면 방법은 프로필을 변경했을 때 기존에 있던

 

프로필 사진은 스토리지에서 지우고,

 

똑같은 이름으로 새로운 프로필 사진을 넣어주는 것이다.

 

그렇다면 프로필 사진을 아무리 바꿔도

 

스토리지에 저장된 프로필 사진은 계속 하나일 것이다.

 

코드로 살펴보자.

 

파이어 베이스 스토리지 응용(프로필 사진)

 // TODO: 2021-03-16 우선 파이어베이스 저장하는 법
    /**파이어베이스로 프로필 이미지 저장 및 기존 이미지 삭제 */
    private void createProfile_Photo_and_Delete() {
        //storage
        FirebaseStorage storage = FirebaseStorage.getInstance(); //스토리지 인스턴스를 만들고,
        StorageReference storageRef = storage.getReference();//스토리지를 참조한다
        //파일명을 만들자.
        String filename = "profile" + num + ".jpg";  //ex) profile1.jpg 로그인하는 사람에 따라 그에 식별값에 맞는 프로필 사진 가져오기
        Uri file = uri;
        Log.d("유알", String.valueOf(file));
        //여기서 원하는 이름 넣어준다. (filename 넣어주기)
        StorageReference riversRef = storageRef.child("profile_img/" + filename);
        UploadTask uploadTask = riversRef.putFile(file);

        // TODO: 2021-03-17 기존 이미지 삭제
        // Create a reference to the file to delete
        StorageReference desertRef = storageRef.child("profile_img/" + "profile" + num + ".jpg"); //삭제할 프로필이미지 명
        // Delete the file
        desertRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception exception) {
            }
        });


        // TODO: 2021-03-17 새로운 프로필 이미지 저장
        // Register observers to listen for when the download is done or if it fails
        uploadTask.addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception exception) {
            }
        }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                Toast.makeText(getContext(), "프로필 이미지가 변경되었습니다.", Toast.LENGTH_SHORT).show();
            }
        });
    }


    // TODO: 2021-03-16 존나 중요!! 파이어베이스 이미지 (시작할때 프로필 가져오기)
    /**프로필 이미지 (파이어베이스 스토리지에서 가져오기) */
    private void getFireBaseProfileImage(int num) {
        //우선 디렉토리 파일 하나만든다.
        File file = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES + "/profile_img"); //이미지를 저장할 수 있는 디렉토리
        //구분할 수 있게 /toolbar_images폴더에 넣어준다.
        //이 파일안에 저 디렉토리가 있는지 확인
        if (!file.isDirectory()) { //디렉토리가 없으면,
            file.mkdir(); //디렉토리를 만든다.
        }
        downloadImg(num); //이미지 다운로드해서 가져오기 메서드
    }

    /**이미지 다운로드해서 가져오기 메서드 */
    private void downloadImg(int num) {
        FirebaseStorage storage = FirebaseStorage.getInstance(); //스토리지 인스턴스를 만들고, //다운로드는 주소를 넣는다.
        StorageReference storageRef = storage.getReference();//스토리지를 참조한다
        storageRef.child("profile_img/" + "profile" + num + ".jpg").getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
            @Override
            public void onSuccess(Uri uri) {
                Log.d("오냐오냐", String.valueOf(uri));
                Glide.with(getContext()).load(uri).into(userView);
                dialogwithUri = uri; //첫 다이얼로그 프로필 보여주기
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception exception) {
            }
        });
    }

복잡할 수 있으니, 자신의 코드로 복사해서 사용해보길 바란다.

 

아 그리고 나 같은 경우는 상황이 상황인지라,

 

프래그먼트 위에서 위 코드를 사용했으므로,

 

File객체를 만들 때, getActivity 메서드를 지워주길 바란다.

 

getExternalFilesDir 메서드를 사용하려면,

 

액티비티 객체가 필요하므로,

 

저런 식으로 객체를 가져오기 위해

 

앞에다 붙여둔 것이다.

 

이 것 외에도 저런 식으로,

 

액티비티에서만 쓸 수 있는 메서드들이 많은데,

 

프래그먼트에서 사용하는 상황이 발생하면,

 

웬만하면 저 getActivity를 사용하길 바란다.

 

반대로 프래그먼트에서 사용되는 메서드를 액티비티에서

 

사용하게 된다면, 오류가 날 경우

 

getContext메서드를 사용하면 될 것이다.

 

오늘은 firebase storage 사용법을 알아보았다.

 

나 또한 구글 연동 로그인을 잠시 배울 때,

 

잠깐 사용했던 파이어 베이스이지만,

 

스토리지라는 저장소를 사용하고, 매우 편리하다는 것을 느꼈다.

 

아무래도 어느 정도는 무료지만, 사용량에 따라

 

요금이 발생될 수 있어, 이점은 고려해야 한다.

 

그럼 오늘은 여기까지 하겠다.

728x90
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading