팀 내의 서버 프레임워크를 Django -> Spring Boot 로 마이그레이션 하자는 의사 결정이 내려왔다.

Java에 Spring Boot를 쓰면 커리어 적으로는 호재이기는 한데... 거의 2년 만에 만져보는거라 걱정이 되기도 한다.

많이 까먹은 김에, 처음 부터 다시 쌓아올린다고 생각하고 기초부터 차근차근 다져볼 생각이다. (시간이 허락한다면...)

 

본론으로 들어가면, 팀 내에서 프로젝트의 의존성을 gradle로 관리하기로 결정하여, 정리를 좀 하고 넘어가려고 한다.

 

Gradle 이란?

그루비(Groovy)를 기반으로 한 빌드 도구이다.

 

Ant Maven과 같은 이전 세대 빌드 도구의 단점을 보완하고 장점을 취합하여 만든 오픈소스로 공개된 빌드 도구라고 하는데, 정확히 어떤 단점을 보완했다는 것일까?

  • 직관적으로 봐도, 가독성 면에서 Gradle이 매우 뛰어나다. Maven은 스크립트를 XML로 정의하여 길이가 길고 이로인한 가독성이 떨어진다.
  • 빌드 및 테스트 시 성능이 앞도적으로 뛰어나다. Gradle은 캐시를 사용하기 때문에 테스트 반복 시 차이가 점점 더 커지고, 이로 인해 프로젝트의 규모가 커지면서 의존성이 늘어날수록 성능과 스크립트 품질의 차이가 심해진다.

 

Buildscript

buildscript에는 SpringBoot Version 정보, Maven Repository 정보, Dependency 모듈을 지정하여 스프링 부트 플러그인을 사용할 수 있는 기본 바탕을 정의한다. 

 

Apply

플러그인을 적용한다.

  • apply plugin: 'java' → java용 웹 프로젝트를 생성한다.
  • sourceCompatibility: '1.8' 호환 버전을 지정하여 java 웹 프로젝트에서 사용할 java를 명시한다.
  • apply plugin: 'io.spring.dependency-management' → Spring IO Platform의 Gradle Plugin인 dependency-management를 사용한다. 스프링 부트 1.x에서는 디폴트로 사용되었지만 2.x에서는 명시적으로 선언해 주어야 한다.

 

 

Dependency

프로젝트에서 사용할 모듈을 정의한다.

Dependency Options

implementation: 의존 라이브러리 수정시 본 모듈까지만 재빌드한다.
본 모듈을 의존하는 모듈은 해당 라이브러리의 api 를 사용할 수 없음


api: 의존 라이브러리 수정시 본 모듈을 의존하는 모듈들도 재빌드
본 모듈을 의존하는 모듈들도 해당 라이브러리의 api 를 사용할 수 있음


compileOnly: 이름에서 알 수 있듯이 compile 시에만 빌드하고 빌드 결과물에는 포함하지 않는다.
runtime 시 필요없는 라이브러리인 경우 (runtime 환경에 이미 라이브러리가 제공되고 있는가 하는 등의 경우)

runtimeOnly: runtime 시에만 필요한 라이브러리인 경우


annotationProcessor: annotation processor 명시 (ex:lombok)

 

testImplementation : 테스트 코드를 수행할 때만 적용.

 

References

https://cantcoding.tistory.com/59

 

Gradle 의존성 옵션 정리(Compile VS implementation,옵션)

Gradle 이란? 그래들(이하 Gradle)은 그루비(Groovy)를 기반으로 한 빌드 도구. Ant와 Maven과 같은 이전 세대 빌드 도구의 단점을 보완하고 장점을 취합하여 만든 오픈소스로 공개된 빌드 도구. 처음 Sprin

cantcoding.tistory.com

https://docs.gradle.org/current/userguide/what_is_gradle.html

 

What is Gradle?

Gradle bases its design on the following fundamentals: High performance Gradle avoids unnecessary work by only running tasks that need to do work because inputs or outputs have changed. Gradle uses various caches to reuse outputs from previous builds. With

docs.gradle.org

 

로컬에 저장되어 있는 이미지를 base64로 인코딩하여 프론트로 내보내는 방법을 알아보고자 한다.

 

