티스토리 뷰

(꼭 이구조를 사용할 필요는 없지만 관리하기 좋다.)

CRUD 구조

본 프로젝트는 자바스프링의 MVC 구조를 모방한다.
프로세스의 흐름은 Controller --> Service --> DAO의 순서를 따르며
각 구조별 파일명은 다음과 같다. (예: Department)

Model (테이블 정의 파일): /models/department.js
Controller (라우터 파일): /routes/department.js
Service (비즈니스 로직 파일): /service/departmentService.js
DAO (데이터 액세스 파일): /dao/departmentDao.js
(참고: 아직 만들어지지 않은 파일이 있으니 찾지 말 것.)

코딩 순서는 Model --> DAO --> Service --> Router 순으로 한다.

부서 등록에 대해서 코드를 짜보자.

1) DAO

Model파일은 이미 만들었으니 DAO를 만들도록 하자.
DAO파일에는 DB처리에 관련된 사항만 넣도록 한다.(sequelize 함수 위주로 코딩 한다.)

다음과 같은 파일을 생성 한다.

User Dao

/dao/userDao.js

const { Op } = require('sequelize');
const { User, Department } = require('../models/index');

const dao = {
  // 등록
  insert(params) {
    return new Promise((resolve, reject) => {
      User.create(params).then((inserted) => {
        // password는 제외하고 리턴함
        const insertedResult = { ...inserted };
        delete insertedResult.dataValues.password;
        resolve(inserted);
      }).catch((err) => {
        reject(err);
      });
    });
  },
  // 리스트 조회
  selectList(params) {
    // where 검색 조건
    const setQuery = {};
    if (params.name) {
      setQuery.where = {
        ...setQuery.where,
        name: { [Op.like]: `%${params.name}%` }, // like검색
      };
    }
    if (params.userid) {
      setQuery.where = {
        ...setQuery.where,
        userid: params.userid, // '='검색
      };
    }

    // order by 정렬 조건
    setQuery.order = [['id', 'DESC']];

    return new Promise((resolve, reject) => {
      User.findAndCountAll({
        ...setQuery,
        attributes: { exclude: ['password'] }, // password 필드 제외
        include: [
          {
            model: Department,
            as: 'Department',
          },
        ],
      }).then((selectedList) => {
        resolve(selectedList);
      }).catch((err) => {
        reject(err);
      });
    });
  },
};

module.exports = dao;

위와 같이 사용자 리스트(selectList)함수에서 include를 통해 join관계를 표시할 수 있다.

User Service 파일

/service/userService.js

const logger = require('../lib/logger');
const userDao = require('../dao/userDao');

const service = {
  // user 입력
  async reg(params) {
    let inserted = null;

    try {
      inserted = await userDao.insert(params);
      logger.debug(`(userService.reg) ${JSON.stringify(inserted)}`);
    } catch (err) {
      logger.error(`(userService.reg) ${err.toString()}`);
      return new Promise((resolve, reject) => {
        reject(err);
      });
    }

    // 결과값 리턴
    return new Promise((resolve) => {
      resolve(inserted);
    });
  },
  // selectList
  async list(params) {
    let result = null;

    try {
      result = await userDao.selectList(params);
      logger.debug(`(userService.list) ${JSON.stringify(result)}`);
    } catch (err) {
      logger.error(`(userService.list) ${err.toString()}`);
      return new Promise((resolve, reject) => {
        reject(err);
      });
    }

    return new Promise((resolve) => {
      resolve(result);
    });
  },
};

module.exports = service;

User Router 파일

/routes/user.js

const express = require('express');

const router = express.Router();
const logger = require('../lib/logger');
const userService = require('../service/userService');

// 등록
router.post('/', async (req, res) => {
  try {
    const params = {
      departmentId: req.body.departmentId,
      name: req.body.name,
      userid: req.body.userid,
      password: req.body.password,
      role: req.body.role,
      email: req.body.email,
      phone: req.body.phone,
    };
    logger.info(`(user.reg.params) ${JSON.stringify(params)}`);

    // 입력값 null 체크
    if (!params.name || !params.userid || !params.password) {
      const err = new Error('Not allowed null (name, userid, password)');
      logger.error(err.toString());

      res.status(500).json({ err: err.toString() });
    }

    // 비즈니스 로직 호출
    const result = await userService.reg(params);
    logger.info(`(user.reg.result) ${JSON.stringify(result)}`);

    // 최종 응답
    res.status(200).json(result);
  } catch (err) {
    res.status(500).json({ err: err.toString() });
  }
});

