안녕하세요. 요새 직장생활을 하느라 정신이 없는 와중, 파이썬에 대한 공부를 시간이 날때마다 하고 있는 개발자입니다.

예전에는 '지금 하고 있는 언어라도 잘하면 다행이지..' 라는 생각으로 항상 다른 언어에 대한 공부를 미뤄두고 있었습니다.

 

하지만 최근 들어서, 회사에서도 파이썬을 중요시하는 분위기가 생겨서 혼자서 틈틈이 공부를 하기 시작했습니다.

노마드코더님의 웹 스크래퍼 클론코딩, 스핑크스(문서화), 웹 소켓을 통한 채팅 프로그램 구현 등 제가 만들고 싶은 것을 찾아서 만들고 파이썬에 대한 기본적인 구조를 공부했습니다.

 

다만, 현재 현업으로 삼고 있는 JAVA와 관련하여 파이썬이 어떤 점이 더 좋을까에 대한 의문에 대해서는 해답을 내지 못했습니다.

 

워낙 파이썬에 대한 기초도 조금 부족하기도 했고, 기초부터 하기에는 시간도 그리 여유롭지는 못했던거같습니다.

그래서, 언젠가 '책을 사서 한번 공부해보고 싶은데..' 라는 생각을 하게 됐고 우연치 않은 기회로 이런 좋은 책을 만나게 됐습니다.

 

책을 받자마자 짬나는 시간마다 책을 열어 보기 시작했습니다.

확실히 인터넷에서 접하는 정보들보다 보다 책의 내용 자체가 쉽게 구성되어 있어서, 전공을 하지 않으셨던 비전공자분들이 봐도 충분히 이해할 수 있는 내용이 많았습니다.

 

또한 책 중간중간 실습문제와, 실제 사용예제들에 대한 설명도 풍부하게 쓰여있어서 "프로그래밍 언어"에 대한 진입장벽을 걱정하시는 분들에겐 정말 최고의 교재가 되지않을까 싶습니다.

 

평일에는 퇴근 후, 주말에는 일어나서 바로 책을 펼쳐보고 "아는 것"과 "모르는 것"을 정리하기 시작했습니다.

특별히 더 신경써서 정리한 부분은 현재 현업으로 삼고 있는 "JAVA"의 문법과 "Python"의 문법의 차이입니다.

(개인적으로 이 책은 JAVA의 객체지향 개념보다는, 절차지향적인 내용이 많은 것 같습니다. 이 부분은 참고하시길...)

 

예전에는 JAVA나 C를 첫 프로그래밍 언어로 선택하여 현업에까지 활용하는 사람들이 많았습니다.

모두가 그런 것은 아니겠지만 대부분의 예비 개발자분들은 JAVA나 C로 처음 프로그래밍을 접해봤을겁니다.

저 또한, C에서 JAVA까지 공부를 한 뒤 실제론 JAVA 개발자로 취직을 했으니까요. :)

 

그러나, 이제는 시대가 조금 변했고 AI에 대한 관심이 증가하면서 파이썬에 대한 관심 또한 증가했습니다. 그래서 요즘엔 파이썬을 첫 언어로 선택하여 공부하는 예비 개발자분들도 많다고 들었습니다.

 

왜 사람들이 JAVA나 C보다, 파이썬을 처음으로 시작하는지에 대해서는 이 교재를 보면 보다 쉽게 이해할 수 있을거라 생각합니다. 물론 프로그래밍 언어의 시작에 있어서, 어떤 프로그래밍 언어를 처음 학습할지는 개인의 선택이지만 타 언어에 비해 쉽게 이해하고 배울 수 있는 언어 중 파이썬은 나름 독보적이라고 생각합니다.

 

모든 프로그램은 유행을 따르고, 그 유행에 따라 개발자는 유동적으로 공부를 해야하는 직업이기때문에 개인적으로 파이썬을 첫 프로그래밍 언어로 선택해도 큰 문제는 없을 것 같습니다.

"프로그래밍의 정석 : 파이썬" 한줄평
 : 처음 개발을 접하시는 분들도, 어렵지 않게 따라할 수 있으며 프로그래밍의 전반적인 이론과 실제 예제를 통해 개발 경험을 쌓을 수 있는 책

고구마S X 생능출판사로부터 책을 제공받았습니다.

 

프로그래밍의 정석: 파이썬

