본문 바로가기
ICIA 수업일지

2021.08.12 수업일지(MySQL, node.js, multer)

by 주성씨 2021. 8. 12.

- VSC 터미널 입력 커맨드

express -e (프로젝트명)
npm install - 기본 라이브러리 설치
npm install mysql - DB 연결 라이브러리 설치
npm install --save multer - 사진 업로드를 위한 라이브러리
npm install nodemon -> 안했으면

 

- 웹 구현하기

C:\data\node\ex08\app.js

// 2021.08.12 라우터 위치
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
app.use('/', indexRouter);
app.use('/users', usersRouter);

 

C:\data\node\ex08\routes\index.js

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: '익스프레스' }); //index.ejs에 reder하겠다.
});

module.exports = router;

 

C:\data\node\ex08\views\index.ejs

<!DOCTYPE html>
<html>

<head>
  <title><%= title %></title>
  <link rel='stylesheet' href='/stylesheets/style.css' />
  <script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<style>
  @font-face {
    font-family: 'SLEIGothicTTF';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2104@1.0/SLEIGothicTTF.woff') format('woff');
    font-weight: normal;
    font-style: normal;
  }

  body {
    font-family: 'SLEIGothicTTF';
    letter-spacing: 0.5px;
  }

  #container {
    width: 960px;
    border: 1px solid brown;
    margin: 0px auto;
    padding: 20px;
  }

  #header {
    text-align: center;
    border: 1px solid brown;
    padding: 20px;
    margin-bottom: 20px;
  }

  #center {
    border: 1px solid brown;
    padding: 20px;
    margin-bottom: 20px;
    overflow: hidden;
  }

  #menu {
    width: 150px;
    padding: 20px;
    margin-bottom: 20px;
    float: left;
  }

  #menu li {
    margin-bottom: 10px;
  }

  #content {
    text-align: center;
    width: 680px;
    padding: 20px;
    margin-bottom: 20px;
    float: left;
    border-left: 1px solid brown;
  }

  #footer {
    text-align: center;
    padding: 20px;
    border: 1px solid brown;
  }
</style>

<body>
  <div id="container">
    <div id="header">
      <h2>쇼핑몰관리자</h2>
    </div>
    <div id="center">
      <div id="menu">
        <ul>
          <li>상품관리</li>
          <li>회원관리</li>
        </ul>
      </div>
      <div id="content">
        <h3>내용이 들어갈 부분</h3>
      </div>
    </div>
    <div id="footer">
      <h3>Copyright. LJS. All Right reserved</h3>
    </div>
  </div>
</body>

</html>

 

 

- 회사소개 메인 파일 만들기

C:\data\node\ex08\views\info.ejs

<h3>쇼핑몰소개</h3>
<p>유신사는 10명의 회원을 보유한 국내 1위(가 목표인) 온라인 패션 플랫폼입니다. 스트릿, 글로벌 명품, 디자이너 등 5개 브랜드가 입점한 「유신사 스토어」와 국내·외 최신 패션 트렌드와 정보를 전달하는 패션 매거진 「유신사 매거진」을 운영하고 있습니다. 2019년 연 거래액 9,000원을 돌파했으며, 아시아 No.1 패션 커머스를 비전 삼아 2020년 연 거래액 10,000원을 목표하고 있습니다.</p>

 

C:\data\node\ex08\routes\index.js

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: '쇼핑몰관리자', pageName:'info.ejs' }); //index.ejs에 reder하겠다.
});

module.exports = router;

 

C:\data\node\ex08\views\index.ejs

      <div id="content">
        <%-include(pageName)%>
      </div>

 

메인 화면

 

- 라우터 만들기

new C:\data\node\ex08\routes\product.js

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function (req, res, next) {
    res.render('index', {
        title: '상품관리',
        pageName: './product/list.ejs'
    }); //index.ejs에 reder하겠다.
});

module.exports = router;

C:\data\node\ex08\app.js

// 2021.08.12 라우터 위치
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var productRouter = require('./routes/product');
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/product', productRouter);

 

new C:\data\node\ex08\views\product\list.ejs

<h3>상품목록</h3>

 

C:\data\node\ex08\views\index.ejs

<body>
  <div id="container">
    <div id="header">
      <a href="/"><h2>쇼핑몰관리자</h2></a>
    </div>
    <div id="center">
      <div id="menu">
        <ul>
          <a href="/product"><li>상품관리</li></a>
          <li>회원관리</li>
        </ul>
      </div>
      <div id="content">
        <%-include(pageName)%>
      </div>
    </div>
    <div id="footer">
      <h3>Copyright. LJS. All Right reserved</h3>
    </div>
  </div>
