반응형

NestJS Prisma, MySQL 사용하는 방법입니다.

Prisma는 NodeJS및 Typescript용 오픈소스 ORM입니다. 이는 일반 SQL문을 작성하거나 SQL 쿼리 빌드 또는 ORM과 같은 다른 데이터베이스 액세스 도구를 사용하는 대안으로 사용됩니다. Prisma는 현재 PostgreSQL, MySQL, SQL Server, SQLite, MongoDB 및 WrocachDB( 미리 보기 )를 지원합니다.

 

구성

  • Prisma Client: NodeJS와 Typescript 전용 Type Safe 및 자동 생성 쿼리빌더
  • Prisma Migrate: Migration System, 데이터 모델링
  • Prisma Studio: GUI를 통해 DB를 수정할 수 있는 기능

prisma client는 모든 nodeJS or typescript backend 어플리케이션에서 사용이 가능하다고 합니다.

 

 

NestJS를 생성한 폴더에서 prisma를 설치해줍니다.

$ npm install prisma --save-dev

$ npx prisma init

 

prisma init을 하면 schema.prisma가 생성됩니다.

 

schema.prisma 파일에 provider를 사용할 데이터 베이스로 연결해줍니다.

 

.env 파일에 DATABASE_URL을 변경해줍니다.

mysql: DB종류, root: 유저이름, 빨간부분: 비밀번호, 127~.1: 호스트주소 ( localhost ), 3306: PORT번호, karaoke: DB이름, 스키마=퍼블릭

 

테이블을 작성합니다.

@default(autoincrement()): 자동 번호추가

@default(false): 기본 boolean설정 false

 

migration을 해줍니다.

$ npx prisma migrate dev

 

migrate해주고 이름을 정해줍니다.

 

migrations폴더에 지정해준 이름으로 폴더가 생성되고, 안에 migration.sql이 생성됩니다.

 

Prisma Client를 설치합니다.

$ npm install @prisma/client

 

src/prisma.service.ts 파일을 생성합니다.

데이터 베이스 연결 내용입니다.

import { Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }
}

 

:: Module과 Service 생성하는 방법

--flat을 설정하면 폴더를 생성하지 않고 바로 만들어줍니다.

g: generate 줄임말

co: controller 줄임말

s: service 줄임말

$ nest g module name
$ nest g controller todo/controller/todo --flat
$ nest g service todo/service/todo --flat

 

app.module.ts

app module에 imports를 추가해줍니다.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

// 모듈 추가
import { TodoModule } from './todo/todo.module';

@Module({
  imports: [
    TodoModule
  ],
  controllers: [
    AppController
  ],
  providers: [
    AppService
  ],
})
export class AppModule {}

 

todo.module.ts

컨트롤러와 서비스를 추가해줍니다.

import { Module } from '@nestjs/common';

// 컨트롤러
import { TodoController } from './controller/todo.controller';

// 서비스
import { TodoService } from './service/todo.service';
import { PrismaService } from 'src/prisma.service';

@Module({
  // 추가내용
  controllers: [TodoController],
  providers: [TodoService, PrismaService]
})
export class TodoModule {}

 

todo.service.ts

import { Injectable } from '@nestjs/common';
// 프리즈마 서비스를 찾아옵니다.
import { PrismaService } from 'src/prisma.service';

import { Todo } from '@prisma/client';

@Injectable()
export class TodoService {
    constructor(private prismaService: PrismaService) {

    }

    // 전체 가져오기
    async fetchAllTodos(): Promise<Todo[]> {
        return this.prismaService.todo.findMany();
    }

    // 단일 가져오기
    async fetchTodoItem(id: Number): Promise<Todo | null> {
        return this.prismaService.todo.findUnique({
            where: { id: Number(id) }
        });
    }

    // 삭제하기
    async deleteTodoItem(id: Number): Promise<Todo | null> {
        return this.prismaService.todo.delete({
            where: { id: Number(id) }
        });
    }

    // 추가하기
    async createTodoItem(data: Todo): Promise<Todo> {
        return this.prismaService.todo.create({ data: data });
    }

    // 수정하기
    async updateTodoItem(id: Number, title: string, content: string, isDeleted: boolean): Promise<Todo | null> {
        return this.prismaService.todo.update({
            where: { id: Number(id) },
            data: {
                title: title,
                content: content,
                isDeleted: isDeleted
            }
        });
    }
}

 

todo.controller.ts

import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { TodoService } from '../service/todo.service';
import { Todo } from '@prisma/client';

// 호출 주소
@Controller('api/todo')
export class TodoController {

