728x90

SQL 넣기 적합 여부이유

config/ 설정 정보 (DB, env 등) SQL은 설정이 아니라 로직이라 부적합
controllers/ 라우터에서 받아서 처리 로직 담당 직접 SQL을 들고 있기엔 무거움
models/ DB 테이블 매핑 또는 ORM 사용 시 오라클 점검은 보통 비즈니스 데이터 아님
public/ 정적 파일 (HTML, 이미지 등) JS 넣으면 안 됨
router/ 라우팅 정의 SQL 넣을 자리 아님
services/ 비즈니스 로직, DB 작업 등 핵심 처리 가장 적합 점검 SQL을 포함한 로직을 담기에 제일 좋음
➕ queries/ (추가 가능) 순수 SQL만 따로 모아놓는 폴더로 추가할 수도 있음 ✅ 추천 (옵션) 보기 좋고 확장성 있음
728x90
반응형

'Dev > Javascript' 카테고리의 다른 글

[nodejs] 기본 폴더 파일 구조  (2) 2024.12.04
[git] add, commit 취소  (0) 2024.11.28
[JavaScript] 화살표 함수 기본  (1) 2024.11.27
[Node.js] 오라클 연동 NJS-116, DPI-1047 해결  (1) 2024.11.26
[git] 커밋하고 푸시  (1) 2024.11.23
728x90
project-root/
│
├── app.js               # 메인 서버 파일 (애플리케이션 진입점)
├── package.json         # 프로젝트 메타데이터 및 의존성 관리
├── config/              # 환경 설정 및 데이터베이스 설정
│   ├── config.js        # 환경변수 및 설정
│   └── db.js            # 데이터베이스 연결 설정
│
├── controllers/         # 요청 처리 로직
│   ├── userController.js
│   └── productController.js
│
├── models/              # 데이터베이스 모델 정의
│   ├── userModel.js
│   └── productModel.js
│
├── routes/              # 라우팅 처리
│   ├── userRoutes.js
│   └── productRoutes.js
│
├── services/            # 비즈니스 로직 (Controller와 Model 사이 로직)
│   ├── userService.js
│   └── productService.js
│
├── middlewares/         # 미들웨어 함수 (인증, 로깅 등)
│   ├── authMiddleware.js
│   └── errorHandler.js
│
├── views/               # 템플릿 파일 (EJS, Pug 등)
│   └── index.ejs
│
├── public/              # 정적 파일 (CSS, JavaScript, 이미지 등)
│   ├── css/
│   ├── js/
│   └── images/
│
├── utils/               # 공통 유틸리티 함수
│   └── helper.js
│
└── tests/               # 테스트 코드 (Jest, Mocha 등)
    ├── user.test.js
    └── product.test.js

 

기본 파일 및 폴더 구조

 
 

각 폴더 및 파일 설명

  1. app.js 또는 server.js
    • 기능: 애플리케이션의 진입점.
    • 내용: 서버 설정, 미들웨어 등록, 라우트 연결.
  2. package.json
    • 기능: 프로젝트의 의존성 및 스크립트 관리.
    • 내용: 설치된 패키지 목록과 실행 스크립트 정의.
  3. config/
    • 기능: 환경 설정 및 데이터베이스 연결 정보.
    • 파일 예시: config.js(환경 변수), db.js(DB 설정).
  4. controllers/
    • 기능: HTTP 요청을 처리하고, 비즈니스 로직 호출.
    • 내용: 요청을 받아 서비스를 호출하고 응답 반환.
  5. models/
    • 기능: 데이터베이스 스키마 및 모델 정의.
    • 내용: ORM(Mongoose, Sequelize 등)으로 데이터 구조 정의.
  6. routes/
    • 기능: URL 경로와 컨트롤러 연결.
    • 내용: RESTful API 경로 정의.
  7. services/
    • 기능: 비즈니스 로직 구현 (Controller와 Model 사이 로직).
    • 내용: 데이터 처리, 복잡한 연산 수행.
    • services 폴더Node.js 프로젝트에서 비즈니스 로직이나 외부 서비스와의 상호작용을 처리하는 코드를 포함하는 데 사용됩니다. 이를 통해 컨트롤러라우터에서 복잡한 로직을 분리하고, 재사용성유지보수성을 높일 수 있습니다.
      1. 비즈니스 로직 처리: 데이터베이스 연산, 데이터 처리 등 핵심 로직을 구현.
      2. 외부 API 호출: 다른 서비스나 API와 통신하는 코드 작성.
      3. 코드 재사용: 컨트롤러나 라우터에서 자주 사용되는 기능을 모듈화.
      4. 비즈니스 규칙 적용: 애플리케이션의 주요 규칙이나 정책을 포함.
  8. middlewares/
    • 기능: 요청 전/후 처리 작업 (인증, 로깅, 에러 처리).
    • 예시: JWT 인증, 에러 핸들링 미들웨어.
  9. views/
    • 기능: 서버 사이드 렌더링을 위한 템플릿.
    • 내용: EJS, Pug, Handlebars 등의 템플릿 파일.
  10. public/
    • 기능: 정적 파일 제공.
    • 내용: CSS, JavaScript, 이미지 파일.
  11. utils/
    • 기능: 공통 유틸리티 함수 저장.
    • 내용: 데이터 포맷, 암호화, 공통 함수.
  12. tests/
    • 기능: 테스트 코드 작성.
    • 내용: 단위 테스트 및 통합 테스트 파일.
728x90
반응형

'Dev > Javascript' 카테고리의 다른 글

[javascript] mvc 패턴 디렉토리 역할  (0) 2025.04.09
[git] add, commit 취소  (0) 2024.11.28
[JavaScript] 화살표 함수 기본  (1) 2024.11.27
[Node.js] 오라클 연동 NJS-116, DPI-1047 해결  (1) 2024.11.26
[git] 커밋하고 푸시  (1) 2024.11.23
728x90

git add 취소하기(파일 상태를 Unstage로 변경하기)
아래와 같이 실수로 git add * 명령을 사용하여 모든 파일을 Staging Area에 넣은 경우,
Staging Area(git add 명령 수행한 후의 상태)에 넣은 파일을 빼고 싶을 때가 있다.
// 모든 파일이 Staged 상태로 바뀐다.
$ git add *
// 파일들의 상태를 확인한다.
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
  renamed:    README.md -> README
  modified:   CONTRIBUTING.md
이때, git reset HEAD [file] 명령어를 통해 git add를 취소할 수 있다.

뒤에 파일명이 없으면 add한 파일 전체를 취소한다.
CONTRIBUTING.md 파일을 Unstaged 상태로 변경해보자.
// CONTRIBUTING.md 파일을 Unstage로 변경한다.
$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M CONTRIBUTING.md
// 파일들의 상태를 확인한다.
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
  renamed:    README.md -> README
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
  modified:   CONTRIBUTING.md