</body>

ㄴ 링크로 연결해서 클릭시 해당 페이지로 이동하게 하였다.

 

+css

<style>
    a {
      text-decoration: none;
    }

    .aHeader:visited{
      color: white;
    }
    .aMenu:visited{
      color: black;
    }
</style>

 

C:\data\node\ex08\public\images\product

해당 경로에 어제 받은 상품 이미지를 넣는다.

 

-back to mysql

-- 2021.08.12 테이블 만들기
drop table product;

create table product(
   id int auto_increment primary key,
    title varchar(100),
    price int,
    image varchar(100)
);

insert into product(title,price,image)
values('명태냉면1인분', 8700, '/images/product/img01.jpg');
insert into product(title,price,image)
values('오징어볶음1인분', 8900, '/images/product/img02.jpg');
insert into product(title,price,image)
values('채끝 찹스테이크', 9100, '/images/product/img03.jpg');
insert into product(title,price,image)
values('플랫브레드루꼴라피자1인분', 8900, '/images/product/img04.jpg');
insert into product(title,price,image)
values('불락전골1인분', 10900, '/images/product/img05.jpg');
insert into product(title,price,image)
values('닭볶음탕1인분', 7800, '/images/product/img06.jpg');
insert into product(title,price,image)
values('자장밥1인분', 2800, '/images/product/img07.jpg');
insert into product(title,price,image)
values('황태양념구이1인분', 7800, '/images/product/img08.jpg');

select * from product;

 

 

- DB에 연결할 준비한다.

new C:\data\node\ex08\db.js

var mysql = require('mysql');
var conn;
exports.connect = function () {
    conn = mysql.createPool({
        connectionLimit: 100,
        host: 'localhost',
        user: 'shopping',
        password: 'pass',
        database: 'shoppingdb'
    });
}
exports.get = function () {
    return conn;
};

 

C:\data\node\ex08\app.js

//2021.08.12
//데이타베이스 연결
var db = require('./db');
db.connect(function(err){
  if(err){
    console.log('DB error.......');
    process.exit(1);
  }else{
    console.log('DB Success......');
  }
});

ㄴ 추가

 

C:\data\node\ex08\routes\product.js

var express = require('express');
var router = express.Router();
var db = require('../db.js'); // new

/* GET 상품 목록 페이지 출력. */
router.get('/', function (req, res, next) {
    res.render('index', {
        title: '상품관리',
        pageName: './product/list.ejs'
    }); //index.ejs에 render하겠다.
});

// GET 상품목록 데이터 // new
router.get('/list.json',function(req,res){
    var sql = 'select * from product;';
    db.get().query(sql,[],function(err,rows){
        res.send(rows);
    })
});

module.exports = router;

 

- list.ejs에 상품목록 출력을 위한 스크립트 만들기 + 더보기 버튼으로 목록 추가

C:\data\node\ex08\views\product\list.ejs

<h3>상품목록</h3>
<div id="product"></div>
<span id="more">더보기</span>
<style>
    .item {
        box-shadow: 5px 5px 5px rgb(0, 0, 51);
        border: 1px solid rgb(230, 230, 255);
        padding: 10px;
        margin-bottom: 20px;
        overflow: hidden;
        border-radius: 10px;
        cursor: pointer;
    }

    .item:hover {
        border: 1px solid rgb(0, 0, 51);
    }

    img {
        float: left;
    }

    .info {
        margin-left: 20px;
        float: left;
        font-size: 20px;
    }

    #more {
        padding: 10px;
        display: inline-block;
        cursor: pointer;
        color: rgb(102, 102, 255);
    }

    #more:hover {
        background-color: rgb(0, 0, 51);
        color: white;
        border-radius: 5px;
    }

</style>

<script>
    var page = 1;
    getList();

    $('#more').on('click',function(){
        page++;
        getList();
    })

    function getList() {
        $.ajax({
            type: 'get',
            url: '/product/list.json',
            dataType: 'json',
            data: {
                'page': page
            },
            success: function (data) {
                var str = '';
                $(data).each(function () {
                    var id = this.id;
                    var title = this.title;
                    var price = this.fprice;
                    var image = this.image;
                    str += `<div class="item">`;
                    str += `<img src="${image}" width=150/>`;
                    str += `<div class="info">`;
                    str += `<div class="id">상품번호 : ${id}</div>`;
                    str += `<div class="title"> 상품명 : ${title}</div>`;
                    str += `<div class="price">가격 : <b>${price}</b>원</div>`;
                    str += `</div>`;
                    str += `</div>`;
                });
                $('#product').append(str);
            }
        });
    };
