728x90
반응형

생각보다 적은 시간 동안 삽질 끝에 스프링부트 프로젝트 배포에 성공했다.

수동 배포이다 보니 상시 실행 중 상태가 아니라

수정사항이 있을 경우라던지 한 번 서버를 가동할 때 손이 많이 가는 만큼

빠른 시일 내에 자동 배포어떤 방식으로 할지 고민해 보고 적용시켜 보아야겠다.

 

기존에 EC2, RDS는 생성해 두었던 상태고

RDS는 프로젝트에 미리 적용시켜 사용 중이었기 때문에

본론부터 바로! 서버 접속부터~어떤 과정으로 배포하였는지 기록해 본다.


먼저, 나는 node.js 프로젝트에서 사용한 3000번 포트만 열어둔 상태라

EC2 / 보안 그룹 / 인바운드 규칙에 8080 포트를 추가해 주었다. (본인 프로젝트 포트에 맞게 설정)

 

 

1. 서버에 접속 후 자바 설치

sudo apt-get install openjdk-11-jdk

// 설치된 자바 버전 확인
java --version

 

 

2. 깃허브 Repository에서 git clone / git pull

본인 Repository 들어가서 코드 클릭 후 HTTPS 링크 복사 (링크 우측에 창 아이콘 클릭 시 copy)

 

 

콘솔에서 아래 코드를 입력하여 프로젝트를 git clone, pull을 진행한다.

git clone https://github.com/jangmimi/LectureEvaluation-SpringBoot.git
git pull

 

 

3. 프로젝트 디렉터리로 이동

- ls로 현재 디렉토리의 폴더 및 파일 확인(보기)

- cd로 디렉토리 이동

 

 

4. Gradlew에 권한 부여 후 빌드

sudo chmod 777 ./gradlew
./gradlew build

여기서 테스트 코드 관련 에러가 발생헀는데

아래 에러 해결 부분에서 테스트 코드 제외 빌드에 관해 설명하였다.

 

 

5. 빌드 후 생성된 jar 파일을 java로 실행

빌드를 성공적으로 마친다면 build/libs 폴더에. jar 파일이 생성되었을 것이다.

나는 LectureEvaluationSpring-0.0.1-SNAPSHOT.jar 파일과 plane이 붙은 2개의 jar 파일이 생성되었다.

(plane jar 파일 생성에 대해서는 좀 더 알아보고, 다루는 글을 올려야겠다.)

 

 

./build/libs 폴더까지 진입해서 아래 코드와 같이 실행해도 되고

 

java -jar LectureEvaluationSpring-0.0.1-SNAPSHOT.jar

 

프로젝트 루트 폴더에서 경로를 같이 입력하고 실행해도 된다.

// jar 파일에 plane이 붙지 않은 파일로 선택
java -jar ./build/libs/생성된jar파일.jar

// 본인 프로젝트 예시
java -jar ./build/libs/LectureEvaluationSpring-0.0.1-SNAPSHOT.jar

 

이렇게 실행하면 매우 반가운 모습을 볼 수 있다.

 

URL창에 서버주소:8080(포트번호)를 입력하면 프로젝트 사이트가 정상적으로 가동된다.

 

아 물론, 위 내용은 정말 단순하게 기본적인 내용으로 작성된 글이다.

나는 프로젝트의 yml 파일에 중요한 정보들을  암호화했었고,

VM Options에 암호 키를 적용해서 프로젝트를 빌드해 왔어서

서버에 올린 프로젝트를 암호화 관련 설정 없이 빌드하면서

당연하게도 몇몇 에러를 마주하게 되었다.

아래에서 마주한 에러 내용들을 다뤄보겠다.


일단, 모든 코드에서 오타를 주의하도록 하자.

사소한 실수로 삽질하는 시간낭비는 최소화하는 것이 좋다. (경험에서 몸소 깨달은 바ㅎ)

 

1. 처음에 마주했던 에러 아닌 에러는 빌드 중 76% 정도에서 멈춤(무한대기) 현상이었는데

EC2 서버를 재부팅하고 다시 우분투 접속 후 빌드해 보니 해당 문제는 해결되었다.

 