https://gmlwjd9405.github.io/2018/05/25/git-add-cancle.html

 

 

완료한 commit을 취소해야 할 때가 있다.
너무 일찍 commit한 경우
어떤 파일을 빼먹고 commit한 경우 이때, git reset HEAD^ 명령어를 통해 git commit을 취소할 수 있다.
// commit 목록 확인
$ git log
https://gmlwjd9405.github.io/2018/05/25/git-add-cancle.html

 

 

// [방법 1] commit을 취소하고 해당 파일들은 staged 상태로 워킹 디렉터리에 보존
$ git reset --soft HEAD^
// [방법 2] commit을 취소하고 해당 파일들은 unstaged 상태로 워킹 디렉터리에 보존
$ git reset --mixed HEAD^ // 기본 옵션
$ git reset HEAD^ // 위와 동일
$ git reset HEAD~2 // 마지막 2개의 commit을 취소
// [방법 3] commit을 취소하고 해당 파일들은 unstaged 상태로 워킹 디렉터리에서 삭제
$ git reset --hard HEAD^
https://gmlwjd9405.github.io/2018/05/25/git-add-cancle.html

728x90
반응형
728x90

함수 표현식보다 단순하고 간결한 문법으로 함수를 만들 수 있는 방법이 있습니다.

바로 화살표 함수(arrow function)를 사용하는 것입니다. 화살표 함수라는 이름은 문법의 생김새를 차용해 지어졌습니다.

let func = (arg1, arg2, ...argN) => expression

이렇게 코드를 작성하면 인자 arg1..argN를 받는 함수 func이 만들어집니다. 함수 func는 화살표(=>) 우측의 표현식(expression)을 평가하고, 평가 결과를 반환합니다.

아래 함수의 축약 버전이라고 할 수 있죠.

let func = function(arg1, arg2, ...argN) {
  return expression;
};

좀 더 구체적인 예시를 살펴봅시다.

 
 
let sum = (a, b) => a + b;

/* 위 화살표 함수는 아래 함수의 축약 버전입니다.

let sum = function(a, b) {
  return a + b;
};
*/

alert( sum(1, 2) ); // 3

보시는 바와 같이 (a, b) => a + b는 인수 a와 b를 받는 함수입니다. (a, b) => a + b는 실행되는 순간 표현식 a + b를 평가하고 그 결과를 반환합니다.

  • 인수가 하나밖에 없다면 인수를 감싸는 괄호를 생략할 수 있습니다. 괄호를 생략하면 코드 길이를 더 줄일 수 있습니다.
     
     
    let double = n => n * 2;
    // let double = function(n) { return n * 2 }과 거의 동일합니다.
    
    alert( double(3) ); // 6
  • 예시:
  • 인수가 하나도 없을 땐 괄호를 비워놓으면 됩니다. 다만, 이 때 괄호는 생략할 수 없습니다.
  •  
     
    let sayHi = () => alert("안녕하세요!");
    
    sayHi();

화살표 함수는 함수 표현식과 같은 방법으로 사용할 수 있습니다.

아래 예시와 같이 함수를 동적으로 만들 수 있습니다.

 
 
let age = prompt("나이를 알려주세요.", 18);

let welcome = (age < 18) ?
  () => alert('안녕') :
  () => alert("안녕하세요!");

welcome();

화살표 함수를 처음 접하면 가독성이 떨어집니다. 익숙지 않기 때문입니다. 하지만 문법이 눈에 익기 시작하면 적응은 식은 죽 먹기가 됩니다.

함수 본문이 한 줄인 간단한 함수는 화살표 함수를 사용해서 만드는 게 편리합니다. 타이핑을 적게 해도 함수를 만들 수 있다는 장점이 있습니다.

본문이 여러 줄인 화살표 함수

위에서 소개해 드린 화살표 함수들은 => 왼쪽에 있는 인수를 이용해 => 오른쪽에 있는 표현식을 평가하는 함수들이었습니다.

그런데 평가해야 할 표현식이나 구문이 여러 개인 함수가 있을 수도 있습니다. 이 경우 역시 화살표 함수 문법을 사용해 함수를 만들 수 있습니다. 다만, 이때는 중괄호 안에 평가해야 할 코드를 넣어주어야 합니다. 그리고 return 지시자를 사용해 명시적으로 결괏값을 반환해 주어야 합니다.

아래와 같이 말이죠.

 
 
let sum = (a, b) => {  // 중괄호는 본문 여러 줄로 구성되어 있음을 알려줍니다.
  let result = a + b;
  return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 합니다.
};

alert( sum(1, 2) ); // 3
아직 끝나지 않았습니다.

지금까진 간결함이라는 특징을 중심으로 화살표 함수에 대해 알아보았습니다. 하지만 이게 다가 아닙니다!

화살표 함수는 여기서 소개한 기능 이외에도 다른 흥미로운 기능을 지원합니다.

자세한 내용을 배우려면 자바스크립트의 다른 내용들을 더 알아야 합니다. 화살표 함수의 깊은 내용을 알기위해 필요한 내용을 배운 후에 화살표 함수 다시 살펴보기에서 그 내용들을 다루도록 하겠습니다.

지금까진 본문이 한 줄인 화살표 함수, 화살표 함수가 콜백으로 쓰인 경우에 대해서 알아보았습니다.

요약

화살표 함수는 본문이 한 줄인 함수를 작성할 때 유용합니다. 본문이 한 줄이 아니라면 다른 방법으로 화살표 함수를 작성해야 합니다.

  1. 중괄호 없이 작성: (...args) => expression – 화살표 오른쪽에 표현식을 둡니다. 함수는 이 표현식을 평가하고, 평가 결과를 반환합니다.
  2. 중괄호와 함께 작성: (...args) => { body } – 본문이 여러 줄로 구성되었다면 중괄호를 사용해야 합니다. 다만, 이 경우는 반드시 return 지시자를 사용해 반환 값을 명기해 주어야 합니다.
728x90
반응형

'Dev > Javascript' 카테고리의 다른 글

[nodejs] 기본 폴더 파일 구조  (2) 2024.12.04
[git] add, commit 취소  (0) 2024.11.28
[Node.js] 오라클 연동 NJS-116, DPI-1047 해결  (1) 2024.11.26
[git] 커밋하고 푸시  (1) 2024.11.23
[git] vscode commit push 무한 로딩  (0) 2024.11.21
728x90

 

오라클 계정 중 password version 에 10G 즉 verifier를 10g 버전으로 사용하는 계정이 있으면 

thin 모드의 oracledb 라이브러리에선 이를 지원 하지 않는다. 

 

즉, 암호 검증 유형 0x939는 Thin 모드의 node-oracledb에서 지원되지 않는다. 

(아래 참고) 