</script>

 

C:\data\node\ex08\routes\product.js

var express = require('express');
var router = express.Router();
var db = require('../db.js')

/* GET 상품 목록 페이지 출력. */
router.get('/', function (req, res, next) {
    res.render('index', {
        title: '상품관리',
        pageName: './product/list.ejs'
    }); //index.ejs에 render하겠다.
});

// GET 상품목록 데이터
router.get('/list.json',function(req,res){
    var page=parseInt(req.query.page);
    var sql = 'select *,format(price,0) fprice from product order by id desc limit ?,5;';
    db.get().query(sql,[(page-1)*5],function(err,rows){
        res.send(rows);
    })
});

module.exports = router;

 

 

 

- 상품등록을 위한 라우터를 만들어준다.

C:\data\node\ex08\views\product\list.ejs

<h3>상품목록</h3>
<a href="/product/insert">상품등록</a>
<div id="product"></div>

 

C:\data\node\ex08\routes\product.js

var express = require('express');
var router = express.Router();
var db = require('../db.js')

//상품등록 페이지
router.get('/insert',function(req,res){
    res.render('index',{title:'상품등록',pageName:'./product/insert.ejs'});
})

 

new C:\data\node\ex08\views\product\insert.ejs

<h2>상품등록</h2>

 

- 상품등록란에 상품등록 버튼을 눌러 상품등록 페이지로 이동하고 해당 페이지에서 이름, 가격, 이미지를 등록할 수 있는 input 태그를 만들고 미리보기를 구현해보자.

C:\data\node\ex08\views\product\insert.ejs

<style>
    input[type=text]{
        height: 25px;
        margin: 5px;
        padding: 2px;
    }
    #image:hover{
        cursor: pointer;
    }
</style>

<h2>상품등록</h2>
<!-- form 지정명은 name으로 -->
<form name="frm">
    <div>
        <div><input type="text" name="title" placeholder="상품명을 입력하세요." size="70"/></div>
        <div><input type="text" name="price" placeholder="상품가격을 입력하세요." size="70" /></div>
        <div><img src="http://placehold.it/250/250" width="250" id="image"/>
            <div><input type="file" name="image" accept="image/*" style="display: none;"></div>
        </div>
        <hr>
        <div>
            <input type="submit" value="상품등록" />
            <input type="reset" value="등록취소" />
        </div>
    </div>
</form>

<script>
    // #image를 클릭하여 이미지 등록 
    $('#image').on('click',function(){
        $(frm.image).click();
    })

    // 이미지가 바뀔때 미리보기
    $(frm.image).on('change', function (e) {
        var reader = new FileReader();
        reader.onload = function (e) {
            $('#image').attr('src', e.target.result);
        }
        reader.readAsDataURL(this.files[0]);
    });
</script>

 

 

- 상품명, 상품가격, 이미지 input에 대한 유효성 체크를 해보자.

<script>
    // submit 이전 유효성 검사
    $(frm).on('submit', function (e) {
        e.preventDefault();
        var title = $(frm.title).val();
        if (title == '') {
            alert('상품명을 입력하세요.');
            $(frm.title).focus();
            return;
        };

        var price = $(frm.price).val();
        if (price == '') {
            alert('가격을 입력하세요.');
            $(frm.price).focus();
            return;
        };

        var image = $(frm.image).val();
        if (image == '') {
            alert('이미지를 등록하세요.');
            $(frm.image).focus();
            return;
        };

        if (price.replace(/[0-9]/g, '') || price == "") {
            alert('가격은 숫자만 입력하세요.');
            $(frm.price).focus();
            return;
        };

        if (!confirm('상품을 등록하시겠습니까?')) {
            return;
        };
    });

 

 

- 이미지 업로드 및 업로드한 이미지를 특정 폴더에 넣기위한 multer 작업을 한다.

C:\data\node\ex08\routes\product.js

const {
    request
} = require('express');
var express = require('express');
var router = express.Router();
var db = require('../db.js')

// 이미지 업로드 new
var multer = require('multer');
var uploadPath = './public/images/product';
var upload = multer({
    storage: multer.diskStorage({
        destination: (req, file, done) => {
            done(null, uploadPath);
        },
        filename: (req, file, done) => {
            done(null, Date.now() + '_' + file.originalname);
        }
    })
});