2. 또다시 마주한 에러는 테스트코드에서의 빌드 실패였는데,

테스트 코드 빌드를 제외하고 실제 프로젝트 내용만 빌드하도록 설정하였다.

(테스트 코드가 완성되지 않은 것도 있고

본 스프링부트 프로젝트는 일단 배포하는 방식을 익혀보자는 목표로

테스트코드 빌드를 제외하게 되었다.)

 

*테스트코드 제외 빌드*

./gradlew build -x test

 

*여기서 나는 VM Options 설정 때문에 실제로 빌드 시에는 위 코드에 추가로 암호화 키 관련 코드를 넣어주었다.

(자바 실행할 때도 동일하게 암호화 키 관련 코드 삽입)

java -jar -Djasypt.encryptor.키변수명=키값 생성된jar파일명.jar

// 빌드에서도 동일하게 '-Djasypt.encryptor.키변수명=키값' 이부분을 추가

서버에서 실행 화면

 

 

이 내용은 모두에게 해결책이 될 수는 없을 것이다.

나와 유사하게 yml 혹은 properties 파일의 중요 정보를 jasypt로 암호화하고

VM Options에 설정하고 빌드한 경우에만 유사한 에러를 마주하고

이와 같은 방식으로 해결이 될 수도 있을 것이며

다양하게 검색을 해보고 정확하게 원인을 파악한다면 생각보다 간단하게 해결할 수 있을 것이다.

물론 오랜 시간이 걸릴 수도 있지만...(예전에 STS 세팅만 반나절 해본 경험 有 ^^)


+

파이널 프로젝트에서 한 팀원이 채팅 관련 배포를 하게 되면서 마주했던 에러가 있었는데

컨트롤러의 매핑에서 경로 부분 return 값의 '/' 문제로 페이지 호출이 되지 았던 것이었고

이 부분은 이미 숙지한 상태라서 연관 에러는 전혀 발생하지 않았다. (뿌듯)

원인은 찾아보니 리눅스에서 파일 위치를 찾아 못하는 상황이 발생해서 그렇다고 한다.

(Thymeleaf 템플릿 엔진을 사용할 경우 발생한다고 하는 것 같다.)

// 에러 발생 가능성 코드
@RequestMapping("/join")
public String join() {
    return "/user/join";
}
    
// 정상 작동 코드
@RequestMapping("/join")
public String join() {
    return "user/join";
}

// return에서 맨 앞 '/' 제거
// redirect의 경우는 정상적으로
// return 'redirect:/'; 로 해주면 된다.

 

728x90
반응형
728x90
반응형
개발에 있어서 매우 중요한 것 중 하나, 보안!

 

이전 팀 프로젝트와 개인 프로젝트에서는 아직 제대로 된 프로퍼티 암호화를 적용하지 않았어서

아이디와 비밀번호가 기재된 계정이나 DB 접속 정보와 같은 민감한 내용을

GitHub에 공백 또는 임의의 값으로 올리거나 .gitignore로 처리하는 번거로움이 있었다.

이번 개인 프로젝트에는 이 부분에 대한 개선을 위해 Jasypt를 활용한 프로퍼티 암호화를 적용해보아서 기록해 둔다.

 

Jasypt (Java Simplified Encryption)

Jasypt는 개발자가 암호화 작동 방식에 대한 깊은 지식이 없어도

최소한의 노력으로 프로젝트에 기본 암호화 기능을 추가할 수 있게 해주는 자바 라이브러리이다.

 

 

유튜브로 강의도 보고, 검색도 많이 해보았는데

대부분이 설명하는 글이라서 암호화하는 키(password)를

String = "my_key_value" 이런 식으로 프로퍼티 내부에 명시를 해두었는데

이럴 경우에 해당 값으로 누구나 디코딩이 가능하게 되어서 결국 암호화 한 의미가 없다.

더 나은 방법으로, 인텔리제이에서 JVM Option을 설정할 수 있어서

VM Option으로 값을 전달하는 방식으로 적용했다.


먼저 의존성을 추가해 준다. (gradle 기준)

implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4'	// jasypt 의존성 추가 (프로퍼티 암호화)

Jasypt 설정 및 Bean 등록

package com.springproject.config;

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JasyptConfig {

    @Value("${jasypt.encryptor.password}")
    private String password;

    @Bean(name = "jasyptStringEncryptor")
    public StringEncryptor stringEncryptor() {
//        String password = "비밀번호";    // VM Option으로 전달하는 방식이 더 안전해서 변경 적용 완료
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();

        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(password);   // 암호화할 때 사용하는 키
        config.setAlgorithm("PBEWithMD5AndDES");    // 암호화 알고리즘
        config.setKeyObtentionIterations("1000");   // 반복할 해싱 횟수
        config.setPoolSize("1");    // 인스턴스 pool
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");    // salt 생성 클래스
        config.setStringOutputType("base64");   // 인코딩 방식

        encryptor.setConfig(config);
        return encryptor;
    }
}

간단한 테스트에서는 위 내용에서 stringEncryptor() 내부에

주석처리된 password="비밀번호" 부분에 원하는 값을 넣어 key를 설정하면 되지만,

실제로 프로젝트에 적용하고자 하면 key 또한 별도로 감추어주는 것이 좋다.


프로퍼티 암호화

프로퍼티 암호화를 위해 암·복호화 사이트에 방문해서

① 암호화할 값을 입력

② Two Way Encryption(With Secret Text) 선택

③ Key값을 입력

마지막으로 Encrypt 버튼을 클릭하면 암호화 값을 확인할 수 있다.

 

아래 이미지는 암호화 사이트 모습으로

우측에 암호화된 값과 Key(password로 언급했던) 값을 넣어주면

암호화 전 원래의 값을 확인할 수 있다. (복호화)

암호화 사이트 모습(좌-암호화, 우-복호화)

Key 값은 잊어버리지 않도록 별도로 작성 후 저장해 두는 것이 좋다.


application.yml에 반영

실제로 프로젝트에 적용하기 위해 application.yml 파일 내 DB 접속정보 값을 ENC(암호화 값)로 수정한다. 

spring:
  datasource:
    url: ENC(zQVsiPgBkSc0hJ2pb/Gjf6D9xTou+FFqEE6Eb6hvWy9fJ3jO6LisA2hjK9LB52cL7LbZCs+EJqk=)
    username: ENC(yc/9dYuj6thDEZmI5/N5iA==)
    password: ENC(8HxW/0iGqW6VJtzhVoX3qw==)
    driver-class-name: com.mysql.cj.jdbc.Driver

VM Options 추가

-Djasypt.encryptor.password=암호화에 사용할 키 값


테스트 코드로 암호화 결과 확인해 보기

테스트 코드 실행 시에도 위 내용처럼 VM Options을 통해 암호화 Key값을 전달해 주어도 된다.

아래는 작성한 테스트 코드이다.

package com.springproject.config;

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class JasyptConfigTest {

    @Value("${jasypt.encryptor.password}")
    private String password;

    @Test
    void encryptTest() {
        String url = "enc_test_url";
        String id = "enc_test_id";
        String password = "enc_test_pw";

        System.out.println("db_url : " + jasyptEncoding(url));
        System.out.println("db_id : " + jasyptEncoding(id));
        System.out.println("db_password : " + jasyptEncoding(password));
    }

    public String jasyptEncoding(String value) {
        StandardPBEStringEncryptor pbeEnc = new StandardPBEStringEncryptor();
        pbeEnc.setAlgorithm("PBEWithMD5AndDES");
        pbeEnc.setPassword(password);
        return pbeEnc.encrypt(value);
    }
}

위 테스트 코드를 실행하여 암호화 된 값을 결과로 확인한다.

테스트 실행 결과

실행할 때 마다 결과 값은 항상 다르다.

Why?

Jasypt보안을 강화하기 위해 Salt 값을 사용한다,

Salt는 암호화된 데이터의 보안성을 높이기 위해 사용되며, 매번 실행할 때마다 랜덤한 Salt 값을 생성하여 데이터를 암호화한다.

