'Back-End'에 해당되는 글 287건

  1. 2019.07.04 게시판 만들기 (상세화면)
  2. 2019.07.03 게시판 만들기 (검색기능)
  3. 2019.07.03 오라클 반복문 (for loop, while loop)
  4. 2019.07.03 오라클 변수 선언
  5. 2019.07.03 게시판 만들기 (페이지 나누기) 1
  6. 2019.07.02 게시판 만들기 (게시글 쓰기)
  7. 2019.07.02 게시판 만들기 (게시글 목록)
  8. 2019.07.02 게시판 만들기 (기본구조, 테이블 생성)

게시판 만들기 (상세화면)

Back-End/Spring 2019. 7. 4. 12:17

게시판 만들기 (상세화면)



 list.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    <c:forEach var="row" items="${map.list}"
    <!-- 컨트롤러에서 map안에 list를 넣었기 때문에 이렇게 받는다. -->
    <tr>
        <td>${row.bno}</td>
        <td>

//클릭하면 컨트롤러의 view.do로 이동하고, 게시물번호, 페이지번호,
//검색 옵션, 키워드를 같이 넘긴다.
//그렇게 같이 넘겨야 페이지나 검색이 풀리지 않는다.

<a href="${path}/board/view.do?bno=${row.bno}>      
&curPage=${map.pager.curPage} //페이지 번호
&search_option=${map.search_option} 
&keyword=${map.keyword}">${row.title}</a></td>
        <td>${row.name}</td>
        <td><fmt:formatDate value="${row.regdate}"
            pattern="yyyy-MM-dd HH:mm:ss"/> </td>
        <td>${row.viewcnt}</td>
    </tr>
    </c:forEach>    
cs



BoardController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RequestMapping("view.do", method=RequestMethod.GET)
    //list.jsp 페이지에서 넘긴 게시물번호, 페이지번호, 검색옵션, 키워드를 받는다.
    public ModelAndView view(@RequestParam int bno,
        @RequestParam int curPage,
        @RequestParam String search_option,
        @RequestParam String keyword,                    
        HttpSession session) throws Exception {
 
        //조회수 증가 처리
        boardService.increaseViewcnt(bno);

BoardServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    //조회수 증가 처리
//조회수 처리를 할때 일정 시간이 지난후 다시 클릭할때만 조회수가 증가하도록 설정.
    @Override
    public void increaseViewcnt(int bno, HttpSession session)
//글번호와 세션에 저장된 값들을 매개값으로 받음 
            throws Exception {
        long update_time=0; // null을 방지하기 위해 초기값을 null로 설정
        if(session.getAttribute("update_time_"+bno)!=null) {
            //최근에 조회수를 올린 시간이 null이 아니면
            update_time=
                    (long)session.getAttribute("update_time_"+bno);
        }
        long current_time=System.currentTimeMillis();
        //일정 시간이 경과한 후 조회수 증가 처리
        if(current_time - update_time > 5*1000) {
//그러니까 조회수가 1증가했을때로부터 5000초 후에 다시 클릭을 해야 조회수가 다시 1증가한다는 말..
            //조회수 증가 처리
            boardDao.increateViewcnt(bno);
            //조회수를 올린 시간 저장
            session.setAttribute("update_time_"+bno, current_time);
        }
    }
 
cs



BoardDAOImpl.java

1
2
3
4
5
    //조회수 증가 처리
    @Override
    public void increateViewcnt(int bno) throws Exception {
        sqlSession.update("board.increaseViewcnt", bno);
    }
cs



boardMapper.xml

1
2
3
4
5

<mapper namespace="board">

<!-- 조회수 증가 처리 -->
    <update id="increaseViewcnt">
//글번호에 해당하는 조회수를 +1하는 쿼리문
        update board set viewcnt=viewcnt+1
        where bno=#{bno}
    </update>

cs



        ModelAndView mav=new ModelAndView();
        mav.setViewName("board/view"); //포워딩할 뷰의 이름
        
        //view로 자료를 넘기기 위해 mav에 값들을 저장해서 view.jsp로 리턴시킴
        mav.addObject("dto"boardService.read(bno)); //상세보기를 한번 클릭하면 조회수를 1 증가시켜야 하므로 조회수 증가 구문


BoardServiceImpl.java

1
2
3
4
    @Override
    public BoardDTO read(int bno) throws Exception {
        return boardDao.read(bno);
    }
cs



BoardDAOImpl.java

1
2
3
4
5
    //게시물 조회
    @Override
    public BoardDTO read(int bno) throws Exception {
        return sqlSession.selectOne("board.read", bno); 
    }
cs



boardMapper.xml

1
2
3
4
5
6
7
8
<mapper namespace="board">
 
<select id="read" 
resultType="com.example.spring02.model.board.dto.BoardDTO">
//board테이블의 작성자와 member테이블의 유저아이디가 같고, 글번호가 클릭한 글번호와 같은
//글번호, 제목, 조회수, 날짜, 내용, 이름, 작성자를 검색.
        select bno,title,regdate,content,viewcnt,name,writer 
        from board b, member m
        where b.writer=m.userid and bno=#{bno}    
    </select>
cs




        mav.addObject("curPage", curPage);
        mav.addObject("search_option", search_option);
        mav.addObject("keyword", keyword);
        return mav; //  views/board/view.jsp로 넘어가서 출력됨
    }


cs




view.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
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!-- views/board/view.jsp -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
<script src="${path}/include/js/common.js"></script>
 
<!-- ckeditor의 라이브러리를 사용하기 위해 추가하는 코드 -->
<script src="${path}/ckeditor/ckeditor.js"></script>

 
<script>
$(function(){ //자동으로 실행되는 코드
    //댓글 목록 출력
    listReply2();
    
    //댓글 쓰기
    $("#btnReply").click(function(){
        var replytext=$("#replytext").val(); //댓글 내용
        var bno="${dto.bno}"//게시물 번호
        var param="replytext": replytext, "bno": bno};
        //var param="replytext="+replytext+"&bno="+bno;
        $.ajax({
            type: "post",
            url: "${path}/reply/insert.do",
            data: param,
            success: function(){
                alert("댓글이 등록되었습니다.");
                listReply2(); //댓글 목록 출력
            }
        });
    });
    
    $(".fileDrop").on("dragenter dragover",function(e){
        //기본 효과 막음
        e.preventDefault();
    });
    $(".fileDrop").on("drop",function(e){
        e.preventDefault();
        //첫번째 첨부파일
        var files=e.originalEvent.dataTransfer.files;
        var file=files[0];
        //폼 데이터에 첨부파일 추가
        var formData=new FormData();
        formData.append("file",file);
        $.ajax({
            url: "${path}/upload/uploadAjax",
            data: formData,
            dataType: "text",
            processData: false,
            contentType: false,
            type: "post",
            success: function(data){
                //console.log(data);
                //data : 업로드한 파일 정보와 Http 상태 코드
                var fileInfo=getFileInfo(data);
                //console.log(fileInfo);
                var html="<a href='"+fileInfo.getLink+"'>"+
                    fileInfo.fileName+"</a><br>";
                html += "<input type='hidden' class='file' value='"
                    +fileInfo.fullName+"'>";
                $("#uploadedList").append(html);
            }
        });
    });
    
    
    //목록 버튼
    $("#btnList").click(function(){
        location.href="${path}/board/list.do";
    });
    //수정 버튼
    $("#btnUpdate").click(function(){
        //첨부파일 이름들을 폼에 추가
        var str="";
        $("#uploadedList .file").each(function(i){
            str+=
                "<input type='hidden' name='files["+i+"]' value='"
                +$(this).val()+"'>";
        });
        $("#form1").append(str);
        document.form1.action="${path}/board/update.do";
        document.form1.submit();
    });
    //삭제 버튼
    $("#btnDelete").click(function(){
        if(confirm("삭제하시겠습니까?")){
            document.form1.action="${path}/board/delete.do";
            document.form1.submit();
        }
    });
    
    listAttach();
    
    //첨부파일 삭제
    //id가 uploadedList인 태그의 class가 file_del인 태그 클릭
    $("#uploadedList").on("click",".file_del",function(e){
        var that=$(this); //클릭한 태그
//data: {fileName: $(this).attr("data-src") },        
        $.ajax({
            type: "post",
            url: "${path}/upload/deleteFile",
            data: "fileName="+    $(this).attr("data-src"),        
            dataType: "text",
            success: function(result){
                if(result=="deleted"){
                    //화면에서 태그 제거
                    that.parent("div").remove();
                }
            }
        });
    });
    
    $("#btnSave").click(function(){
        var str="";
        // uploadedList 내부의 .file 태그 각각 반복
        $("#uploadedList .file").each(function(i){
            console.log(i);
            //hidden 태그 구성
            str += 
"<input type='hidden' name='files["+i+"]'    value='"
    + $(this).val()+"'>";
        });
        //폼에 hidden 태그들을 붙임
        $("#form1").append(str);
        document.form1.submit();
    });
    
});
//댓글 목록 출력 함수
function listReply(){
    $.ajax({
        type: "get",
        url: "${path}/reply/list.do?bno=${dto.bno}",
        success: function(result){
            //result : responseText 응답텍스트(html)
            $("#listReply").html(result);
        }
    });
}
//타임스탬프값(숫자형)을 문자열 형식으로 변환
function changeDate(date){
    date = new Date(parseInt(date));
    year=date.getFullYear();
    month=date.getMonth();
    day=date.getDate();
    hour=date.getHours();
    minute=date.getMinutes();
    second=date.getSeconds();
    strDate = 
        year+"-"+month+"-"+day+" "+hour+":"+minute+":"+second;
    return strDate;
}
 