// POST 상품등록 new
router.post('/insert', upload.single('image'), function (req, res) {
    var title = req.body.title;
    var price = parseInt(req.body.price);
    var image = '/images/product/' + req.file.filename;
    var sql = `insert into product(title,price,image) values(?,?,?);`;
    db.get().query(sql, [title, price, image], function (err, rows) {
        res.sendStatus(200);
    });
})

//상품등록 페이지
router.get('/insert', function (req, res) {
    res.render('index', {
        title: '상품등록',
        pageName: './product/insert.ejs'
    });
})

/* GET 상품 목록 페이지 출력. */
router.get('/', function (req, res, next) {
    res.render('index', {
        title: '상품관리',
        pageName: './product/list.ejs'
    }); //index.ejs에 render하겠다.
});

// GET 상품목록 데이터
router.get('/list.json', function (req, res) {
    var page = parseInt(req.query.page);
    var sql = 'select *,format(price,0) fprice from product order by id desc limit ?,5;';
    db.get().query(sql, [(page - 1) * 5], function (err, rows) {
        res.send(rows);
    })
});

module.exports = router;

 

C:\data\node\ex08\views\product\insert.ejs

<style>
    input[type=text] {
        height: 25px;
        margin: 5px;
        padding: 2px;
    }

    #image:hover {
        cursor: pointer;
    }
</style>

<h2>상품등록</h2>
<!-- form 지정명은 name으로 -->
<form name="frm" enctype="multipart/form-data"><!--new-->
    <div>
        <div><input type="text" name="title" placeholder="상품명을 입력하세요." size="70" /></div>
        <div><input type="text" name="price" placeholder="상품가격을 입력하세요." size="67" />원</div>
        <div><img src="http://placehold.it/250/250" width="250" id="image" />
            <div><input type="file" name="image" accept="image/*" style="display: none;"></div>
        </div>
        <hr>
        <div>
            <input type="submit" value="상품등록" />
            <input type="reset" value="등록취소" />
        </div>
    </div>
</form>

<script>
    // submit 이전 유효성 검사
    $(frm).on('submit', function (e) {
        e.preventDefault();
        var title = $(frm.title).val();
        if (title == '') {
            alert('상품명을 입력하세요.');
            $(frm.title).focus();
            return;
        };

        var price = $(frm.price).val();
        if (price == '') {
            alert('가격을 입력하세요.');
            $(frm.price).focus();
            return;
        };

        var image = $(frm.image).val();
        if (image == '') {
            alert('이미지를 등록하세요.');
            $(frm.image).focus();
            return;
        };

        if (price.replace(/[0-9]/g, '') || price == "") {
            alert('가격은 숫자만 입력하세요.');
            $(frm.price).focus();
            return;
        };

        if (!confirm('상품을 등록하시겠습니까?')) {
            return;
        };

        // 상품등록 // new
        var formData = new FormData();
        formData.append('title', title);
        formData.append('price', price);
        formData.append('image', $(frm.image)[0].files[0]); // 여러개중 첫번째
        $.ajax({
            type: 'post',
            url: '/product/insert',
            data: formData,
            processData: false,
            contentType: false,
            success: function () {
                alert('상품등록 성공');
                location.href = '/product';
            }
        });
    });

    // #image를 클릭하여 이미지 등록 
    $('#image').on('click', function () {
        $(frm.image).click();
    })

    // 이미지가 바뀔때 미리보기
    $(frm.image).on('change', function (e) {
        var reader = new FileReader();
        reader.onload = function (e) {
            $('#image').attr('src', e.target.result);
        }
        reader.readAsDataURL(this.files[0]);
    });
</script>

 

 

- item tag를 클릭하여 상품에 대한 정보를 출력하는 페이지를 만들어보자.

C:\data\node\ex08\routes\product.js

// GET 상품정보 출력페이지 new
router.get('/read',function(req,res){
    var id = req.query.id;
    var sql = 'select * from product where id=?';
    db.get().query(sql,[id],function(err,rows){
        res.render('index',{title:'상품정보',pageName:'./product/read.ejs',product:rows[0]});
    });
});

 

new C:\data\node\ex08\views\product\read.ejs

<style>
    input[type=text] {
        height: 25px;
        margin: 5px;
        padding: 2px;
    }

    #image:hover {
        cursor: pointer;
    }
</style>