https://github.com/oracle/node-oracledb/issues/1584

 

클라이언트 다운로드 링크

https://www.oracle.com/kr/database/technologies/instant-client/winx64-64-downloads.html

 

Error: Error: NJS-116: password verifier type 0x939 is not supported by node-oracledb in Thin mode
    at Object.throwErr (D:\dev\nodejs\node_modules\oracledb\lib\errors.js:693:10)
    at AuthMessage.encode (D:\dev\nodejs\node_modules\oracledb\lib\thin\protocol\messages\auth.js:210:20)
    at Protocol._encodeMessage (D:\dev\nodejs\node_modules\oracledb\lib\thin\protocol\protocol.js:109:20)
    at Protocol._processMessage (D:\dev\nodejs\node_modules\oracledb\lib\thin\protocol\protocol.js:163:18)
    at ThinConnectionImpl.connect (D:\dev\nodejs\node_modules\oracledb\lib\thin\connection.js:843:30)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async ThinPoolImpl.bgThreadFunc (D:\dev\nodejs\node_modules\oracledb\lib\thin\pool.js:455:11) {
  code: 'NJS-116'

 

 

그래서 Thick 모드로 연결을 시도 하던중 기존 오라클 클라이언트 경로를 환경 변수 Path에 추가 해 주고 다음과 같이 경로를 잡아 주었는데,,

const oracle = require('oracledb');
//Thick mode 활성화
try {
  // Oracle Instant Client의 경로 설정
  oracle.initOracleClient({ libDir: 'C:\Oracle\client_19\instantclient_19_25' });
  console.log('Thick mode initialized');
} catch (err) {
  console.error('Error initializing Oracle client:', err);
}

 

아래와 같은 에러가 났다. 

Error initializing Oracle client: Error: DPI-1047: Cannot locate a 64-bit Oracle Client library: "The specified module could not be found". See https://node-oracledb.readthedocs.io/en/latest/user_guide/installation.html for help
Node-oracledb installation instructions: https://node-oracledb.readthedocs.io/en/latest/user_guide/installation.html
You must have Windows 64-bit Oracle Client libraries in your PATH environment variable.
If you do not have Oracle Database on this computer, then install the Instant Client Basic or Basic Light package from
https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html
A Microsoft Visual Studio Redistributable suitable for your Oracle client library version must be available.

    at Object.initOracleClient (D:\dev\nodejs\node_modules\oracledb\lib\oracledb.js:783:20)
    at Object.<anonymous> (D:\dev\nodejs\server.js:9:10)
    at Module._compile (node:internal/modules/cjs/loader:1546:14)
    at Object..js (node:internal/modules/cjs/loader:1689:10)
    at Module.load (node:internal/modules/cjs/loader:1318:32)
    at TracingChannel.traceSync (node:diagnostics_channel:315:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:218:24)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5)
    at node:internal/main/run_main_module:36:49 {
  code: 'DPI-1047'
}
Oracle connection pool created
Server is running on http://localhost:3000

 

결국 클라이언트 전체 디렉터리를 프로젝트 폴더 아래에 복사하고 다음과 같이 경로를 잡아 주니 해결..!

const oracle = require('oracledb');
//Thick mode 활성화
try {
  // Oracle Instant Client의 경로 설정
  oracle.initOracleClient({ libDir: './instantclient_19_25' });
  console.log('Thick mode initialized');
} catch (err) {
  console.error('Error initializing Oracle client:', err);
}

 

 

728x90
반응형

'Dev > Javascript' 카테고리의 다른 글

[git] add, commit 취소  (0) 2024.11.28
[JavaScript] 화살표 함수 기본  (1) 2024.11.27
[git] 커밋하고 푸시  (1) 2024.11.23
[git] vscode commit push 무한 로딩  (0) 2024.11.21
[Node.js] DB Daily Check 자동화 (1) 환경 설정  (0) 2024.11.21
728x90

▶[git] 커밋하고 푸시하기 과정 (git commit, push)


▶설명


오늘은 일반적으로 git에서 파일을 수정한 후에

커밋(commit)하고 푸시(push)하는 과정에 대해 다뤄보겠습니다.

 

▶과정


해당 과정은 파일을 수정한 후부터 다루고 있습니다.

 

1. git pull 명령어로 원격 저장소의 데이터를 로컬 저장소에 최신화합니다.

만약 이 과정을 건너뛰고 커밋(commit)하면 푸시(push)할 때 충돌이 발생하여 pull하고나서 병합(merge) 된 내용을 푸시(push)하게 될 것입니다.

git pull

 

Already up to date.

 

만약 Already up to date.라고 뜨면 이미 최신화되어 있다는 의미입니다.

 

2. git status 명령어로 로컬 작업 공간의 상태를 확인합니다.

git status

 

 

예시로 README.md 파일을 수정하였습니다.

 

3. git diff 명령어로 수정된 파일의 내용을 확인합니다.

git diff

 

 

 

4. 내용을 확인했으면 git add 명령어로 작업 사항을 스테이지에 추가합니다.

git add .

. 은 모든 파일을 의미합니다.

 

 

모든 파일을 스테이지에 올리고 싶지 않은 경우에는 파일명으로 스테이지에 추가하시기 바랍니다.

예시)

git add README.md

 

5. git status 명령어로 상태를 확인합니다.

git status

 

 

스테이지에 파일이 추가된 것을 확인합니다.

 

6. git commit 명령어로 커밋(commit)합니다.

-m 옵션은 커밋 메시지를 남길 때 사용하는 옵션입니다.

git commit -m "Message Text"

 

 

 

7. git status 명령어로 상태를 확인합니다.

git status

 

 

예시에서는 현재 원격 저장소에 푸시(push)할 수 있는 커밋(commit)이 1건 존재하는 것을 확인할 수 있습니다.

 

8.git push 명령어를 사용하여 로컬 저장소에 있는 커밋(commit)을 원격 저장소로 올립니다.

git push

 

 

만일 작업 중에 원격 저장소에 누군가가 올렸을 경우 최신화가 되지 않았기 때문에 git pull 과정을 거쳐야 할 수도 있습니다.

 

이로써 파일을 수정한 후에 커밋(commit)하고 푸시(push)하는 과정은 끝입니다.

 

▶마치며


이번에는 git에서 커밋(commit)하고 푸시(push)하는 과정을 상세하게 다뤄봤습니다.

 

도움이 되었으면 좋겠습니다.

출처: https://extbrain.tistory.com/155 [확장형 뇌 저장소:티스토리]

728x90
반응형
728x90

 

PS C:\Dev\nodejs> git init

PS C:\Dev\nodejs> git commit -m "start!!"
[main b282740] start!!

 134 files changed, 31959 insertions(+), 2 deletions(-)

... 생략 