    constructor(private readonly todoService: TodoService) {
    }
    @Get()
    async fetchAllTodos(): Promise<Todo[]> {
        return this.todoService.fetchAllTodos();
    }

    @Get(":id")
    async fetchTodoItem(@Param("id") id: Number): Promise<Todo | null> {
        return this.todoService.fetchTodoItem(id);
    }

    @Delete(":id")
    async deleteTodoItem(@Param("id") id: Number): Promise<Todo | null> {
        return this.todoService.fetchTodoItem(id);
    }

    @Post()
    async createTodoItem(@Body() data: Todo): Promise<Todo> {
        return this.todoService.createTodoItem(data);
    }

    @Put(":id")
    async updateTodoItem(@Param("id") id: Number, @Body() data: Todo): Promise<Todo | null> {
        return this.todoService.updateTodoItem(id, data.title, data.content, data.isDeleted);
    }
}

 

 

공식 홈페이지

반응형

'NodeJS > NestJS' 카테고리의 다른 글

[ NestJS ] NestJS 시작하기  (3) 2023.12.21
반응형

NestJS 생성하는 방법입니다.

 

nestjs 글로벌 설치

$ npm install -g @nestjs/cli

 

 

프로젝트 생성하기

$ nest new project-name

 

package manager를 선택해줍니다. ( Ex: npm )

 

 

프로젝트 구동하기

$ npm run start
$ npm run start:dev

 

npm run start:dev로 실행할 경우 --watch로 src폴더가 변경되면 자동으로 컴파일을 해줍니다.

 

반응형

'NodeJS > NestJS' 카테고리의 다른 글

[ NestJS ] NestJS Prisma, MySQL 사용하기  (2) 2023.12.21
반응형

node.js에서 ejs를 사용해 POST로 데이터를 넘기는 방법입니다.

관리자만 사용하기 위해 필요한 페이지를 만들기 위해 node.js에서 ejs를 사용했습니다. ( ex: 공지사항 )

FrontEnd에서 관리자 페이지를 생성 하게되면 어쩌다 url을 입력해 들어가지는 상황이나 잘못하면 누군가에 의해 뚫리는 상황이 올 수도 있습니다. 이럴때 좀 더 안전하게 사용하는 방식을 사용하기 위해 BackEnd에 ejs를 사용하게 되었습니다.

 

ejs를 사용하는 방법 바로가기

 

app.js

...

app.use('/api/notice', '/noticeController');
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get("/notices", (req, res) => {
    res.render(__dirname+"/views/view.ejs");
})

...

ejs 파일을 렌더링 해주기 위해 사용했습니다. ( ejs를 사용하는 방법은 위 바로가기를 확인해주세요. 여기서는 전부 생략했습니다. )

 

./views/view.ejs

<form method="post" action="/api/notice/create">
    <label for="name">이름: </label>
    <input type="text" id="name" name="name" required>
    <br>
    <label for="email">이메일 :</label>
    <input type="email" id="email" name="email" required>
    <br>
    <input type="submit" value="Submit">
</form>

간단하게 이름과 이메일을 보내는 formData형식입니다.

 

./views/view.ejs

<body>
    <div>
        <input type="text" id="inputName" onchange="nameChange()" />

        <input type="email" id="inputEmail" onchange="emailChange()" />

        <button onclick="create()">보내기</button>
    </div>
</body>

<script>
    let data = {
        name: "",
        email: ""
    }
    
    function nameChange() {
        data.name = document.getElementById("inputName").value;
    }
    
    function emailChange() {
        data.email = document.getElementById("inputEmail").value;
    }
    
    function create() {
        fetch("/api/notice/create", {
            method: "POST",
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(notice)
        })
        .then(res => res.json())
        .then(data => {
            console.log(data);
        })
    }
</script>

fetch를 사용하여 데이터 보내주기

 

./api/notice/create

const router = plugins.express.Router();

router.post("/create", (req, res) => {

    const item = req.body;

    console.log(item);
    console.log("들어왔는지 확인하기");

    res.status(200).json({
        code: "y"
    })
})

module.exports = router;

post형식으로 보냈기때문에 post형식으로 받아주고, req.body를 통해서 값을 받아오면 됩니다.

 

반응형
반응형

NodeJS에서 Multer를 사용하는 방법입니다.

파일을 보내서 저장하는 방법을 기록한 내용입니다.

 

npm

npm install multer

 

FrontEnd

먼저 Front에서 폼데이터를 사용해 내용을 넘겨줘야합니다. ( if문은 TypeScript라서 추가해준 내용입니다. )