프로그래밍 전문가가 제대로 만든 책이 책을 제대로 배운다면 다른 프로그래밍 언어도 쉽게 배울 수 있습니다.프로그래밍 교육을 진행하면서 학생들과 프로그래밍 연구자들에게 직접 검증받고

book.naver.com

 

또한 해당 도서는 온라인 유튜브 강의도 제공하니, 이 점 참고하세요!

 

프로그래밍의 정석 : 파이썬

제어 구조의 설계 원리를 중심으로 배우는 프로그래밍의 정석 : 파이썬, 도경구 지음, 생능출판사, 2020

www.youtube.com

 

Django channels 기본 환경 세팅 시, channels를 install할 때 발생하는 오류를 정리해보는 포스팅이다.

* 개발환경 : 윈도우 10(Windows 10), 64bit 기준

 

발생한 오류 :

error : command 'C:\\Program Fiels (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\x86_amd64\\cl.exe' failed with exit code 2

 

먼저 위의 오류가 뜨기 전에, Microsoft Visual Studio 14.0 을 설치하라는 오류가 있었다. 해당 오류 내용은 단순히 설치만 하면 되니, 그 방법에 대해서는 따로 포스팅하지 않겠다.

 

그럼 위에서 발생한 오류인 'failed with exit code 2'의 해결법을 알아보자.

 

1. 파이썬 버전과 Django 버전 간의 호환성을 확인한다.

> 필자는 파이썬 버전이 (3.9.1) 이고, Django의 버전은 (3.1.6) 이다.

> 만약 파이썬 버전과 Django 버전이 맞지 않는 경우 꼭 버전에 맞는 패키지를 설치하길 바란다.

> 필자의 경우엔 파이썬 버전도 가장 최신을 다운로드 했기 때문에, Django 버전 또한 최신으로 맞춰주기로 했다.

 

python -m pip install django --upgrade django

 

 

장고 버전 파이썬 버전
1.11 2.7, 3.4, 3.5, 3.6, 3.7(1.11.17에 추가됨)
2.0 3.4, 3.5, 3.6, 3.7
2.1 3.5, 3.6, 3.7
2.2 3.5, 3.6, 3.7, 3.8 (added in 2.2.8), 3.9 (added in 2.2.17)
3.0 3.6, 3.7, 3.8, 3.9 (added in 3.0.11)
3.1 3.6, 3.7, 3.8, 3.9 (added in 3.1.3)

참조 : docs.djangoproject.com/ko/3.1/faq/install/

 

2. twisted의 버전을 확인한다.

www.lfd.uci.edu/~gohlke/pythonlibs/#twisted

 

Python Extension Packages for Windows - Christoph Gohlke

by Christoph Gohlke, Laboratory for Fluorescence Dynamics, University of California, Irvine. Updated on 8 February 2021 at 08:15 UTC. This page provides 32- and 64-bit Windows binaries of many scientific open-source extension packages for the official CPyt

www.lfd.uci.edu

자신의 python 버전과 맞는 twisted를 다운로드 하여 설치한다.

필자의 경우 해당 페이지(2021-02-09 기준)에서 Twisted-20.3.0-cp39-cp39-win_amd64.whl 파일을 다운로드했다.

해당 파일을 다운로드 한 뒤 아래 명령어를 실행한다.

 

python -m pip install 경로명\Twisted-20.3.0-cp39-cp39-win_amd64.whl

 

3. 이후 아래의 명령어를 실행하면 정상적으로 install이 이루어질 것이다.

pip install -U channels

 

 

본 포스팅은 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있습니다.

 

본 포스팅은 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있습니다.

 

제가 직접 구매하여 사용하고 있는 정림전자 게이밍모니터 제품입니다.

구매한지 약 한달 정도 되었는데, 큰 문제 없이 잘 사용하고 있습니다.

fps 게임을 주로 하시는분들께 강력추천 드리는 모니터이니 한번 둘러보고 가세요^^

 

 

본 포스팅은 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있습니다.

 

특장점

  • 패널 : 광시야각 PVA패널
  • 최적해상도 : 1920 x 1080 (FHD)
  • 무게 : 4.4kg (스탠드 포함)
  • 세분화된 프레임 및 빠른 응답 속도로 게임에 유용
  • 슬림 베젤을 채용하여 세련되고 감각적인 디자인
  • HDMI, DP 등의 포트를 지원해 기기 연결이 용이
  • 모니터가 깜빡거리는 것을 막는 플리커 프리 기술
  • 화면의 청색광을 억제하는 로우 블루 라이트 기술
  • 틸트 기능을 이용해 사용자에게 맞는 각도로 조절

 