<h2>상품정보</h2>
<!-- form 지정명은 name으로 -->
<form name="frm" enctype="multipart/form-data">
    <div>
        <div><input type="text" name="title" value="<%=product.title%>" size="70" /></div>
        <div><input type="text" name="price" value="<%=product.price%>" size="67" />원</div>
        <div><img src="<%=product.image%>" width="250" id="image" />
            <div><input type="file" name="image" accept="image/*" style="display: none;"></div>
        </div>
        <hr>
        <div>
            <input type="submit" value="상품수정" />
            <input type="button" value="상품삭제" />
            <input type="reset" value="등록취소" />
        </div>
    </div>
</form>

 

 

- 상품삭제 버튼을 통해서 삭제하기

C:\data\node\ex08\views\product\read.ejs

        <div>
            <input type="submit" value="상품수정" />
            <input type="button" value="상품삭제" id="btnDelete" />
            <input type="reset" value="등록취소" />
        </div>
    </div>
</form>

<script>
    var id = "<%=product.id%>";
    var title = "<%=product.title%>";
    var oldImage = "<%=product.image%>";

    // 상품 삭제버튼을 클릭한 경우
    $('#btnDelete').on('click', function () {
        if (!confirm(id + "번 상품을 삭제하시겠습니까?")) {
            return;
        };
        $.ajax({
            type:'get',
            url:'/product/delete',
            data:{id:id, oldImage:oldImage},
            success:function(){
                alert('상품삭제 완료');
                location.href='/product';
            }
        });
    });

 

C:\data\node\ex08\routes\product.js

const {
    request
} = require('express');
var express = require('express');
var router = express.Router();
var db = require('../db.js');
var fs = require('fs'); // new

// GET 상품삭제 // new
router.get('/delete', function (req, res) {
    var id = req.query.id;
    var oldImage = req.query.oldImage;
    var sql = 'delete from product where id=?;';
    db.get().query(sql, [id], function (err, rows) {
        fs.unlink('./public' + oldImage, function (err) {
            res.sendStatus(200);
        });
    });
});

 

- update로 수정하기

C:\data\node\ex08\views\product\read.ejs

<script>
    var id = "<%=product.id%>";
    var title = "<%=product.title%>";
    var oldImage = "<%=product.image%>";

    // 상품 삭제버튼을 클릭한 경우
    $('#btnDelete').on('click', function () {
        if (!confirm(id + "번 상품을 삭제하시겠습니까?")) {
            return;
        };
        $.ajax({
            type:'get',
            url:'/product/delete',
            data:{id:id, oldImage:oldImage},
            success:function(){
                alert('상품삭제 완료');
                location.href='/product';
            }
        });
    });

    // submit 이전 유효성 검사
    $(frm).on('submit', function (e) {
        e.preventDefault();
        var title = $(frm.title).val();
        if (title == '') {
            alert('상품명을 입력하세요.');
            $(frm.title).focus();
            return;
        };

        var price = $(frm.price).val();
        if (price == '') {
            alert('가격을 입력하세요.');
            $(frm.price).focus();
            return;
        };

        // 이미지는 수정안할 수 있으니 주석처리하자.
        // var image = $(frm.image).val();
        // if (image == '') {
        //     alert('이미지를 등록하세요.');
        //     $(frm.image).focus();
        //     return;
        // };

        if (price.replace(/[0-9]/g, '') || price == "") {
            alert('가격은 숫자만 입력하세요.');
            $(frm.price).focus();
            return;
        };

        if (!confirm('상품을 등록하시겠습니까?')) {
            return;
        };

        // 상품등록
        var formData = new FormData();
        formData.append('id', id); // new update
        formData.append('title', title);
        formData.append('price', price);
        formData.append('image', $(frm.image)[0].files[0]); // 여러개중 첫번째 새로운 이미지
        formData.append('oldImage', oldImage); // 전역변수 oldImage 넣어주기
        $.ajax({
            type: 'post',
            url: '/product/update',
            data: formData,
            processData: false,
            contentType: false,
            success: function () {
                alert('상품수정 성공');
                location.href = '/product';
            }
        });
    });

 

C:\data\node\ex08\routes\product.js

const {
    request
} = require('express');
var express = require('express');
var router = express.Router();
var db = require('../db.js');
var fs = require('fs');

// 이미지 업로드
var multer = require('multer');
var uploadPath = './public/images/product';
var upload = multer({
    storage: multer.diskStorage({
        destination: (req, file, done) => {
            done(null, uploadPath);
        },
        filename: (req, file, done) => {
            done(null, Date.now() + '_' + file.originalname);
        }
    })
});