const formData = () => {
    const formData = new FormData();
    
    // 아이디 | 이미지 | 제목
    formData.append("_id", "고유 아이디");
    if (enrollData.coverImage) formData.append("coverImage", enrollData.coverImage);
    formData.append("coverTitle", "제목");
    
    // 배열을 보내줄때는 for문을 사용해서 하나씩 보내줍니다.( ex: )
    for (let i = 0; i < enrollData.images; i++) formData.append("images", enrollData.images[i]);
}

api.post("enroll/createCover", formData)
.then(res => {
    if (res.data.code === "y") {
        console.log(res.data);
    }
})

 

BackEnd

업로드 서비스를 따로 만들어주었습니다.

 

uploadService.js

서버에 새로운 폴더를 만들어 그곳에 저장합니다.

const multer = require("multer");
const path = require("path");

const coverUpload = multer({
    storage: multer.diskStorage({
        destination: function(req, res, cb) {
            cb(null, "covers/");
        },
        filename: function (req, file, cb) {
            cb(null, new Date().valueOf() + path.extname(file.originalname));
        }
    })
})

 

Controller.js

formData와 이름을 맞춰주면 됩니다.

const ...

// Single
router.post("/createCover", coverUpload.single("coverImage"), async (req, res) => {
    
    const file = = req.file;
    
    console.log(file);
}

// Fields
router.post("/create", enrollUpload.fields([{ name: "coverImage" }, { name: "imagesFile" }]), async (req, res) => {
    
    const { coverImage, imagesFile } = req.files;
    
    console.log(coverImage);
    console.log(imagesFile);
}

// Array
router.post("/create", enrollUpload.array("images"), async (req, res) => {

    const files = = req.files;
    
    console.log(files);
}

 

중간중간 생략한 부분들이 많아서 일단 이렇게 정리해두고 나중에 다시 정리해서 올릴 생각입니다. ( __ )

반응형
반응형

NodeJS에서 MySQL을 사용할 때 다중쿼리를 처리하는 방법에 대한 내용입니다.

NodeJS에서 다중 쿼를 처리를 하려면 하나의 쿼리문을 처리 한 이후에 콜백 함수를 사용해서 처리해야 합니다.

물론 두세개 정도 쿼리문을 처리할 때는 복잡하지 않지만 더 늘어날수록 코드가 매우 복잡해지기 때문에 이를 해결하고자 mysql 모듈에는 다중쿼리를 처리해주는 내용이 있습니다.

 

NodeJS + MySQL 연결 바로가기

 

npm

npm install mysql2

 

mysql.createConnection부분

const mysql = require('mysql2');

const conn = mysql.createConnection({
    host: process.env.DB_HOST,
    port: process.env.DB_PORT,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_DATABASE,
    dateStrings: "date",
    // 아래부분을 추가해줍니다.
    multipleStatements: true
});

module.exports = conn;

mysql에서 multipleStatements부분을 true로 추가시켜줍니다.

 

test.js

const _sql_one = `SELECT * FROM test WHERE type='test';`;
const _sql_two = `SELECT * FROM test WHERE age='16';`;

conn.query(_sql_one + _sql_two, (err, result) => {
    if (err) return console.log("Error Controller");
    
    // result[0]: _sql_one 내용
    // result[1]: _sql_two 내용
    console.log(result[0]);
    console.log(result[1]);
})

이런식으로 배열형태로 가져오게 됩니다.

multipleStatements부분을 추가하지 않은 상태로는 에러가 발생하기 때문에 꼭 추가를 시킨 이후에 사용을 해줘야합니다.

 

반응형
반응형

NodeJS에 MySQL을 사용하는 방법입니다.

MySQL 유저 생성 바로가기

NodeJS 서버 열기 바로가기

.env 파일 만들기 바로가기

위에서 생성한 유저를 NodeJS서버와 연결하는 방법입니다.

 

npm

npm install mysql2

 

app.js

const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);

...

// DB
const conn = require('./config/conn');
conn.connect(err => {
    if (err) return console.log("Connection Error", err);

    console.log("DB Connect");
})

// SERVER
const port = 8080;
app.set('port', port);
server.listen(port, () => {
    const message = `
        [ Test Server ]
        Running Port : localhost:${port}
        Start Time : ${Date()}
    `;
    console.log(message);
});

app.js안에 mysql정보를 바로 넣어 줄수도 있지만, 조금 더 깔끔하기 위해 mysql정보는 밖으로 빼주었습니다.

 

./config/conn.js

const mysql = require('mysql2');

const conn = mysql.createConnection({
    host: process.env.DB_HOST,
    port: process.env.DB_PORT,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_DATABASE,
    dateStrings: "date",
});

module.exports = conn;

 

MySQL 유저를 생성할 때 나온 내용들을 추가해줍니다.

.env 파일을 활용하여 위처럼 정보를 조금 더 안전하게 보호할 수 있습니다.

반응형
반응형

서버인 NodeJS의 Express 정적폴더 내부에 존재하는 내부 파일을 프론트에서 불러올 수 있도록 하는 방법입니다.

NodeJS 서버가 실행된다는 가정하에 작성된 내용입니다.

NodeJS 서버 여는방법 바로가기

 

const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);

...

// 프론트와 폴더 연결해주기
app.use("/profiles", express.static("profiles"));

// SERVER
const port = 8080;
app.set('port', port);
server.listen(port, () => {
    const message = `
        [ Test Server ]
        Running Port : localhost:${port}
        Start Time : ${Date()}
    `;
    console.log(message);
});

위처럼 app.use를 통해 static 폴더를 연결해주면 profiles폴더의 파일들을 프론트에서 불러올 수 있게 됩니다.

 

반응형
반응형

NodeJS를 사용하면서 EJS를 적용하는 방법입니다.

오랜만에 NodeJS에서 EJS를 사용할 일이 생겨서 작성하는 내용입니다.

NodeJS 서버가 실행된다는 가정하에 작성된 내용입니다.

( ejs파일을 부른다음 json파일까지 불러서 화면에 띄워주는 방법까지 입니다. )

NodeJS 서버 여는방법 바로가기

 

npm

npm install ejs --save

 

app.js

const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);