// 리스트 조회
router.get('/', async (req, res) => {
  try {
    const params = {
      name: req.query.name,
      userid: req.query.userid,
    };
    logger.info(`(user.list.params) ${JSON.stringify(params)}`);

    const result = await userService.list(params);
    logger.info(`(user.list.result) ${JSON.stringify(result)}`);

    // 최종 응답
    res.status(200).json(result);
  } catch (err) {
    res.status(500).json({ err: err.toString() });
  }
});

module.exports = router;

User Router 등록

/routes/index.js

const express = require('express');
const logger = require('../lib/logger');
const departmentRouter = require('./department');
const userRouter = require('./user');

const router = express.Router();

...(중간생략)...

router.use('/departments', departmentRouter);
router.use('/users', userRouter);

module.exports = router;

Post Man 에서 Get Post 테스트.(서버로 값을 보내고 받는 테스트할 수 있는 앱)

 

사용자 등록

request

method: POST
url: /users
body: 
{
    "departmentId": 1,
    "name": "김개발",
    "userid": "kim",
    "password": "1",
    "role": "member",
    "email": "kim@email.com",
    "phone": "010-1234-5678"
}

response

{
    "id": 1,
    "departmentId": 1,
    "name": "김개발",
    "userid": "kim",
    "role": "member",
    "email": "kim@email.com",
    "phone": "010-1234-5678",
    "updatedAt": "2022-01-20T06:40:15.500Z",
    "createdAt": "2022-01-20T06:40:15.500Z",
    "updatedPwDate": null,
    "deletedAt": null
}

사용자 리스트

request

method: GET
url: /users
query: name, userid

response

{
    "count": 1,
    "rows": [
        {
            "id": 1,
            "departmentId": 1,
            "name": "김개발",
            "userid": "kim",
            "role": "member",
            "email": "kim@email.com",
            "phone": "010-1234-5678",
            "updatedPwDate": null,
            "createdAt": "2022-01-20T06:40:15.500Z",
            "updatedAt": "2022-01-20T06:40:15.500Z",
            "deletedAt": null,
            "Department": {
                "id": 1,
                "name": "개발팀",
                "code": "dev",
                "description": null,
                "createdAt": "2022-01-20T06:27:10.315Z",
                "updatedAt": "2022-01-20T06:27:10.315Z",
                "deletedAt": null
            }
        }
    ]
}

userDao.js파일에서 사용한 include에 대한 내용이
위와 같이 Department객체에 Join된 부서정보로 출력 된다.

참고 이 때 sequelize에 의해 자동으로 생성되는 쿼리는 다음과 같다.

SELECT "User"."id", "User"."department_id" AS "departmentId", "User"."name", "User"."userid", "User"."role", "User"."email", "User"."phone", "User"."updated_pw_date" AS "updatedPwDate", "User"."created_at" AS "createdAt", "User"."updated_at" AS "updatedAt", "User"."deleted_at" AS "deletedAt", "Department"."id" AS "Department.id", "Department"."name" AS "Department.name", "Department"."code" AS "Department.code", "Department"."description" AS "Department.description", "Department"."created_at" AS "Department.createdAt", "Department"."updated_at" AS "Department.updatedAt", "Department"."deleted_at" AS "Department.deletedAt" 
FROM "users" AS "User" 
LEFT OUTER JOIN "departments" AS "Department" ON "User"."department_id" = "Department"."id" 
AND ("Department"."deleted_at" IS NULL) 
WHERE ("User"."deleted_at" IS NULL) 
ORDER BY "User"."id" DESC;

사용자 상세정보

request

method: GET
url: /users/<:id>

response

{
    "id": 1,
    "departmentId": 1,
    "name": "김개발",
    "userid": "kim",
    "role": "member",
    "email": "kim@email.com",
    "phone": "010-1234-5678",
    "updatedPwDate": null,
    "createdAt": "2022-01-20T06:40:15.500Z",
    "updatedAt": "2022-01-20T06:40:15.500Z",
    "deletedAt": null
}

사용자 정보 수정

request

 

method: PUT
url: /users/<:id>
body:
{
    "departmentId": 1,
    "name": "김개발",
    "role": "member",
    "email": "kim@email.com",
    "phone": "010-1234-5678"
}

response

{
    "updatedCount": 1
}

사용자 삭제

request

method: DELETE
url: /users/<:id>

response

{
    "deletedCount": 1
}

참고 사용자 삭제처리 시 실제 데이터가 삭제되지 않고 deleted_at에 삭제날짜가 기록 된다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함