function listReply2(){
    $.ajax({
        type: "get",
        contentType: "application/json",
        url: "${path}/reply/list_json.do?bno=${dto.bno}",
        success: function(result){
            console.log(result);
            var output="<table>";
            for(var i in result){
                var repl=result[i].replytext;
                repl = repl.replace(/  /gi,"&nbsp;&nbsp;");//공백처리
                repl = repl.replace(/</gi,"&lt;"); //태그문자 처리
                repl = repl.replace(/>/gi,"&gt;");
                repl = repl.replace(/\n/gi,"<br>"); //줄바꿈 처리
                
                output += "<tr><td>"+result[i].name;
                date = changeDate(result[i].regdate);
                output += "("+date+")";
                output += "<br>"+repl+"</td></tr>";
            }
            output+="</table>";
            $("#listReply").html(output);
        }
    });
}
 
//첨부파일 리스트를 출력하는 함수
function listAttach(){
    $.ajax({
        type: "post",
        url: "${path}/board/getAttach/${dto.bno}",
        success: function(list){
            // list : json
            //console.log(list);
            $(list).each(function(){
                var fileInfo=getFileInfo(this);
                //console.log(fileInfo);
                var html="<div><a href='"+fileInfo.getLink+"'>"
                    +fileInfo.fileName+"</a>&nbsp;&nbsp;";
                <c:if test="${sessionScope.userid == dto.writer}">    
                    html+="<a href='#' class='file_del' data-src='"
                        +this+"'>[삭제]</a></div>";
                </c:if>
                $("#uploadedList").append(html);
            });
        }
    });
}
 
</script>
 
<style>
<!--css로 스타일 시트를 적용-->
.fileDrop {
    width: 600px;
    height: 100px;
    border: 1px dotted gray;
    background-color: gray;
}
</style>
 
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>게시물 보기</h2>
<!-- 게시물을 작성하기 위해 컨트롤러의 insert.do로 맵핑 -->
<form id="form1" name="form1" method="post"
action="${path}/board/insert.do">
    <div>제목 <input name="title" id="title" size="80"
                    value="${dto.title}"
                    placeholder="제목을 입력하세요">
<!-- placeholder은 제목을 입력할 수 있도록 도움말을 출력함 -->
    </div>
    <div>조회수 : ${dto.viewcnt}    </div>
    <div style="width:800px;">
        내용 <textarea id="content" name="content"
rows="3" cols="80" 
placeholder="내용을 입력하세요">${dto.content}</textarea>
 
<!-- 마찬가지로 내용을 입력하도록 도움말을 출력함 -->
<script>
// ckeditor 적용
//id가 content인 태그 (글의 내용을 입력하는 태그)를 ck에디터를 적용한다는 의미
CKEDITOR.replace("content",{
    filebrowserUploadUrl: "${path}/imageUpload.do",
    height: "300px"
});
</script>

    </div>
    <div> 첨부파일을 등록하세요
        <div class="fileDrop"></div>
        <div id="uploadedList"></div>
    </div>

    <div style="width:700px; text-align:center;">
<!-- 수정,삭제에 필요한 글번호를 hidden 태그에 저장 -->    
        <input type="hidden" name="bno" value="${dto.bno}">
        
        <!-- 본인만 수정,삭제 버튼 표시 -->
        <c:if test="${sessionScope.userid == dto.writer}">
            <button type="button" id="btnUpdate">수정</button>
            <button type="button" id="btnDelete">삭제</button>
        </c:if>
        
        <!-- 목록은 본인이 아니어도 확인이 가능하게 할 예정 -->
        <button type="button" id="btnList">목록</button>
    </div>
</form>


<!-- 댓글 작성 -->
<div style="width:700px; text-align:center;">
     <c:if test="${sessionScope.userid != null }">
         <textarea rows="5" cols="80" id="replytext"
             placeholder="댓글을 작성하세요"></textarea>
         <br>
         <button type="button" id="btnReply">댓글쓰기</button>
     </c:if>
</div>
<!-- 댓글 목록 -->
<div id="listReply"></div>
 
</body>
</html>
cs


:

게시판 만들기 (검색기능)

Back-End/Spring 2019. 7. 3. 18:16

게시판 만들기 (검색기능 구현)


list.jps 중 일부 (검색 폼 추가)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- 검색폼 -->
<form name="form1" method="post"
    action="${path}/board/list.do"> //'조회' 버튼을 누르면 컨트롤러의 list.do로 맵핑된다.
    <select name="search_option">
        <option value="name"
<c:if test="${map.search_option == 'name'}">selected</c:if>
        >이름</option>
        <option value="title" 
<c:if test="${map.search_option == 'title'}">selected</c:if>
        >제목</option>
        <option value="content" 
<c:if test="${map.search_option == 'content'}">selected</c:if>
        >내용</option>
        <option value="all" 
<c:if test="${map.search_option == 'all'}">selected</c:if>
        >이름+내용+제목</option>
    </select>
    <input name="keyword" value="${map.keyword}">
    <input type="submit" value="조회">
</form>
cs