이렇게 하면 동일한 데이터라도 매번 다른 암호화 결과가 생성된다.

(동일한 데이터에 대해 매번 같은 결과라면 암호화 의미가 없음!!)

 

 

참고 사이트
 

[Spring] Jasypt를 이용한 암호화

Jasypt는 자바에서 암호화를 쉽게 할 수 있도록 도와주는 라이브러리이다. When? Spring에서 datasource를 연동할 때, application.yml 파일에 다음과 같이 설정할 수 있다. spring: datasource: url: jdbc:mysql://... user

gksdudrb922.tistory.com

 

GitHub - ulisesbocchio/jasypt-spring-boot: Jasypt integration for Spring boot

Jasypt integration for Spring boot. Contribute to ulisesbocchio/jasypt-spring-boot development by creating an account on GitHub.

github.com

 

Jasypt: Java simplified encryption - Jasypt: Java simplified encryption - Main

Jasypt 1.9.3 RELEASED! (May 25th, 2019) [DOWNLOAD and ChangeLogs] [WHAT'S NEW IN JASYPT 1.9] Java Simplified Encryption Jasypt is a java library which allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and wi

www.jasypt.org

암호화/복호화 사이트 (Free)
 

Programming Blog Article Feeds as per your Interest | DevGlan

Best programming article feeds as per your Interest on different technologies. Subscribe to any technology and explore the best articles from around the web.

www.devglan.com

 

728x90
반응형
728x90
반응형
 SOLID

객체지향적으로 설계할 때 지켜야 하는 5대 원칙

1. SRP(단일 책임 원칙),
2. OCP(개방-폐쇄 원칙),
3. LSP(리스코프 치환 원칙),
4. ISP(인터페이스 분리 원칙),
5. DIP(의존 역전 원칙)를 말하고 앞글자를 따서 SOLID 원칙이라고 부른다.


SRP (Single Responsiblity Principle)
단일 책임 원칙
- 모든 클래스는 각각 하나의 책임만 가져야 한다.
 
OCP (Open Closed Principle)
개방-폐쇄 원칙
- 확장에는 열려있고, 수정에는 닫혀있는,
  기존 코드를 변경하지 않고서도(Closed) 기능을 추가할 수 있도록(Open) 설계가 되어야 한다.
 
LSP (Liskov Substitution Principle)
리스코프 치환 원칙
- 자식클래스는 부모클래스를 대체할 수 있어야 한다.
  자식클래스는 부모클래스의 확장만 수행하도록 해야 LSP가 만족된다.
 
ISP (Interface Segregation Principle)
인터페이스 분리 원칙
- 하나의 일반적인 인터페이스보다 여러 개의 구체적인 인터페이스를 사용하는 것이 좋다.
 
DIP (Dependency Inversion Principle)
의존 역전 원칙
- 의존관계를 맺을 때 구체적인 클래스보다 좀 더 추상화된 클래스와 관계를 맺는 것이 좋다.
 
 
객체지향프로그래밍은 배워도 배워도 끝이 없는 것 같다.
OOP 그 자체에 머무르지 않고 구체적인 OOP 설계 방법을 알게 되었는데
이 5가지 원칙들은 전부 연결이 된다고 생각했다.

이 원칙들에 대해서 좀 더 확실한 이해를 돕도록
예시 코드도 직접 작성해 보면서 정확하게 숙지하도록 해야겠다.
 
 

참고 영상
- 개발자 장고님의 유튜브
728x90
반응형
728x90
반응형

Spring Boot로 프로젝트를 진행하면서

JPA를 활용해 코드를 작성하다보면 코드가 간결해져서

효율적으로 시간 분배하며 프로젝트를 진행할 수 있었다.

가끔은 하드코딩으로 처음세팅과 DB 연결부터

쿼리 작성까지했던 MyBatis가 조금은 그립다는 생각을 했다.

JPA를 다룰줄은 아는데, 내가 알고 있는 개념이 모호한 것 같아서

정확한 이해도를 잡기 위해 JPA 연관 기능들의 개념과 차이점을 정리해본다.

 

JPA, Spring Data JPA, Hibernate

- 모두 자바에서 관계형 데이터베이스와 상호 작용하기 위한 기술이지만 서로 다른 개념과 역할을 갖고 있다.

 


JPA (Java Persistence API)
- Java에서 데이터베이스와 상호 작용하는 자바 표준 API
- 데이터베이스 테이블과 자바 객체 간의 매핑을 처리하며, 객체 지향 프로그래밍과 관계형 데이터베이스 간의 매핑을 담당
- 인터페이스와 추상 클래스로 이루어져 있으며, 구현체는 제공하지 않음.
  대표적인 JPA 구현체 : Hibernate, EclipseLink, Apache OpenJPA 등


Hibernate
- JPA 스펙을 구현한 JPA 구현체 중 하나
- JPA를 구현한 라이브러리로서, JPA 스펙을 준수하면서도 JPA 스펙 외의 기능과 확장성을 제공
- 영속성 관리, 객체와 테이블 간의 매핑, 데이터베이스 쿼리 작성 및 실행, 캐싱 등을 제공

 

Spring Data JPA
- Spring 프레임워크와 JPA를 결합하여 사용하기 쉽게 만든 프로젝트
- 개발자가 JPA를 더 쉽게 사용하고 반복적인 작업을 줄이도록 돕는 목적으로 만들어졌습니다.
- JPA 리포지토리를 생성하고, 쿼리 메소드를 정의하며, 데이터베이스 액세스 작업을 단순화합니다.

 

 

출처 : docs.jboss.org

요약
JPA  자바 표준 데이터베이스 액세스 API
Hibernate  JPA 구현체 중 하나
Spring Data JPA Spring 프레임워크와 JPA를 연동하여 JPA를 더 쉽게 사용할 수 있도록 돕는 프로젝트

개발 환경과 요구사항에 따라 이러한 기술을 선택하고 결합하여 사용하면 된다.

 

 

 

참고하면 좋을 레퍼런스

https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html

728x90
반응형
728x90
반응형

스프링 이니셜라이저를 사용하여 프로젝트를 생성 할 때 궁금했던 부분을 정리해보고자 한다.

 

 

나같은 경우 STS툴 썼을 땐 메이븐(Maven), IntelliJ툴 썼을 땐 그레들(Gradle) 둘 다 써본 입장으로

메이븐이 기본 세팅 부분이나 의존성 추가하는 부분에 있어서 꽤 편리했다고 생각한다!

지금도 개인 프로젝트는 그레들로 만들고 있지만, 둘 다 익숙해지기 위해서

편향적으로 선택해 작업하기 보다는 골고루 익혀두면 실무에서도 유용할 것 같아

다음번에는 오랜만에 메이븐으로 프로젝트 도전해 보는 걸로 :)

 

