const process = {
nicknameCheck : async (req, res) => {
let inputNickname = req.body.nickname;
let result = await service.duplicationCheck.nicknameCheck(inputNickname);
// 아이디가 존재할 시 result : 1
// 아이디가 존재하지 않을시 result : 0
res.json(result);
}
}
controller 에서 localhost:3000/login/nicknameCheck 로 요청이 들어오기는 하나 프론트에서 보내준 파라미터 값이 서버에서 req.body 로 받아지지 않는 현상 발생
create table paging(
num number not null,
title varchar2(30) not null,
pdate varchar2(10) not null,
count number not null,
primary key(num)
);
create sequence test_num;
글 작성시 이동되는 /write 경로 page_router.js 에 작성 ( post 방식 )
page_controller.js 에 async - await 을 통해 동기처리 하여 작성
page_service.js 에 pageInsert 부분 작성
pageDAO.js 에 글에 관련된 데이터 DB 에 저장하는 로직 작성 ( nextval : DB 에 sequence 로 생성해놓은 1씩 값이 증가하며 저장되는 부분을 의미 )
서버 실행
글 작성부분 구현 완료
글 상세보기 구현
list.ejs 에 글 타이틀에 글 번호를 경로로 하는 a 태그 작성
page_router.js 에 경로 작성 :num 으로 글 번호를 변수로 받음
page_controller.js 에 변수로 받은 num 을 service 로 넘겨주는 코드 작성
page_service.js 에 넘겨받은 글 번호를 dao 쪽으로 넘겨서 연산하는 코드 작성
dao 에 넘겨 받은 글 번호랑 일치하는 행을 찾는 코드를 작성 후 return 으로 해당 데이터를 service 로 반환
content.ejs 작성
글 상세보기 구현 완료
조회수 증가시키는 부분 구현
page_service.js 에 조회수 증가시키는 부분 로직 작성
dao 에 조회수 증가 로직 작성
서버 실행 ( 만약 조회수가 글을 눌러서 상세보기가 켜지자 마자 늘어나길 원한다면 조회수 늘어나는 로직에 async - await 을 적용해주면 된다 )
글 조회수 증가 구현 완료
페이징 처리
페이징 방식
글의 총 갯수를 가져오는 totalContent 를 page_controller.js 에 작성
page_service.js 에 글 전체 갯수 가져오는 로직 작성
pageDAO.js 에 DB 에 접근하여 전체 글 갯수 가져오는 로직 작성
list.ejs 에 totalContent 출력해 봄 ( 콘솔과 웹 출력 결과물 )
페이지를 확인할 수 있는 start 라는 변수를 생성하여 로직을 작성할 것, page_controller.js 작성
page_service.js 에서 로직 작성
start 값을 출력해 봄
이전을 누르면 start -1 값을 전달, 다음을 누르면 start +1 값을 전달, start 값이 1이면 이전 버튼을 비활성화, start 값이 totalContent 와 같아면 다음 버튼을 비활성화
rownum : 가상의 행의 수
( 의미는 없지만, 만약 글의 번호로 데이터를 처리한다고 가정했을 때 한 페이지에 글을 5개씩 출력하고자 할 때 2번째 작성 글이 삭제되었다면 오류가 발생하거나 첫번째 페이지에 1, 3, 4, 5 글 4개만 출력되게 된다..... 그래서 오라클에서 지원하는 가상의 행{결과 값이 출력되는 행만큼 임의의 번호를 붙여주는 rownum}인 rownum 을 사용하여 글이 삭제되었어도 빈 값이 없이 1, 3, 4, 5, 6 식으로 출력되게끔 설정한다 )
마지막 페이지 값을 담은 page 정보도 page_controller.js 에 작성
page_service.js 에서 pageNum 에 한 페이지 당 출력될 글의 갯수 설정 후 연산을 통해 toPage(총 페이지) 설정, startNum 과 endNum 은 DB 에 글의 rownum 연산을 할 때 필요한 값을 선언 ( start 는 현재 몇번째 페이지인지 나타냄 )
page_service.js 에서 페이지 정보를 DAO 에 전달하여 연산
list.ejs 에서 전달받은 page 의 totPage(토탈 페이지) 값으로 목록을 출력한다
Node.js 파일에서 Oracle Cloud DB 에 접속하여 쿼리문을 실행시켜 볼 것이다
우선은 자신의 Oracle Cloud DB 에 접속하여 접속 가능한 IP 설정을 진행한다
엑세스 제어 목록 - 편집 클릭
값에 접속할 IP 를 설정해준다 ( 내 IP 주소 추가를 누르면 내 공인 IP 가 추가되며 내 아이피 외에 다른 아이피가 접속하려면 다른 공인 IP 를 기입해주면 된다 ) - 저장
mTLS 인증 옆의 편집 클릭
mTLS 인증 필요의 체크박스를 해제 후 저장 클릭
데이터 베이스 접속 클릭
접속 문자열에서 TLS 클릭
TNS 의 접속 문자열 중
high, low, medium 중 하나 복사 ( high, low, medium 은 성능을 나타냄 )
high - 최고 성능, 가장 빠른 응답 속도로 수행되지만 실행할 수 있는 동시 SQL 문 수가 3개
medium - high 보다 동시에 많은 SQL 문을 수행할 수 있으나 high 에 비해서는 낮은 수준의 성능을 제공
low - 동시에 가장 많은 SQL 문을 수행하며 각 SQL 문 마다 최소로 작은 수준의 리소스를 제공
const oracledb = require('oracledb');
// Oracle Cloud 자율운영 데이터베이스 연결 정보
const dbConfig = {
user: 'admin',
password: 'Oracle1234567',
connectString: '!!!!Oracle DB의 접속 TLS 정보를 기입!!!!'
// connectString 에 TLS 에서 복사한 정보를 기입
};
async function run() {
let connection;
try {
// Oracle 데이터베이스에 연결
connection = await oracledb.getConnection(dbConfig);
// 연결 확인
console.log('Connected to database!');
// 여기에 쿼리 실행 또는 기타 작업 추가
// 예를 들어:
// const result = await connection.execute('SELECT * FROM my_table');
// console.log(result);
let result = await connection.execute("select * from test");
console.log("result : ", result);
} catch (err) {
console.error('Error connecting to database:', err);
} finally {
// 연결 닫기
if (connection) {
try {
await connection.close();
console.log('Connection closed.');
} catch (err) {
console.error('Error closing connection:', err);
}
}
}
}
run();
dbConfig 에서 connectString 부분에 복사한 oracleDB 의 TLS 주소를 넣어준다
테스트로 생성해둔 test 테이블의 결과를 출력했으며 응답은 다음과 같다.
rows 열에 있는 데이터를 꺼내 쓰면 될 듯 하다
지금은 배열 형식의 Object 를 사용하지만 key 로 값을 가져오는 Object 형식으로 변환하는 코드를 추가
const oracledb = require('oracledb');
oracledb.autoCommit = true;
// 쿼리문 작성 시 자동으로 커밋되는 기능 활성화
oracledb.outFormat = oracledb.OBJECT;
// 데이터 베이스로부터 데이터를 얻어올때 Object 자료형으로 가져온다
// 위 설정을 하면 [{}, {}, {}] 형식으로 들어오고
// 위 설정을 하지 않으면 [[], [], []] 형식으로 데이터가 들어온다
// 키와 값으로 사용하기 위해 해당 설정을 한다
// Oracle Cloud 자율운영 데이터베이스 연결 정보
const dbConfig = {
user: 'admin',
password: 'Oracle1234567',
connectString: '(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=adb.us-chicago-1.oraclecloud.com))(connect_data=(service_name=g72f610f5f11b4c_orcl_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))'
// connectString 에 TLS 에서 복사한 정보를 기입
};
async function run() {
let connection;
try {
// Oracle 데이터베이스에 연결
connection = await oracledb.getConnection(dbConfig);
// 연결 확인
console.log('Connected to database!');
// 여기에 쿼리 실행 또는 기타 작업 추가
// 예를 들어:
// const result = await connection.execute('SELECT * FROM my_table');
// console.log(result);
let result = await connection.execute("select * from test");
console.log("result : ", result);
} catch (err) {
console.error('Error connecting to database:', err);
} finally {
// 연결 닫기
if (connection) {
try {
await connection.close();
console.log('Connection closed.');
} catch (err) {
console.error('Error closing connection:', err);
}
}
}
}
run();
oracledb.autoCommit=true;
// 쿼리문 작성 시 자동으로 커밋되는 기능 활성화
oracledb.outFormat=oracledb.OBJECT;
// 데이터 베이스로부터 데이터를 얻어올때 Object 자료형으로 가져온다
// 위 설정을 하면 [{}, {}, {}] 형식으로 들어오고
// 위 설정을 하지 않으면 [[], [], []] 형식으로 데이터가 들어온다
// 키와 값으로 사용하기 위해 해당 설정을 한다
위 부분이 추가됐으며, 결과 값은 아래와 같다
기존 결과 값과 다르게 키, 값의 형식으로 가져오는 모습 여기서 키는 row 의 값으로 변환되어 나온다
이전에 DAO 를 사용하는 형식으로 사용될 때 db의 Config 파일만 고쳐주면 사용이 가능하다
파일 업로드, 다운로드는 post 방식을 사용하기 때문에 body-parser 사용 router 위임
router.js 에서 app 을 위임받아 사용 후 바로 router 를 export
router 에서 /file 경로로 들어오는 부분은 fileRouter 를 변수로 생성하여 위임 후 file_router.js 에서는 /file 경로로 들어올때 내용을 처리하고 router 를 다시 export 로 반환
file_router 에서는 세부 경로를 다시 file_controller 로 위임
file_controller 에서 Object 를 하나 변수로 선언하여 키와 값으로 경로들을 묶어서 export 하고 file_router.js 에서는 사용 하고자 하는 키로 값을 가져와 사용한다
controller 작성, file_index.ejs 작성 후 작동 결과
form 태그 내에서 파일을 전송하는 경우
enctype="multipart/form-data"
위 코드를 적용해줘야 함
file_router 에 파일 선택 후 업로드할때 출력될 페이지 경로 설정 ( 파일 전송이기 때문에 post 방식 )
단순히 화면을 출력하는 부분은 view 라는 Object 에 모아서 사용, process 라는 Object 에는 연산을 하는 부분을 넣어서 사용, file_router 에서도 코드 수정
controller 에서 기존처럼 사용하지 않는 이유는 결국 controller 에 세부 경로가 많아질 수록 코드가 쌓이게 되는데 코드에서 문제가 생길 시 단순 출력 부분과 연산 부분 중 어느 부분이 문제가 생긴지 파악하고 쉽게 고칠 수 있기 때문... 또한 Object 로 묶어서 사용하는 이유는 exports 의 코드가 너무 길어지기 때문이므로 Object 를 exports 하여 router 에서 Object.key 형식으로 함수를 사용한다
router 에 multer 설정 및 파일 업로드 부분에 multer 의 기능을 추가.... controller 에서 console 로 출력 코드 적고 파일 전송해봄
저장되는 파일의 이름을 원본 파일과 동일하게 저장하기 위해 코드를 수정
코드 실행
특정 파일 형식만 사용하고 싶은 경우
filter 를 따로 구성하여 multer 에 추가한다
사용할 수 없는 확장자를 올리는 경우 filter 에서 확장자가 일치하지 않는 경우 req.fileValidation 에 문구를 설정하고 req.fileValidation 은 controller 에서도 사용할 수 있기 때문에 컨트롤러에서 확인하여 분류한다
코드 동작 영상
다운로드 구현
router 와 controller 에 이미지가 저장된 디렉토리의 내용을 읽어오는 코드를 작성
읽어온 이미지를 /file/list 경로로 보내줘서 출력 후 a 태그를 걸어 다운로드 링크를 생성
라우터에 다운로드 경로 추가, 컨트롤러에 다운로드 기능 추가
res.download(경로) : 해당 경로를 다운로드
다운로드 기능 구현 완료
이미지 업로드 시 미리보기 기능 구현
이미지 미리보기 구현은 파일 올리는 부분의 ejs 에서만 처리해주면 된다
onchange="readURL(this)" : 만약 파일이 선택되면 태그에 변경이 일어나기 때문에 readURL() 함수를 실행시킨다, 이때 매개변수로 자기 자신 태그가 가지고 있는 파일 정보를 전송한다.
readURL 함수에서는 이 파일의 정보를 input 변수로 넘겨 받아서 해당 변수의 files 라는 키 안에 들어있는 파일의 저장 경로를 file 함수로 담아준다
> 만약 파일 경로가 비어있지 않다면 ( 파일이 정상적으로 올라왔다면 ) 이 파일의 정보를 FileReader 를 사용하여 읽어서 변수 e 로 만든다.
> 이후에 이 변수의 target 이라는 키 안에 result 키에 담겨있는 이미지에 대한 경로를 가져와서 html 코드의 img 경로를 변경해준다
나중에 쇼핑몰같은 홈페이지의 경우 썸네일을 모두 원본으로 사용해버리면 용량이 너무 커지기 때문에 썸네일용으로 따로 파일을 처리해서 사용해야 한다 ( 구선생님께 노드 썸네일 생성 으로 검색하면 나옴 )
파일 삭제 구현
ejs 작성, router 작성
controller 에 삭제 기능 구현
파일 수정
원본 파일을 삭제 후 저장
수정기능 경로로 가는 ejs 파일 작성, router 에 경로와 파일이름 같이 전송
controller 에 views 에 modify_form 경로로 가는 부분 작성
modify_form.ejs 작성
modify_form.ejs 에 hidden 으로 코드 추가
수정 부분 router 에 추가 ( 파일을 전송하기 때문에 post 방식 )
파일을 수정하면 원본으로 있던 파일을 삭제하는 코드를 controller 에 작성, 그리고 수정을 누르는 순간 router 에서 수정될 이미지는 upload 명령어를 사용해서 저장하기 때문에 따로 새로 수정될 이미지를 저장하는 코드는 작성하지 않음
자바스크립트 파일과 css 파일을 하나의 파일로 분리하여 관리
중복된 스크립트 코드를 image_read.js 라는 파일에 옮겨놓음
스크립트가 들어있는 경로를 /static 으로 설정 후 file_index.ejs 파일과 modify_form.ejs 파일에 설정