PS C:\Dev\nodejs> git branch -M main 
PS C:\Dev\nodejs> git remote add origin https://...
error: remote origin already exists.
PS C:\Dev\nodejs> git push -u origin main
Enumerating objects: 159, done.
Counting objects: 100% (159/159), done.
Delta compression using up to 8 threads
Compressing objects: 100% (151/151), done.
Writing objects: 100% (155/155), 1.31 MiB | 1.71 MiB/s, done.
Total 155 (delta 41), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (41/41), completed with 3 local objects.
To https://github.com/EunjungSong87/nodejs.git
   77dffe3..b282740  main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

728x90
반응형
728x90

https://p-elideveloper.tistory.com/69

 

[Node.js] 게시판(1/4) CRUD 만들기, 게시글 작성/상세/수정/삭제

환경설정 vscode로 새 프로젝트를 만들어서 해당 디렉터리에 npm package를 만들어줍니다. npm init -y 필요한 라이브러리를 설치해줍니다. npm install express cors body-parser mysql2 Express Express는 Node.js 기반의

p-elideveloper.tistory.com

 

매일 하는 업무인 DB 점검 업무에 대해 화면으로 보면 좋겠다. 생각하여, 요즘 관심있는 nodejs를 이용해 개발을 해보기로한다. 먼저 위의 블로그를 참조해 환경 구성을 해주었다. 

 

Express 

 

Express는 Node.js 기반의 웹 응용 프레임워크로, 웹 응용 프로그램 및 RESTful API를 손쉽게 구축할 수 있게 해주는 도구입니다. 간결하면서도 강력한 기능을 제공하여 서버 사이드 로직을 쉽게 작성할 수 있도록 도와줍니다.

 

CORS(Cross-Origin Resource Sharing)

 

CORS는 웹 브라우저에서 실행 중인 JavaScript가 다른 출처의 리소스에 접근하는 것을 허용하는 메커니즘을 제공합니다. 서로 다른 도메인 간의 HTTP 요청이 보안 정책에 의해 차단되는 것을 우회할 수 있게 해주는 중요한 보안 기능 중 하나입니다. Express에서는 cors 미들웨어를 사용하여 CORS 문제를 처리합니다.

 

Body-Parser

 

Body-Parser는 Express에서 HTTP 요청의 본문을 쉽게 파싱 할 수 있도록 도와주는 미들웨어입니다. 클라이언트에서 서버로 전송되는 데이터를 해석하여 서버에서 사용할 수 있도록 만들어줍니다. JSON, URL-encoded 및 기타 형식의 데이터를 파싱할 수 있습니다.

 

oracledb

 

위 블로그와 달리 현재 내 운영DB는 Oracle 이므로 Oracle 모듈을 대신 설치 해주기로 한다.

요약

  • Express는 Node.js를 기반으로 한 웹 응용 프레임워크로, 빠르고 간편한 웹 애플리케이션 및 API를 만들 수 있도록 지원합니다.
  • CORS는 다른 출처의 리소스에 대한 웹 브라우저에서의 접근을 허용하는 메커니즘으로, Express에서는 cors 미들웨어를 통해 처리합니다.
  • Body-Parser는 Express에서 HTTP 요청의 본문을 쉽게 파싱 하여 서버에서 사용할 수 있도록 도와줍니다.
  • mysql2는 Node.js에서 MySQL 데이터베이스와의 상호 작용을 위한 드라이버로, 비동기 쿼리와 프라미스를 지원하여 효율적인 코드 작성을 가능케 합니다.

 

필요한 라이브러리 설치 

npm install express cors body-parser

 

PS E:\nodejs> npm install express cors body-parser

added 2 packages, and audited 68 packages in 6s

13 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
PS E:\nodejs>

 

 

오라클 모듈 설치

 npm install oracledb --save

 

PS E:\nodejs>  npm install oracledb --save

added 1 package, and audited 69 packages in 6s

13 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

 

Server.js 생성

// server.js

// 필요한 모듈을 가져옵니다.
const express = require('express');
const oracle = require('oracledb');
const cors = require('cors');
const bodyParser = require('body-parser');

// Express 애플리케이션을 생성합니다.
const app = express();

// 서버를 위한 포트를 설정합니다.
const port = 3000;

// 모든 라우트에 대해 CORS를 활성화하여 교차 출처 문제를 방지합니다.
app.use(cors());

// 서버를 특정 포트에서 실행합니다.
app.listen(port, () => {
    console.log(`게시판 앱이 포트 ${port}에서 실행 중입니다.`);
});

 

Database 연결 설정 

 

1. config 폴더를 생성 후 database 정보를 입력할 database.js 파일 생성 

// 오라클 DB 설정 파일 

module.exports = {  user			:process.env.NODE_ORACLEDB_USER || "suzi",		
                    password		:process.env.NODE_ORACLEDB_PASSWORD || "a123",		
                    connectString	:process.env.NODE_ORACLEDB_CONNECTIONSTRING || "localhost:1521/xe",		
                    externalAuth	:process.env.NODE_ORACLEDB_EXTERNALAUTH ? true : false
                 };

 

2. 외부 파일에서 데이터베이스 구성을 가져올 수 있게 server.js에 DB 정보 추가 

// server.js

// ... 코드 생략...

// 외부 파일에서 데이터베이스 구성을 가져옵니다.
const dbConfig = require('./config/database.js');

// 제공된 구성을 사용하여 ORACLE 연결 풀을 만듭니다.
const connection = oracle.createPool(dbConfig);

 

 

JSON 데이터 처리를 위한 JSON 파서 추가 

// server.js

// ... 코드 생략

// 들어오는 JSON 데이터를 처리하기 위한 JSON 파서를 설정합니다.
const jsonParser = bodyParser.json();

 

 

이제 html 파일 작성을 위한 public 폴더 생성 

public 폴더에 메인 페이지를 만들기 위해 index.html 파일을 생성해 준다. 

 

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- 페이지의 스타일을 지정하는 CSS 코드입니다. -->
    <style>
        body {
            font-family: 'Arial', sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f8f9fa;
        }

        h1 {
            background-color: #343a40;
            color: #ffffff;
            padding: 20px;
            margin: 0;
        }

        nav ul {
            list-style: none;
            padding: 0;
            margin: 0;
            background-color: #343a40;
            overflow: hidden;
        }

        nav ul li {
            float: left;
            display: inline;
            padding: 10px;
        }

        nav ul li a {
            text-decoration: none;
            color: #ffffff;
            font-weight: bold;
            display: inline-block;
            padding: 10px 20px;
            background-color: #343a40;
            transition: background-color 0.3s ease;
        }

        nav ul li a:hover {
            background-color: #495057;
        }

        #articles-list {
            list-style: none;
            padding: 0;
            margin: 20px;
        }

        #articles-list li {
            background-color: #ffffff;
            border: 1px solid #ced4da;
            padding: 15px;
            margin-bottom: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        #articles-list li a {
            text-decoration: none;
            color: #343a40;
            font-weight: bold;
        }

        #articles-list li a:hover {
            color: #007bff;
        }
    </style>