spring initializr

 

Gradle과 Maven은 주요 빌드 도구로, Java와 다른 JVM 언어를 사용하여 프로젝트를 관리하고 빌드하는 데 사용된다.

다음은 Gradle과 Maven의 주요 특징과 차이점이다.

Maven
- XML 기반 설정: Maven은 프로젝트 구조와 라이프사이클 관리를 위해 XML 기반의 설정 파일(pom.xml)을 사용한다. 이 설정 파일은 프로젝트 정보, 의존성, 빌드 설정 및 플러그인 설정을 포함한다.
- 약속된 라이프사이클: Maven은 표준 빌드 라이프사이클을 정의하고, 각 라이프사이클에 연결된 특정 명령어를 제공한다. 이를 통해 빌드, 패키징, 테스트, 배포 등의 작업을 간단하게 수행할 수 있다.
- 중앙 저장소: Maven은 중앙 저장소를 통해 프로젝트 의존성을 관리하며, 필요한 라이브러리 및 아티팩트를 다운로드한다.
- 제한된 스크립팅 언어: Maven은 XML 기반으로 설정되어 있어서 복잡한 빌드 작업을 수행하기 위해 스크립팅 언어를 사용하기 어렵다.

Gradle
- Groovy 또는 Kotlin 기반 DSL: Gradle은 Groovy 또는 Kotlin 기반의 스크립트로 빌드 스크립트를 작성한다. 이를 통해 빌드 스크립트를 보다 간결하게 작성할 수 있다.
- 라이프사이클 기반이 아닌 작업 지향: Gradle은 태스크(Task)라는 개념을 사용하여 빌드 작업을 정의한다. 이는 더 세밀한 커스터마이징을 가능하게 한다.
- 용도에 맞게 다양한 플러그인: Gradle은 다양한 플러그인을 지원하며, Java, Android, 웹 개발, 프로젝트 관리 등 다양한 용도의 프로젝트에 대응할 수 있다.
- 멀티 프로젝트 빌드: Gradle은 멀티 프로젝트 구성을 지원하고 각 프로젝트 간에 의존성을 관리할 수 있다.
- 빌드 캐싱: Gradle은 빌드 캐싱을 지원하여 중복된 작업을 최소화하고 빌드 속도를 향상시킬 수 있다.

 


