SpringBoot + React 프로젝트를 AWS EC2에 Docker 환경으로 배포한 뒤,
서비스 보안을 위해 HTTPS(SSL 인증서) 를 적용했다.

이번 글에서는 Docker + Nginx 환경에서 Let's Encrypt 인증서를 적용하는 과정을 정리한다.


1. 프로젝트 배포 구조

이번 프로젝트는 다음과 같은 구조로 구성되어 있다.

Client

HTTPS

Nginx (Docker)

Spring Boot (Docker)
 

프론트엔드는 React 정적 파일을 nginx에서 서빙하고,
API 요청은 SpringBoot 컨테이너로 전달하는 Reverse Proxy 구조이다.


2. HTTPS 적용에 사용한 기술

이번 설정에서 사용한 기술 스택은 다음과 같다.

  • AWS EC2 (Ubuntu)
  • Docker
  • Docker Compose
  • Nginx
  • Let's Encrypt (SSL 인증서)
  • Certbot
  • DuckDNS (무료 도메인)

3. 무료 도메인 연결 (DuckDNS)

Let's Encrypt 인증서를 발급하려면 도메인이 필요하다.

무료 도메인 서비스인 DuckDNS를 사용했다.

로그인 후 원하는 도메인을 생성한다.

예시

example.duckdns.org
 

그리고 해당 도메인을 EC2 Public IP와 연결하면 바로 사용 가능하다.


4. Certbot 설치

EC2 서버에 Let's Encrypt 인증서를 발급하기 위해 Certbot을 설치한다.

 
sudo apt update
sudo apt install certbot -y
 

5. Docker 환경에서 인증서 발급 방식

일반적인 환경에서는 아래 명령어로 인증서를 발급할 수 있다.

certbot --nginx
 

하지만 이번 환경에서는 nginx가 Docker 컨테이너 내부에서 실행되기 때문에
이 방식은 사용할 수 없다.

그래서 webroot 방식을 사용한다.


6. SSL 인증서 발급

다음 명령어로 인증서를 발급한다.

 
sudo certbot certonly \
--webroot \
-w /home/ubuntu/deploy/certbot/www \
-d example.duckdns.org
 

발급이 완료되면 인증서는 다음 경로에 생성된다.

/etc/letsencrypt/live/example.duckdns.org/
 

주요 파일

fullchain.pem
privkey.pem
 

7. Docker nginx에서 인증서 사용하기

nginx 컨테이너가 인증서를 읽을 수 있도록
docker-compose에 인증서 경로를 연결해야 한다.

 
volumes:
- /etc/letsencrypt:/etc/letsencrypt:ro
 

8. Nginx HTTPS 설정

nginx 설정 파일에 SSL 설정을 추가한다.

 
server {
listen 443 ssl;
server_name example.duckdns.org;

ssl_certificate /etc/letsencrypt/live/example.duckdns.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.duckdns.org/privkey.pem;

root /usr/share/nginx/html;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}

location /api/ {
proxy_pass http://backend:8080;
}
}
 

9. HTTP → HTTPS 리다이렉트

HTTP 접속 시 자동으로 HTTPS로 이동하도록 설정한다.

 
server {
listen 80;
server_name example.duckdns.org;

location / {
return 301 https://$host$request_uri;
}
}
 

10. Docker 재배포

설정이 완료되면 컨테이너를 다시 실행한다.

 
docker compose down
docker compose up -d --build
 

11. HTTPS 적용 확인

이제 다음 주소로 접속하면 HTTPS가 적용된 것을 확인할 수 있다.

브라우저 주소창에 🔒 보안 연결 표시가 나타난다.


12. 인증서 자동 갱신

Let's Encrypt 인증서는 90일 유효기간을 가진다.

갱신 테스트

 
sudo certbot renew --dry-run
 

Certbot은 자동으로 갱신 스케줄을 등록한다.


13. 트러블슈팅

nginx 컨테이너에서 인증서를 찾지 못하는 문제