// POST 상품수정
// 상품을 수정할 경우에도 이미지가 chage될 수 있으므로 upload.single
router.post('/update', upload.single('image'), function (req, res) {
    var id = req.body.id;
    var title = req.body.title;
    var price = req.body.price;
    var image = req.body.oldImage; // 기존이미지

    if (req.file != null) { // 이미지가 바뀐경우
        image = '/images/product/'+req.file.filename; // 바꾼이미지
        fs.unlink('./public' + req.body.oldImage, function (err) {
        });
    }
    var sql = 'update product set title=?, price=?, image=? where id=?;';
    db.get().query(sql, [title, price, image, id], function (err, rows) {
        res.sendStatus(200);
    });
});

 

 

- 회원관리를 위한 테이블 만들기

- back to mysql

-- member 테이블을 추가하고 데이터를 insert해보자.
create table member(
id nvarchar(20) primary key,
pass nvarchar(100) not null,
name nvarchar(20) not null,
photo nvarchar(100)
);

insert into member(id,pass,name,photo) values('user01','pass','송중기','/images/member/img01.png');
insert into member(id,pass,name,photo) values('user02','pass','조승우','/images/member/img02.png');
insert into member(id,pass,name,photo) values('user03','pass','지성','/images/member/img03.png');
insert into member(id,pass,name,photo) values('user04','pass','조인성','/images/member/img04.png');
insert into member(id,pass,name,photo) values('user05','pass','현빈','/images/member/img05.png');

select * from member;

 

 

- back to vsc

C:\data\node\ex08\views\index.ejs

<!DOCTYPE html>
<html>

<head>
  <title><%= title %></title>
  <link rel='stylesheet' href='/stylesheets/style.css' />
  <script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<style>
  a {
    text-decoration: none;
  }

  .aHeader {
    font-size: 30px;
  }

  .aHeader:visited {
    color: white;
  }

  .aMenu,
  .aMember :visited {
    color: black;
  }
</style>

<body>
  <div id="container">
    <div id="header">
      <a href="/" class="aHeader">
        <h2>쇼핑몰관리자</h2>
      </a>
    </div>
    <div id="center">
      <div id="menu">
        <ul>
          <a href="/product" class="aMenu">
            <li>상품관리</li>
          </a>
          <a href="/member" class="aMenu"> <!--new-->
            <li>회원관리</li>
          </a>
        </ul>
      </div>
      <div id="content">
        <%-include(pageName)%>
      </div>
    </div>
    <div id="footer">
      <h3>Copyright. LJS. All Right reserved</h3>
    </div>
  </div>
</body>

</html>

[new] C:\data\node\ex08\public\images\member

해당 경로에 위의 이미지를 넣어놓는다.

photo.zip
0.24MB

 

C:\data\node\ex08\app.js

// 2021.08.12 라우터 위치
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var productRouter = require('./routes/product');
var memberRouter = require('./routes/member');
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/product', productRouter);
app.use('/member', memberRouter);

 

new C:\data\node\ex08\views\member\list.ejs

<h2 style="font-size: 30px;">회원목록</h2>

 

C:\data\node\ex08\views\index.ejs

<!DOCTYPE html>
<html>

<head>
  <title><%= title %></title>
  <link rel='stylesheet' href='/stylesheets/style.css' />
  <script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<style>
  a {
    text-decoration: none;
  }

  .aHeader {
    font-size: 30px;
  }

  .aHeader:visited {
    color: white;
  }

  .aMenu,
  .aMember :visited {
    color: black;
  }
</style>

<body>
  <div id="container">
    <div id="header">
      <a href="/" class="aHeader">
        <h2>쇼핑몰관리자</h2>
      </a>
    </div>
    <div id="center">
      <div id="menu">
        <ul>
          <a href="/product" class="aMenu">
            <li>상품관리</li>
          </a>
          <a href="/member" class="aMenu"> <!--new-->
            <li>회원관리</li>
          </a>
        </ul>
      </div>
      <div id="content">
        <%-include(pageName)%>
      </div>
    </div>
    <div id="footer">
      <h3>Copyright. LJS. All Right reserved</h3>
    </div>
  </div>
</body>

</html>

 

C:\data\node\ex08\routes\member.js

var express = require('express');
var router = express.Router();
var db = require('../db');