const fs = require('fs');

app.get('/', (req, res) => {
    fs.readFile("file.json", "utf-8", function (err, data) {
        let saveData = JSON.parse(data);

        res.render(__dirname+"/views/index.ejs", {saveData});
    });
});

// SERVER
const port = 8080;
app.set('port', port);
server.listen(port, () => {
    const message = `
        [ Test Server ]
        Running Port : localhost:${port}
        Start Time : ${Date()}
    `;
    console.log(message);
});

 

file.json

{
    "data": [
        {
            "title": "제목",
            "contents": "내용"
        },
        {
            "title": "제목",
            "contents": "내용"
        },
        {
            "title": "제목",
            "contents": "내용"
        },
        {
            "title": "제목",
            "contents": "내용"
        },
        {
            "title": "제목",
            "contents": "내용"
        }
    ]
}

 

./views/index.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <ul>
            <!-- for문 -->
            <% for(let i=0; i<saveData.data.length; i++) { %>
                <li><%= saveData.data[i].title %></li>
                <!-- if문 -->
                <% if (saveData.data[i].contents.indexOf("제") > -1) { %>
                    <li style="color: red;"><%= saveData.data[i].contents %></li>
                <% } else { %>
                    <li style="color: blue;"><%= saveData.data[i].contents %></li>
                <% } %>
            <% } %>
        </ul>
    </div>
</body>
</html>

html형식으로 사용가능합니다.

ejs를 사용하면 react나 angular처럼 html내부에서 for문, if문 등을 사용가능합니다. ( 이 때문에 사용한다고 해도 과언이 아닐듯합니다..! )

ejs에서 for문을 사용할 때는 주의를 해주어야 하는 부분들이 있습니다.

// 작동안함
for (let i = 0; i < saveData.data.length; i++) {}
// 작동함
for (let i = 0; i<saveData.data.length; i++) {}

예를 들어, 위에 for문의 차이는 띄어쓰기 차이입니다. 저도 평소에는 첫번째 for문처럼 띄어쓰기를 사용하지만 ejs에서는 부등호 표시가 걸리면서 작동을 하지 않게 됩니다.

그리고 위쪽에 <li>~</li>부분에 <%= %>이런식으로 표현한 부분이 있는데, 이런부분들도 조심해야 할 부분들입니다.

 

이처럼 ejs를 사용할 때는 은근히 주의해줘야 할 점들이 있습니다. 이점들만 주의해서 사용한다면 상당히 편리하면서 간단하게 페이지를 생성할 수 있습니다.

 

ejs 태그에 대하여 ( 자주 사용하지 않다보니 까먹어서 적어두는 내용입니다. )

  • <%제어 흐름을 위한 'Scriptlet' 태그, 출력 없음
  • <%_'Whitespace Slurping' 스크립틀릿 태그, 그 앞의 모든 공백 제거
  • <%=값을 템플릿으로 출력(HTML 이스케이프됨)
  • <%-이스케이프 처리되지 않은 값을 템플릿으로 출력합니다.
  • <%#주석 태그, 실행 없음, 출력 없음
  • <%%리터럴 '<%' 출력
  • %>일반 종료 태그
  • -%>트림 모드('newline slurp') 태그, 줄 바꿈 다음 트림
  • _%>'Whitespace Slurping' 종료 태그, 그 뒤의 모든 공백 제거

