Skip to content

Commit a0b83c2

Browse files
committed
Oracle DB를 Docker Compose로 전환
깃허브 로그인을 붙이려면, DB 테이블 수정이 필요한데, 테이블 수정을 하게되면 이전 챕터와 호환되지 않게 될 수도 있어, DB를 Docker Compose로 분리하고, 분리하는김에 DB 버전도 23c로 올려버렸다. 😅
1 parent aa28faa commit a0b83c2

9 files changed

Lines changed: 295 additions & 8 deletions

File tree

part-last/my-board-mds/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ part07의 jex06-board 프로젝트를 Spring 7 + Spring Security 7 + Java 21 환
6969
## TODO:
7070

7171
- [ ] 이 프로젝트에 먼저 Github 로그인을 먼저 붙여볼까?
72-
- [ ] 이 프로젝트는 아직 Oracle이긴한데... 다른 Part Last 의 프로젝트처럼 간편한 확인 테스트를 위해 HSQLDB로 바꾸는게 좋을 것 같다.
73-
- [ ] 다른 프로젝트엔 tui.editor를 붙여보긴 했는데... 여기도 에디터를 붙여보면 좋을 것 같다.
72+
- [x] DB 테이블 수정이 필요한데, Oracle을 Docker로 실행해서 이전 챕터에서 부터 쭈욱 써왔던 DB와 분리되야할 것 같다.
73+
- DB를 Docker Compose로 전환해서, `db-start.bat`를 실행하면 OracleXE 23c가 실행되며 테이블/데이터도 초기화된다.
74+
- `db-start.bat`: Oracle DB 컨테이너 생성 및 실행 (이미 있다면 DB 컨테이너 실행만 함)
75+
- `db-stop.bat`: Oracle DB 컨테이너만 종료, 데이터는 유지됨
76+
- `db-clean.bat`: Oracle DB 컨테이너 종료 및 데이터 삭제
77+
- [ ] 다른 프로젝트엔 tui.editor를 붙여보긴 했는데... 여기도 에디터를 붙여보면 좋을 것 같다.
7478

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@echo off
2+
echo [WARNING] This will permanently delete the Oracle XE container and ALL data!
3+
echo.
4+
set /p confirm=Are you sure you want to proceed? (y/N):
5+
if /i not "%confirm%"=="y" (
6+
echo Cancelled.
7+
pause
8+
exit /b 0
9+
)
10+
11+
echo.
12+
echo Stopping and removing Oracle XE container and volumes...
13+
cd /d "%~dp0"
14+
docker compose down -v
15+
echo.
16+
echo Done. The init-scripts will be re-executed on the next startup.
17+
pause
18+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@echo off
2+
echo Starting Oracle XE Docker container...
3+
cd /d "%~dp0"
4+
docker compose up -d
5+
echo.
6+
echo Oracle XE is starting up. It may take 1-2 minutes to be fully ready.
7+
echo - JDBC URL : jdbc:oracle:thin:@//localhost:1521/FREEPDB1
8+
echo - Username : book_ex
9+
echo - Password : book_ex
10+
echo.
11+
echo To check logs: docker compose logs -f oracle-xe
12+
pause

part-last/my-board-mds/db-stop.bat

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@echo off
2+
echo Stopping Oracle XE 23c Docker container...
3+
cd /d "%~dp0"
4+
docker compose stop
5+
echo.
6+
echo Done. Data is preserved. Run db-start.bat to restart.
7+
pause
8+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
services:
2+
oracle-xe:
3+
image: gvenzl/oracle-free:23-slim
4+
container_name: oracle_xe_23c-local
5+
environment:
6+
ORACLE_PASSWORD: sys_ex
7+
APP_USER: book_ex
8+
APP_USER_PASSWORD: book_ex
9+
TZ: Asia/Seoul
10+
ports:
11+
- "1521:1521"
12+
volumes:
13+
- oracle-data:/opt/oracle/oradata
14+
- ./docker/init-scripts:/container-entrypoint-initdb.d
15+
healthcheck:
16+
test: ["CMD", "healthcheck.sh"]
17+
interval: 10s
18+
timeout: 5s
19+
retries: 10
20+
start_period: 30s
21+
start_interval: 5s
22+
23+
volumes:
24+
oracle-data:
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
-- ============================================================
2+
-- 01_schema.sql
3+
-- book_ex 스키마 DDL (테이블, 시퀀스 등) - Oracle 23c
4+
-- ============================================================
5+
-- @formatter:off
6+
CONNECT book_ex/book_ex@//localhost:1521/FREEPDB1
7+
-- @formatter:on
8+
9+
-- 시퀀스 (Oracle 23c: IF NOT EXISTS 지원)
10+
CREATE SEQUENCE IF NOT EXISTS seq_board START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
11+
CREATE TABLE IF NOT EXISTS tbl_board
12+
(
13+
bno NUMBER(10, 0),
14+
title VARCHAR2(200) NOT NULL,
15+
content VARCHAR2(2000) NOT NULL,
16+
writer VARCHAR2(50) NOT NULL,
17+
regdate DATE DEFAULT SYSDATE,
18+
updatedate DATE DEFAULT SYSDATE,
19+
replycnt NUMBER(10) DEFAULT 0,
20+
CONSTRAINT pk_board PRIMARY KEY (bno)
21+
);
22+
23+
CREATE SEQUENCE IF NOT EXISTS seq_reply START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
24+
CREATE TABLE IF NOT EXISTS tbl_reply
25+
(
26+
rno NUMBER(19) NOT NULL,
27+
bno NUMBER(19) NOT NULL,
28+
reply VARCHAR2(1000) NOT NULL,
29+
replyer VARCHAR2(50) NOT NULL,
30+
replydate TIMESTAMP(6) DEFAULT SYSTIMESTAMP,
31+
updatedate TIMESTAMP(6) DEFAULT SYSTIMESTAMP,
32+
CONSTRAINT pk_reply PRIMARY KEY (rno)
33+
);
34+
35+
ALTER TABLE tbl_reply
36+
ADD CONSTRAINT fk_reply_board
37+
FOREIGN KEY (bno) REFERENCES tbl_board (bno);
38+
39+
CREATE TABLE IF NOT EXISTS tbl_attach
40+
(
41+
uuid VARCHAR2(100) NOT NULL,
42+
uploadpath VARCHAR2(200) NOT NULL,
43+
filename VARCHAR2(100) NOT NULL,
44+
filetype CHAR(1) DEFAULT 'I',
45+
bno NUMBER(10, 0),
46+
CONSTRAINT pk_attach PRIMARY KEY (uuid)
47+
);
48+
49+
ALTER TABLE tbl_attach
50+
ADD CONSTRAINT fk_board_attach FOREIGN KEY (bno) REFERENCES tbl_board (bno);
51+
52+
CREATE TABLE IF NOT EXISTS tbl_member
53+
(
54+
userid VARCHAR2(50) NOT NULL,
55+
userpw VARCHAR2(200) NOT NULL,
56+
username VARCHAR2(100) NOT NULL,
57+
enabled CHAR(1) CHECK (enabled IN ('Y', 'N')) NOT NULL,
58+
regdate DATE DEFAULT SYSDATE,
59+
updatedate DATE DEFAULT SYSDATE,
60+
CONSTRAINT pk_member PRIMARY KEY (userid)
61+
);
62+
63+
CREATE TABLE IF NOT EXISTS tbl_member_auth
64+
(
65+
userid VARCHAR2(50) NOT NULL,
66+
auth VARCHAR2(50) NOT NULL,
67+
CONSTRAINT pk_member_auth PRIMARY KEY (userid, auth),
68+
CONSTRAINT fk_member_auth FOREIGN KEY (userid) REFERENCES tbl_member (userid)
69+
);
70+
71+
-- 자동로그인 토큰 저장 테이블
72+
-- Spring Security의 JdbcTokenRepositoryImpl가 사용하는 테이블
73+
CREATE TABLE IF NOT EXISTS persistent_logins
74+
(
75+
username VARCHAR2(64) NOT NULL,
76+
series VARCHAR2(64) NOT NULL,
77+
token VARCHAR2(64) NOT NULL,
78+
last_used TIMESTAMP NOT NULL,
79+
CONSTRAINT pk_persistent_logins PRIMARY KEY (series)
80+
);
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
-- ============================================================
2+
-- 02_data.sql
3+
-- book_ex 초기 데이터 (DML) - Oracle 21c
4+
-- ============================================================
5+
-- @formatter:off
6+
CONNECT book_ex/book_ex@//localhost:1521/FREEPDB1
7+
-- @formatter:on
8+
9+
-- 회원 등록
10+
INSERT INTO tbl_member (userid, userpw, username, enabled)
11+
VALUES ('user00', '{bcrypt}$2a$10$CdNsrwk7cDs7eBNuW7cp8unvLAA8NKXSqA3UfRgysCjvtZyqCLsWm', '일반사용자00', 'Y');
12+
INSERT INTO tbl_member (userid, userpw, username, enabled)
13+
VALUES ('user01', '{bcrypt}$2a$10$7OrtlXQoaVQjnQEMtK12kuxcqA9g58ZfNZJ9nNElnxuBT4HkPDKNO', '일반사용자01', 'Y');
14+
INSERT INTO tbl_member (userid, userpw, username, enabled)
15+
VALUES ('user02', '{bcrypt}$2a$10$szmbgkK4OalTS9t5409tXelO2Xpsrc8fXRudXFZw6f0p2kLOCZpBe', '일반사용자02', 'Y');
16+
17+
INSERT INTO tbl_member (userid, userpw, username, enabled)
18+
VALUES ('manager80', '{bcrypt}$2a$10$3crhdaHx07QIcj.kZ6rwmOPTwI0mGBk7lh9ubFCh2fy4mwwmKGuGW', '운영자80', 'Y');
19+
INSERT INTO tbl_member (userid, userpw, username, enabled)
20+
VALUES ('manager81', '{bcrypt}$2a$10$a0D7O6DzXUlc4UGXrqyGJeVZvXY8RvUWSP4bEflLWtx1c4VOONQBC', '운영자81', 'Y');
21+
INSERT INTO tbl_member (userid, userpw, username, enabled)
22+
VALUES ('manager82', '{bcrypt}$2a$10$J0N5lEnYviHq2RZTlbssIuaC/WMdSZ.KZ0Az.CkzDlvqXbj5.C5Kq', '운영자82', 'Y');
23+
24+
INSERT INTO tbl_member (userid, userpw, username, enabled)
25+
VALUES ('admin90', '{bcrypt}$2a$10$dcB0GXMEhQwW7E0i3yyR/OGdW1N/QQfioIf/OGN60qAf.Gmjt3fNy', '관리자90', 'Y');
26+
INSERT INTO tbl_member (userid, userpw, username, enabled)
27+
VALUES ('admin91', '{bcrypt}$2a$10$kd0PNukIe.v15HghkXUJIO31BB7ZulAPdMi00LH2O//HuAJAFElMC', '관리자91', 'Y');
28+
INSERT INTO tbl_member (userid, userpw, username, enabled)
29+
VALUES ('admin92', '{bcrypt}$2a$10$JqLbWg6o6PfnLr.yObk4v.LZpFHp0/R7cXc0V8gW2AjaXnkImi7WC', '관리자92', 'Y');
30+
31+
-- 회원 권한 등록
32+
INSERT INTO tbl_member_auth (userid, auth)
33+
VALUES ('user00', 'ROLE_USER');
34+
INSERT INTO tbl_member_auth (userid, auth)
35+
VALUES ('user01', 'ROLE_USER');
36+
INSERT INTO tbl_member_auth (userid, auth)
37+
VALUES ('user02', 'ROLE_USER');
38+
39+
INSERT INTO tbl_member_auth (userid, auth)
40+
VALUES ('manager80', 'ROLE_MEMBER');
41+
INSERT INTO tbl_member_auth (userid, auth)
42+
VALUES ('manager81', 'ROLE_MEMBER');
43+
INSERT INTO tbl_member_auth (userid, auth)
44+
VALUES ('manager82', 'ROLE_MEMBER');
45+
46+
INSERT INTO tbl_member_auth (userid, auth)
47+
VALUES ('admin90', 'ROLE_ADMIN');
48+
INSERT INTO tbl_member_auth (userid, auth)
49+
VALUES ('admin91', 'ROLE_ADMIN');
50+
INSERT INTO tbl_member_auth (userid, auth)
51+
VALUES ('admin92', 'ROLE_ADMIN');
52+
53+
-- 게시물 등록 (bno는 seq_board 시퀀스 사용)
54+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
55+
VALUES (seq_board.NEXTVAL, '게시물 001 제목', '게시물 001 본문', 'admin90',
56+
TO_TIMESTAMP('2022-12-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'),
57+
TO_TIMESTAMP('2022-12-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
58+
59+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
60+
VALUES (seq_board.NEXTVAL, '게시물 002 제목', '게시물 002 본문 - 댓글 달지 마세요!', 'admin90',
61+
TO_TIMESTAMP('2022-12-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'),
62+
TO_TIMESTAMP('2022-12-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
63+
64+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
65+
VALUES (seq_board.NEXTVAL, '게시물 003 제목', '게시물 003 본문', 'admin90',
66+
TO_TIMESTAMP('2022-12-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'),
67+
TO_TIMESTAMP('2022-12-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
68+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
69+
VALUES (seq_board.NEXTVAL, '게시물 004 제목', '게시물 004 본문', 'admin90',
70+
TO_TIMESTAMP('2022-12-01 00:10:00', 'YYYY-MM-DD HH24:MI:SS'),
71+
TO_TIMESTAMP('2022-12-01 00:10:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
72+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
73+
VALUES (seq_board.NEXTVAL, '게시물 005 제목', '게시물 005 본문', 'admin90',
74+
TO_TIMESTAMP('2022-12-01 00:20:00', 'YYYY-MM-DD HH24:MI:SS'),
75+
TO_TIMESTAMP('2022-12-01 00:20:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
76+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
77+
VALUES (seq_board.NEXTVAL, '게시물 006 제목', '게시물 006 본문', 'admin90',
78+
TO_TIMESTAMP('2022-12-01 00:30:00', 'YYYY-MM-DD HH24:MI:SS'),
79+
TO_TIMESTAMP('2022-12-01 00:30:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
80+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
81+
VALUES (seq_board.NEXTVAL, '게시물 007 제목', '게시물 007 본문', 'admin90',
82+
TO_TIMESTAMP('2022-12-01 00:40:00', 'YYYY-MM-DD HH24:MI:SS'),
83+
TO_TIMESTAMP('2022-12-01 00:40:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
84+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
85+
VALUES (seq_board.NEXTVAL, '게시물 008 제목', '게시물 008 본문', 'admin90',
86+
TO_TIMESTAMP('2022-12-01 00:50:00', 'YYYY-MM-DD HH24:MI:SS'),
87+
TO_TIMESTAMP('2022-12-01 00:50:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
88+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
89+
VALUES (seq_board.NEXTVAL, '게시물 009 제목', '게시물 009 본문', 'admin90',
90+
TO_TIMESTAMP('2022-12-01 01:00:00', 'YYYY-MM-DD HH24:MI:SS'),
91+
TO_TIMESTAMP('2022-12-01 01:00:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
92+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
93+
VALUES (seq_board.NEXTVAL, '게시물 010 제목', '게시물 010 본문', 'admin90',
94+
TO_TIMESTAMP('2022-12-01 02:00:00', 'YYYY-MM-DD HH24:MI:SS'),
95+
TO_TIMESTAMP('2022-12-01 02:00:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
96+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
97+
VALUES (seq_board.NEXTVAL, '게시물 011 제목', '게시물 011 본문', 'admin90',
98+
TO_TIMESTAMP('2022-12-01 03:00:00', 'YYYY-MM-DD HH24:MI:SS'),
99+
TO_TIMESTAMP('2022-12-01 03:00:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
100+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
101+
VALUES (seq_board.NEXTVAL, '게시물 012 제목', '게시물 012 본문', 'admin90',
102+
TO_TIMESTAMP('2022-12-01 04:00:00', 'YYYY-MM-DD HH24:MI:SS'),
103+
TO_TIMESTAMP('2022-12-01 04:00:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
104+
INSERT INTO tbl_board (bno, title, content, writer, regdate, updatedate, replycnt)
105+
VALUES (seq_board.NEXTVAL, '게시물 013 제목', '게시물 013 본문', 'admin90',
106+
TO_TIMESTAMP('2022-12-01 05:00:00', 'YYYY-MM-DD HH24:MI:SS'),
107+
TO_TIMESTAMP('2022-12-01 05:00:00', 'YYYY-MM-DD HH24:MI:SS'), 0);
108+
109+
-- 댓글 등록 (rno는 seq_reply 시퀀스 사용, bno=1 은 첫 번째 게시물)
110+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
111+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 01', 'admin90');
112+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
113+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 02', '댓글 작성자 02');
114+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
115+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 03', '댓글 작성자 03');
116+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
117+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 04', '댓글 작성자 04');
118+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
119+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 05', '댓글 작성자 05');
120+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
121+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 06', '댓글 작성자 06');
122+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
123+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 07', '댓글 작성자 07');
124+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
125+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 08', '댓글 작성자 08');
126+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
127+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 09', '댓글 작성자 09');
128+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
129+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 10', '댓글 작성자 010');
130+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
131+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 11', '댓글 작성자 011');
132+
INSERT INTO tbl_reply (rno, bno, reply, replyer)
133+
VALUES (seq_reply.NEXTVAL, 1, '댓글 본문 12', '댓글 작성자 012');
134+
135+
-- 게시물 1번의 댓글 수 업데이트
136+
UPDATE tbl_board
137+
SET replycnt = (SELECT COUNT(*) FROM tbl_reply WHERE bno = 1)
138+
WHERE bno = 1;
139+
140+
-- 첨부파일 등록
141+
INSERT INTO tbl_attach (uuid, uploadpath, filename, filetype, bno)
142+
VALUES ('5c96644a-fbd3-457c-ab1f-50061153d375', '2022/12/01', '이미지_파일.jpg', 'I', 1);
143+
144+
COMMIT;

part-last/my-board-mds/src/main/java/org/fp024/config/SecurityConfig.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
1111
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
1212
import org.springframework.security.core.userdetails.UserDetailsService;
13-
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
13+
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
1414
import org.springframework.security.crypto.password.PasswordEncoder;
1515
import org.springframework.security.web.SecurityFilterChain;
1616
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
@@ -54,12 +54,9 @@ public UserDetailsService customUserDetailsService(MemberService memberService)
5454
return new CustomUserDetailsService(memberService);
5555
}
5656

57-
// 💡 PasswordEncoder를 BCryptPasswordEncoder로 고정하여 사용
58-
// Spring Security 6 까지는 prefix가 없어도 기본으로 BCrypt로 처리가 되었었는데,
59-
// Spring Security 7부터는 prefix가 필요하다. 그래서 일단 BCryptPasswordEncoder로 고정해서 사용해보자!
6057
@Bean
6158
public PasswordEncoder passwordEncoder() {
62-
return new BCryptPasswordEncoder();
59+
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
6360
}
6461

6562
@Bean
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
jdbc.driver=oracle.jdbc.OracleDriver
2-
jdbc.url=jdbc:oracle:thin:@localvmdb.oracle_xe_18c:1521:XE
2+
jdbc.url=jdbc:oracle:thin:@//localhost:1521/FREEPDB1
33
jdbc.username=book_ex
44
jdbc.password=book_ex

0 commit comments

Comments
 (0)