</head>
<body>
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 목록</title>
    <!-- 페이지 상단에 표시되는 제목입니다. -->
    <h1>게시글 목록</h1>
    
    <!-- 네비게이션 링크 -->
    <nav>
        <ul>
            <!-- 게시글 작성 페이지로 이동하는 링크 -->
            <li><a href="create.html">게시글 작성</a></li>
        </ul>
    </nav>

    <!-- 게시글 목록을 표시하는 부분입니다. -->
    <ul id="articles-list"></ul>
    
    </body>
</html>

 

 

작성 후 server.js에서 메인페이지를 지정해 준다. 

// server.js

// 메인 HTML 파일을 제공하는 라우트입니다.
app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html')});

 

게시글을 작성할 수 있게 public 디렉터리 안에 create.html 생성

<!-- create.html -->

<style>
    /* create.html에 해당하는 CSS 스타일 */

    body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
        background-color: #f4f4f4;
    }

    form {
        max-width: 600px;
        margin: 20px auto;
        padding: 20px;
        background-color: #fff;
        border: 1px solid #ddd;
    }

    label {
        display: block;
        margin-bottom: 5px;
        font-weight: bold;
    }

    input[type="text"],
    textarea {
        width: 100%;
        padding: 8px;
        margin-bottom: 10px;
        box-sizing: border-box;
    }

    button {
        background-color: #333;
        color: #fff;
        padding: 10px;
        border: none;
        cursor: pointer;
        border-radius: 5px;
        margin-right: 10px; /* 추가된 부분: 뒤로가기 버튼과의 간격을 조절합니다. */
    }

    button:hover {
        background-color: #555;
    }

</style>

<!-- 페이지 상단에 표시되는 제목입니다. -->
<h1>Create Article</h1>

<!-- 게시글 작성 폼입니다. -->
<form id="create-form">
    <label for="title">제목:</label>
    <input type="text" id="title" name="title" required><br>

    <label for="writer">작성자:</label>
    <input type="text" id="writer" name="writer" required><br>

    <label for="content">내용:</label>
    <textarea id="content" name="content" required></textarea><br>

    <!-- 게시글 작성 버튼 -->
    <button type="submit">게시글 작성</button>

    <!-- 뒤로가기 버튼 -->
    <button onclick="goBack()">뒤로 가기</button>
</form>

<!-- 뒤로가기 버튼을 처리하는 스크립트입니다. -->
<script>
    // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
    function goBack() {
        window.history.back();
    }
</script>

 

 

server.js에 게시글 등록 기능을 만든다.

// server.js

// ...코드 생략...

// 새로운 게시글을 작성하는 라우트입니다.
app.post('/article', jsonParser, (req, res) => {
    // 'board' 테이블에 새 레코드를 삽입하기 위한 SQL 쿼리입니다.
    const sql = 'INSERT INTO board (title, writer, content) VALUES (?,?,?)';
    const title = req.body.title;
    const writer = req.body.writer;
    const content = req.body.content;
    const params = [title, writer, content];
    // 주어진 매개변수로 쿼리를 실행합니다.
    connection.query(sql, params, (err, rows, fields) => {
        if (err) throw err;
        console.log(rows);
        // 쿼리 결과를 응답으로 전송합니다 (클라이언트에게 무언가를 전송하려고 가정합니다).
        res.send(rows);
    });
});

 

기능을 다 만들었다면 이제 create.html에 가서 게시글을 작성할 이벤트 처리 스크립트를 생성해준다.

public 디렉터리 안에 createArticle.js 파일 생성 

 

// DOMContentLoaded 이벤트가 발생하면 실행되는 콜백 함수입니다.
document.addEventListener('DOMContentLoaded', function () {
    // 'create-form' 아이디를 가진 폼 엘리먼트를 가져옵니다.
    const createForm = document.getElementById('create-form');

    // 폼에 submit 이벤트 리스너를 추가합니다.
    createForm.addEventListener('submit', function (event) {
        // 기본 폼 제출 동작을 막습니다.
        event.preventDefault();

        // FormData를 사용하여 폼 데이터를 가져옵니다.
        const formData = new FormData(this);

        // 서버에 POST 요청을 보내기 위한 fetch 함수를 사용합니다.
        fetch('http://localhost:3000/article', {
            method: 'POST', // HTTP 메서드는 POST입니다.
            headers: {
                'Content-Type': 'application/json', // 요청 본문의 형식은 JSON입니다.
            },
            // FormData를 JSON 형식으로 변환하여 요청 본문에 추가합니다.
            body: JSON.stringify(Object.fromEntries(formData)),
        })
        // 서버 응답을 JSON 형식으로 파싱합니다.
        .then(response => response.json())
        .then(article => {
            // 서버에서 반환한 게시글 정보를 콘솔에 출력합니다.
            console.log('게시글이 생성되었습니다:', article);

            // 게시글이 생성된 후에 index.html로 리디렉션합니다.
            window.location.href = 'http://localhost:3000/';
        })
        .catch(error => {
            // 오류가 발생하면 콘솔에 오류 메시지를 출력합니다.
            console.error('게시글 생성 중 오류 발생:', error);
        });
    });
});

 

이제 create.html 에 가서 createArticle.js 를 로드해 준다.

<!-- create.html -->

<!-- ... css 코드 생략... -->

<!-- 페이지 상단에 표시되는 제목입니다. -->
<h1>Create Article</h1>

<!-- 게시글 작성 폼입니다. -->
<form id="create-form">
    <label for="title">제목:</label>
    <input type="text" id="title" name="title" required><br>

    <label for="writer">작성자:</label>
    <input type="text" id="writer" name="writer" required><br>

    <label for="content">내용:</label>
    <textarea id="content" name="content" required></textarea><br>

    <!-- 게시글 작성 버튼 -->
    <button type="submit">게시글 작성</button>

    <!-- 뒤로가기 버튼 -->
    <button onclick="goBack()">뒤로 가기</button>
</form>

<!-- 게시글 작성 스크립트 파일을 로드합니다. -->
<script src="createArticle.js"></script>

<!-- 뒤로가기 버튼을 처리하는 스크립트입니다. -->
<script>
    // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
    function goBack() {
        window.history.back();
    }
</script>

 

server.js에서 createArticle.js 참조할 수 있게 public 디렉터리를 연동해 줍니다.

// server.js

//...코드 생략...

// 'public' 디렉토리에서 정적 파일을 제공합니다.
app.use(express.static('public', { "Content-Type": "application/javascript" }));

 

이제 게시글 목록을 볼 수 있게 server.js 에 게시글 목록 쿼리를 추가해 줍니다.

