2023.11.24(금)
ORACLE
, MySQL
, MariaDB
, … → SQL
사용
INSERT
), 조회(SELECT
), 수정(UPDATE
), 삭제(DELETE
) 등과 같은 기능 수행 가능![]() | ![]() |
---|
도커 컨테이너는 일종의 소프트웨어를 소프트웨어의 실행에 필요한 모든 것을 포함하는 완전한 파일 시스템 안에 감싼다. 여기에는 코드, 런타임, 시스템 도구, 시스템 라이브러리 등 서버에 설치되는 무엇이든 아우른다. 이는 실행 중인 환경에 관계 없이 언제나 동일하게 실행될 것을 보증한다.
docker pull mariadb
docker run --name mariadb -d -p 3306:3306 --restart=always -e MYSQL_ROOT_PASSWORD=root mariadb
docker images
docker exec -it mariadb /bin/bash
docker ps
mariadb -u root -p
- 명령어를 모두 소문자로 적었지만 관습적으로 가독성을 위해 대문자로 많이 쓰는 것 같다.
- JavaScript처럼 꼭 문장 끝에
;
를 쓰자.
DB 보기 : show databases;
DB 생성하기 : create database db_name;
DB 삭제하기 : drop database db_name;
DB 사용하기 : use db_name;
Table 보기 : show tables;
Table 생성 : create table tbl_name (create_definition,...);
Table 삭제 : drop table tbl_name;
Table 이름 변경 : rename table tbl_name to new_tbl_name;
Table 데이터 삽입 : insert [col1, col2, … ] into tbl_name values (val1, val2, …), (val1, val2, …), ...;
Table 데이터 조회 : select col_name, ... from tbl_name;
*
으로 전체 column 가져올 수 있음
Table 데이터 수정 : update tbl_name set col = val where cond;
Table 데이터 삭제 : delete from tbl_name where cond;
VS Code Terminal에 npm install mysql --save
로 Node.js에 mysql(mariadb의 모체가 mysql이기 때문) 모듈 설치
database/connect/mariadb.js
를 생성하고 mariadb의 database와 웹 서버를 연결 ([mariadb](https://hub.docker.com/_/mariadb) 이미지를 가져와서 설치 & 설정(port = 3306, password = root) 에서 설정한 값들을 넣어줌)
const mariadb = require('mysql');
const conn = mariadb.createConnection( // mariadb의 database와 연결
{
host: 'localhost',
port: 3306,
user: 'root',
password: 'root',
database: 'tennis'
}
);
module.exports = conn;
최종 Code
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="./img/tennis.ico" type="image/x-icon">
<link rel="stylesheet" href="main.css">
<title>Tennis Market</title>
</head>
<body>
<div id="title">
<h1>🎾Tennis Market</h1>
Welcome to Tennis market!
<br>
Enjoy your shopping.
<br>
<br>
<button class="link_btn"><a href="./orderlist">🛒Order List</a></button>
</div>
<div id="card_list">
<div class="card">
<img class="card_img" src="./img/redRacket.jpg">
<p class="card_title">Red Racket</p>
<input class="card_btn" type="button" value="order" onclick="location.href='/order?productId=1';">
</div>
<div class="card">
<img class="card_img" src="./img/blueRacket.jpg">
<p class="card_title">Blue Racket</p>
<input class="card_btn" type="button" value="order" onclick="location.href='/order?productId=2';">
</div>
<div class="card">
<img class="card_img" src="./img/blackRacket.jpg">
<p class="card_title">Black Racket</p>
<input class="card_btn" type="button" value="order" onclick="location.href='/order?productId=3';">
</div>
</div>
<!-- <script src="main.js"></script> -->
</body>
</html>
orderlist.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="./img/tennis.ico" type="image/x-icon">
<link rel="stylesheet" href="main.css">
<title>Order List</title>
</head>
<body>
<div id="title">
<h1>🛒Order List</h1>
<button class="link_btn"><a href="./">🏠Go Home</a></button>
</div>
<div id="table">
<table>
<th>No</th>
<th>Product</th>
<th>Description</th>
<th>Price</th>
<th>Order Date</th>
<!-- <tr>
<td>1</td>
<td>product1</td>
<td>description1</td>
<td>price1</td>
<td>date1</td>
</tr>
<tr>
<td>2</td>
<td>product2</td>
<td>description2</td>
<td>price2</td>
<td>date2</td>
</tr>
<tr>
<td>3</td>
<td>product3</td>
<td>description3</td>
<td>price3</td>
<td>date3</td>
</tr>
</table> -->
</div>
</body>
</html>
main.css
html {
font-size: 10px;
}
body {
margin: 0;
}
a {
text-decoration: none;
color: black;
}
table {
margin: auto;
border: 1px solid #545454;
border-collapse: collapse;
font-size: 1.5rem;
}
th, td {
border: 1px solid #444444;
padding: 0.5rem;
}
#table {
margin-top: 1rem;
}
#title {
text-align: center;
width: 100vw;
font-size: 1.5rem;
}
#card_list {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
margin-top: 10rem;
}
.card {
width: calc(33% - 1rem);
margin: 0.5rem;
text-align: center;
}
.card_img {
width: calc(75% - 1rem);
}
.card_title {
font-size: 15px;
font-weight: bold;
}
.card_btn {
position: relative;
border: 0;
padding: 0.8rem 3rem;
display: inline-block;
text-align: center;
color: white;
box-shadow:0px 4px 0px #454545;
background-color: #7b7b7b;
border-radius:8px;
}
.card_btn:hover {
background-color: rgb(161, 161, 161);
}
.card_btn:active {
box-shadow: none;
}
.link_btn {
position: relative;
border: 0;
padding: 0.8rem;
display: inline-block;
text-align: center;
box-shadow:0px 4px 0px #8a8a8a;
background-color: #d4d4d4;
border-radius:8px;
}
@media screen and (max-width: 768px) {
#card_list {
margin-top: 2.5rem;
}
}
@media screen and (max-width: 480px) {
.card {
width: 100%;
}
}
index.js
let server = require('./server');
let router = require('./router');
let requestHandler = require('./requestHandler');
const mariadb = require('./database/connect/mariadb');
mariadb.connect();
server.start(router.route, requestHandler.handle);
server.js
url.parse()
가 더 이상 사용되지 않아서 new URL()
로 대체함searchParams
로 url로 부터 query 값들을 가져와야 하고 get()
method로 특정 query 값을 가져올 수 있음let http = require('http');
// let url = require('url'); // URL class is a global reference for require('url').URL
function start(route, handle){
function onRequest(request, response) {
// let pathname = url.parse(request.url).pathname; //url.parse is deprecated.
let pathname = new URL(request.url, `http://${request.headers.host}`).pathname;
// let queryData = url.parse(request.url, true).query; //url.parse is deprecated.
let queryData = new URL(request.url, `http://${request.headers.host}`).searchParams;
if (!request.url.includes('favicon.ico')) {
// route(pathname, handle, response, queryData.productId);
route(pathname, handle, response, queryData.get('productId'));
}
}
http.createServer(onRequest).listen(8888); // localhost:8888
}
exports.start = start;
router.js
function route(pathname, handle, response, productId) {
console.log('pathname :', pathname);
if (typeof handle[pathname] == 'function') {
handle[pathname](response, productId);
} else { // 등록된 path가 아닌 경우
response.writeHead(404, {'Content-Type':'text/html'});
response.write('<h1>Page Not Found 😓</h1><br><a href="./">🏠Go Home</a>');
response.end();
}
}
exports.route = route;
requestHandler.js
mariadb.query()
를 통해 query문으로 처리를 함response.end()
는 반드시 response.write()
와 같은 코드 블럭에 위치해야 함 (response.write()
를 실행한 뒤 response.end()
를 실행하지 않으면, 클라이언트는 서버로부터 응답이 완료되지 않은 상태이기 때문에 해당 위치에서 다음 작업을 위해 계속해서 대기하게 되기 때문)const fs = require('fs'); // file system module
const main_view = fs.readFileSync('./main.html', 'utf-8');
const orderlist_view = fs.readFileSync('./orderlist.html', 'utf-8');
const mariadb = require('./database/connect/mariadb');
function main(response) {
mariadb.query("SELECT * FROM product", function(err, rows) {
console.log(rows);
})
response.writeHead(200, {'Content-Type':'text/html'});
response.write(main_view);
response.end();
}
function redRacket(response) {
fs.readFile('./img/redRacket.jpg', function(err, data) {
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
});
}
function blueRacket(response) {
fs.readFile('./img/blueRacket.jpg', function(err, data) {
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
});
}
function blackRacket(response) {
fs.readFile('./img/blackRacket.jpg', function(err, data) {
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
});
}
function mainCSS(response) {
fs.readFile('./main.css', function(err, data) {
response.writeHead(200, {'Content-Type':'text/css'});
response.write(data);
response.end();
});
}
function order(response, productId) {
response.writeHead(200, {'Content-Type':'text/html'});
const options = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
};
mariadb.query(`INSERT INTO orderlist VALUES (${productId}, '${new Date().toLocaleDateString('ko-KR', options)}');`, function(err, rows) {
if (err) {
console.log(err);
response.write('<a href="./">order success</a>');
response.end();
} else {
console.log(rows);
response.write('<a href="./">order success</a>');
response.end();
}
})
}
function orderlist(response) {
response.writeHead(200, {'Content-Type':'text/html'});
const sqlQuery = `
SELECT orderlist.product_id, product.name, product.description, product.price, orderlist.order_date
FROM orderlist
JOIN product ON orderlist.product_id = product.id
ORDER BY orderlist.order_date;
`;
mariadb.query(sqlQuery, function(err, rows) {
response.write(orderlist_view);
rows.forEach(element => {
response.write(`
<tr>
<td>${element.product_id}</td>
<td>${element.name}</td>
<td>${element.description}</td>
<td>${element.price}</td>
<td>${element.order_date}</td>
</tr>
`);
});
response.write("</table>");
response.end();
})
}
let handle = {};
handle['/'] = main;
handle['/order'] = order;
handle['/orderlist'] = orderlist;
/* image directory */
handle['/img/redRacket.jpg'] = redRacket;
handle['/img/blueRacket.jpg'] = blueRacket;
handle['/img/blackRacket.jpg'] = blackRacket;
/* css file */
handle['/main.css'] = mainCSS;
exports.handle = handle;
동작
To Do