본 포스팅은, 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있습니다.

 

 

 

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
31
32
<table class="table" style="text-align: center;">
        <thead>
            <tr>
                <td>번호</td>
                <td style="width: 50%;">제목</td>
                <td>작성자</td>
                <td>등록일</td>
                <td>수정일</td>                
                <td>조회수</td>                
            </tr>
        </thead>
        
        <tbody>
            <c:set var="num" value="${searchVo.totalCount - ((searchVo.curPage-1) * 10) }"/>
            <c:forEach var="rs" items="${visitorList }">
            <tr>
                <td>${num }</td>
                <td style="text-align: left; color: red;">
                    <c:url var="viewUrl" value="/board/visitorViewForm.do">
                        <c:param name="bdNum" value="${rs.bdNum }"></c:param>
                    </c:url>
                    <a href="${viewUrl }">${rs.bdTitle }</a> (${rs.cmtCnt })
                </td>
                <td>${rs.bdWriter }</td>
                <td>${rs.bdWDate }</td>
                <td>${rs.bdUDate }</td>
                <td>${rs.bdCnt }</td>
            </tr>
            <c:set var="num" value="${num-1 }"></c:set>
            </c:forEach>
        </tbody>
    </table>
cs




<c:set var="num" value="${searchVo.totalCount - ((searchVo.curPage-1) * 10) }"/>

* 핵심 : 현재 게시판 레코드의 토탈 갯수 - ((현재 페이지-1) * 한 화면에 보여질 레코드의 갯수)


forEach문이 모두 돌고 나서

<c:set var="num" value="${num-1 }"></c:set>

해주면 게시판의 번호가 역순으로 출력 됩니다.


출력 화면



이번 포스팅에서는 Datepicker를 활용하여 시작일과 종료일 제한을 주도록 하겠습니다.

활용 방법으로는 검색 조건으로 Datepicker를 사용하여 시작일/종료일로 검색이 가능해지겠네요.


1
2
3
<link rel="stylesheet" href="http://code.jquery.com/ui/1.8.18/themes/base/jquery-ui.css" type="text/css" />  
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>  
<script src="http://code.jquery.com/ui/1.8.18/jquery-ui.min.js"></script>
cs


가장 먼저, 위의 스크립트들을 JSP 위쪽에 붙여 넣어 줍니다.


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
31
32
33
34
35
36
37
38
39
40
41
<script type="text/javascript">
    $(document).ready(function () {
            $.datepicker.setDefaults($.datepicker.regional['ko']); 
            $( "#startDate" ).datepicker({
                 changeMonth: true
                 changeYear: true,
                 nextText: '다음 달',
                 prevText: '이전 달'
                 dayNames: ['일요일''월요일''화요일''수요일''목요일''금요일''토요일'],
                 dayNamesMin: ['일''월''화''수''목''금''토'], 
                 monthNamesShort: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],
                 monthNames: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],
                 dateFormat: "yymmdd",
                 maxDate: 0,                       // 선택할수있는 최소날짜, ( 0 : 오늘 이후 날짜 선택 불가)
                 onClose: function( selectedDate ) {    
                      //시작일(startDate) datepicker가 닫힐때
                      //종료일(endDate)의 선택할수있는 최소 날짜(minDate)를 선택한 시작일로 지정
                     $("#endDate").datepicker( "option""minDate", selectedDate );
                 }    
 
            });
            $( "#endDate" ).datepicker({
                 changeMonth: true
                 changeYear: true,
                 nextText: '다음 달',
                 prevText: '이전 달'
                 dayNames: ['일요일''월요일''화요일''수요일''목요일''금요일''토요일'],
                 dayNamesMin: ['일''월''화''수''목''금''토'], 
                 monthNamesShort: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],
                 monthNames: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],
                 dateFormat: "yymmdd",
                 maxDate: 0,                       // 선택할수있는 최대날짜, ( 0 : 오늘 이후 날짜 선택 불가)
                 onClose: function( selectedDate ) {    
                     // 종료일(endDate) datepicker가 닫힐때
                     // 시작일(startDate)의 선택할수있는 최대 날짜(maxDate)를 선택한 시작일로 지정
                     $("#startDate").datepicker( "option""maxDate", selectedDate );
                 }    
 
            });    
    });