// server.js

//...코드 생략...

// 게시판에서 게시판 목록을 가져오는 라우트입니다.
app.get('/articles', (req, res) => {
    // 'board' 테이블에서 모든 레코드를 선택하기 위한 데이터베이스 쿼리를 실행합니다.
    connection.query('SELECT * FROM board order by idx desc', (err, rows) => {
        if (err) throw err;
        console.log(rows);
        // 검색된 레코드를 응답으로 전송합니다.
        res.send(rows);
    });
});

 

public 디렉터리 안에 index.html 파일을 수정합니다.

스크립트 코드를 추가해 줍니다.

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

 <!-- css 코드생략...>
 
</head>
<body>
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 목록</title>
    <!-- 페이지 상단에 표시되는 제목입니다. -->
    <h1>게시글 목록</h1>
    
    <!-- 네비게이션 링크 -->
    <nav>
        <ul>
            <!-- 게시글 작성 페이지로 이동하는 링크 -->
            <li><a href="create.html">게시글 작성</a></li>
        </ul>
    </nav>

    <!-- 게시글 목록을 표시하는 부분입니다. -->
    <ul id="articles-list"></ul>

    <!-- JavaScript 코드입니다. -->
    <script>
        // 게시글 목록을 가져오는 함수
        fetch('http://localhost:3000/articles')
            .then(response => response.json())
            .then(articles => {
                const articlesList = document.getElementById('articles-list');
                articles.forEach(article => {
                    const li = document.createElement('li');
                    li.innerHTML = `
                        <strong>Title:</strong> ${article.title}<br>
                        <strong>Writer:</strong> ${article.writer}<br>
                        <strong>Content:</strong> ${article.content}<br>
                        <strong>Views:</strong> ${article.view_cnt}<br>
                        <strong>Insert Time:</strong> ${article.insert_time}<br>
                        <strong>Update Time:</strong> ${article.update_time ? article.update_time : 'N/A'}<br>
                        <a href="article-details.html?id=${article.idx}">상세 정보 보기</a><br>
                        <hr>
                    `;
                    articlesList.appendChild(li);
                });
            });
    </script>
</body>
</html>

 

이제 게시글 상세 보기 기능을 만들어보겠습니다.

server.js 에 코드를 추가해 줍니다.

// server.js

// ...코드 생략...

// 특정 ID에 대한 게시글 세부 정보를 가져오는 라우트입니다.
app.get('/articles/:id', (req, res, next) => {
    const articleId = parseInt(req.params.id);

    // 게시글 조회 시 view_cnt 증가를 위한 UPDATE 쿼리
    const updateViewCountQuery = `UPDATE board SET view_cnt = view_cnt + 1 WHERE idx = ?`;
    connection.query(updateViewCountQuery, [articleId], (updateErr, updateResult) => {
        if (updateErr) {
            console.error('게시글 조회 시 view_cnt 증가 중 오류 발생:', updateErr);
            // 오류가 발생하면 계속 진행하지 않고 오류 응답을 전송합니다.
            return res.status(500).send('서버 오류');
        }

        // 'board' 테이블에서 모든 레코드를 선택하기 위한 데이터베이스 쿼리를 실행합니다.
        const selectQuery = `SELECT * FROM board WHERE idx = ?`;
        connection.query(selectQuery, [articleId], (err, rows) => {
            if (err) {
                console.error('게시글 조회 중 오류 발생:', err);
                // 오류가 발생하면 계속 진행하지 않고 오류 응답을 전송합니다.
                return res.status(500).send('서버 오류');
            }

            // 주어진 ID를 기반으로 검색된 레코드에서 게시글을 찾습니다.
            const article = rows[0];
            if (!article) {
                // 게시글을 찾지 못하면 404 상태와 메시지를 전송합니다.
                return res.status(404).send('ID를 찾을 수 없습니다.');
            }

            // 찾은 게시글을 응답으로 전송합니다.
            res.send(article);
        });
    });
});

 

이제 상세 보기 페이지를 만들어줍니다.

public 디렉터리 안에 article-details.html 파일을 만들어줍니다.

<!-- article-details.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 상세 정보</title>

    <!-- 페이지의 스타일을 지정하는 CSS 코드입니다. -->
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }

        h1 {
            background-color: #333;
            color: #fff;
            padding: 10px;
            margin: 0;
        }

        h1 a {
            text-decoration: none;
            color: #fff;
            transition: color 0.3s ease;
        }

        h1 a:hover {
            color: blue;
        }

        #article-details {
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
            background-color: #fff;
            border: 1px solid #ddd;
        }

        #article-details strong {
            font-weight: bold;
        }

        #article-details hr {
            margin: 10px 0;
            border: 0;
            border-top: 1px solid #ddd;
        }

        #article-button {
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
            background-color: #f4f4f4;
        }

        #update-button,
        #delete-button,
        #goBack {
            display: inline-block;
            padding: 10px;
            margin: 10px 5px 20px; /* 여기 수정: 버튼 아래 마진 추가 */
            background-color: #333;
            color: #fff;
            text-decoration: none;
            border: none;
            cursor: pointer;
            border-radius: 5px;
        }

        #update-button:hover,
        #delete-button:hover {
            background-color: #555;
        }
    </style>
</head>
<body>

    <!-- 페이지 상단에 위치하는 제목 부분입니다. -->
    <h1><a href="http://localhost:3000/">게시글 상세 정보</a></h1>

    <!-- 게시글의 상세 정보를 표시하는 부분입니다. -->
    <div id="article-details"></div>

    <!-- 업데이트 및 삭제 버튼이 있는 부분입니다. -->
    <div id="article-button">  
        <!-- 업데이트 버튼 -->
        <button id="update-button">게시글 수정</button>
        
        <!-- 삭제 버튼 -->
        <button id="delete-button">게시글 삭제</button>

        <!-- 뒤로가기 버튼 -->
        <button id="goBack" onclick="goBack()">뒤로 가기</button>
    </div>
    <script>
                // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
            function goBack() {
                window.history.back();
            }
    </script>
</body>
</html>

 

상세 보기 목록을 불러올 스크립트 코드를 추가해 줍니다.

<!-- article-details.html -->