BoardController.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
@RequestMapping("list.do"//세부적인 url pattern
    public ModelAndView list(//RequestParam 값들을 받아오고, 옵션, 키워드, 페이지의 기본값을 각각 설정해준다.
    @RequestParam(defaultValue="name"int curPage,
    @RequestParam(defaultValue=""String search_option,
    @RequestParam(defaultValue="1"String keyword)
    //defaultValue를 설정하지 않으면 null point 에러가 발생할수 있기 때문에 기본값을 설정해주어야 한다.
                        throws Exception{
        //레코드 갯수 계산
        int count = boardService.countArticle(search_option,keyword);
        
        //페이지 관련 설정, 시작번호와 끝번호를 구해서 각각 변수에 저장함
        Pager pager=new Pager(count, curPage);
        int start=pager.getPageBegin();
        int end=pager.getPageEnd();
        
        //게시물 목록을 출력하기 위해 <BoardDTO>타입에 list변수에 게시물 목록관련 값들을 저장함.
        //넣어야될 값들이 여러개 있으므로 haspmap.put 메소드를 사용해서 값들을 넣어서 list에 저장
        
        List<BoardDTO> list= boardService.listAll(search_option,keyword,start,end); //게시물 목록

System.out.println("list:"+list);
        
        ModelAndView mav=new ModelAndView(); //자료를 보낼 페이지를 지정해야하고, 자료를 지정해야 하기 때문에 
                                                //ModelAndView 객체를 생성한다.
 
        HashMap<String,Object> map=new HashMap<>(); //여러개의 값들을 저장해야하기 때문에 hashmap() 객체를 생성
        
        map.put("list", list); //map에 자료 저장
        map.put("count", count);
        map.put("pager", pager); //페이지 네비게이션을 위한 변수
        map.put("search_option", search_option);
        map.put("keyword",keyword); 
        mav.setViewName("board/list"); //포워딩할 뷰의 이름
        mav.addObject("map", map); //ModelAndView에 map을 저장
        return mav; // board/list.jsp로 이동
    }
cs



BoardServiceImpl.java

1
2
3
4
5
6
7
@Override
    public List<BoardDTO> listAll(
            //매개변수는 시작 레코드번호, 끝번호, 옵션과 키워드가 들어간다
String search_option, String keyword,int start, int end)
            throws Exception {
        return boardDao.listAll(search_option,keyword,start,end); 
    }
cs



BoardDAOImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
  //게시물 목록 리턴
    @Override
    public List<BoardDTO> listAll(
String search_option, String keyword,int start, int end) 
                throws Exception {
        Map<String,Object> map=new HashMap<>();
        map.put("search_option", search_option);
        map.put("keyword""%"+keyword+"%");
        map.put("start", start); //맵에 자료 저장
        map.put("end", end);
 // mapper에는 2개 이상의 값을 전달할 수 없음(dto 또는 map 사용)        
        return sqlSession.selectList("board.listAll",map); 
    }
cs



boardMapper.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
<select id="listAll"
    resultType="com.example.spring02.model.board.dto.BoardDTO">
    <!-- 결과는 boardDTO타입이 된 -->
        <include refid="paging_header" /
        <!-- ref는 다른테이블을 의미한다. -->
        <!-- 번호, 제목, 작성자, 이름, 날짜, 조회수 , 그리고 댓글의 갯수를 검색 -->
        <!-- board 테이블과 member 테이블로 부터 검색 -->
            select bno,title,writer,name,regdate,viewcnt             
            from board b, member m
            
            <!-- bno의 내림차순으로 검색 -->
            <!-- where절은 (조건)은 include 태그를 이용했음 -->
            <include refid="search" /> //밑에있는 id가 search인 구문을 조건으로 실행한다.
            order by bno desc   
            
        <include refid="paging_footer" />
    </select>
    <sql id="paging_header">
    <!-- 게시물을 한페이지에 10개씩 볼 수 있게하는 쿼리 윗부분-->
        select *
        from (
            select rownum as rn, A.*
            from (    
    </sql>
    <sql id="paging_footer">
    <!-- 게시물을 한페이지에 10개씩 볼 수 있게하는 쿼리  아랫 부분-->
    <!-- 새로 매겨진 일련번호 1~10번 글까지 1페이지 -->
    <!-- 11~20번 글까지 2페이지.. -->
            ) A
        ) where rn between #{start} and #{end}    
    </sql>
 
 
====================================================================
 
    <sql id="search">
        <choose>
            <when test="search_option == 'all' ">
            <!-- all일때는 3가지를 다 찾아야 하기때문에 이름, 내용, 제목으로 찾아본다. -->
                where b.writer=m.userid 
                    and (name like '%' ||#{keyword}||'%'
                    or content like '%'||#{keyword}||'%'
or title like '%'||#{keyword}||'%' )           
            </when>
            <otherwise>
            <!-- 그렇지 않으면 옵션과 키워드를 이용해서  찾는다.-->
            <!-- $를 붙이면 따움표가 빠지게 되고, #을 붙이면 따움표가 붙게 된다. -->
                where b.writer=m.userid 
                   and ${search_option} like '%'||#{keyword}||'%'           
            </otherwise>
        </choose>
    </sql>
cs



이 구문을 실행한후에 컨트롤러에서 값들을 받고, search_option과 keyword를 다시 되돌려 준다.


이렇게 하고 실행을 하면 검색을 한 뒤에 검색 조건이 초기화되기 때문에 이것을 방지하기 위해서


list.jsp 페이지를 수정해준다.



list.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- 검색폼 -->
<form name="form1" method="post"
    action="${path}/board/list.do">
    <select name="search_option"> //검색을 한 뒤에 검색 조건이 초기화되는것을 방지하는 코드
        <option value="name"
<c:if test="${map.search_option == 'name'}">selected</c:if>
        >이름</option>
        
        <option value="title" 
<c:if test="${map.search_option == 'title'}">selected</c:if>
        >제목</option>
        <option value="content" 
<c:if test="${map.search_option == 'content'}">selected</c:if>
        >내용</option>
        <option value="all" 
<c:if test="${map.search_option == 'all'}">selected</c:if>
        >이름+내용+제목</option>
    </select>
    <input name="keyword" value="${map.keyword}">
    <input type="submit" value="조회">
</form>
cs




:

오라클 반복문 (for loop, while loop)

Back-End/Data Base 2019. 7. 3. 13:42

- for loop -


[문법 예시]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SET serveroutput ON; //서버에서 출력되는 값을 기본값을 설정
 
BEGIN // 반복문의 시작 부
 
FOR i in 1..4 LOOP // 4번 회전시킨다는 의미
 
if mod(i, 2= 0 then //짝수인지 홀수인지 판단하기 위해 i를 2로 나누었을때의 값이 0인지 아닌지 판ㅇ
 
dbms_output.put_line(i || '는 짝수!!'); //if구문이 참이면 실행되는 구문 ex) 2는 짝수!!
 
else
 
dbms_output.put_line(i || '는 홀수!!'); //if구문이 거짓이면 실행되는 구문 ex) 3는 거짓!!
 
end if; //if구문의 끝
 
END LOOP; LOOP를 종료시킨다는 의미
 
END; //반복문의 끝 부분
cs




- while -


[문법]


1
2
3
4
while 조건

LOOP

처리문;

END LOOP;
cs



while 문은 loop 문과 비슷하지만 while 다음에 조건을 붙여 해당 조건에 만족할 때만 루프를 돌면서 로직을 처리한다.


while 다음에 조건처리를 한 부분만 제외하면 다른 부분은 LOOP 문과 같지만, LOOP문과 달리 vn_cnt값이 9보다 작거나


같은 경우라는 조건을 주었다는 점을 살펴보자.


LOOP문에서는 루프를 빠져 나가는 조건을 주었지만, while 문에서는 루프를 수행하는 조건을 준 것이다.


while문에서도 루프를 돌다가 특정 조건에 부합하면 exit를 써서 루프를 빠져 나올 수 있다.




- while 문을 사용해 구구단 3단을 출력하는 예시 -


1
2
3
4
5
6
7
8
9
10
DECLARE
    vn_base_num NUMBER := 3; //변하지 않는 기본값
    vn_cnt      NUMBER := 1; //3단을 출력해야하므로 1씩 증가하는 숫자
BEGIN
WHILE vn_cnt <= 9     --vn_cnt가 9보다 작거나 같을 때만 반복 
LOOP
    DBMS_OUTPUT.PUT_LINE (vn_base_num || '*' || vn_cnt || '=' || vn_base_num * vn_cnt);
    vn_cnt := vn_cnt + 1--vn_cnt 값을 1씩 증가
END LOOP;
END;
cs



출력된 결과값

1
2
3
4
5
6
7
8
9
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
3 * 4 = 12
3 * 5 = 15
3 * 6 = 18
3 * 7 = 21
3 * 8 = 24
3 * 9 = 27
cs


'Back-End > Data Base' 카테고리의 다른 글

ERD (ER 다이어그램) Cloud  (0) 2019.07.08
MongoDB 문법, SQL과의 비교  (0) 2019.07.08
오라클 변수 선언  (0) 2019.07.03
기본 용어 정리  (0) 2019.06.27
무결성이란?  (0) 2019.06.27
:

오라클 변수 선언

Back-End/Data Base 2019. 7. 3. 11:10

* 오라클 변수 선언


1.    declare 변수이름 데이터타입;


declare 변수이름 데이터타입 := 값;


declare 변수이름 데이터타입 default 기본값;



* 데이터 타입 선언 방법


varchar2 (byte 수)

number (자리수)

date

테이블이름%RowType => 특정테이블 행전체타입 (참조변수)

테이블이름.컬럼명%type => 특정테이블의 컬럼타입



ex) 여러개의 변수 선언

declare name varchar2(20);

age number(20) := 50;



* 특정 문장을 실행하기 위한 방법

begin


실행 문장을 작성

ex) dbms_output.put_line(출력내용);

end;




'Back-End > Data Base' 카테고리의 다른 글

MongoDB 문법, SQL과의 비교  (0) 2019.07.08
오라클 반복문 (for loop, while loop)  (0) 2019.07.03
기본 용어 정리  (0) 2019.06.27
무결성이란?  (0) 2019.06.27
오라클 SQL Develope 다운로드 및 설치  (0) 2019.05.28
:

게시판 만들기 (페이지 나누기)

Back-End/Spring 2019. 7. 3. 11:02


 - 페이지 나누기 구현 -



 - 페이지당 게시물수 : 10개


 - 전체 게시물수 : 991개


 - 몇 페이지? : 100


 991 / 10 => 99.1 올림 => 100


(99.1에서 올림을 한 이유는 한 페이지에 글이 1개만 들어갈 수도 있기 때문.. (맨 오래전에 쓴 맨 첫글같은 경우))



 - 페이지의 시작번호, 끝번호 계산


 where rn between 1 and 10


 1페이지 => 1 ~ 10

 2페이지 => 11 ~ 20

 .....

 11페이지 => 101 ~ 110

 57페이지 => 561 ~ 570

 99페이지 => 981 ~ 990

 100페이지 => 991 ~ 1000


시작번호 = (현재페이지 - 1) * 페이지당 게시물수 + 1


1페이지 => (1-1) * 10 + 1 => 1

2페이지 => (2-1) * 10 + 1 => 11

7페이지 => (7-1) * 10 + 1 => 61


끝번호 = 시작번호 + 페이지당 게시물수 - 1


1페이지 => 1 + 10 - 1 => 10

2페이지 => 11 + 10 -1 => 20


 * 전체 페이지 블록수 = 전체 페이지 갯수 / 10

(페이지가 한꺼번에 다 나오면 알아보기가 힘들기때문에 10페이지씩 1블록을 만들어 저장)

91 / 10 => 9.1 => 10개


 

예시 )


1    2    3    4    5    6    7    8    9    10    [다음]

[이전]    11    12    13    14    15    16    17    18    19    20    [다음]

[이전]    21    22


22페이지가 끝일 경우에는 그 다음페이지는 표시되지 않아야 하고, [다음] 버튼도 출력되면 안된다.



현재 페이지가 속한 블록 = (현재 페이지 - 1) / 페이지 블록 단위 + 1


1페이지 => 몇번째 블록? 1

(1-1) / 10 + 1 => 1


9페이지 => 1블록

(9-1) / 10 + 1 => 1


11페이지 => 2블록

(11-1) / 10 + 1 => 2


57페이지

(57-1) / 10 + 1 => 6


* 페이지 블록의 시작번호 = (현재블록 - 1) * 블록단위 + 1


1블록 => (1-1) * 10 + 1 => 1

2블록 => (2-1) * 10 + 1 => 11

6블록 => (6-1) * 10 + 1 => 51


* 페이지 블록의 끝번호 = 블록 시작번호 + 블록단위 - 1


1블록 => 1 + 10 - 1 => 10

2블록 => 11 + 10 - 1 => 20

6블록 => 51 + 10 - 1 => 60




board테이블과 member테이블을 join을 해야 작성자의 이름을 알 수 있다.



board 테이블



member 테이블



(연습) board테이블과 member테이블을 join해서 작성자가 작성한 게시글의 정보를 조회하는 쿼리

1
2
3
4
select bno, title, writer, name, regdate, viewcnt // 글번호, 제목, 작성자, 이름, 날짜, 조회수를 검색
from board b, member m // board 테이블과 member테이블로 부터 (b와 m은 약자로 쓴다는 의미)
where b.writer=m.userid // board 테이블의 작성자id와 member 테이블의 회원id가 같은 것을 검색
order by bno desc; // 글번호의 내림차순으로 검색
cs



boardMapper.xml에서 코드를 수정 (위에서 실행해본 SQL 구문을 listAll에 삽입한다)

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 다른 mapper와 중복되지 않도록 네임스페이스 기재 -->
 
<mapper namespace="board">
 
<select id="listAll"
resultType="com.example.spring02.model.board.dto.BoardDTO">
select bno, title, writer, name, regdate, viewcnt     
from board b, member m                               
where b.writer=m.userid                            
order by bno desc;
 
</select>
cs



list.jsp 중 일부 코드 수정 (게시판에서 작성자 이름이 출력될 수 있도록....)

이렇게 하면 name에 join된 이름이 출력되게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<c:forEach var = "row" items = "${map.list}">
    <tr>
        <td>${row.bno}</td>
        <td>${row.title}</td>
        <td>${row.name}</td//write를 name로 변경
        <td><fmt:formatDate value = "${row.regdate}"
            pattern = "yyyy-MM-dd HH:mm:ss" /></td>
        <td>${row.viewcnt}</td>
    </tr>
</c:forEach>
</table>
</body>
</html>
cs



게시물 1000개를 입력하기 위해 데이터베이스에서 반복문을 만들어서 실행한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
declare
    i number := 1-- declare는 선언문, i의 값을 1로 대입하는것을 선언,
begin
    while i <= 1000 loop
        insert into board (bno,title,content,writer) values
        ((select nvl(max(bno)+1,1)from board),'제목'||i, '내용'||i, 'park');
 
        -- 시퀀스를 만들긴 했지만 번호가 깔끔하게 나오지 않기때문에 서브쿼리를 사용해서 번호를 1씩 증가시킨다.
        -- ||는 숫자와 문자열을 더할때 사용한다 이 쿼리에서는 제목1, 제목2 이런식으로 출력이 되게 된다.
        -- id는 member 테이블에 있는 id만 사용해야 한다. 그렇게 해야 join이 되기 때문에
 
        i := i+1;
        --한 바퀴 돌때마다 i를 1씩 증가시킨다는 의미 (1000바퀴 돌때까지)
    end loop;
end;
/


commit; //게시물 1000개를 집어넣은 후 commit를 실시해서 작업을 완료함.
cs


게시물을 한페이지에 10개씩 볼 수 있게하는 쿼리 (연습)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- rownum : 출력순서
-- 아래sql 문에서는 원래 from 문이 먼저 실행되고, 
-- where문이 다음으로 실행되고, 
-- 그 다음 맨위쪽 문장이 실행된다.
-- 마지막에는 order by문이 실행된다.
 
select * 
from (
    select rownum as rn, A.* --rownum을 rn이란 문자로 줄여쓴다. 밑에 from문을 A로 줄여쓴다. 
    from ( --이 from문이 먼저 실행된 다음에 번호를 붙였기 때문에 일련번호가 다시 새로 매겨졌다.
        --이 안쪽의 쿼리가 가장 중요함
        select rownum, bno, title, regdate, viewcnt, name --3번째로 실행
        from board b, member m --1번째로 실행
        where b.writer=m.userid --2번째로 실행
        order by bno desc --4번째로 실행
    ) A
where rn between 1 and 10-- 새로매겨진 일련번호 1~10번 글까지 1페이지
                             -- 11~20번 글까지 2페이지 ..
 
cs



페이지를 나누기 위한 클래스 작성


Pager.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package com.example.spring02.service.board;
 
public class Pager {
    public static final int PAGE_SCALE=10;    //페이지당 게시물수
    public static final int BLOCK_SCALE=10;    //화면당 페이지수
    
    private int curPage;     //현재 페이지
    private int prevPage;    //이전 페이지
    private int nextPage;    //다음 페이지
    private int totPage;    //전체 페이지 갯수
    private int totBlock;     //전체 페이지블록 갯수
    private int curBlock;     //현재 블록
    private int prevBlock;     //이전 블록
    private int nextBlock;     //다음 블록
    private int pageBegin;     // #{start} 변수에 전달될 값
    private int pageEnd;     // #{end} 변수에 전달될 값
    private int blockBegin; //블록의 시작페이지 번호
    private int blockEnd;     //블록의 끝페이지 번호
    
    //생성자
    // Pager(레코드갯수, 출력할페이지번호)
    public Pager(int count, int curPage) {
        curBlock = 1//현재블록 번호
        this.curPage = curPage; //현재 페이지 번호
        setTotPage(count); //전체 페이지 갯수 계산
        setPageRange(); // #{start}, #{end} 값 계산하는 메소드
        setTotBlock(); // 전체 블록 갯수 계산
        setBlockRange(); //블록의 시작,끝 번호 계산
    } 
    public void setBlockRange() {
        //원하는 페이지가 몇번째 블록에 속하는지 계산
        curBlock=(curPage-1)/BLOCK_SCALE + 1;
        //블록의 시작페이지,끝페이지 번호 계산
        blockBegin=(curBlock-1)*BLOCK_SCALE+1;
        blockEnd=blockBegin+BLOCK_SCALE-1;
        //마지막 블록 번호가 범위를 초과하지 않도록 처리
        if(blockEnd > totPage) {
            blockEnd = totPage;
        }
        //[이전][다음]을 눌렀을 때 이동할 페이지 번호
        prevPage=(curBlock==1) ? 1 : (curBlock-1)*BLOCK_SCALE;
        nextPage=curBlock>totBlock ? (curBlock*BLOCK_SCALE)
                : (curBlock*BLOCK_SCALE)+1;
        //마지막 페이지가 범위를 초과하지 않도록 처리
        if(nextPage >= totPage) {
            nextPage=totPage;
        }
    }
    
    //페이지블록의 총 갯수 계산 (총 100페이지라면 10개의 블록이다)
    public void setTotBlock() {
        totBlock = (int)Math.ceil(totPage*1.0 / BLOCK_SCALE);
    }
    
// where rn between #{start} and #{end}에 입력될 값        
    public void setPageRange() {
// 시작번호=(현재페이지-1)x페이지당 게시물수 + 1
// 끝번호=시작번호 + 페이지당 게시물수 - 1        
        pageBegin = (curPage-1* PAGE_SCALE + 1;
        pageEnd = pageBegin + PAGE_SCALE - 1;
    }
    
    public int getCurPage() {
        return curPage;
    }
    public void setCurPage(int curPage) {
        this.curPage = curPage;
    }
    public int getPrevPage() {
        return prevPage;
    }
    public void setPrevPage(int prevPage) {
        this.prevPage = prevPage;
    }
    public int getNextPage() {
        return nextPage;
    }
    public void setNextPage(int nextPage) {
        this.nextPage = nextPage;
    }
    public int getTotPage() {
        return totPage;
    }
    
    //전체 페이지 갯수 계산
    public void setTotPage(int count) {
        // Math.ceil() 올림        
        totPage = (int)Math.ceil(count*1.0 / PAGE_SCALE);
    }
    public int getTotBlock() {
        return totBlock;
    }
    public void setTotBlock(int totBlock) {
        this.totBlock = totBlock;
    }
    public int getCurBlock() {
        return curBlock;
    }
    public void setCurBlock(int curBlock) {
        this.curBlock = curBlock;
    }
    public int getPrevBlock() {
        return prevBlock;
    }
    public void setPrevBlock(int prevBlock) {
        this.prevBlock = prevBlock;
    }
    public int getNextBlock() {
        return nextBlock;
    }
    public void setNextBlock(int nextBlock) {
        this.nextBlock = nextBlock;
    }
    public int getPageBegin() {
        return pageBegin;
    }
    public void setPageBegin(int pageBegin) {
        this.pageBegin = pageBegin;
    }
    public int getPageEnd() {
        return pageEnd;
    }
    public void setPageEnd(int pageEnd) {
        this.pageEnd = pageEnd;
    }
    public int getBlockBegin() {
        return blockBegin;
    }
    public void setBlockBegin(int blockBegin) {
        this.blockBegin = blockBegin;
    }
    public int getBlockEnd() {
        return blockEnd;
    }
    public void setBlockEnd(int blockEnd) {
        this.blockEnd = blockEnd;
    }    
}
cs



BoardController.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
116
117
118
119
120
121
122
package com.example.spring02.controller.board;
 
import java.util.HashMap;
import java.util.List;
 
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
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 org.springframework.web.servlet.ModelAndView;
 
import com.example.spring02.model.board.dto.BoardDTO;
import com.example.spring02.service.board.BoardService;
import com.example.spring02.service.board.Pager;
@Controller //controller bean
@RequestMapping("board/*"//공통적인 url pattern
public class BoardController {
    @Inject 
    BoardService boardService;
 
    //첨부파일 목록을 리턴
    //ArrayList를 json 배열로 변환하여 리턴
    @RequestMapping("getAttach/{bno}")
    @ResponseBody // view가 아닌 데이터 자체를 리턴 
    public List<String> getAttach(@PathVariable int bno){
        return boardService.getAttach(bno);
    }
    
    @RequestMapping("delete.do")
    public String delete(int bno) throws Exception {
        boardService.delete(bno); //삭제 처리
        return "redirect:/board/list.do"//목록으로 이동
    }
    
//게시물 내용 수정    
    @RequestMapping("update.do")
    public String update(BoardDTO dto) throws Exception {
        System.out.println("dto:"+dto);
        if(dto != null) {
            boardService.update(dto); //레코드 수정
        }
        // 수정 완료 후 목록으로 이동
        //return "redirect:/board/list.do";
        // 상세 화면으로 되돌아감
        return "redirect:/board/view.do?bno="+dto.getBno();
    }
    
    @RequestMapping("list.do"//세부적인 url pattern
    public ModelAndView list(//RequestParam으로 옵션, 키워드, 페이지의 기본값을 각각 설정해준다.
    @RequestParam(defaultValue="1"int curPage,
    @RequestParam(defaultValue="all"String search_option,
    @RequestParam(defaultValue=""String keyword)
    //defaultValue를 설정하지 않으면 null point 에러가 발생할수 있기 때문에 기본값을 설정해주어야 한다.
                        throws Exception{
        //레코드 갯수 계산
        int count = 1000;
        
        //페이지 관련 설정, 시작번호와 끝번호를 구해서 각각 변수에 저장함
        Pager pager=new Pager(count, curPage); //레코드 번호와 원하는 페이지의 번호를 주게 되면 
        int start=pager.getPageBegin();
        int end=pager.getPageEnd();
        
        //게시물 목록을 출력하기 위해 <BoardDTO>타입에 list변수에 게시물 목록관련 값들을 저장함.
        //넣어야될 값들이 여러개 있으므로 haspmap.put 메소드를 사용해서 값들을 넣어서 list에 저자
        
        List<BoardDTO> list= boardService.listAll(search_option,keyword,start,end); //게시물 목록
        
        ModelAndView mav=new ModelAndView(); //자료를 보낼 페이지를 지정해야하고, 자료를 지정해야 하기 때문에 
                                                //ModelAndView 객체를 생성한다.
 
        HashMap<String,Object> map=new HashMap<>(); //여러개의 값들을 저장해야하기 때문에 hashmap() 객체를 생성
        
        map.put("list", list); //map에 자료 저장
        map.put("count", count);
        map.put("pager", pager); //페이지 네비게이션을 위한 변수
        map.put("search_option", search_option);
        map.put("keyword",keyword); 
        mav.setViewName("board/list"); //포워딩할 뷰의 이름
        mav.addObject("map", map); //ModelAndView에 map을 저장
        return mav; // board/list.jsp로 이동
    }
    
    @RequestMapping("view.do")
    public ModelAndView view(int bno, HttpSession session)
        throws Exception {
        //조회수 증가 처리
        boardService.increaseViewcnt(bno, session); 
        ModelAndView mav=new ModelAndView();
        mav.setViewName("board/view"); //포워딩할 뷰의 이름
        mav.addObject("dto", boardService.read(bno)); //자료 저장
        return mav; //  views/board/view.jsp로 넘어가서 출력됨
    } 
    
    @RequestMapping("write.do")
    public String write() {
        // 글쓰기 폼 페이지로 이동
        return "board/write";
    }
    // write.jsp에서 입력한 내용들이 BoardDTO에 저장됨    
    @RequestMapping("insert.do")
    public String insert(@ModelAttribute BoardDTO dto
            , HttpSession session) //세션은 아이디를 확인하기위해서 필요하므로 세션을 가져온다.
        throws Exception {
        
        // 로그인한 사용자의 아이디
        String writer=(String)session.getAttribute("userid");
        dto.setWriter(writer); //로그인한 아이디를 dto에 저장
 
        //레코드 저장
        boardService.create(dto); //서비스와 dao를 통해서 레코드에 추가가된다.
        
        //게시물 목록으로 이동
        return "redirect:/board/list.do";
    }
}
cs



BoardDAOImpl.java 중 일부 (게시물 목록을 리턴하는 메소드를 수정함)

1
2
3
4
5
6
7
8
9
10
11
12
13
//게시물 목록 리턴
    @Override
    public List<BoardDTO> listAll(
String search_option, String keyword,int start, int end) 
                throws Exception {
        Map<String,Object> map=new HashMap<>();
        map.put("search_option", search_option);
        map.put("keyword""%"+keyword+"%");
        map.put("start", start); //맵에 자료 저장
        map.put("end", end);
// mapper에는 2개 이상의 값을 전달할 수 없음(dto 또는 map 사용)        
        return sqlSession.selectList("board.listAll",map); 
    }
cs



boardMapper.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
<?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와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="board">
 
    <select id="listAll"
resultType="com.example.spring02.model.board.dto.BoardDTO">
    <!-- 결과는 boardDTO타입이 된 -->
 
        <include refid="paging_header" />
 
    <!-- ref는 다른테이블을 의미한다. -->
    <!-- 번호, 제목, 작성자, 이름, 날짜, 조회수 , 그리고 댓글의 갯수를 검색 -->
    <!-- board 테이블과 member 테이블로 부터 검색 -->
            select bno,title,writer,name,regdate,viewcnt,show
                  ,(select count(*) from reply where bno=b.bno) cnt                    
            from board b, member m
 
    <!-- bno의 내림차순으로 검색 -->
            <include refid="search" />
            order by bno desc   
        <include refid="paging_footer" />
    </select>
 
    <sql id="paging_header">
<!-- 게시물을 한페이지에 10개씩 볼 수 있게하는 쿼리 윗부분-->
        select *
        from (
            select rownum as rn, A.*
            from (    
    </sql>
    <sql id="paging_footer">
<!-- 게시물을 한페이지에 10개씩 볼 수 있게하는 쿼리  아랫 부분-->
    <!-- 새로 매겨진 일련번호 1~10번 글까지 1페이지 -->
    <!-- 11~20번 글까지 2페이지.. -->
            ) A
        ) where rn between #{start} and #{end}    
    </sql>
    
    <insert id="insert">
        insert into board (bno,title,content,writer) values
        ( seq_board.nextval, #{title}, #{content}, #{writer} )
    </insert>
 
</mapper>
cs



list.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
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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
<script>
$(function(){ //아이디가 btnWrite인 버튼을 누르게 되면 write.do 컨트롤러로 맵핑
    $("#btnWrite").click(function(){
        location.href="${path}/board/write.do";
    });
});
 
function list(page){ //현재 페이지의 조건을 넘겨준다. +뒤에있는 것들은 검색 
    location.href="${path}/board/list.do?curPage="+page
        +"$search_option=${map.search_option}"
        +"$keyword=${map.keyword}";
}
 
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>게시판</h2>
 
 
<button type="button" id="btnWrite">글쓰기</button>
${map.count}개의 게시물이 있습니다.<!-- map에 저장된 개시물의 갯수를 불러옴 -->
<table border="1" width="600px">
    <tr>
        <th>번호</th>
        <th>제목</th>
        <th>이름</th>
        <th>날짜</th>
        <th>조회수</th>
    </tr>
    <!-- forEach var="개별데이터" items="집합데이터" -->
<c:forEach var="row" items="${map.list}"<!-- 컨트롤러에서 map안에 list를 넣었기 때문에 이렇게 받는다. -->
    <tr>
        <td>${row.bno}</td>
        <td>
<a href="${path}/board/view.do?bno=${row.bno}">
${row.title}
</a>
            <c:if test="${row.cnt > 0}">
                <span style="color:red;">( ${row.cnt} )</span>
            </c:if>   
        </td>
        <td>${row.name}</td>
        <td><fmt:formatDate value="${row.regdate}"
            pattern="yyyy-MM-dd HH:mm:ss"/> </td>
        <td>${row.viewcnt}</td>
    </tr>
</c:forEach>    
<!-- 페이지 네비게이션 출력 -->
    <tr>
        <td colspan="5" align="center">
            <c: forEach var = "num" begin = "1" end = "${map.pager.totPage}">
                <a href = "javascript : list ('${num}')">${num}</a>
            </c:forEach>
        </td>
    </tr>
</table>
</body>
</html>
cs



위에서 페이지 나누기 기능을 추가하기 위해서 페이지 네비게이션 부분에 페이지 나누기 코드를 추가


list.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
42
43
44
45
46
<!-- 페이지 네비게이션 출력 -->
    <tr>
        <td colspan="5" align="center">
        
            <c:if test="${map.pager.curBlock > 1}">
  <a href="#" onclick="list('1')">[처음]</a>
            </c:if<!-- 현재 블록이 1블록보다 크면 (뒤쪽에 있기때문에) 처음으로 갈 수 있도록 링크를 추가 -->
        
            <c:if test="${map.pager.curBlock > 1}">
                <a href="#" onclick="list('${map.pager.prevPage}')">
                [이전]</a>
            </c:if<!-- 현재 블록이 1블록보다 크면 이전 블록으로 이동할 수 있도록 링크 추가 -->
            
            <c:forEach var="num" 
                begin="${map.pager.blockBegin}"
                end="${map.pager.blockEnd}">
                <c:choose>
                    <c:when test="${num == map.pager.curPage}">
                    
                    <!-- 현재 페이지인 경우 하이퍼링크 제거 -->
                    <!-- 현재 페이지인 경우에는 링크를 빼고 빨간색으로 처리를 한다. -->
                        <span style="color:red;">${num}</span>
                    </c:when>
                    <c:otherwise>
                        <a href="#" onclick="list('${num}')">${num}</a>
                    </c:otherwise>
                    
                </c:choose>
            </c:forEach>
            
            <c:if test="${map.pager.curBlock <= map.pager.totBlock}">
                <a href="#" 
                onclick="list('${map.pager.nextPage}')">[다음]</a>
            </c:if<!-- 현재 페이지블록이 총 페이지블록보다 작으면 다음으로 갈 수있도록 링크를 추가 -->
            
            
            <c:if test="${map.pager.curPage <= map.pager.totPage}">
                <a href="#" 
                onclick="list('${map.pager.totPage}')">[끝]</a>
            </c:if<!-- 현재 페이지블록이 총 페이지블록보다 작거나 같으면 끝으로 갈 수 있도록 링크를 추가함-->
              
            
        </td>
    </tr>
</table>
</body>
</html>
cs




컨트롤러에서 게시물 갯수를 확인하는 count 변수의 값을 boardService에서 얻어 올 수 있게 변경


BoardController.java 중 일부

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    @RequestMapping("list.do"//세부적인 url pattern
        public ModelAndView list(//RequestParam으로 옵션, 키워드, 페이지의 기본값을 각각 설정해준다.
        @RequestParam(defaultValue="1"int curPage,
        @RequestParam(defaultValue="all"String search_option,
        @RequestParam(defaultValue=""String keyword)
    //defaultValue를 설정하지 않으면 null point 에러가 발생할수 있기 때문에 기본값을 설정해주어야 한다.
                        throws Exception{
        //레코드 갯수 계산
        int count = boardService.countArticle(search_option, keyword); //검색옵션과 키워드를 고려
        
        //페이지 관련 설정, 시작번호와 끝번호를 구해서 각각 변수에 저장함
        Pager pager=new Pager(count, curPage); //레코드 번호와 원하는 페이지의 번호를 주게 되면 
        int start=pager.getPageBegin();
        int end=pager.getPageEnd();
cs



BoardServiceImpl.java 중 일부

1
2
3
4
5
    @Override
    public int countArticle(
            String search_option, String keyword) throws Exception {
        return boardDao.countArticle(search_option,keyword); 
//boardDao를 호출해서 리턴
    }
cs




BoardDAO.Impl.java 중 일부

1
2
3
4
5
6
7
8
9
//레코드 갯수 계산
//검색옵션과 키워드를 같이 전달해야하기 때문에 haspmap로 묶어서 같이 전달한다.

    @Override
    public int countArticle(
            String search_option, String keyword) throws Exception {
        Map<String,String> map=new HashMap<>();
        map.put("search_option", search_option);
        map.put("keyword""%"+keyword+"%");
        return sqlSession.selectOne("board.countArticle",map);
    }
cs



boardMapper.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
<!-- 다른 mapper와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="board">
 
<!-- 레코드 갯수 계산 -->    
    <select id="countArticle" resultType="int">
        select count(*)
        from board b,member m    
        <include refid="search" />
    </select>
 
<sql id="search">
        <choose>
<!--검색옵션을 설정 글내용과, 작성자, 제목으로 검색할 수있도록 설정)
<!--검색 옵션에 따라 실행되는 구문이 틀려짐--!>
            <when test="search_option == 'all' ">
                where b.writer=m.userid 
                    and (name like '%'||#{keyword}||'%'
                     or content like '%' || #{keyword}||'%'
or title like '%'||#{keyword}||'%' )  //검색 옵션이 all이면 실행         
            </when>
            <otherwise>
                where b.writer=m.userid 
                    and ${search_option} like '%'||#{keyword}||'%' //검색 옵션이 all이 아니면 실행되는 구문
</otherwise>
        </choose>
    </sql>
cs


:

게시판 만들기 (게시글 쓰기)

Back-End/Spring 2019. 7. 2. 18:18

-게시글 쓰기 구현-


1. list.jsp 중 일부 

글쓰기 링크 버튼과 스크립트 태그를 추가

1
2
3
4
5
6
7
8
9
10
11
<script>
$(function(){ //아이디가 btnWrite인 버튼을 누르게 되면 write.do 컨트롤러로 맵핑
    $("#btnWrite").click(function(){
        location.href="${path}/board/write.do";
    });
});
</script>
 
=========================================================================
 
<button type="button" id="btnWrite">글쓰기</button>
cs



2. BoardController.java 중 일부

list.jsp 페이지에서 맵핑된 write.do가 맵핑된 메소드를 만듦


1
2
3
4
5
6
@RequestMapping("write.do")
    public String write() {
        // 글쓰기 폼 페이지로 이동
        return "board/write"; //write.jsp 페이지로 이동
    }
// write.jsp에서 입력한 내용들이 BoardDTO에 저장됨    
cs



3. write.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
42
43
44
45
46
47
48
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
<script src="${path}/include/js/common.js"></script>
<!-- ckeditor의 라이브러리 -->
<script src="${path}/ckeditor/ckeditor.js"></script>
<script>
$(function(){ //id가 btnSave인 버튼을 클릭하면 실행되는 구문. 
              //post 방식으로 자료를 insert.do (컨트롤러)로 보낸다. 
    $("#btnSave").click(function(){
        document.form1.submit();
    });
});
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>글쓰기</h2>
<form id="form1" name="form1" method="post"
action="${path}/board/insert.do">
    <div>제목 <input name="title" id="title" size="80"
                    placeholder="제목을 입력하세요"<!-- 제목 입력 -->
    </div>
    <div style="width:800px;">
        내용 <textarea id="content" name="content"
rows="3" cols="80" placeholder="내용을 입력하세요"></textarea><!-- 내용 입력 -->
    </div>
    <div> 첨부파일을 등록하세요
        <div class="fileDrop"></div>
        <div id="uploadedList"></div>
    </div>
    <div style="width:700px; text-align:center;">
        <button type="button" id="btnSave">확인</button>
    </div>
</form>
</body>
</html>
cs



write.jsp 에서 입력한 내용들이 dto를 거쳐서 BoardController.java 페이지로 이동함



4. BoardController.java 중 일부

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// write.jsp에서 입력한 내용들이 BoardDTO에 저장됨    
    @RequestMapping("insert.do")
    public String insert(@ModelAttribute BoardDTO dto
            , HttpSession session//세션은 아이디를 확인하기위해서 필요하므로 세션을 가져온다.
        throws Exception {
        
        // 로그인한 사용자의 아이디
        String writer=(String)session.getAttribute("userid");
        dto.setWriter(writer); //로그인한 아이디를 dto에 저장
 
        //레코드 저장
        boardService.create(dto); //서비스와 dao를 통해서 레코드에 추가가된다.
        
        //게시물 목록으로 이동
        return "redirect:/board/list.do";
    }
cs



5. BoardServiceImpl.java 중 일부

1
2
3
4
    @Override
    public void create(BoardDTO dto) throws Exception {
        boardDao.create(dto);  //dto를 매개값으로 dao를 호출
    }
cs



6. BoardDAOImpl.java 중 일부

1
2
3
4
5
    @Override
    public void create(BoardDTO dto) throws Exception {
        sqlSession.insert("board.insert", dto); 
    }
 
cs



7. boardMapper.xml 중 일부 (namespace와 id를 맵핑)

1
2
3
4
    
<!--다른 mapper과 중복되지 않도록 namespace를 기재--!>
<mapper namespace = "board">
<insert id="insert">

         //게시글번호는 시퀀스로 하고 (생성할때마다 숫자가 1씩 증가하게함)
//제목
//글 내용
//작성자를 삽입함
insert into board (bno,title,content,writer) values
        ( seq_board.nextval, #{title}, #{content}, #{writer} )
    </insert>
cs



8. 글번호를 시퀀스로 만들기 위해서 board 테이블을 삭제함

1
delete from board;
cs



9. 게시물 번호 계산용 시퀀스를 생성

1
2
3
create sequence seq_board
start with 1
increment by 1;
cs



10. 게시글이 정상적으로 삽입되는지 확인해보기위해서 게시글을 삽입

1
2
insert into board (bno, title, content, writer) values
(seq_board.nextval, '제목''내용''park');
cs



11. 생성이 끝난후에는 작업완료를 하기위해 commit을 실시함.

1
commit;
cs




-추가-

로그인 되어있지 않은 상태에서 게시글을 작성하려고 하면 에러가 발생하므로 servlet-context에 있는
인터셉터에 write.do와 insert.do를 호출할때 인터셉터를 거치도록 코드를 수정

인터셉터를 거치도록 하면 만약 로그인이 안된 상태에서 게시글을 작성을 하려고 하면 로그인을 먼저 하라고 로그인 창으로
이동시켜 준다.

(왜냐하면 인터셉터에 id값이 null일때 처리할 수 있는 코드가 작성되어 있기 때문에 이곳을 거쳐야 null 처리를 할 수 있기 때문에)


servlet-context 중 일부
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<beans:bean id="loginInterceptor" class="com.example.spring02.interceptor.LoginInterceptor" />
 
==============================================================================================
 
<!-- 인터셉터 호출을 위한 url mapping -->
<!-- write.do나 insert.do를 호출하면 loginInterceptor 한번 거쳐 가라는 뜻--!>

    <interceptors>
        <interceptor>
            <mapping path="/shop/**" />
            <beans:ref bean="sampleInterceptor" />
        </interceptor>
        <interceptor>
            <mapping path="/board/write.do" />
            <mapping path="/board/insert.do" />
            <mapping path="/board/update.do" />
            <mapping path="/board/delete.do" />
            <mapping path="/shop/cart/list.do"/>
            <mapping path="/shop/cart/insert.do"/>
            <beans:ref bean="loginInterceptor"/>
        </interceptor>
cs



LoginInterceptor.java 중 일부

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//메인 액션이 실행되기 전
    @Override
    public boolean preHandle(HttpServletRequest request
            , HttpServletResponse response, Object handler) 
                    throws Exception {

        //세션 객체 생성
        HttpSession session=request.getSession();

        //세션이 없으면(로그인되지 않은 상태)
        if(session.getAttribute("userid"== null) {

            //login 페이지로 이동
            response.sendRedirect(request.getContextPath()
                    +"/member/login.do?message=nologin");
            return false//메인 액션으로 가지 않음
        }else {
            return true//메인 액션으로 이동
        }
    }
cs


:

게시판 만들기 (게시글 목록)

Back-End/Spring 2019. 7. 2. 16:20

- 게시글 목록 보기 구현 -



1. menu.jsp에 게시글 목록을 볼수있는 링크를 추가

1
<a href="${path}/board/list.do">게시판</a> |  
cs



2. BoardDTO.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
package com.example.spring02.model.board.dto;
 
import java.util.Arrays;
import java.util.Date;
 
//게시글을 저장할 dto 클래스
public class BoardDTO {
    private int bno;        //게시물 번호
    private String title;    //제목
    private String content;    //내용
    private String writer;     //작성자 아이디
    private Date regdate;     //날짜
    private int viewcnt;    //조회수
    private String name;     //작성자 이름 (member 테이블과 조인할것을 고려해서 만들었음)
    private int cnt;         //댓글 갯수
    private String show;     //화면 표시 여부
    private String[] files; //첨부파일 배열
    
    //getter,setter,toString()
    
    public int getBno() {
        return bno;
    }
    public void setBno(int bno) {
        this.bno = bno;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String getWriter() {
        return writer;
    }
    public void setWriter(String writer) {
        this.writer = writer;
    }
    public Date getRegdate() {
        return regdate;
    }
    public void setRegdate(Date regdate) {
        this.regdate = regdate;
    }
    public int getViewcnt() {
        return viewcnt;
    }
    public void setViewcnt(int viewcnt) {
        this.viewcnt = viewcnt;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getCnt() {
        return cnt;
    }
    public void setCnt(int cnt) {
        this.cnt = cnt;
    }
    public String getShow() {
        return show;
    }
    public void setShow(String show) {
        this.show = show;
    }
    public String[] getFiles() {
        return files;
    }
    public void setFiles(String[] files) {
        this.files = files;
    }
    @Override
    public String toString() {
        return "BoardDTO [bno=" + bno + ", title=" + title + ", content=" + content + ", writer=" + writer + ", regdate="
                + regdate + ", viewcnt=" + viewcnt + ", name=" + name + ", cnt=" + cnt + ", show=" + show + ", files="
                + Arrays.toString(files) + "]";
    }
    
}
 
cs



3. BoardDAO.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
package com.example.spring02.model.board.dao;
 
import java.util.List;
 
import com.example.spring02.model.board.dto.BoardDTO;
 
public interface BoardDAO {
    public void deleteFile(String fullName); //첨부파일 삭제
    public List<String> getAttach(int bno); //첨부파일 정보
    public void addAttach(String fullName); //첨부파일 저장
    
    
    public void updateAttach(String fullName, int bno); //첨부파일 수정
    public void create(BoardDTO dto) throws Exception; //글쓰기 
    public void update(BoardDTO dto) throws Exception; //글수정
    public void delete(int bno) throws Exception; //글삭제
    
    //목록 (페이지 나누기, 검색 기능 포함)
    //매개변수는 시작 레코드번호, 끝번호, 옵션과 키워드가 들어간다)

    public List<BoardDTO> listAll(
String search_option, String keyword,int start, int end) 
                throws Exception;
    
    //조회수 증가 처리
    public void increateViewcnt(int bno) throws Exception;
    
    //레코드 갯수 계산
    public int countArticle(
            String search_option, String keyword) throws Exception;
    
    //레코드 조회
    public BoardDTO read(int bno) throws Exception;
}
cs



4. boardDAOImpl.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
package com.example.spring02.model.board.dao;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.inject.Inject;
 
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
 
import com.example.spring02.model.board.dto.BoardDTO;
 
@Repository // dao bean
public class BoardDAOImpl implements BoardDAO {
 
    @Inject //의존관계 주입(Dependency Injection, DI)
    SqlSession sqlSession;
 
//게시물 목록 리턴
    @Override
    public List<BoardDTO> listAll(
//매개변수는 시작 레코드번호, 끝번호, 옵션과 키워드가 들어간다)
String search_option, String keyword,int start, int end) 
                throws Exception {     
        return sqlSession.selectList("board.listAll"); 
    }
cs



5. boardMapper.xml 만들기

1
2
3
4
5
6
7
    <!-- 다른 mapper와 중복되지 않도록 네임스페이스 기재 --> <mapper namespace="board">

<select id="listAll"
    resultType="com.example.spring02.model.board.dto.BoardDTO">
    <!-- 결과는 boardDTO타입이 된다. -->
            select bno,title,writer,name,regdate,viewcnt                    
            from board
            order by bno desc   
    </select>
cs



6. boardService.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
package com.example.spring02.service.board;
 
import java.util.List;
 
import javax.servlet.http.HttpSession;
 
import com.example.spring02.model.board.dto.BoardDTO;
 
public interface BoardService {
    public void deleteFile(String fullName);    //첨부파일 삭제
    public List<String> getAttach(int bno);        //첨부파일 목록
    public void create(BoardDTO dto) throws Exception;    //글쓰기
    public BoardDTO read(int bno) throws Exception;        //글읽기
    public void update(BoardDTO dto) throws Exception;    //글 수정
    public void delete(int bno) throws Exception;        //글 삭제
    
 
    //목록 (페이지 나누기, 검색 기능 포함)
    //매개변수는 시작 레코드번호, 끝번호, 옵션과 키워드가 들어간다)
    public List<BoardDTO> listAll(
String search_option, String keyword,int start, int end) 
                throws Exception;
    
    //조회수 증가 처리
    public void increaseViewcnt(int bno, HttpSession session) throws Exception; 
    
    //레코드 갯수 계산
    public int countArticle( String search_option, String keyword) throws Exception;
}
cs



7. boardServiceImpl.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
package com.example.spring02.service.board;
 
import java.util.List;
 
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
 
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import com.example.spring02.model.board.dao.BoardDAO;
import com.example.spring02.model.board.dto.BoardDTO;
 
@Service // service bean
public class BoardServiceImpl implements BoardService {
 
    @Inject //dao를 호출하기 때문에 의존성을 주입
    BoardDAO boardDao; 
 
 
@Override
    public List<BoardDTO> listAll(
    String search_option, String keyword,int start, int end)
            throws Exception {
        return boardDao.listAll(search_option,keyword,start,end); 
    }
cs



8. BoardController.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
package com.example.spring02.controller.board;
 
import java.util.HashMap;
import java.util.List;
 
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
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 org.springframework.web.servlet.ModelAndView;
 
import com.example.spring02.model.board.dto.BoardDTO;
import com.example.spring02.service.board.BoardService;
import com.example.spring02.service.board.Pager;
 
@Controller //controller bean
@RequestMapping("board/*"//공통적인 url pattern
 
public class BoardController {
    
    @Inject 
    BoardService boardService; //서비스를 사용하기 위해 의존성을 주입
 
@RequestMapping("list.do"//세부적인 url pattern
    public ModelAndView list() throws Exception{
        List<BoardDTO> list=
boardService.listAll(search_option,keyword,start,end); //게시물 목록
        ModelAndView mav=new ModelAndView();
        Map<String,Object> map=new HashMap<>(); //데이터가 많기 때문에 hashmap<>에 저장한다.
        map.put("list", list); //map에 list(게시글 목록)을 list라는 이름의 변수로 자료 저장
        mav.addObject("map", map); //ModelAndView에 map을 저장
        return mav; // board/list.jsp로 이동
    }
    
cs



9. list.jsp (view 파일)

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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>게시판</h2>
<table border="1" width="600px">
    <tr>
        <th>번호</th>
        <th>제목</th>
        <th>이름</th>
        <th>날짜</th>
        <th>조회수</th>
    </tr>
    <!-- forEach var="개별데이터" items="집합데이터" -->
<c:forEach var="row" items="${map.list}"<!-- 컨트롤러에서 map안에 list를 넣었기 때문에 이렇게 받는다. -->
    <tr>
        <td>${row.bno}</td> //글 번호
        <td>${row.title}</td> //글 제목
        <td>${row.writer}</td> // 작성자 이름
        <td><fmt:formatDate value = "{row.regdate}"
            pattern="yyyy-MM-dd HH:mm:ss"    /></td> //날짜의 출력형식을 변경
        <td>${row.viewcnt}</td> //조회수
    </tr>
</c:forEach>
</table>
</body>
</html>
cs




:

게시판 만들기 (기본구조, 테이블 생성)

Back-End/Spring 2019. 7. 2. 12:24

-게시판의 주요 기능-


1. 기본 기능


ㄱ. 로그인 후 게시물 등록, 수정이 가능하도록 처리


ㄴ. 글쓰기 (스마트 에디터 적용, 태그 문자 처리, 공백 처리, 줄바꿈 처리)


ㄷ. 게시물 상세정보, 조회수 증가 처리


ㄹ. 게시물 수정


ㅁ. 게시물 삭제 (delete 방식)


ㅂ. 게시물 삭제 (update 방식)


ㅅ. 검색 기능


ㅇ. 페이지 나누기



2. 파일업로드 (ajax)


ㄱ. 게시판에 파일 첨부


ㄴ. 첨부파일 목록, 다운로드, 삭제


ㄷ. 수정화면에서 새로운 파일 올리기



3. 댓글 기능


ㄱ. 일반적인 방식으로 댓글쓰기 (RestController, REST 방식)

$.ajax( ) 함수 호출하여 insert

컨트롤러에서 뷰로 포워딩한 responseText를 html 태그에 출력


ㄴ. 컨트롤러에서 ArrayList json 형식으로 리턴받아 댓글 목록 출력 (list_json.do)


ㄷ. 목록에 댓글 갯수 표시


ㄹ. 댓글 페이지 나누기 (댓글 목록은 일반적인 방식으로 처리)


ㅁ. 비밀댓글 쓰기, 표시


ㅂ. REST 방식으로 댓글 쓰기 (insert_rest.do)

크롬 확장 프로그램을 이용한 입력 처리

{ "replytext" : "댓글", "replyer" : "kim", "bno" : "1", "secret_reply" : "n" }


ㅅ. REST 방식으로 댓글 목록 출력


ㅇ. REST 방식으로 댓글 상세 화면, 수정, 삭제 기능 구현



4. 페이지 나누기


- 페이지당 게시물수 : 10개


- 전체 게시물수 : 991개


- 몇 페이지? : 100


991 / 10 => 99.1 올림 => 100



- 페이지의 시작번호, 끝번호 계산


where rn between 1 and 10


1페이지 => 1 ~ 10

2페이지 => 11 ~ 20

.....

11페이지 => 101 ~ 110

57페이지 => 561 ~ 570

99페이지 => 981 ~ 990

100페이지 => 991 ~ 1000


시작번호 = (현재페이지 - 1) * 페이지당 게시물수 + 1


1페이지 => (1-1) * 10 + 1 => 1

2페이지 => (2-1) * 10 + 1 => 11

7페이지 => (7-1) * 10 + 1 => 61


끝번호 = 시작번호 + 페이지당 게시물수 - 1


1페이지 => 1 + 10 - 1 => 10

2페이지 => 11 + 10 -1 => 20


* 전체 페이지 블록수

전체 페이지 갯수 / 10

91 / 10 => 9.1 => 10개


 

예시 )


1    2    3    4    5    6    7    8    9    10    [다음]

[이전]    11    12    13    14    15    16    17    18    19    20    [다음]



현재 페이지가 속한 블록


(현재 페이지 - 1) / 페이지 블록 단위 + 1


1페이지 => 몇번째 블록? 1

(1-1) / 10 + 1 => 1


9페이지 => 1블록

(9-1) / 10 + 1 => 1


11페이지 => 2블록

(11-1) / 10 + 1 => 2


57페이지

(57-1) / 10 + 1 => 6


* 페이지 블록의 시작번호

(현재블록 - 1) * 블록단위 + 1

1블록 => (1-1) * 10 + 1 => 1

2블록 => (2-1) * 10 + 1 => 11

6블록 => (6-1) * 10 + 1 => 51


* 페이지 블록의 끝번호

블록 시작번호 + 블록단위 - 1;

1블록 => 1 + 10 - 1 => 10

2블록 => 11 + 10 - 1 => 20

6블록 => 51 + 10 - 1 => 60



-데이터베이스 게시판 테이블 만들기-



1
drop table board cascade constraints; //기존의 테이블과 중복되지 않도록 제약조건까지 모두 삭제
cs


1
2
3
4
5
6
7
8
9
create table board ( //테이블 생성
bno number not null, // 게시물 번호
title varchar2(200not null, // 제목
content varchar2(4000), // 내용
writer varchar2(50not null, // 작성자 아이디 (member테이블과 join할 예정)
regdate date default sysdate, // 작성 날짜 (기본값으로 현재 시간이 들어가게됨)
viewcnt number default 0, // 조회수 (기본값이 0이기 때문에 0부터 시작)
primary key(bno) //기본키는 게시물 번호로 설정함
);
cs



1
2
insert into board (bno,title,content,writer) values
((select nvl(max(bno)+1,1)from board),'제목','내용','pard');
//게시물의 번호를 시퀀스를 이용해도 되지만 객체를 따로 관리해야 하기때문에
//서브쿼리를 작성하여서 관리
기본적으로 board에서 가장 큰 게시글 번호에서 1을 더하거나, 값이 없을때 (초기값) 은 1을 준다는 쿼리이다.
cs


1
commit; //작업을 완료시키는 쿼리
cs


'Back-End > Spring' 카테고리의 다른 글

게시판 만들기 (게시글 쓰기)  (0) 2019.07.02
게시판 만들기 (게시글 목록)  (0) 2019.07.02
Spring Editor (CKEditor, SummerNote) 사용  (1) 2019.07.02
Spring 이메일 보내기  (1) 2019.07.01
Spring xml bean property 정리  (0) 2019.07.01
: