Certification/Spring(2V0-72.22, SCP)

Spring MVC - 게시판 만들기 feat.입문편

엘호리스 2018. 8. 10. 14:51

스프링에서 제공하는 MVC 프레임워크를 이용해 게시판을 만들어 보자.

* 서비스 되는 게시판이 아닌 학습용 예제에 맞는 게시판이다.


보통 필자는 게시판을 만드는 프로세스는 다음과 같이 진행한다.


  1. DB에 게시판 테이블 생성하기
  2. 테이블 컬럼 값들을 DTO(VO) 객체 클래스에 매핑
  3. CRUD 만들기 SQL문 쿼리 작성하기
  4. MyBatis Mapper 작성(xml)
  5. DAO 인터페이스 만들기
  6. DAO implements 메서드 구현
  7. Service 인터페이스 만들기
  8. Service implements 메서드 구현
  9. Controller 클래스 만들기
  10. View 역할의 게시판 페이지 board_list.jsp 코드 작성

그러나 이번 포스팅에서 진행할 프로세스는 게시판 목록 페이지 구현을 위해서

'최소한'의 작업만 진행할 것이기에 저 프로세스에서 간략화 된 작업만 진행 할 것이다.

예제 소스 파일 다운로드

example.zip



1. DB에 게시판 테이블 생성하기 (오라클 11g)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 게시판 테이블 만들기
CREATE TABLE board (
    bno number not null primary key --게시물번호
    ,title varchar2(200not null   --게시물제목
    ,content varchar2(4000)         --게시물내용
    ,writer varchar2(50not null   --게시물작성자
    ,regdate date default sysdate   --게시물작성일자
    ,viewcnt number default 0       --게시물조회수
);
-- 테이블 데이터 삭제
DELETE FROM board;
-- 게시물 레코드 1000개 삽입하기
declare
i number := 1; begin
while i<=1000 loop
insert into board (bno,title,content,writer) values
((select nvl(max(bno)+1,1from board) ,'제목'||i,'내용'||i,'kim');
i := i+1;
end loop; end;
/
select count(*from board; select * from board;
-- commit
commit;
cs


2. 테이블 컬럼 값들을 DTO(VO) 객체 클래스에 매핑

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
package com.example.spring01.model.dto;
 
import java.util.Date;
 
public class BoardDTO {
    //Field
    private int bno;        //게시물번호
    private String title;    //게시물제목
    private String content;    //게시물내용
    private String writer;    //게시물작성자
    private Date regdate;    //게시물작성일자
    private int viewcnt;    //게시물조회수
    
    //Constructor
    public BoardDTO() {}
    public BoardDTO(int bno, String title, String content, String writer, Date regdate, int viewcnt) {
        super();
        this.bno = bno;
        this.title = title;
        this.content = content;
        this.writer = writer;
        this.regdate = regdate;
        this.viewcnt = viewcnt;
    }
    
    //getter & setter
    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;
    }
 
    //toString
    @Override
    public String toString() {
        return "BoardDTO [bno=" + bno + ", title=" + title + ", content=" + content + ", writer=" + writer
                + ", regdate=" + regdate + ", viewcnt=" + viewcnt + "]";
    }
 
}
cs



3. CRUD 만들기 - SQL문 쿼리 작성하기 (여기선 게시판 목록 불러오는 쿼리만 작성하겠다.)

1
2
select bno,title,writer,regdate,viewcnt
from board order by bno desc
cs


4. boardMapper.xml 작성하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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="boardList" resultType="com.board.example.dto.BoardDTO">
            select bno,title,writer,regdate,viewcnt
            from board order by bno desc
    </select>
 
</mapper>
cs



5. DAO 인터페이스 만들기

1
2
3
4
5
6
7
8
9
10
11
package com.board.example.dao;
 
import java.util.List;
 
 
import com.board.example.dto.BoardDTO;
 
public interface BoardDAO {
    // 게시물 목록 보기
    public List<BoardDTO> boardList() throws Exception;
}
cs



6. DAO implements 메서드 구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.board.example.dao;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
 
import com.board.example.dto.BoardDTO;
 
@Repository
public class BoardDAOImpl implements BoardDAO {
    @Inject
    SqlSession sqlSession;
 
    @Override
    public List<BoardDTO> boardList() throws Exception {
        return sqlSession.selectList("board.boardList"); 
    }
}
cs



7. Service 인터페이스 만들기

1
2
3
4
5
6
7
8
9
10
11
package com.board.example.service;
 
import java.util.List;
 
 
import com.board.example.dto.BoardDTO;
 
public interface BoardService {
    // 게시물 목록 조회
    public List<BoardDTO> boardList() throws Exception;
}
cs



8. Service implements 메서드 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.board.example.service;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.springframework.stereotype.Service;
 
import com.board.example.dao.BoardDAO;
import com.board.example.dto.BoardDTO;
 
@Service
public class BoardServiceImpl implements BoardService {
    @Inject
    BoardDAO boardDao;
 
    @Override
    public List<BoardDTO> boardList() throws Exception {
        return boardDao.boardList(); 
    }
}
cs



9. Controller 클래스 만들기

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
package com.board.example.controller;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
import com.board.example.dto.BoardDTO;
import com.board.example.service.BoardService;
 
 
@Controller
@RequestMapping("/board/*")
public class BoardController {
    @Inject
    BoardService boardService;
    
    // 과거 ModelAndView를 활용한 방법
//    @RequestMapping("list.do")
//    public ModelAndView boardMenu() throws Exception {
//        List<BoardDTO> list = boardService.boardList();
//        ModelAndView mav = new ModelAndView();
//        mav.setViewName("board/board_list");
//        mav.addObject("list", list);
//        return mav; // board/board_list.jsp로 이동
//    }
    
    // 현재 자주 쓰는 Model 클래스를 DI 하는 방법
    @RequestMapping("list.do")
    public String boardList(Model model) throws Exception {
        List<BoardDTO> list = boardService.boardList(); // list 변수에 결과 값을 담는다
        model.addAttribute("list", list); // model에 데이터 값을 담는다
        return "board/board_list"// board/board_list.jsp로 이동
    }
    
}
cs

위 Controller에서 두가지 구현 방법을 명시해놨는데

ModelAndView는 @RequestMapping 나오기 전의 방법이고 아래 코드보다 많은 코드를 필요로 하는 것을 볼 수 있다.

그 과정에서 메서드 안에서 ModelAndView 클래스를 new 하는 과정도 있고 아래 코드보다 조금 번거로운 면이 있다.

필자는 아래 소스코드를 선호하며 파라미터로 Model 클래스를 주입하는 것이 스프링과 좀 더 어울리지 않나 생각한다.

* String으로 jsp 파일 이름을 리턴하고 Model 클래스를 의존주입하며 모델 안에 데이터를 담아 값을 넘기는 방식



10. View 역할의 게시판 페이지 board_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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- fmt를 사용하기위한 태그 라이브러리 -->
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <%@ include file="../include/menu.jsp" %>
    <h2>board_list 페이지입니다.</h2>
    <table border="1">
        <tr>
            <th>번호</th>
            <th>제목</th>
            <th>글쓴이</th>
            <th>작성일자</th>
            <th>조회수</th>
        </tr>
        <!-- forEach 문은 리스트 객체 타입을 꺼낼때 많이 활용된다. -->
        <c:forEach var="row" items="${list}">
        <tr>
            <!-- 컨트롤러에서 넘겨준 list 모델 객체를 쓰는 방법을 잘 익혀두자 -->
            <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



* 별첨 (home.jsp와 menu.jsp 파일 소스코드 첨부)

home.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <title>Home</title>
</head>
<body>
<%@ include file="include/menu.jsp" %>
<h1>Hello world!</h1>
<P>  The time on the server is ${serverTime}. </P>
</body>
</html>
cs


menu.jsp

1
2
3
4
5
6
7
8
9
10
11
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="path" 
value="${pageContext.request.contextPath}" />
<div style="text-align: center;">
    <a href="${path}/">main</a>
    <a href="${path}/board/list.do">게시판</a>
</div>
<hr>
cs



View 출력 화면 (메뉴에 게시판을 클릭했을때 모습)



이렇게 게시판 리스트 값을 DB에서 가져와 테이블 형태로 뷰 화면에 출력하는 것을 완료하였다.

지금은 아주 기본적으로 DB에서 정보를 가져와 테이블로 출력하는 아주아주 기본적인 작업만 진행한 상태다.

게시판이라고 할 수 있는 상태가 아니다.

이외에 목록을 클릭했을때 해당 게시물에 대한 컨텐츠 내용을 출력할 수 있게 구현해야 하며

게시글 작성, 게시글 삭제, 게시글 수정, 게시글 목록 페이징 처리 등.....

앞으로 작업해야 할 일들이 많다.


이제 그 기능들을 차츰차츰 구현해 나가보자.