<script>
        // Get Article ID from URL
        const urlParams = new URLSearchParams(window.location.search);
        const articleId = urlParams.get('id');

        // Fetch Article Details
        fetch(`http://localhost:3000/articles/${articleId}`)
            .then(response => response.json())
            .then(article => {
                const articleDetails = document.getElementById('article-details');
                if (article) {
                    // 게시글이 존재하는 경우 상세 정보를 표시합니다.
                    articleDetails.innerHTML = `
                        <strong>Title:</strong> ${article.title}<br>
                        <strong>Writer:</strong> ${article.writer}<br>
                        <strong>Content:</strong> ${article.content}<br>
                        <strong>Views:</strong> ${article.view_cnt}<br>
                        <strong>Insert Time:</strong> ${article.insert_time}<br>
                        <strong>Update Time:</strong> ${article.update_time ? article.update_time : 'N/A'}<br>
                        <strong>Delete Time:</strong> ${article.delete_time ? article.delete_time : 'N/A'}<br>
                        <hr>
                    `;
                } else {
                    // 게시글이 존재하지 않는 경우 메시지를 표시합니다.
                    articleDetails.innerHTML = '<p>게시글을 찾을 수 없습니다.</p>';
                }
            });

        // Add event listener to the Update button
        const updateButton = document.getElementById('update-button');
        updateButton.addEventListener('click', function () {
            // Update.html 페이지로 게시글 ID와 함께 리디렉션합니다.
            window.location.href = `update.html?id=${articleId}`;
        });
 <script>

 

update 기능을 만들어봅시다.

server.js에서 코드를 추가합니다.

// server.js

// 기존 게시글을 ID를 기반으로 업데이트하는 라우트입니다.
app.put('/article/:id', jsonParser, (req, res, next) => {
    // 현재 날짜 및 시간을 얻습니다.
    const currentTime = new Date().toISOString().slice(0, 19).replace("T", " ");

    // 주어진 ID를 기반으로 'board' 테이블에서 해당 게시글을 찾는 데이터베이스 쿼리를 실행합니다.
    connection.query('SELECT * FROM board WHERE idx = ?', [req.params.id], (err, rows, fields) => {
        if (err) throw err;

        // 주어진 ID를 기반으로 검색된 레코드에서 게시글을 찾습니다.
        const article = rows[0];

        if (!article) {
            // 게시글을 찾지 못하면 404 상태와 메시지를 전송합니다.
            return res.status(404).send('ID를 찾을 수 없습니다.');
        }

        // 'board' 테이블에서 게시글을 업데이트하는 SQL 쿼리입니다.
        const sql = 'UPDATE board SET title = ?, writer = ?, content = ?, update_time = ? WHERE idx = ?';
        const title = req.body.title;
        const writer = req.body.writer;
        const content = req.body.content;

        // 주어진 매개변수로 쿼리를 실행합니다.
        connection.query(sql, [title, writer, content, currentTime, req.params.id], (err, rows, fields) => {
            if (err) throw err;

            // 쿼리 결과를 응답으로 전송합니다 (클라이언트에게 무언가를 전송하려고 가정합니다).
            res.send(rows);
        });
    });
});

 

public 디렉터리 안에 update.html 파일을 만들어 줍니다.

<!-- update.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

</head>
<style>
    /* 페이지의 스타일을 지정하는 CSS 코드입니다. */

    body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
        background-color: #f4f4f4;
    }

    form {
        max-width: 600px;
        margin: 20px auto;
        padding: 20px;
        background-color: #fff;
        border: 1px solid #ddd;
    }

    label {
        display: block;
        margin-bottom: 5px;
        font-weight: bold;
    }

    input[type="text"],
    textarea {
        width: 100%;
        padding: 8px;
        margin-bottom: 10px;
        box-sizing: border-box;
    }

    button {
        background-color: #333;
        color: #fff;
        padding: 10px;
        border: none;
        cursor: pointer;
        border-radius: 5px;
        margin-right: 10px;
    }

    button:hover {
        background-color: #555;
    }

    h1 a {
        text-decoration: none;
        color: #333;
    }

    h1 a:hover {
        color: #555;
    }
</style>
<body>
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 수정</title>
    <!-- 페이지 상단에 표시되는 제목입니다. -->
    <h1>게시글 수정</h1>

    <!-- 게시글 수정 폼입니다. -->
    <form id="update-form">
        <!-- 게시글 ID를 감추어서 전송합니다. -->
        <input hidden id="id" name="id">
        
        <!-- 제목 입력란 -->
        <label for="title">제목:</label>
        <input type="text" id="title" name="title" required><br>
        
        <!-- 작성자 입력란 -->
        <label for="writer">작성자:</label>
        <input type="text" id="writer" name="writer" required><br>
        
        <!-- 내용 입력란 -->
        <label for="content">내용:</label>
        <textarea id="content" name="content" required></textarea><br>

        <!-- 게시글 수정 버튼 -->
        <button type="submit">게시글 수정</button>

        <!-- 뒤로가기 버튼 -->
        <button onclick="goBack()">뒤로 가기</button>
    </form>
    <script>
            // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
        function goBack() {
            window.history.back();
        }
    </script>

    <!-- 게시글 수정 스크립트 파일을 로드합니다. -->
    <script src="updateArticle.js"></script>
</body>
</html>

 

업데이트 후 게시글 정보를 가져와서 볼 수 있게 스크립트 문을 추가해 줍니다.

<!-- update.html -->

<script>
        // URL에서 게시글 ID를 가져옵니다.
        const urlParams = new URLSearchParams(window.location.search);
        const articleId = urlParams.get('id');

        // 게시글 상세 정보를 가져와서 폼에 미리 채웁니다.
        fetch(`http://localhost:3000/articles/${articleId}`)
            .then(response => response.json())
            .then(article => {
                // 폼 필드에 기존 데이터로 채웁니다.
                document.getElementById('id').value = article.idx;
                document.getElementById('title').value = article.title;
                document.getElementById('writer').value = article.writer;
                document.getElementById('content').value = article.content;
            });
<script>

 

이제 업데이트 이벤트를 만들어 줍니다.

public 디렉터리 안에 update.Article.js 파일을 만들어줍니다.

// DOMContentLoaded 이벤트가 발생하면 실행되는 콜백 함수입니다.
document.addEventListener('DOMContentLoaded', function () {
    // 'update-form' 아이디를 가진 폼 엘리먼트를 가져옵니다.
    const updateForm = document.getElementById('update-form');

    // 폼에 submit 이벤트 리스너를 추가합니다.
    updateForm.addEventListener('submit', function (event) {
        // 기본 폼 제출 동작을 막습니다.
        event.preventDefault();

        // FormData를 사용하여 폼 데이터를 가져옵니다.
        const formData = new FormData(this);

        // 업데이트할 게시글의 ID를 폼 데이터에서 가져옵니다.
        const articleId = formData.get('id');

        // 서버에 PUT 요청을 보내어 게시글을 업데이트합니다.
        fetch(`http://localhost:3000/article/${articleId}`, {
            method: 'PUT', // HTTP 메서드는 PUT입니다.
            headers: {
                'Content-Type': 'application/json', // 요청 본문의 형식은 JSON입니다.
            },
            // FormData를 JSON 형식으로 변환하여 요청 본문에 추가합니다.
            body: JSON.stringify(Object.fromEntries(formData)),
        })
        // 서버 응답을 JSON 형식으로 파싱합니다.
        .then(response => response.json())
        .then(article => {
            // 서버에서 반환한 업데이트된  정보를 콘솔에 출력합니다.
            console.log('게시글이 업데이트되었습니다:', article);
            alert("게시글이 업데이트 되었습니다.");

            // 게시글 업데이트된 후에 index.html로 리디렉션합니다.
            window.location.href = 'http://localhost:3000/';
        })
        .catch(error => {
            // 오류가 발생하면 콘솔에 오류 메시지를 출력합니다.
            console.error('게시글 업데이트 중 오류 발생:', error);
        });
    });
});

 