// 회원목록 데이터 출력
router.get('/list.json',function(req,res){
    var sql = 'select * from member;';
    db.get().query(sql,[],function(err,rows){
        res.send(rows);
    });
})
/* GET 회원목록 페이지. */
router.get('/', function(req, res, next) {
  res.render('index', { title: '회원목록', pageName:'./member/list.ejs' }); //index.ejs에 reder하겠다.
});

module.exports = router;

 

 

C:\data\node\ex08\routes\member.js

const {
    request
} = require('express');
var express = require('express');
var router = express.Router();
var db = require('../db.js');
var fs = require('fs');

// 4_1. 회원아이디 중복체크
router.get('/idchk', function (req, res) {
    var id = req.query.id
    var sql = 'select * from member where id=?;';
    db.get().query(sql, [id], function (err, rows) {
        var result;
        if (rows.length == 1) {
            result = 1;
        } else {
            result = 0;
        };
        res.send({result:result});
    });
});

// 7_1. 이미지 업로드
var multer = require('multer');
var uploadPath = './public/images/member';
var upload = multer({
    storage: multer.diskStorage({
        destination: (req, file, done) => {
            done(null, uploadPath);
        },
        filename: (req, file, done) => {
            done(null, Date.now() + '_' + file.originalname);
        }
    })
});

// 7. POST 회원수정
// 회원을 수정할 경우에도 이미지가 chage될 수 있으므로 upload.single
router.post('/update', upload.single('photo'), function (req, res) {
    var id = req.body.id;
    var pass = req.body.pass;
    var name = req.body.name;
    var photo = req.body.oldPhoto; // 기존이미지

    if (req.file != null) { // 이미지가 바뀐경우
        photo = '/images/member/' + req.file.filename; // 바꾼이미지
        fs.unlink('./public' + req.body.oldPhoto, function (err) {});
    }
    var sql = 'update member set pass=?, name=?, photo=? where id=?;';
    db.get().query(sql, [pass, name, photo, id], function (err, rows) {
        res.sendStatus(200);
    });
});

// 6. GET 회원삭제
router.get('/delete', function (req, res) {
    var id = req.query.id;
    var oldPhoto = req.query.oldPhoto;
    var sql = 'delete from member where id=?;';
    db.get().query(sql, [id], function (err, rows) {
        fs.unlink('./public' + oldPhoto, function (err) {
            res.sendStatus(200);
        });
    });
});

// 5. GET 회원정보 출력페이지
router.get('/read', function (req, res) {
    var id = req.query.id;
    var sql = 'select * from member where id=?';
    db.get().query(sql, [id], function (err, rows) {
        res.render('index', {
            title: '회원정보',
            pageName: './member/read.ejs',
            member: rows[0]
        });
    });
});

// 4. POST 회원등록
router.post('/insert', upload.single('photo'), function (req, res) {
    var id = req.body.id;
    var pass = req.body.pass;
    var name = req.body.name;
    var photo = '/images/member/' + req.file.filename;
    var sql = `insert into member(id,pass,name,photo) values(?,?,?,?);`;
    db.get().query(sql, [id, pass, name, photo], function (err, rows) {
        res.sendStatus(200);
    });
})

// 3. 회원등록 페이지
router.get('/insert', function (req, res) {
    res.render('index', {
        title: '회원등록',
        pageName: './member/insert.ejs'
    });
})

// 2. 회원목록 데이터 출력
router.get('/list.json', function (req, res) {
    var sql = 'select * from member order by id desc;';
    db.get().query(sql, [], function (err, rows) {
        res.send(rows);
    });
})

/* 1. GET 회원목록 페이지. */
router.get('/', function (req, res, next) {
    res.render('index', {
        title: '회원목록',
        pageName: './member/list.ejs'
    }); //index.ejs에 reder하겠다.
});

module.exports = router;

 

new C:\data\node\ex08\views\member\list.ejs

<h2 style="font-size: 30px;">회원목록</h2>
<a href="/member/insert" class="mInsert">[회원등록]</a>
<div id="member"></div>
<style>
    .mInsert{
        display: inline-block;
        font-size: 20px;
        margin-bottom: 20px;
    }
    .mInsert:visited{
        color: black;
    }
    .item {
        box-shadow: 5px 5px 5px rgb(0, 0, 51);
        border: 1px solid rgb(230, 230, 255);
        padding: 10px;
        margin-bottom: 20px;
        overflow: hidden;
        border-radius: 10px;
        cursor: pointer;
    }

    .item:hover {
        border: 1px solid rgb(0, 0, 51);
    }

    img {
        float: left;
    }

    .info {
        margin-left: 20px;
        float: left;
        font-size: 20px;
    }

    /* #more {
        padding: 10px;
        display: inline-block;
        cursor: pointer;
        color: rgb(102, 102, 255);
    }

    #more:hover {
        background-color: rgb(0, 0, 51);
        color: white;
        border-radius: 5px;
    } */
