어제 한 숙제 확인(윗부분은 답안과 동일해 pass)
<html>
<body>
숙제
</body>
</html>
<script>
// 숙제 2-2 : async / await
const data = (num) => {
return new Promise((resolve, reject) => {
typeof num === 'number' ? resolve(num) : reject({code: 500, message: "숫자가 아님"})
})
}
// 수업시간
;(
async () => {
try {
const res = await data(3) // await : promise가 resolve 하는 걸 기다려 주겠다(결과 resolve(3)) / await 안하면 promise가 그대로 넘어온다
console.log("res:", res)
const res1 = await new Promise(resolve => { // await가 없으면 promise 객체가 넘어온다
setTimeout(() => {
resolve(res + 1)
}, 1000)
})
console.log("res1:", res1)
const res2 = await new Promise(resolve => {
setTimeout(() => {
resolve(`${res1} X 7 = ${res1 * 7}`) // 위에서 선언한 res1 이용
}, 1000)
})
console.log("res2:", res2)
} catch(err) {
console.error(err)
}
}
)()
</script>
Express
REST 서버
GET, POST, PUT, PATCH, DELETE 등
GET/users : 사용자 목록이구나! 알기 쉽게 패턴을 권장
가장 대표적인 모듈
프론트 - axios : 요청을 위해 필요
서버 - express : 요청을 처리하는 웹서버를 만들기 위해 필요
express 설치 과정
npm init으로 package.json 파일 먼저 생성
{
"name": "220106",
"version": "1.0.0",
"description": "",
"main": "exp.js",
"dependencies": {
"express": "^4.17.2"
},
"devDependencies": {
"nodemon": "^2.0.15"
},
"scripts": {
"start": "nodemon exp" // start 추가 / nodemon app 써도 됨
},
"author": "",
"license": "ISC"
}
express 설치
npm install express
nodemon 설치
npm i -D nodemon // -D = -dev 개발자모드로 설치
exp.js
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => { // '/'=> route 부분(기본)
res.send('Hello, Express')
})
app.listen(port, () => {
console.log(port, "번 포트에서 대기중")
})
결과
Postman
request 추가
GET
환경변수
localhost:3000(반복되는 부분)을 환경변수로 만들어 재사용하기
설정
{{}}안에 변수 넣어주기
마우스로 확인 가능
express
app.use, app.post 추가
const express = require('express')
const app = express()
const port = 3000
app.use(express.json())
app.get('/', (req, res) => { // '/'=> route 부분(기본)
res.send('Hello, Express')
})
app.post('/', (req, res) => {
console.log('post 실행')
console.log("바디:", req.body)
res.send('post 실행')
})
app.listen(port, () => {
console.log(port, "번 포트에서 대기중")
})
postman으로 데이터 보내보기
미들웨어
요청과 응답 중간에서 조작하는 역할
app.use((req, res, next) -> { 처리할 내용 next() }
순서가 중요 => get 위에 해야 미들웨어를 먼저 거쳐감
const express = require('express')
const app = express()
const port = 3000
app.use(express.json())
app.use('/', (req, res, next) => { // 미들웨어 : get 위에 있어야 미들웨어를 거쳐감 ('/' 똑같음))
console.log("미들웨어 입니다.")
next() // next를 안하면 넘어가질 않음(서버가 응답을 안주고 계속 돌기만 함)
})
app.get('/', (req, res) => { // '/'=> route 부분(기본)
res.send('Hello, Express')
})
app.post('/', (req, res) => {
console.log('post 실행')
console.log("바디:", req.body)
res.send('post 실행')
})
app.listen(port, () => {
console.log(port, "번 포트에서 대기중")
})
미들웨어 안에 넣기
// ...
app.use(express.json())
// app.use('/', (req, res, next) => { // 미들웨어 : get 위에 있어야 미들웨어를 거쳐감 ('/' 똑같음))
// console.log("미들웨어 입니다.")
// next() // next를 안하면 넘어가질 않음(서버가 응답을 안주고 계속 돌기만 함)
// })
app.get('/', (req, res, next) => { // '/'=> route 부분(기본)
console.log("안에 들어온 미들웨어 입니다.") // 요청하는 부분 중간에 함수 형태로 넣을 수 있다
res.send("미들웨어 거쳐갑니다")
next() // 여기를 거쳐간다
}, (req, res) => {
res.send('Hello, Express')
})
// ...
미들웨어로 에러 메세지 처리
// ...
app.get('/', (req, res, next) => { // '/'=> route 부분(기본)
console.log("안에 들어온 미들웨어 입니다.") // 요청하는 부분 중간에 함수 형태로 넣을 수 있다
next() // 여기를 거쳐간다
}, (req, res) => {
throw new Error('에러 발생!')
res.send('Hello, Express')
})
app.use((err, req, res, next) => { // 에러 처리(catch 역할) 안쓰는 게 있어도 무조건 4개 맞춰야함
console.error(err)
res.status(500).send(err.message)
})
// ...
status, send
status : 서버가 어떤 상태인지 간단하게 알려줌(코드는 다 정해져있음)
send : 메세지를 반환함
// ...
app.get('/', (req, res, next) => { // '/'=> route 부분(기본)
console.log("안에 들어온 미들웨어 입니다.") // 요청하는 부분 중간에 함수 형태로 넣을 수 있다
next() // 여기를 거쳐간다
}, (req, res) => {
// throw new Error('에러 발생!')
res.status(200).send('Hello, Express')
})
app.use((err, req, res, next) => { // 에러 처리(catch 역할) 안쓰는 게 있어도 무조건 4개 맞춰야함
console.error(err)
res.status(500).send(err.message) // status() : 상태 코드, 반환할 메세지 : send()
})
// ...
실무에서 자주 사용하는 패키지 설치
$ npm i morgan cookie-parser express-session dotenv
app.js
// 실무에서 자주 사용하는 패키지
const express = require('express')
const morgan = require('morgan')
const cookieParser = require('cookie-parser')
const session = require('express-session')
const dotenv = require('dotenv')
const path = require('path')
dotenv.config()
const app = express()
const port = 3000
app.use(morgan('dev')) // 로그 정보 나오게 하기(dev, conbined 등의 옵션이 있다)
app.use('/', express.static(path.join(__dirname, 'public'))) // public 폴더 하위 데이터에도 접근 가능
app.use(express.json()) // 들어온 데이터 처리하는 기능 1 (json 요청을 json으로 처리)
app.use(express.urlencoded({ extend:false })) // 들어온 데이터 처리하는 기능 2 form, unrencoded 형식
app.use(cookieParser(process.env.COOKIE_SECRET)) // http 웹서버에서 prarseCookies 함수와 비슷
// app.use(session({
// resave: false,
// saveUninitialized: false,
// secret: process.env.COOKIE_SECRET,
// cookie: {
// httpOnly: true,
// secure: false
// },
// name: 'session-cookie'
// })) // 에러로 인해 생략
app.use((req, res, next) => {
console.log('모든 요청에 다 실행됩니다.')
next()
})
app.listen(port, () => {
console.log(port, "번 포트에서 대기중")
})
라우터 추가
// 새로운 라우터 추가
//...
app.get('/users', (req, res) => {
const users = [
{id: 0, name: "abc"},
{id: 1, name: "qwe"},
{id: 2, name: "zxc"}
]
res.status(200).send(users)
})
// ...
user/:id 추가
// ...
// users/:id 추가
app.get('/users/:id', (req, res) => { // request.param에 그대로 쓸 수 있음
console.log(req.params.id) // id 대신 data 써도 상관 없음
const users = [
{id: 0, name: "abc"},
{id: 1, name: "qwe"},
{id: 2, name: "zxc"}
]
res.status(200).send(users)
})
//...
해당 id 값 데이터 불러오기
// ...
// users/:id 추가
app.get('/users/:id', (req, res) => { // request.param에 그대로 쓸 수 있음
console.log(req.params.id) // id 대신 data 써도 상관 없음
const { id } = req.params // id 구조분해할당
const users = [
{id: 0, name: "abc"},
{id: 1, name: "qwe"},
{id: 2, name: "zxc"}
]
if(users[id]) res.status(200).send(users[id]) // users id가 있을때만 send 하겠다
else res.status(400).send("값이 없음") // 에러 처리
// 삼항연산자로 변경
users[id] ? res.status(200).send(users[id]) : res.status(400).send("값이 없음")
})
// ...
유저 등록
// ...
const users = [
{id: 0, name: "abc"},
{id: 1, name: "qwe"},
{id: 2, name: "zxc"}
]
// post
app.post('/users', (req, res) => {
console.log(req.body) // 데이터를 postman의 body에 입력하면 받아옴
const newUserData = req.body
users.push(newUserData) // 받아온 데이터를 위에 있는 users에 넣어준다
res.send(users) // 완료된 users를 확인한다
})
// ...
라우터 분리
app.js
// 라우터 분리
const express = require('express')
const morgan = require('morgan')
const cookieParser = require('cookie-parser')
const session = require('express-session')
const dotenv = require('dotenv')
const path = require('path')
const userRouter = require('./router/users')
const app = express()
const port = 3000
app.use(morgan('dev'))
app.use('/', express.static(path.join(__dirname, 'public')))
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use(cookieParser(process.env.COOKIE_SECRET))
app.get('/', (req, res, next) => { // '/'=> route 부분(기본)
console.log("안에 들어온 미들웨어 입니다.") // 요청하는 부분 중간에 함수 형태로 넣을 수 있다
next() // 여기를 거쳐간다
}, (req, res) => {
res.status(200).send('Hello, Express')
})
app.use('/users', userRouter)
app.use((err, req, res, next) => { // 에러 처리(catch 역할) 안쓰는 게 있어도 무조건 4개 맞춰야함
console.error(err)
res.status(500).send(err.message) // status() : 상태 코드, 반환할 메세지 : send()
})
app.post('/', (req, res) => {
console.log('post 실행')
console.log("바디:", req.body)
res.send('post 실행')
})
app.listen(port, () => {
console.log(port, "번 포트에서 대기중")
})
user.js
const express = require('express')
const router = express.Router()
// 반복되는 /users를 분리 했다
const users = [
{id: 0, name: "abc"},
{id: 1, name: "qwe"},
{id: 2, name: "zxc"}
]
// users 추가
router.get('/', (req, res) => {
res.status(200).send(users)
})
// 파라미터 쓸 때 순서 주의!
router.get('/like', (req, res) => { // like도 위의 :id에 들어가서 get이 작동 안됨! 따라서 :id 위에 써야됨
res.send("like 입니다")
})
// users/:id 추가
router.get('/:id', (req, res) => { // request.param에 그대로 쓸 수 있음
console.log(req.params.id) // id 대신 data 써도 상관 없음
const { id } = req.params // id 구조분해할당
users[id] ? res.status(200).send(users[id]) : res.status(400).send("값이 없음")
})
// post
router.post('/', (req, res) => {
console.log(req.body) // 데이터를 postman의 body에 입력하면 받아옴
const newUserData = req.body
users.push(newUserData) // 받아온 데이터를 위에 있는 users에 넣어준다
res.send(users) // 완료된 users를 확인한다
})
module.exports = router // 모듈 내보내기
Sequlize
db에 코드로 명령하고 싶을 때 sequelize를 쓰면 된다
받은 파일 실행 전 체크 사항
backend 폴더
config - config.json : host를 localhost 로 수정
simulator 폴더
app.js : 포트 안겹치게 수정
middlewares - mqtt-util.js : mqtt.connect('mqtt://localhost:1883') 으로 수정(mqttConnectionCheck, simualtorSart 총 두 군데)
frontend 폴더
.env : VUE_APP_MQTT=ws://localhost:8088 로 수정
models\department.js
const Sequelize = require('sequelize')
module.exports = class Department extends Sequelize.Model {
// class Department : table 이름 / 구조는 그대로 쓰면 되고 class명만 변경해주면 됨
static init(sequelize) { // init : 초기화
return super.init({ // table 내의 속성 만들기
name: { // 속성
type: Sequelize.STRING(50) // 속성의 데이터 타입(DB에 들어가면 자동으로 VARCHAR로 변환됨)
},
code: {
type: Sequelize.STRING(50) // Sequlize 모듈 이용
},
description: {
type: Sequelize.TEXT
}
}, { // 옵션 : 보통 그대로 쓰면 됨
sequelize,
underscored: true, // camelCase => snake_case 변경
timestamps: true, // 데이터 생성/수정 날짜 자동 저장
paranoid: false, // 삭제하면 데이터가 삭제되는 대신 deleteAt으로 이동해 sequelize에서는 삭제한걸로 인식함(ex 3개월뒤 삭제되는 유저정보)
charset: 'utf8', // 문자 포맷
collate: 'utf8_general_ci' // 문자 포맷(한글 인식을 위해)
})
}
static associate(db) { // 외래키 설정 : 어려우니 처음 연습할 땐 제외
db.Department.hasMany(db.User, {
foreignKey: { name: 'departmentId', onDelete: 'SET NULL' }
})
db.Department.hasMany(db.Device, {
foreignKey: { name: 'departmentId', onDelete: 'SET NULL'}
})
}
}
models\device.js
const Sequelize = require('sequelize')
module.exports = class Device extends Sequelize.Model {
static init(sequelize) {
return super.init({
name: {
type: Sequelize.STRING(100),
allowNull: false, // null을 허용하지 않겠다(default: true)
unique: true // 중복 허용 안하겠다
},
deviceModelName: {
type: Sequelize.STRING(100)
},
manufacturer: {
type: Sequelize.STRING(100)
},
location: {
type: Sequelize.STRING(100)
},
edgeSerialNumber: {
type: Sequelize.STRING(20),
allowNull: false
},
networkInterface: {
type: Sequelize.STRING(10),
allowNull: false
},
networkConfig: {
type: Sequelize.JSON,
allowNull: false
},
description: {
type: Sequelize.STRING(100)
}
}, {
sequelize,
underscored: true,
timestamps: true,
paranoid: false,
charset: 'utf8',
collate: 'utf8_general_ci'
})
}
static associate(db) {
db.Device.belongsTo(db.Department, { foreignKey: { name: 'departmentId', onDelete: 'SET NULL' }})
db.Device.belongsTo(db.User, { foreignKey: { name: 'userId', onDelete: 'SET NULL' }})
}
}
models\index.js
다 합쳐주는 역할
그대로 가져다 쓰면 된다.
db객체에다 모듈을 추가해주면 된다.(이때 키와 밸류값 같도록 한다)
const Sequelize = require('sequelize')
const User = require('./user') // model 파일 불러오기 (user)
const Department = require('./department') // model 파일 불러오기 (department)
const Device = require('./device') // model 파일 불러오기 (device)
const env = process.env.NODE_ENV || 'development'
const config = require('../config/config')[env];
const db = {}; // db 빈 객체 초기화
const sequelize = new Sequelize(config.database, config.username, config.password, config)
db.sequelize = sequelize;
db.User = User
db.Department = Department
db.Device = Device
User.init(sequelize) // models/user에 있던 init 호출
Department.init(sequelize) // 동일
Device.init(sequelize) // 동일
User.associate(db)
Department.associate(db)
Device.associate(db)
module.exports = db;
==> 여기까지하면 db에 코드로 짠 테이블을 만들어주는 것이다
라우트 폴더
routes\department.js
const express = require('express')
const Department = require('../models/department')
const router = express.Router()
router.route('/') // 메소드에 해당하는 주소('/'처럼)가 같으면 이렇게 쓸 수 있다
.get(async (req, res, next) => {
try {
const department = await Department.findAll()
// promise가 findAll 함수의 return에 담겨있을 것이고 (await)
// 그 promise의 resolve는 모든 데이터를 다 가져오는 기능일 것이다 (findAll 기능)
// DB를 다루는 함수는 대부분 DB를 기다려줘야하니 promise일 확률이 높다
res.json(department)
} catch(err) {
console.error(err)
next(err)
}
}) // DB에서 가져온 모든 데이터를 department에 담는다
.post(async (req, res, next) => {
try {
const {name, code, description} = req.body // req.body에 name, code 등을 입력하면(객체 형태)
const department = await Department.create({ // create = insert : 데이터가 생성된다
name,
code,
description
})
res.status(201).json(department)
} catch(err) {
console.error(err)
next(err)
}
})
router.route('/:id') // 위의 경우처럼 메소드에 해당하는 중복 주소를 따로 뺐다.
.get(async (req, res, next) => {
try {
const department = await Department.findByPk(req.params.id) // id: PK값 => id 값으로 찾는다
res.json(department)
} catch(err) {
console.error(err)
next(err)
}
})
.put(async (req, res, next) => {
try {
const {name, code, description} = req.body
const result = await Department.update({
name,
code,
description
}, {
where: { id: req.params.id } // where: 어디에 있는 걸 업데이트 할지 id로 위치를 지정한다
})
res.json(result)
} catch(err) {
console.error(err)
next(err)
}
})
.delete(async (req, res, next) => {
try {
const result = await Department.destroy({where: {id: req.params.id}}) // where: 삭제할 위치 지정
res.json(result)
} catch(err) {
console.error(err)
next(err)
}
})
module.exports = router
app.js
const express = require('express')
const path = require('path')
const morgan = require('morgan')
const { sequelize } = require('./models') // 사실은 db.sequelize
const indexRouter = require('./routes')
const usersRouter = require('./routes/users')
const departmentsRouter = require('./routes/departments')
const devicesRouter = require('./routes/devices')
const app = express()
app.set('port', process.env.PORT || 3000)
app.use(morgan('dev'))
app.use(express.static(path.join(__dirname, 'public')))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
sequelize.sync({force: false})
// DB에 연동해 모델 파일의 테이블을 DB에 만들어주는 역할
// force : 모델 파일 변경 시 그 내용으로 DB에 새로운 테이블 생성(기존 테이블은 날아감)
// 따라서 처음에 데이터가 없이 개발할 땐 true로 해도 상관 없으나
// 운영 중에 true로 하면 모델 파일 변경시 기존 DB에 있던 추가된 데이터가 모두 날아갈 위험이 있다
.then(()=> {
console.log('데이터베이스 연결 성공')
})
.catch(err => {
console.error(err)
})
app.use('/', indexRouter)
app.use('/users', usersRouter)
app.use('/departments', departmentsRouter)
app.use('/devices', devicesRouter)
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`)
error.status = 404
next(error)
})
app.use((err, req, res, next) => {
// res.locals.message = err.message
// res.locals.error = process.env.NODE_ENV !== 'production' ? err : {}
res.status(err.status || 500)
// res.render('error')
res.send(err)
})
app.listen(app.get('port'), () => {
console.log(app.get('port'), '번 포트에서 대기중')
})
mqtt box
mosquitto.conf 파일 전달받은 파일로 덮어쓰기(웹소켓 서버 localhost:8081로 실행하기 위함)
mosquitto 시작
작업관리자 - 서비스 탭
mqtt box
MQTT 통신
토픽을 구독하면 해당하는 토픽이 있을 시 토픽에 대한 메세지를 받을 수 있다(퍼블리싱을 해준 값을 브로커가 전달해준다)
발행하는 값, 토픽(어떤 주제로 발행 하는 지) 필요
iot에 좋다
Topic to publish : 퍼블리싱할 토픽명
Payload : 보낼 값
Topic to subscrib : 구독할 토픽명(#을 넣으면 모든 토픽에 대한 정보를 받아올 수 있다)
구독하고 퍼블리싱하면 받아온다(순서 중요!)
node js에서 mqtt 해보자
mqtt_nodejs
nodemon으로 실행시키면 값이 바뀔 때마다 실시간으로 퍼블리싱한다
npx nodemon .\publish.js(파일명)
가상의 온습도 감지 가능
simulator 폴더
* 헷갈리지 말자! 본 파일에선 프론트엔드 실행은 npm run serve / 백엔드 실행은 npm start 로 했다
느낀 점
확실히 처음 백엔드 배웠을 때보단 이해가 훨씬 많이 되었다.
데이터를 연동해보니 신기하고 재미도 있었다.
백엔드가 왜 경험이 필요하다고 하는 지 조금은 알 것 같았다.
'공부 > Digital Twin Bootcamp' 카테고리의 다른 글
TIL_220110_IOT (0) | 2022.01.11 |
---|---|
TIL_220107_IOT (0) | 2022.01.07 |
TIL_210105_Backend (0) | 2022.01.05 |
TIL_220104_Vision 인식 (0) | 2022.01.04 |
TIL_210103_Vision 인식 (0) | 2022.01.03 |