작성 후 update.html에 스크립트 파일을 로드해 줍니다.

<!-- update.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

</head>

<!-- css 코드생략...-->

<body>
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 수정</title>
    <!-- 페이지 상단에 표시되는 제목입니다. -->
    <h1>게시글 수정</h1>

    <!-- 게시글 수정 폼입니다. -->
    <form id="update-form">
        <!-- 게시글 ID를 감추어서 전송합니다. -->
        <input hidden id="id" name="id">
        
        <!-- 제목 입력란 -->
        <label for="title">제목:</label>
        <input type="text" id="title" name="title" required><br>
        
        <!-- 작성자 입력란 -->
        <label for="writer">작성자:</label>
        <input type="text" id="writer" name="writer" required><br>
        
        <!-- 내용 입력란 -->
        <label for="content">내용:</label>
        <textarea id="content" name="content" required></textarea><br>

        <!-- 게시글 수정 버튼 -->
        <button type="submit">게시글 수정</button>

        <!-- 뒤로가기 버튼 -->
        <button onclick="goBack()">뒤로 가기</button>
    </form>

    <!-- JavaScript 코드입니다. -->
    <script>
        // URL에서 게시글 ID를 가져옵니다.
        const urlParams = new URLSearchParams(window.location.search);
        const articleId = urlParams.get('id');

        // 게시글 상세 정보를 가져와서 폼에 미리 채웁니다.
        fetch(`http://localhost:3000/articles/${articleId}`)
            .then(response => response.json())
            .then(article => {
                // 폼 필드에 기존 데이터로 채웁니다.
                document.getElementById('id').value = article.idx;
                document.getElementById('title').value = article.title;
                document.getElementById('writer').value = article.writer;
                document.getElementById('content').value = article.content;
            });

        // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
        function goBack() {
            window.history.back();
        }
    </script>

    <!-- 게시글 수정 스크립트 파일을 로드합니다. -->
    <script src="updateArticle.js"></script>
</body>
</html>

 

이제 게시글 삭제하기 기능을 만들어봅시다.

server.js 에 가서 코드를 추가해 줍니다.

// server.js

// ID를 기반으로 게시글을 삭제하는 라우트입니다.
app.delete('/article/:id', (req, res, next) => {
    // 'board' 테이블에서 모든 레코드를 선택하기 위한 데이터베이스 쿼리를 실행합니다.
    connection.query('SELECT * FROM board', (err, rows, fields) => {
        if (err) throw err;
        // 주어진 ID를 기반으로 검색된 레코드에서 게시글을 찾습니다.
        const article = rows.find(art => art.idx === parseInt(req.params.id));
        if (!article) {
            // 게시글을 찾지 못하면 404 상태와 메시지를 전송합니다.
            return res.status(404).send('ID를 찾을 수 없습니다.');
        }
        // 'board' 테이블에서 게시글을 삭제하는 SQL 쿼리입니다.
        connection.query('DELETE FROM board WHERE idx = ?', [req.params.id], (err, rows, fields) => {
            if (err) throw err;
            // JSON 응답을 통해 삭제를 나타냅니다.
            res.json('삭제됨: ' + req.params.id);
        });
    });
});

 

게시글 삭제 이벤트 기능을 만들어줄 파일을 만들기 위해 article-details.html에 스크립트 코드를 추가해 줍니다.

// article-details.html

// Add event listener to the Delete button
        const deleteButton = document.getElementById('delete-button');
        deleteButton.addEventListener('click', function () {
            // 삭제 전 확인 메시지를 표시합니다.
            const confirmDelete = confirm('이 게시글을 삭제하시겠습니까?');
            if (confirmDelete) {
                // 게시글 삭제를 요청합니다.
                fetch(`http://localhost:3000/article/${articleId}`, {
                    method: 'DELETE',
                })
                .then(response => response.json())
                .then(deletedArticle => {
                    console.log('게시글이 삭제되었습니다:', deletedArticle);

                    // 삭제 후 index.html 페이지로 리디렉션합니다.
                    window.location.href = 'http://localhost:3000/';
                })
                .catch(error => {
                    console.error('게시글 삭제 중 오류 발생:', error);
                });
            }
        });

 

728x90
반응형
728x90

1. 원격 저장소 생성

 

 

과거와 다르게 default branch의 이름이 main 인점에 주목하자. 

2. 원격 저장소 지정

git remote add origin [ 복사한 저장소 주소 ]

 

 

PS E:\nodejs> git remote add origin https://...

 

3. 원격 저장소에 있는 내용을 현재 디렉토리로 pull

git pull origin main --allow-unrelated-histories

 

과거는 default branch 이름이 master여서 main 대신 master 를 적어줬다. 

PS E:\nodejs> git pull origin main --allow-unrelated-histories
remote: Enumerating objects: 773, done.
remote: Counting objects: 100% (773/773), done.
remote: Compressing objects: 100% (578/578), done.
Receiving objects: 100% (773/773), 1.99 MiB | 113.00 KiB/s, done.d 0 (from 0)

Resolving deltas: 100% (158/158), done.
From https://github.com/EunjungSong87/nodejs
 * branch            main       -> FETCH_HEAD
 * [new branch]      main       -> origin/main

 

 

4.  로컬 저장소에 push한 내용을 원격 저장소에 반영

git push -u origin main

 

 

728x90
반응형
728x90

  nodejs 환경 세팅 중 다음과 같은 권한 오류를 만난다면

npm : 이 시스템에서 스크립트를 실행할 수 없으므로 C:\Program Files\nodejs\npm.ps1 파일을 로드할 수 없습니다. 자세한 내용은 about_Execution_Policies(https://go.microsoft.com/ 
fwlink/?LinkID=135170)를 참조하십시오.
위치 줄:1 문자:1
+ npm init
+ ~~~
    + CategoryInfo          : 보안 오류: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

 

 

아래와 같이 실행 정책 변경

 

PS C:\Dev\nodejs> Set-ExecutionPolicy RemoteSigned
PS C:\Dev\nodejs> Get-ExecutionPolicy
RemoteSigned
PS C:\Dev\nodejs> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (nodejs)
728x90
반응형

+ Recent posts