</style>

<script>
    getList();

    function getList() {
        $.ajax({
            type: 'get',
            url: '/member/list.json',
            dataType: 'json',
            success: function (data) {
                var str = '';
                $(data).each(function () {
                    var id = this.id;
                    var pass = this.pass;
                    var name = this.name;
                    var photo = this.photo;
                    str += `<div class="item">`;
                    str += `<a href="/member/read?id=${id}"><img src="${photo}" width=150/></a>`;
                    str += `<div class="info">`;
                    str += `<div class="id">회원번호 : ${id}</div>`;
                    str += `<div class="name"> 회원이름 : ${name}</div>`;
                    str += `</div>`;
                    str += `</div>`;
                });
                $('#member').append(str);
            }
        });
    };
</script>

 

new C:\data\node\ex08\views\product\read.ejs

<style>
    input[type=text] {
        height: 25px;
        margin: 5px;
        padding: 2px;
    }

    #image:hover {
        cursor: pointer;
    }
</style>

<h2>상품정보</h2>
<!-- form 지정명은 name으로 -->
<form name="frm" enctype="multipart/form-data">
    <div>
        <div><input type="text" name="title" value="<%=product.title%>" size="70" /></div>
        <div><input type="text" name="price" value="<%=product.price%>" size="67" />원</div>
        <div><img src="<%=product.image%>" width="250" id="image" />
            <div><input type="file" name="image" accept="image/*" style="display: none;"></div>
        </div>
        <hr>
        <div>
            <input type="submit" value="상품수정" />
            <input type="button" value="상품삭제" id="btnDelete" />
            <input type="reset" value="등록취소" />
        </div>
    </div>
</form>

<script>
    var id = "<%=product.id%>";
    var title = "<%=product.title%>";
    var oldImage = "<%=product.image%>";

    // 상품 삭제버튼을 클릭한 경우
    $('#btnDelete').on('click', function () {
        if (!confirm(id + "번 상품을 삭제하시겠습니까?")) {
            return;
        };
        $.ajax({
            type:'get',
            url:'/product/delete',
            data:{id:id, oldImage:oldImage},
            success:function(){
                alert('상품삭제 완료');
                location.href='/product';
            }
        });
    });

    // submit 이전 유효성 검사
    $(frm).on('submit', function (e) {
        e.preventDefault();
        var title = $(frm.title).val();
        if (title == '') {
            alert('상품명을 입력하세요.');
            $(frm.title).focus();
            return;
        };

        var price = $(frm.price).val();
        if (price == '') {
            alert('가격을 입력하세요.');
            $(frm.price).focus();
            return;
        };

        // 이미지는 수정안할 수 있으니 주석처리하자.
        // var image = $(frm.image).val();
        // if (image == '') {
        //     alert('이미지를 등록하세요.');
        //     $(frm.image).focus();
        //     return;
        // };

        if (price.replace(/[0-9]/g, '') || price == "") {
            alert('가격은 숫자만 입력하세요.');
            $(frm.price).focus();
            return;
        };

        if (!confirm('상품을 등록하시겠습니까?')) {
            return;
        };

        // 상품등록
        var formData = new FormData();
        formData.append('id', id); // new update
        formData.append('title', title);
        formData.append('price', price);
        formData.append('image', $(frm.image)[0].files[0]); // 여러개중 첫번째 새로운 이미지
        formData.append('oldImage', oldImage); // 전역변수 oldImage 넣어주기
        $.ajax({
            type: 'post',
            url: '/product/update',
            data: formData,
            processData: false,
            contentType: false,
            success: function () {
                alert('상품수정 성공');
                location.href = '/product';
            }
        });
    });

    // #image를 클릭하여 이미지 등록 
    $('#image').on('click', function () {
        $(frm.image).click();
    })

    // 이미지가 바뀔때 미리보기
    $(frm.image).on('change', function (e) {
        var reader = new FileReader();
        reader.onload = function (e) {
            $('#image').attr('src', e.target.result);
        }
        reader.readAsDataURL(this.files[0]);
    });
</script>