빌드 도구를 선택할 때 고려사항:
- 프로젝트 요구사항:

프로젝트의 규모, 복잡성 및 요구사항에 따라 Gradle 또는 Maven을 선택

Maven은 단순한 프로젝트 빌드 및 종속성 관리에 적합

Gradle은 더 복잡한 프로젝트 및 커스터마이징된 빌드 스크립트에 적합

- 언어 선호도:

Groovy 또는 Kotlin이 편하다 > Gradle

XML 기반 설정이 익숙하다 > Maven 선택 추천


코틀린(Kotlin)그루비(Groovy)는 둘 다 자바 가상 머신(JVM) 위에서 동작하는 프로그래밍 언어이다.

그러나 이 두 언어 간에는 몇 가지 중요한 차이점이 있다.

1. 컴파일러와 정적 타입 검사
- 코틀린은 정적 타입 검사(static type checking)를 갖는 언어로, 컴파일러가 코드를 미리 분석하여 타입 불일치 오류를 발견할 수 있다. 이로 인해 런타임에 발생하는 많은 예외를 방지할 수 있다.
- 그루비는 동적 타입 언어(dynamic typing)로, 변수의 타입을 런타임에 결정한다. 따라서 컴파일러는 타입 오류를 잡을 수 없고, 런타임 오류가 발생할 가능성이 높다.

 

2. 선택한 언어의 목적
- 코틀린은 주로 안드로이드 앱 개발 및 서버 측 개발을 위한 현대적이고 정적 타입의 언어로 개발되었다.
- 그루비는 스크립트 언어로 시작하여 빌드 스크립트, 테스트 스크립트, DSL(Domain-Specific Language) 개발 및 간단한 웹 애플리케이션을 작성하기 위한 목적으로 사용된다.

 

3. 표현력
- 그루비는 매우 간결하고 표현력이 뛰어난 언어로, 코드를 더 읽기 쉽게 만들 수 있다. 그루비는 동적인 언어로서 매우 유연한 문법을 갖고 있다.
- 코틀린도 간결한 문법을 갖고 있지만, 정적 타입 검사로 코드 안정성을 높인다.

 

4. 자바 호환성
- 코틀린은 자바와 완벽하게 상호 운용 가능하도록 설계되었다. 따라서 기존 자바 코드와의 통합이 매우 쉽다.
- 그루비도 자바와의 호환성이 높지만, 타입 안정성 측면에서 코틀린에 비해 제한적이다.

 

5. 성능
- 코틀린은 정적 타입 검사로 인해 실행 시간에 불필요한 타입 검사를 줄이고 최적화할 수 있어서 실행 속도가 빠를 수 있다.
- 그루비는 동적 타입 언어이기 때문에 실행 시간에 더 많은 타입 검사와 오버헤드가 발생할 수 있다.

 

따라서 코틀린과 그루비는 각각의 사용 사례와 선호하는 프로그래밍 스타일에 따라 선택해야 한다.

코틀린은 안정성과 성능을 중요하게 생각하는 프로젝트에 적합하며, 그루비는 스크립트 및 빠른 프로토타이핑을 위한 작업에 적합하다.

728x90
반응형

+ Recent posts