</script>
cs


스크립트 추가 후 <head> </head> 사이에 위와 같은 스크립트를 붙여 넣어줍니다.


1
2
<input type="text" id="startDate">
<input type="text" id="endDate">
cs


마지막으로 <body> </body> 사이에 위와 같은 스크립트를 붙여 넣어주면 끝입니다.


실행화면



input 태그 디자인의 경우, 뭐 입맛에 맞게 변경해주시면 될 듯합니다.

datepicker 관련 옵션은 아래에 별도로 첨부합니다.





showOn: "button" 옵션을 추가 했을 때




참고 사이트

http://www.nextree.co.kr/p9887/

http://jqueryui.com/datepicker/


이번 시간은 댓글 추가,삭제 기능을 기반으로 포스팅하겠습니다.

Spring MVC 패턴에 맞게 정의한 소스 코드이며, 댓글 관련 소스코드 모두 첨부합니다.


comment.jsp

ajax, javascript, jquery 형식으로 댓글을 추가,수정,삭제 하는 방법입니다.

줄 바꿈의 핵심 로직에는 빨간색으로 표시 해두었으니, 참고하시기 바랍니다.

각 게시글 번호에 맞는 댓글의 갯수와 댓글을 출력해주기 위해 아래 소스 코드에서는 qnaInfo로 조회했습니다.

가장 간단한 방법으로 줄바꿈 기능을 사용해보고자 작성한 소스코드입니다.

원래는 댓글 기능만 추가하려고 했었는데, 질문답변 게시판도 댓글 형식으로 답변을 남겨보자! 하고 시작한 작업입니다.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<script type="text/javascript">
var bno = '${qnaInfo.bdNum}'; //게시글 번호 
//댓글 목록 
function commentList(){
    var upCheck = ${loginInfo.memNum}
    
    $.ajax({
        url : '/comment/list',
        type : 'get',
        data : {'bdNum':bno},
        success : function(data){
            var a =''; 
            $.each(data, function(key, value){ 
                if(upCheck == 1) {
                var contentV = value.cmtContent.replace(/(?:\r\n|\r|\n)/g, '<br>');
                a += '<div class="commentArea" style="border-bottom:1px solid darkgray; margin-bottom: 15px;">';
                a += '<div class="commentInfo'+value.cmtNum+'">'+' 작성자 : '+value.cmtWriter + '<a href="#" onclick="commentDelete('+value.cmtNum+');"> 삭제</a>' + '<a href="#" onclick="commentUpdate('+value.cmtNum+',\''+contentV+'\');"> 수정</a>'; 
                a += '<p class="card-subtitle mb-2 text-muted"><small> (' + value.cmtWDate + ')</small></p>';
                a += '</div>';
                a += '<div class="commentContent'+value.cmtNum+'"> <p id="comp">'+value.cmtContent +'</p>';
                a += '</div></div>';
                } else {
                  a += '<div class="commentArea" style="border-bottom:1px solid darkgray; margin-bottom: 15px;">';
                  a += '<div class="commentInfo'+value.cmtNum+'">'+' 작성자 : '+value.cmtWriter + '<p class="card-subtitle mb-2 text-muted"><small> (' + value.cmtWDate + ')</small></p>';
                  a += '<div class="commentContent'+value.cmtNum+'"> <p>'+value.cmtContent +'</p></div>';
                  a += '</div></div>';
                }
            });
            
            $(".commentList").html(a);
//            $("div[class=commentList]").html(a);
        }
    });
}
 