ejs 홈페이지에서 가져온 내용입니다. ( 사용방법, 옵션 등등 많은 내용들을 확인할 수 있습니다. )

ejs 홈페이지 바로가기

 

반응형

'NodeJS > NodeJS' 카테고리의 다른 글

[ NodeJS ] NodeJS + MySQL 연결하기  (0) 2023.05.30
[ NodeJS ] Express 정적폴더 내부 파일 불러오기  (0) 2023.05.30
[ NodeJS ] nodemailer 사용하기  (0) 2022.11.30
[ NodeJS ] fs  (0) 2022.07.16
[ NodeJS ] crypto 암호화 복호화  (0) 2022.07.15
반응형

typescript로 nodeJS 시작하기

typescript를 이용하여 NodeJS를 실행시키는 방법입니다.

 

global npm

$ npm install -g typescript
$ npm install -g nodemon

nodemon은 있으면 편합니다.

 

npm

$ npm init -y

$ npm install -D express ts-node @types/node @types/express

/* Express용 Typescript 정의입니다. */
$ npm install @types/express-serve-static-core

 

tsconfig.json 작성하기

$ npx tsc --init

위 명령어를 실행하면 아래 json 파일이 생성됩니다.

 

tsconfig.json

{
    "compilerOptions": {
        "target": "ES6", // 컴파일 할 버전
        "jsx": "react", // 생성할 JSX 코드 지정
        "module": "commonjs", // 어떤 모듈 방식으로 컴파일할지 설정
        "rootDir": ".", // 루트 디렉토리
        "moduleResolution": "node", // 모듈 해석 방법
        "outDir": "./dist", // 컴파일 후 JS파일이 생성되는 디렉토리
        "esModuleInterop": true, // 가져오기를 용이하게 하기 위해 추가 Javascript를 내보냅니다.
        "forceConsistentCasingInFileNames": true, // 케이스가 올바른지 확인합니다.
        "strict": true, // strict Option 활성화
        "skipLibCheck": true // 모든 .d.ts파일들 건너뛰기
    }
}

tsconfig.json 파일을 열어보면 주석처리된 내용들이 나옵니다. 그 중에서 위 내용들을 풀어줍니다.

 

package.json 내용 추가하기

 

package.json

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node dist/app.js",
    "build": "tsc -p .",
    "dev": "nodemon --watch \"src/**/*.ts\" --exec \"ts-node\" src/app.ts"
},
  • start: node dist/app.js로 컴파일된 JS파일로 시작합니다.
  • build: "tsc -p ." 타입스크립트를 자바스크립트로 빌드를 시작합니다.

app.ts 작성하기

 

app.ts

import express, { Request, Response, NextFunction } from "express";

const app = express();

app.get("/", (req: Request, res: Response, next: NextFunction) => {
    res.send("성공 !");
});

const PORT = 4000;
app.listen(PORT, () => {
    const message = `
        [ TEST PROJECT ]
        Running PORT: localhost:${PORT}
    `;

    console.log(message);
});

기본 틀입니다.

 

Server 실행하기

$ npm run dev

// yarn을 사용했을 경우
$ yarn dev

 

반응형
반응형

npm

$ npm install nodemailer

 

// 관리자 정보
const email = {
    host: "smtp.naver.com",
    service: 'naver',
    auth: {
        user: "user@naver.com",
        pass: "password"
    }
};

// 메일 옵션
let mailOptions = {
    from: '보내는사람',
    to: '받는사람',
    subject: '제목',
    html: '내용'
};

const transport = plugins.nodemailer.createTransport(email);

transport.sendMail(mailOptions, function(err, info) {
    // 에러일 경우
    if (err) console.log(err);
    // 성공적으로 보내질 경우
    else console.log(info.response);
});

 

네이버를 사용할 경우

메일함 -> 메일함 관리 -> POP3/IMAP 설정 -> 사용함

위처럼 설정해주지 않으면 아래처럼 에러가 뜨게됩니다.

Error: Invalid login: 535 5.7.1 Username and Password not accepted RjdTJcbgTMGcgN72tnNj9Q - nsmtp ...

 

구글을 사용할 경우

구글 보안 바로가기

위 링크에서 2단계 인증을 해주면 아래처럼 앱 비밀번호를 설정할 수 있게됩니다. 이후 앱 비밀번호를 작성하고, nodemailer의 비밀번호로 넣어주면 작동하게 됩니다.

반응형

+ Recent posts