(프론트에서 받아온 이미지를 로컬에 저장하고 DB에 그 경로를 저장하는 방법은 https://princeji-h.tistory.com/3 에 설명되어 있다.)

 

방법은 매우 간단하다.

읽고자 하는 파일을 FileInputStream으로 읽고 byte 배열에 저장한다. 주의할 점은 파일을 읽는 것이 끝나면 FileInputStream을 닫아줘야 한다는 것이다.

 

이후 해당 byte 배열을 base64로 인코딩하여 프론트에 전달한 뒤, 프론트 개발자에게 base64로 디코딩해달라고 부탁하면 된다.

 

데이터가 잘 넘어오는지 확인해보자.

 

포스트맨으로 위에서 구현한 메소드를 호출하는 API를 넘긴 결과이다.

 

결과 값으로 매우 긴 byte배열을 받아오는데, 이를 base64 디코더로 변환하면

위와 같이 이미지로 잘 변환이 되는 것을 확인할 수 있다.

 

야호

'Spring Boot' 카테고리의 다른 글

Spring Boot - Gradle  (0) 2023.03.29
비밀번호 해시 암호화  (0) 2021.05.10
웹서버가 도대체 무엇인가(웹서버와 WAS의 차이)  (0) 2021.05.03
DB에 이미지 저장  (0) 2021.05.02

스프링 부트에서 회원가입 시스템을 구현할 때, 입력한 비밀번호를 암호화 하여 저장하는 기능을 구현하고자 한다. (Spring Security 미사용)

 

MD5, SHA-1, SHA-256 등 다양한 해시함수가 있지만, 이 글에서는 SHA-256을 사용한다.

 

*참고로 SHA-256은 단방향 해시함수이기 때문에 로그인을 시도할 때에도 입력한 비밀번호를 같은 알고리즘으로 암호화 하여 DB의 비밀번호와 비교해야 한다.

String을 변수로 받고, MessageDigest 라이브러리를 사용하여 이를 암호화하고 얻은 byte배열을 다시 String으로 변환하여 반환하도록 구현했다.

 

*byte배열을 String으로 변환하는 방식은 다양하니, 각자 원하는 방식대로 사용하면 될 것 같다.

 

암호화가 잘 되는지 테스트를 해보기 위해 Controller를 만들어고 데이터를 날려볼 차례이다.

해당 예제는 회원가입시에 비밀번호 이외에도 이메일, 이름, 비밀번호 확인, 프로필 이미지(file) 정보를 추가적으로 저장하는 rest api 예제이다.

 

*DB에 이미지를 저장하는 방법이 궁금하면 princeji-h.tistory.com/3 참고

 

여기서는 비밀번호 암호화가 잘 되는지만 확인하면 될 것 같다.

 

 

포스트맨으로 위와 같이 데이터를 날려보았다.

 

 

DB를 확인해보면, 

위와 같이 "123"이 암호화되어 저장된 것을 확인할 수 있다.

 

SHA256 해시 변경 페이지를 사용하여 맞게 변환 됐는지 확인해보자.

www.convertstring.com/ko/Hash/SHA256emn178.github.io/online-tools/sha256.html 에서 확인할 수 있다.

 

변경이 잘 된 것을 확인할 수 있다.

 

야호

Reference

kshman94.tistory.com/84

needjarvis.tistory.com/251

Web Server

  • 클라이언트로부터 HTTP 요청을 받아 정적인 컨텐츠를 제공하는 프로그램
  • Ex) Apache HTTP Server

-> WAS를 거치지 않고 바로 자원을 제공한다. 동적인 컨텐츠가 필요할 경우 WAS에 요청을 전달한다.

 

 

WAS

  • 동적인 컨텐츠를 제공하기 위해 만들어진 Application Server
  • Ex) Apache Tomcat

->HTTP를 통해 애플리케이션을 수행해주는 미들웨어 (Web Container 혹은 Servlet Container)라고도 불린다.

 

*실제 동적 처리를 하는 것은 Servlet이고 WAS는 Servlet들은 관리하는 컨테이너

 

 

Web Server와 WAS의 분리

결론 : Web Server와 WAS의 분리된 사용을 통한 자원 이용의 효율화

  • Web Server
    • 클라이언트에 이미지와 같은 정적인 파일을 보낼 때, 보내진 HTML 문서에 따라 필요한 이미지만 보낸다.
    • 이러한 파일을 Web Server에 저장해 놓으면 필요시 WAS를 거치지 않아도 되기 때문에 서버의 부담이 덜하다.
  • WAS
    • WAS가 존재하지 않는다면 클라이언트에서 필요한 결과값을 모두 미리 만들어 놓고 수행해야 한다.
    • 이는 자원의 한계상 불가능하다.
    • WAS를 통해 요청에 맞는 데이터를 DB에서 가져와서 로직에 맞게 동적으로 결과를 만들어서 제공해야 한다. 