다음과 같은 오류가 발생했다.

cannot load certificate
No such file or directory
 

원인은 Docker nginx가 인증서 경로를 읽지 못하고 있었기 때문이다.

Certbot은 인증서를 다음 경로에 생성한다.

/etc/letsencrypt
 

하지만 nginx 컨테이너는 해당 경로를 접근할 수 없었다.

해결 방법은 docker-compose에 인증서 경로를 연결하는 것이다.

 
volumes:
- /etc/letsencrypt:/etc/letsencrypt:ro
 

이후 정상적으로 HTTPS가 적용되었다.


마무리

Docker 환경에서 HTTPS를 적용할 때 중요한 포인트는 다음 두 가지이다.

1️⃣ Docker nginx에서는 webroot 방식으로 인증서를 발급해야 한다.
2️⃣ 인증서 경로를 Docker 볼륨으로 연결해야 한다.

이를 통해 무료 SSL 인증서를 적용하고
HTTPS 기반의 안전한 서비스 환경을 구성할 수 있었다.

프리티어로 인해 ec2가 만료되어 다시 서버셋팅을 하게 되었다. 그 과정을 정리하기 위한 게시글이다.
React + Spring Boot + AWS RDS로 구성된 풀스택 서비스를 AWS EC2에 Docker 기반으로 배포하였다.
프론트엔드는 Nginx에서 정적 파일을 서빙하고, 백엔드 API는 Nginx Reverse Proxy를 통해 Spring Boot로 전달하는 구조로 구성하였다.


전체 아키텍처

구성은 다음과 같다.

Client (Browser)

Nginx
(Static + Reverse Proxy)

Spring Boot API

AWS RDS
 

EC2 내부에서는 Docker Compose로 서비스를 관리한다.

EC2
├─ nginx container
├─ springboot container
└─ AWS RDS (외부)

1. EC2 인스턴스 생성

AWS EC2에서 Ubuntu 인스턴스를 생성하였다.

보안 그룹 설정:

포트설명
22 SSH
80 HTTP
443 HTTPS

EC2 접속

ssh -i key.pem ubuntu@EC2_PUBLIC_IP
 

2. Docker 설치

EC2에 Docker를 설치한다.

sudo apt update
sudo apt install docker.io -y
sudo systemctl start docker
sudo systemctl enable docker
 

Docker Compose 설치

sudo apt install docker-compose-plugin
 

3. 프로젝트 배포 구조

배포용 디렉토리를 구성하였다.

deploy
├─ docker-compose.yml
├─ nginx
│ ├─ Dockerfile
│ └─ default.conf
├─ backend
│ ├─ Dockerfile
│ └─ app.jar
└─ frontend
└─ build
 

4. React 프로젝트 빌드

React 프로젝트를 production build 한다.

npm run build
 

빌드 결과:

frontend/build
 

이 정적 파일을 Nginx에서 서빙한다.


5. Spring Boot 실행 JAR 생성

Spring Boot 프로젝트에서 실행 가능한 JAR을 생성한다.

Gradle 사용 시

./gradlew bootJar
 

생성된 JAR 파일을 배포 디렉토리로 이동한다.

backend/app.jar
 

6. Spring Boot Dockerfile

Spring Boot 컨테이너 설정

 
FROM eclipse-temurin:17-jre

WORKDIR /app
COPY app.jar app.jar

ENTRYPOINT ["java","-jar","app.jar"]
 

7. Nginx Dockerfile

React 정적 파일을 서빙하도록 설정

 
FROM nginx:alpine

COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
RUN rm -rf /usr/share/nginx/html/*
COPY ./frontend/build/ /usr/share/nginx/html/
 

8. Nginx Reverse Proxy 설정

Nginx는

  • React 정적 파일 서빙
  • API 요청을 Spring Boot로 전달

두 가지 역할을 수행한다.

 
server {
listen 80;

root /usr/share/nginx/html;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}

location /api/ {
proxy_pass http://portfolio-backend:8080;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
 

9. Docker Compose 설정

두 컨테이너를 Compose로 관리한다.

 
version: "3"

services:

backend:
build: ./backend
container_name: portfolio-backend
restart: always
expose:
- "8080"

nginx:
build: .
container_name: portfolio-nginx
ports:
- "80:80"
depends_on:
- backend
 

10. 서비스 실행

Docker Compose로 서비스를 실행한다.

docker compose up -d --build
 

컨테이너 확인

docker ps
 

11. 접속 확인

브라우저에서

http://EC2_PUBLIC_IP
 

로 접속하면 React 화면이 정상적으로 나타난다.

API 요청은 다음 흐름으로 처리된다.

Browser → Nginx → Spring Boot → RDS
 

배포 과정에서 발생했던 문제들

배포 과정에서는 여러 문제가 발생했다.

1. Docker 이미지 빌드 실패

no space left on device
 

원인
EC2 프리티어 기본 디스크 용량 부족

해결
EBS 볼륨 확장


2. Spring Boot 실행 실패

no main manifest attribute
 

원인
실행 가능한 JAR이 아니라 일반 JAR을 배포

해결

bootJar
 

로 실행 가능한 JAR 생성


3. Nginx upstream 연결 실패

host not found in upstream
 

원인
컨테이너 이름 mismatch

해결
Docker Compose 서비스 이름과 nginx upstream 이름을 동일하게 수정


4. React crypto.randomUUID 에러

HTTP 환경에서

crypto.randomUUID is not a function
 

문제 발생

해결
uuid 라이브러리 사용

npm install uuid
 

5. 502 Bad Gateway

connect() failed (111: Connection refused)
 

원인
Nginx Reverse Proxy 설정 문제

해결
proxy_pass 설정 수정


마무리

이번 프로젝트를 통해 다음 기술들을 실제 배포 환경에서 사용해 볼 수 있었다.

  • AWS EC2
  • Docker
  • Docker Compose
  • Nginx Reverse Proxy
  • React 정적 배포
  • Spring Boot API 서버
  • AWS RDS

단순히 로컬에서 실행하는 것을 넘어 실제 서버 환경에서 서비스를 운영하는 구조를 경험할 수 있었다.

aws 서버에 프로젝트 배포를 하는데 build fail 오류가 생겨 해결방법을 기록한다git으로 서버배포할 때 참고한 블로그

-> https://velog.io/@wndudrla1011/chapter-8

 

EC2 서버에 프로젝트 배포하기 - 루타블의 개발일기

🔧 먼저 깃허브에서 코드를 받아올 수 있게 EC2에 깃을 설치하겠다.sudo yum install git🔧 설치가 완료되면 다음 명령어로 설치 상태를 확인git --version🔧 git이 성공적으로 설치되면 git clone으로 프로

velog.io

위에 스텝대로 무난히 진행되다가 build fail 메세지가 출력됨 

$ ./deploy.sh
> Git Pull
Already up to date.
> 프로젝트 Build 시작
Starting a Gradle Daemon (subsequent builds will be faster)

FAILURE: Build failed with an exception.

* What went wrong:
Directory '/home/ubuntu/app/repository/MyApp' does not contain a Gradle build.

A Gradle build should contain a 'settings.gradle' or 'settings.gradle.kts' file in its root directory. It may also contain                                                     a 'build.gradle' or 'build.gradle.kts' file.

To create a new Gradle build in this directory run 'gradlew init'

For more information about the 'init' task, please refer to https://docs.gradle.org/8.5/userguide/build_init_plugin.html i                                                    n the Gradle documentation.

For more details on creating a Gradle build, please refer to https://docs.gradle.org/8.5/userguide/tutorial_using_tasks.ht                                                    ml in the Gradle documentation.

* Try:
> Run gradlew init to create a new Gradle build in this directory.
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Get more help at https://help.gradle.org.

천천히 읽어보니 setting.gradle이 없단다..

로컬에서 프로젝트 폴더에 확인해보니 정말 없다..어휴 결국 직접 파일을 만들어 git에 push 해주었다

#settings.gradle
rootProject.name = 'MyApp'

settinds.gradle 파일은 build.gradle과 같은 경로에 생성해주었다.

다시 ec2로 가서 빌드설정파일을 실행해주었다

$ ./deploy.sh
> Git Pull
remote: Enumerating objects: 32, done.
remote: Counting objects: 100% (32/32), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 17 (delta 6), reused 17 (delta 6), pack-reused 0
Unpacking objects: 100% (17/17), 7.59 KiB | 22.00 KiB/s, done.
From https://github.com/ds-jeong/MyApp
   5fce017..21f8cda  master     -> origin/master
Updating 5fce017..21f8cda
Fast-forward
 .gradle/8.5/executionHistory/executionHistory.bin  | Bin 440109 -> 440109 bytes
 .gradle/8.5/executionHistory/executionHistory.lock | Bin 17 -> 17 bytes
 .gradle/8.5/fileHashes/fileHashes.bin              | Bin 41647 -> 41647 bytes
 .gradle/8.5/fileHashes/fileHashes.lock             | Bin 17 -> 17 bytes
 .gradle/buildOutputCleanup/buildOutputCleanup.lock | Bin 17 -> 17 bytes
 .gradle/file-system.probe                          | Bin 8 -> 8 bytes
 build/libs/MyApp-0.0.1-SNAPSHOT-plain.jar          | Bin 6494917 -> 6494917 bytes
 settings.gradle                                    |   1 +
 8 files changed, 1 insertion(+)
 create mode 100644 settings.gradle
> 프로젝트 Build 시작
<-<-------------> 0% CONFIGURING [11m 13s]
> root project
^C^Z
[1]+  Stopped                 ./deploy.sh

오? 된거같다 근데 command가 멈췃다

흠..springBoot 프로젝트를 배포할땐 느리다는데 그문제인가..

서치를 해보니 나같은 경우가 있더라 

->https://sundries-in-myidea.tistory.com/102

 

AWS EC2 프리티어에서 메모리 부족현상 해결방법

AWS free tier를 사용하다보면 2%가 부족할 때가 있다. AWS 프리티어는 가난한 대학생에게는 한줄기 빛과 같은 존재인데, AWS의 프리티어라서 적게 돈이 나가는 것도 좋고, 실제로 이것저것 해볼 수 있

sundries-in-myidea.tistory.com

감사하게도 위 블로그를 참고했더니 1분도안되서 빌드가 끝나고 튕기는 현상도 없다

$ ./deploy.sh
> Git Pull
Already up to date.
> 프로젝트 Build 시작
Starting a Gradle Daemon, 1 busy Daemon could not be reused, use --status for details

> Task :buildEnvironment

------------------------------------------------------------
Root project 'MyApp'
------------------------------------------------------------

classpath
No dependencies

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 12s
1 actionable task: 1 executed
> step1 디렉토리로 이동
> Build 파일 복사
> 현재 구동 중인 애플리케이션 pid 확인
현재 구동 중인 애플리케이션 pid:
> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않는다.
> 새 애플리케이션 배포
> JAR Name: MyApp-0.0.1-SNAPSHOT-plain.jar

제대로 올라간듯 하다

-> https://velog.io/@m1njae/AWS-%ED%83%84%EB%A0%A5%EC%A0%81-IP-%EC%A3%BC%EC%86%8C-%EC%84%A4%EC%A0%95

 

[AWS] 탄력적 IP 주소 설정

EC2 인스턴스를 껐다가 다시 실행하면 IP가 변경된다고? 탄력적 IP 주소를 설정하자!

velog.io

위에 블로그를 참고해서 화면을 위한 탄력 ip를 할당받았다

-> https://velog.io/@hoooons/AWS-EC2-%EB%A1%9C-React-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0

그리곤 위에 블로그를 참고해서 여러 패키지를 다운로드를 완료했다 

npm error code ENOSPC
npm error syscall write
npm error errno -28
npm error nospc ENOSPC: no space left on device, write
npm error nospc There appears to be insufficient space on your system to finish.
npm error nospc Clear up some disk space and try again.
npm error A complete log of this run can be found in: /home/ubuntu/.npm/_logs/2024-08-05T13_08_44_437Z-debug-0.log

react root 폴더에서 npm start 명령어를 시도했더니 위와 같은 에러를 뱉는다..

서버에서 최적화하고 난리를 쳐도 안되길래 서치끝에 찾아냈다

pakage.json내에 sourcemap 를 false 처리해주는것..

보통 개발환경에서는 바로 소스코드를 확인할수 있도록 디폴트가 true로 되있지만

실서버에선 소스코드를 확인할 일이 없고, 빌드시 해당 과정에서 메모리를 많이 사용한다..

#pakage.json
  /*    "build": "react-scripts build",*/
  "scripts": {
    "start": "react-scripts start",
    "build" : "GENERATE_SOURCEMAP=false react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

해서 위와 같이 수정 후 git에 반영해주고 aws에서는 다시 pull.. 

수정 된 json 파일을 가지고 왔지만 혹시 몰라 디스크공간을 확보 위까지 진행했다

/*시스템 재부팅*/
$ sudo reboot

여기까지하고 보통 npm start가 된다

주소창에 탄력ip:3000으로 치면 화면이나와야 정상

혹시 몰라 aws에 보안 그룹을 확인해보니 3000 port 는 열려있음

원인을 찾다가 캐시문제인가 싶어서 아래 스텝을 진행해보았다

/*임시 파일 삭제*/
$ sudo rm -rf /tmp/*

/*로그 파일 삭제*/
$ sudo rm -rf /var/log/*.log

/*npm 캐시 삭제*/
npm cache clean --force

/*패키지 제거*/
$ sudo apt-get autoremove
$ sudo apt-get clean

/*시스템 재부팅*/
$ sudo reboot

여기까지 실행 후 npm 재설치를 해줬는데.. 여전한 에러..

$ npm install
npm error code ENOTEMPTY
npm error syscall rename
npm error path /home/ubuntu/app/repository/MyApp/src/main/frontend/node_modules/acorn
npm error dest /home/ubuntu/app/repository/MyApp/src/main/frontend/node_modules/.acorn-I5v5oviz
npm error errno -39
npm error ENOTEMPTY: directory not empty, rename '/home/ubuntu/app/repository/MyApp/src/main/frontend/node_modules/acorn' -> '/home/ubuntu/app/repository/MyApp/src/main/frontend/node_modules/.acorn-I5v5oviz'
npm error A complete log of this run can be found in: /home/ubuntu/.npm/_logs/2024-08-05T13_25_20_689Z-debug-0.log
/*node_modules 삭제*/
$ rm -rf node_modules

/*npm 캐시 clean*/
$ npm cache clean --force
$ npm install

/*package-lock.json 삭제*/
$ rm package-lock.json
$ npm install

/*node_modules 권한 수정*/
$ sudo chown -R $USER:$GROUP node_modules

/*.npm 디렉토리 권한 및 파일 확인*/
sudo chown -R $USER:$GROUP ~/.npm

/*시스템 재부팅*/
$ sudo reboot

이제서야 된다..흠? node_modules 충돌인건가; 어쨋든 서버가 올라가는걸 확인했다

쇼핑몰 프로젝트를 진행중인데 목록에 이미지가 노출되야하는데 계속 경로를 못찾아왔다
프로젝트 폴더 경로가 D:에 있으니 파일에 액세스를 못하더라
그래서 일단 프로젝트 경로부터 C:로 옮겼다 그런데 계속 빌드가 안되는 일이발생..
gradle로 빌드를 하려는데 build.gradle을 찾을수가 없으니 폴더를 생성하라는 메세지가 나와서 git에있던 파일을 가져오니 정상적으로 프로젝트가 동작했다
여기까진 그렇다치고..경로를 어디로 해야 React에서 찾을수 있나보니 public으로 보통 경로를 찾아간다 하더라
그래서 public 밑에 upload 폴더를 만들어서 업로드해보니 파일이 생성되었다 생성된 경로로 크롬 주소로 찍어보니 이미지가나오길래 해당 경로를 그대로 img 태그로 가져왔다

<tbody>
{resArr.map((item, index) => (
    <tr key={index}>
        <td>
            <img
            	//process.env.PUBLIC_URL은 public 디렉토리다
                src={process.env.PUBLIC_URL + '/upload/img/' + item.fileNm}
                alt="productImg"
                style={{height: "4.3rem"}}
            />
        </td>
        <td>{item.productNm}</td>
        <td>{item.price}</td>
        <td>{item.author}</td>
    </tr>
))}
</tbody>

  

프로젝트의 폴더구조이다 참고하도록하자

 

'React' 카테고리의 다른 글

React / useHistory가 import 안될때  (0) 2024.07.11
import { useHistory } from 'react-router-dom';

axios 통신 후 화면 목록으로 이동하기 위해 useHistory 사용했더니 import가 안됨
아래코드로 수정 후 반영했더니 화면이동 가능..

import { useNavigate } from 'react-router-dom';
import React, { useState, useRef } from 'react';
import { Form, Button, Container } from 'react-bootstrap';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';

function Write() {
    //폼전송
    const titleRef = useRef();
    const contentRef = useRef();
    const nicknameRef = useRef();
    const fileRef = useRef();
    const navigate = useNavigate();

    const handleSubmit = event => {

        event.preventDefault();

        const formData = new FormData();
        formData.append('title', titleRef.current.value);
        formData.append('content', contentRef.current.value);
        formData.append('nickname', nicknameRef.current.value);
        formData.append('file', fileRef.current.files[0]); // 첨부된 이미지 파일 추가


        axios.post('/qna/qnaSave', formData)
            .then(response => {
                // console.log('Post submitted successfully');
                alert("작성완료되었습니다.");
                // useHistory import 안되면 아래 코드로 수정해서 반영
                // 응답을 받고 Qna화면으로 돌아감
                navigate('/qna');
            })
            .catch(error => {
                console.error('Error submitting post: ', error);
            });
    };

    //파일업로드
    const [selectedFile, setSelectedFile] = useState(null);

    const fileSelectedHandler = event => {
        setSelectedFile(event.target.files[0]);
        //console.log(event.target.files[0]);
    };

    const fileUploadHandler = () => {
        const formData = new FormData();
        formData.append('file', selectedFile);

        axios.post('/utill/imgUpload', formData)
            .then(response => {
                //console.log(response.data);
                // Handle success, e.g., show a success message
            })
            .catch(error => {
                console.error('Error uploading file: ', error);
                // Handle error, e.g., show an error message
            });
    };

    return (
        <div>
            <Container>
                <Form onSubmit={handleSubmit}>
                    <Form.Group controlId="formTitle">
                        <Form.Label>제목</Form.Label>
                        <Form.Control type="text" ref={titleRef} />
                    </Form.Group>

                    <Form.Group controlId="formContent">
                        <Form.Label>내용</Form.Label>
                        <Form.Control as="textarea" rows={5} ref={contentRef} />
                    </Form.Group>

                    <Form.Group controlId="formNickname">
                        <Form.Label>닉네임</Form.Label>
                        <Form.Control type="text" ref={nicknameRef} />
                    </Form.Group>

                    <Form.Group controlId="formImage">
                        <Form.Label>이미지 첨부</Form.Label>
                        <Form.Control type="file" ref={fileRef} onChange={fileSelectedHandler} />
                    </Form.Group>

                    <Button variant="primary" type="submit">
                        작성 완료
                    </Button>
                </Form>
            </Container>
             {/*<button onClick={fileUploadHandler}>Upload</button>*/}
        </div>
    );
}

export default Write;



'React' 카테고리의 다른 글

React / 이미지 경로  (0) 2024.07.11

기존에 쓰던 postgresql과 달리 oracle은 사용법이 달라 기록한다

1.Postgresql

SELECT * FROM TEST_TABLE A 
WHERE A.COLUMN LIKE CONCAT( '%' , #{param.column} , '%')

2.Oracle

SELECT * FROM TEST_TABLE A WHERE A.COLUMN LIKE '%'||#{param.column}||'%'

 

JPA란 Java Persistance API의 약자로서 자바 ORM(Object Relational Mapping) 기술에 대한

표준명세(구조와 기능을 상세하게 기술한 문서)로  JAVA에서 제공하는 API이다

JPA의 스펙은 자바객체와 데이터베이스를 어떻게 매핑하고 동작해야하는지를 정의한다

 

RAM에 있는 데이터들은 휘발성데이터이다

컴퓨터를 부팅하면 열려있던 창이 종료되있는데 이런것들을 휘발성데이터라고 생각하면된다

하드디스크는 비휘발성데이터로 영속성의 특징을 가지고있다

영속성의 특징이란 지속적인 데이터란 뜻으로 데이터가 유지되는 것을 의미한다

JPA(Java Persistance API)는 자바가 지원하는 표준명세로서 ORM을 이용해 DataBase를 매핑할때

하드디스크에 DataBase 영역을 만들어 그안에 데이터를 저장하게 되는데

이러한 데이터들을 영속성(Persistance)데이터라 한다

JPA 는 자바객체가 영속성데이터를 가질 수 있게하는 인터페이스라고 이해하면 편리하다

 

 


 

JPA 에 관한 설명을 이해하는 중 ORM이라는 개념을 이해하기 위해 정리해보겠다

ORM은 객체-관계 매핑을 의미하는데 SQL Mapper와 비교되고 있다

 

SQL Mapper

  • sql문을 직접 기술하여 데이터베이스를 조작한다
  • 필드를 매핑하여 데이터베이스에 접근한다

 

 ORM(Obejct Relational Mapping / 객체-관계 매핑)

  • 메서드로 데이터베이스를 조작한다
  • sql문을 자동으로 생성한다

 


 

Spring-Data-JPA

만약, 개발자가 JPA 구현체를 호출하여 Java와 DataBase가 ConnectionPool(연결) 할 수있는 코드를 작성한다면

DB연결이 필요할때 마다 동일한 코드들을 작성해야하는 반복되는 과정이 생길 것이다

Spring은 반복되는 코드들을 interface로 제공해주어 편리하게 사용이 가능하도록 제공해주는데

이것을 Spring-Data-JPA 모듈이라고 한다

 

https://suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/ 참고

 

JPA, Hibernate, 그리고 Spring Data JPA의 차이점

개요 Spring 프레임워크는 어플리케이션을 개발할 때 필요한 수많은 강력하고 편리한 기능을 제공해준다. 하지만 많은 기술이 존재하는 만큼 Spring 프레임워크를 처음 사용하는 사람이 Spring 프레

suhwan.dev

 

'Spring' 카테고리의 다른 글

Spring / request.getHeader()  (0) 2022.07.15
Spring / Security  (0) 2022.07.15
Spring / Spring Boot 에 Intercapter 란?  (0) 2022.07.14
Spring / Thymeleaf  (0) 2022.07.14

intelij에서 서버를 로드했을때 나오는 에러이다

1099포트가 사용중이라는 것 같은데

cmd 창을 실행 후

netstat -ano|find "1099"

현재 실행 중인 프로그램들이 뜬다

 

끝에보이는 9376 pid를 가진 프로그램들을 삭제하기위해

작업관리자 - 세부정보에서 pid가 9376인 프로그램들을 종료한다

그리고 서버를 가동하면 정상적으로 로드됨

+ Recent posts