//댓글 수정 - 댓글 내용 출력을 input 폼으로 변경 
function commentUpdate(cmtNum, cmtContent){
    var a ='';
    var contentV = cmtContent.split('<br>').join("\r\n");
    var contentW = contentV.split('</a>').join("");
    a += '<div class="input-group">';
    //a += '<input type="text" class="form-control" name="cmtContent_'+cmtNum+'" value="'+cmtContent+'"/>';
    a += '<textarea name="cmtContent_'+cmtNum+'" class="form-control" rows="4" cols="70" placeholder="내용을 입력하세요.">'+ contentW +'</textarea>';
    a += '<span class="input-group-btn"><button class="btn btn-default" type="button" onclick="commentUpdateProc('+cmtNum+');">수정</button> </span>';
    a += '</div>';
    
    $('.commentContent'+cmtNum).html(a);
    
}
//댓글 수정
function commentUpdateProc(cmtNum){
    var updateContent = $('textarea[name=cmtContent_'+cmtNum+']').val();
    
    $.ajax({
        url : '/comment/update',
        type : 'post',
        data : {'cmtContent' : updateContent, 'cmtNum' : cmtNum},
        success : function(data){
            if(data) commentList(cmtNum); //댓글 수정후 목록 출력 
        }
    });
 
//댓글 삭제 
function commentDelete(cmtNum){
    $.ajax({
        url : '/comment/delete/'+cmtNum,
        type : 'post',
        success : function(data){
            if(data) commentList(cmtNum); //댓글 삭제후 목록 출력 
        }
    });
}
$(document).ready(function() {
    
    $('button[name=insertCommentBtn]').click(function(){ //댓글 등록 버튼 클릭시 
        //alert("등록 버튼");
        var insertData = $('form[name=insertCommentForm]').serialize(); //insertCommentForm의 내용을 가져옴
        //alert(JSON.stringify(insertData));
        
        commentInsert(insertData); //Insert 함수호출(아래)
    });
    
    //댓글 등록
    function commentInsert(insertData){
        $.ajax({
            url : '/comment/insertVisitor',
            type : 'post',
            data : insertData,
            success : function(data){
                if(data) {
                    commentList(); //댓글 작성 후 댓글 목록 reload
                    $('#cmtContent').val('');
                }
            }
        });
    }
    commentList(); //페이지 로딩시 댓글 목록 출력 
    
});
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="container">
        <label for="cmtContent">댓글(comments)</label>
                <form name="insertCommentForm">
                    <div class="input-group">
                        <input type="hidden" name="bdNum" value="${qnaInfo.bdNum }"/>
                        <textarea name="cmtContent" id="cmtContent" class="form-control" rows="4" cols="70" placeholder="내용을 입력하세요."></textarea>
                        <span class="input-group-btn">
                            <button class="btn btn-default" type="button" name="insertCommentBtn">등록</button>
                        </span>
                    </div>
                </form>
    </div>
    <br>
    <div class="container">
        <div class="commentList" style="white-space:pre;"></div>
    </div>
cs
cs



CommentVo.java


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package kr.or.infobee.comment.service;
 
import org.apache.commons.lang3.builder.ToStringBuilder;
 
public class CommentVo {
 
    private int cmtNum;
    private int bdNum;
    private String cmtWriter;
    private int memNum;
    private String cmtContent;
    private String cmtDel;
    private String cmtWDate;
 
    public int getCmtNum() {
        return cmtNum;
    }
 
    public void setCmtNum(int cmtNum) {
        this.cmtNum = cmtNum;
    }
 
    public int getBdNum() {
        return bdNum;
    }
 
    public void setBdNum(int bdNum) {
        this.bdNum = bdNum;
    }
 
    public String getCmtWriter() {
        return cmtWriter;
    }
 
    public void setCmtWriter(String cmtWriter) {
        this.cmtWriter = cmtWriter;
    }
 
    public int getEmpNum() {
        return memNum;
    }
 
    public void setEmpNum(int memNum) {
        this.memNum = memNum;
    }
 
    public String getCmtContent() {
        return cmtContent;
    }
 
    public void setCmtContent(String cmtContent) {
        this.cmtContent = cmtContent;
    }
 
    public String getCmtDel() {
        return cmtDel;
    }
 
    public void setCmtDel(String cmtDel) {
        this.cmtDel = cmtDel;
    }
 
    public String getCmtWDate() {
        return cmtWDate;
    }
 
    public void setCmtWDate(String cmtWDate) {
        this.cmtWDate = cmtWDate;
    }
 
    @Override
    public String toString() {
 
        return ToStringBuilder.reflectionToString(this);
    }
}
 
cs



CommentController.java


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package kr.or.infobee.comment.web;
 
import java.util.HashMap;
import java.util.List;
 
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
 
import kr.or.infobee.comment.service.CommentService;
import kr.or.infobee.comment.service.CommentVo;
import kr.or.infobee.login.service.LoginVo;
 
@Controller
@RequestMapping(value = "/comment")
public class CommentController {
 
    private final Logger log = LoggerFactory.getLogger(this.getClass());
 
    @Autowired
    private CommentService commentService;
 
    @RequestMapping(value = "/list")
    public @ResponseBody List<CommentVo> getCommentList(Model model, @ModelAttribute CommentVo commentVo, HttpSession session)
            throws Exception {
        
        session.getAttribute("loginInfo");
        
        return commentService.getCommentList(commentVo);
    }
 
    @RequestMapping(value = "/insertVisitor")
    public @ResponseBody HashMap<String, Object> insertCommentVisitor(@RequestParam int bdNum, @RequestParam String cmtContent,
            HttpSession session) throws Exception {
 
        HashMap<String, Object> result = new HashMap<>();
        try {
 
            LoginVo loginInfo = (LoginVo) session.getAttribute("loginInfo");
 
            CommentVo comment = new CommentVo();
            comment.setBdNum(bdNum);
            comment.setCmtContent(cmtContent);
            
            StringBuilder builder = new StringBuilder(session.getId());
            String setWriter = builder.substring(0,2);
            
            if(loginInfo != null) {
                comment.setCmtWriter(loginInfo.getMemName());
                comment.setEmpNum(loginInfo.getMemNum());
            } else {
                comment.setCmtWriter("손님-" + setWriter);
                comment.setEmpNum(1);                
            }
 
            commentService.insertComment(comment);
            
            result.put("status"true);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            result.put("status"false);
            result.put("message", e.getMessage());
        }
 
        return result;
 
    }
 
    @RequestMapping(value = "/update")
    public @ResponseBody HashMap<String, Object> updateComment(@RequestParam int cmtNum,
            @RequestParam String cmtContent) throws Exception {
 
        HashMap<String, Object> result = new HashMap<>();
        
        try {
            CommentVo comment = new CommentVo();
            comment.setCmtNum(cmtNum);
            comment.setCmtContent(cmtContent);
 
            commentService.updateComment(comment);
            result.put("status"true);
        } catch (Exception e) {
            result.put("status"false);
            result.put("message", e.getMessage());
        }
        return result;
    }
 
    @RequestMapping(value = "/delete/{cmtNum}")
    private @ResponseBody HashMap<String, Object> deleteComment(@PathVariable int cmtNum) throws Exception {
 
        HashMap<String, Object> result = new HashMap<>();
 
        try {
            commentService.deleteComment(cmtNum);
            result.put("status"true);
        } catch (Exception e) {
            result.put("status"false);
            result.put("message", e.getMessage());
        }
        return result;
    }
 
}
 
cs



CommentService.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package kr.or.infobee.comment.service;
 
import java.util.List;
 
public interface CommentService {
 
    public List<CommentVo> getCommentList( CommentVo commentVo) throws Exception;
    
    public void insertComment(CommentVo commentVo) throws Exception;
    
    public void updateComment(CommentVo commentVo) throws Exception;
    
    public void deleteComment(int cmtNum) throws Exception;
}
 
cs



CommentServiceImpl.java


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
31
32
33
34
35
36
37
38
39
40
41
42
package kr.or.infobee.comment.service.impl;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import kr.or.infobee.comment.service.CommentService;
import kr.or.infobee.comment.service.CommentVo;
 
@Service("CommentService")
public class CommentServiceImpl implements CommentService{
 
    @Autowired
    private CommentMapper commentMapper;
    
    @Override
    public List<CommentVo> getCommentList(CommentVo commentVo) throws Exception {
 
        return commentMapper.getCommentList(commentVo);
    }
 
    @Override
    public void insertComment(CommentVo commentVo) throws Exception {
 
        commentMapper.insertComment(commentVo);
    }
 
    @Override
    public void updateComment(CommentVo commentVo) throws Exception {
 
        commentMapper.updateComment(commentVo);
    }
 
    @Override
    public void deleteComment(int cmtNum) throws Exception {
        
        commentMapper.deleteComment(cmtNum);
    }
 
}
 
cs



CommentMapper.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package kr.or.infobee.comment.service.impl;
 
import java.util.List;
 
import org.apache.ibatis.annotations.Mapper;
 
import kr.or.infobee.comment.service.CommentVo;
 
@Mapper
public interface CommentMapper {
    
    // 댓글 갯수
    public int countComment() throws Exception;
    // 댓글리스트
    public List<CommentVo> getCommentList(CommentVo commentVo) throws Exception;
    // 댓글삽입
    public void insertComment(CommentVo commentVo) throws Exception;
    // 댓글수정
    public void updateComment(CommentVo commentVo) throws Exception;
    // 댓글삭제
    public void deleteComment(int cmtNum) throws Exception;
}
 
cs



CommentMapper.xml


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.infobee.comment.service.impl.CommentMapper">
 
<select id="countComment" resultType="int">
    SELECT COUNT(*) FROM BOARD_COMMENT
</select>
 
<select id="getCommentList" parameterType="kr.or.infobee.comment.service.CommentVo" resultType="kr.or.infobee.comment.service.CommentVo">
    SELECT
        cmt_num,
        bd_num,
        cmt_writer,
        mem_num,
        cmt_content,
        cmt_del,
        cmt_w_date
    FROM
        board_comment
    WHERE
        bd_num = #{bdNum}
</select>
 
 
<insert id="insertComment" parameterType="kr.or.infobee.comment.service.CommentVo">
    INSERT INTO BOARD_COMMENT (
    CMT_NUM,
    BD_NUM,
    CMT_WRITER,
    MEM_NUM,
    CMT_CONTENT,
    CMT_DEL,
    CMT_W_DATE
    ) VALUES (
        get_seq('commentSeq'),
        #{bdNum},
        #{cmtWriter},
        #{memNum},
        #{cmtContent},
        'N',
        now()
    )
 
</insert>
 
<update id="updateComment" parameterType="kr.or.infobee.comment.service.CommentVo">
    UPDATE BOARD_COMMENT
        SET
        CMT_CONTENT = #{cmtContent}
        WHERE
            CMT_NUM = #{cmtNum}
 
</update>
 
<delete id="deleteComment" parameterType="int">
    DELETE FROM BOARD_COMMENT WHERE CMT_NUM = #{cmtNum}
 
</delete>
</mapper>
cs


'IT > JSP' 카테고리의 다른 글

[JSP/Spring] 게시판 번호 역순으로 출력하기(Feat. 페이징)  (0) 2019.01.28

Oracle(오라클) 데이터베이스에서는 기본적으로 sequence 객체를 사용하여, 기본키로 설정하는 경우가 많다.

생성하는 방법도 쉽고, 사용하는 방법도 쉬운 오라클 시퀀스 객체에 비해 mysql은 다소 어려운 감이 있다.


/* 오라클 시퀀스 기본 생성 예 */

create sequence [시퀀스 명];

[시퀀스 명].nextval() -- 1씩 순차적으로 증가함.


오라클 데이터베이스에 익숙해진 상태에서, mysql로 똑같은 기능을 구현하려니 많이 답답했다.

이것저것 검색 해 본 뒤에야, 가장 간단하고 쉽게 구현하는 방법을 찾아냈다.


/* mysql 시퀀스 기본 생성 예 */


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
31
32
33
34
35
36
37
38
39
40
41
42
/* seq_mysql 테이블 생성 */
 CREATE TABLE seq_mysql(
 
     id INT NOT NULL
 
     seq_name VARCHAR(50NOT NULL
 
 );
 
/* 생성된 펑션 삭제 */
 DROP FUNCTION IF EXISTS get_seq;
 
/* Auto_increment 적용 */
DELIMITER $$
 
CREATE FUNCTION get_seq (p_seq_name VARCHAR(45))
 
RETURNS INT READS SQL DATA
 
BEGIN
 
DECLARE RESULT_ID INT;
 
UPDATE seq_mysql SET id = LAST_INSERT_ID(id+1
 
 WHERE seq_name = p_seq_name;
 
SET RESULT_ID = (SELECT LAST_INSERT_ID());
 
RETURN RESULT_ID;
 
END $$
 
DELIMITER ;
 
/* 시퀀스 생성 */ 
INSERT INTO seq_mysql
 
 VALUES (0'boardSeq');
 
/* 시퀀스 삽입 */
get_seq('boardSeq')
cs


mysql에서는 테이블을 생성하고, 변수 값으로 시퀀스와 같은 기능을 만들 수 있다.

위의 예처럼 순서대로 생성해주면, get_seq('boardSeq') 라는 값을 시퀀스처럼 사용 가능하다.


시퀀스 객체 초기화를 위해, 많은 방법이 있겠지만

나의 경우에는 위에서 "생성된 펑션 삭제" 구문을 실행해주고, 다시 생성해주는 방법을 사용했다.


mysql이 미숙한 모든 분들에게 좋은 팁이 되었으면 좋겠다.

+ Recent posts