WAS는 DB 조회 및 로직 처리로 인해 이미 바쁘기 때문에 단순한 정적 컨텐츠는 Web Server에서 빠르게 클라이언트에 넘겨주는 것이 효율적이다.

 

References

gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html

'Spring Boot' 카테고리의 다른 글

Spring Boot - Gradle  (0) 2023.03.29
로컬 파일(이미지) 프론트로 내보내는 REST API  (0) 2021.05.20
비밀번호 해시 암호화  (0) 2021.05.10
DB에 이미지 저장  (0) 2021.05.02

Spring Boot와 Maria DB를 사용하여 클라이언트에서 넘어오는 이미지 데이터를 처리하는 방법을 알아보고자 한다.

 

방법은 다음과 같이 2가지이다.

1. binary 형식인 이미지 데이터를 base64로 인코딩하면여 json 형식으로 서버에 보내고 DB에 그대로 저장한다.

 

-> 이 방식을 사용하려면 클라이언트에서 이미지 데이터를 base64 형식으로 인코딩하여 백엔드에 전달해야 한다.

인코딩을 하면 매우 긴 문자열 형태로 데이터가 변환되기 때문에 이를 DB에 저장하기 위해서는 BLOB형태로 저장해야 한다.

 

<진짜 너무 긴 문자열>

이런식의 말도 안되게 긴 문자열을

위와 같은 Entity에

위와 같이 byte[]형식으로 변환하여 BLOB형태로 DB에 저장하고 꺼내야 하기 때문에 효율이 박살이 난다.

꺼내서 이미지로 사용할 때에도 base64 형태인 문자열을 디코딩하여 이미지로 변환해야 하기 때문에 효율이 더욱 낮아지게 된다.

 

<장점>

서버에 이미지를 저장할 필요가 없기 때문에 간편하다.

 

<단점>

그 외 모두

-> 효율이 너무 안좋고, 심지어 인코딩 시에 크기가 33% 정도 증가하므로 메모리 낭비 역시 심하다.

 

결론: 이미지를 DB에 바로 저장하는 방법 사용X

 

 

2. 이미지를 웹 서버의 특정 경로에 저장하고 DB에는 해당 경로만 저장한다.

대부분의 경우 이 방식으로 이미지를 포함한 여러 파일들을 업로드 한다고 보면 된다.

 

파일을 업로드 하면 로컬에 저장하고 그 경로를 DB에 저장하는 방식으로 구현했는데, 추후에는 AWS와 연동하여 이 작업을 수행할 예정이다.

 

<Service>

우선 위와 같이 InputStream으로 파일을 읽어오고 저장하는 메소드를 Service 계층의 FileService 클래스에 정의했다.

 

여기서 MultipartFile 요청은 큰 파일을 청크 단위로 쪼개서 효율적으로 파일을 업로드 할 수 있게 해주며, 스프링에서 제공하는 타입이다.

 

참고로 @Value 어노테이션은 yml 파일이나 properties파일에 접근하게 해주는 기능을 한다.

 

필자는 yml을 사용하기 때문에 위와 같이 정의했고, 이렇게 되면 uploadDir변수의 디폴트 값이 D:\Capstone\Image\가 된다.

 

<Controller>

 

Controller 부분은 위와 같이 구현했다.

 

내가 받아오고자 하는 파일은 USER 엔티티의 프로필 사진이기 때문에, 어떤 유저에게 등록할지를 알기 위해 PathVarible로 userId를 전달받도록 했다. 

 

넘어온 userId와 파일을 저장한 경로를 setImageDir메소드의 매개변수로 넘겨주면 해당 USER의 데이터베이스에 해당 경로가 저장된다.

 

 

 

이제 로직이 잘 돌아가는지 Postman으로 테스트해볼 차례이다. 

기본 세팅은 위와 같다. Header의 Content-Type에 아무것도 넣지 않아야 하며, Body는 form-data로 변경하고 KEY값은 Controller에서 지정한 @RequestParam의 이름과 같아야한다. VALUE는 file로 변경하고 시즈.png라는 이미지를 업로드 했다.

 

DB를 보면 해당 경로가 잘 들어간 것을 확인할 수 있다.

 

야호

 

Reference

velog.io/@byeol4001/Base-64%EC%99%80-base64-img-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

umanking.github.io/2020/01/02/spring-fileupload/

medium.com/@kwangsoo/multipartfil-upload-download-a236bb71093emedium.com/@kwangsoo/multipartfil-upload-download-a236bb71093e

+ Recent posts