본 내용은 혼자 공부하기 위하여 다른 포스트를 보면서 저에게 필요한 부분과 궁금했던 부분을 게시하는 곳입니다.
궁금한 것에 대한 것은 모르는 것이 많겠지만 함께 알아보도록 노력하겠습니다.
참조 게시 포스트 : http://addio3305.tistory.com/
-------------------------------------------------------------------------------------------------------------------------------------------
1. 데이터베이스 테이블 생성 및 데이터 추가
1.1 테이블 생성
CREATE TABLE TB_BOARD ( IDX INT PRIMARY KEY AUTO_INCREMENT, PARENT_IDX INT, TITLE VARCHAR(100) NOT NULL, CONTENTS VARCHAR(400) NOT NULL, HIT_CNT INT NOT NULL, DEL_GB VARCHAR(1) DEFAULT 'N' NOT NULL, CREA_DTM TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CREA_ID VARCHAR(30) );
특별한 칼럼만 설명하자면 IDX는 게시판 번호, PARENT_IDX는 상위 게시판, HIT_CNT 는 조회수, DEL_GB는 게시글의 삭제 여부, CREA_ID는 작성자를 뜻하는 칼럼이다.
1.2 데이터 추가
INSERT INTO TB_BOARD (TITLE, CONTENTS, HIT_CNT, CREA_ID) VALUES('테스트1','테스트1','0','Admin');
게시판 확인을 위해 데이터를 추가해준다. (지금 말고 나중에 추가해주어도 상관은 없음)
2. 데이터 조회 기능 구현
기능 구현 순서는 Controller -> Service -> ServiceImpl -> DAO -> SQL -> JSP 순으로 한다.
2.1 Controller
전에 작성하였던 SampleController를 다음과 같이 작성한다.
@Controller public class SampleController { Logger log = Logger.getLogger(this.getClass()); @Resource(name="sampleService") private SampleService sampleService; @RequestMapping(value="/testInterceptor.do") public ModelAndView testInterceptor(Map<String, Object> commandMap) throws Exception{ ModelAndView mv = new ModelAndView(""); log.debug("인터셉터 테스트"); return mv; } @RequestMapping(value="/sample/openBoardList.do") public ModelAndView openBoardList(Map<String, Object> commandMap) throws Exception{ ModelAndView mv = new ModelAndView("/sample/boardList"); List<Map<String,Object>> list = sampleService.selectBoardList(commandMap); mv.addObject("list", list); return mv; } }
8~14줄은 전에 인터셉터를 테스트한 코드이다.
- 16줄
@RequestMapping으로 클라이언트 요청의 매핑으로 /sample/openBoardList.do 를 value로 줬는데 이 경우 주소가 localhost:8080/myapp/sample/openBoardList.do 라는 클라이언트의 요청에 반응하게 된다.
- 18줄
ModelAndView의 경우 뷰 페이지인 jsp 파일을 뜻하며 sample 폴더 안의 boardList.jsp 파일을 뜻한다.
- 20줄
SampleService의 selectBoardList 메소드로부터 게시글 리스트를 가져온다. 게시글들은 Map으로 저장되어 게시글 번호, 제목 등의 항목이 저장되며, 이 Map들을 List 별로 묶은 것이다.
- 21줄
mv.addObject("list", list);는 서비스로직의 결과를 ModelAndView 객체에 담아서 클라이언트, 즉 jsp에서 그 결과를 사용할 수 있도록 한다. mv에 값을 저장하는것은 map과 똑같이 키(key)와 값(value)로 구성이 되는데, sampleService.selectBoardList 메서드를 통해 얻어온 결과 list를 "list"라는 이름으로 저장하고 있다.
2.2 SampleService, SampleServiceImpl
Service 영역은 두개의 파일로 구성된다. Service 인터페이스와 이 인터페이스를 실제로 구현한 ServiceImpl 클래스로 구성이 되어있다. 이는 Spring의 IoC/DI (Inversion of Control / Dependency Injection) 기능을 이용한 Bean 관리 기능을 사용하기 위함이다.
- com.mycompany.myapp.sample.service 패키지에 밑의 두개의 클래스를 작성한다.
SampleService.java
public interface SampleService { List<Map<String,Object>> selectBoardList(Map<String,Object> map) throws Exception; }
SampleServiceImpl.java
@Service("sampleService")
public class SampleServiceImpl implements SampleService {
@Resource(name="sampleDAO")
private SampleDAO sampleDAO;
@Override
public List<Map<String, Object>> selectBoardList(Map<String, Object> map) throws Exception {
return sampleDAO.selectBoardList(map);
}
}
- 다음으로 서비스의 selectBoardList의 결과값으로 sampleDAO 클래스의 selectBoardList 메서드를 호출하고, 그 결과값을 바로 반환(return) 하였다.
2.3 SampleDAO
DAO는 데이터베이스에 실제로 접근하는 클래스이다.
- com.mycompany.myapp.sample.dao 패키지에 SampleDAO 클래스를 작성한다
SampleDAO.java
@Repository("sampleDAO") public class SampleDAO extends AbstractDAO { @SuppressWarnings("unchecked") public List<Map<String, Object>> selectBoardList(Map<String, Object> map) { return (List<Map<String,Object>>)selectList("sample.selectBoardList", map); } }
- @Repository라는 어노테이션을 통해서 이 클래스가 DAO 임을 선언하고 이름을 "sampleDAO"로 작성하였다.
SampleServiceImpl에서 @Resource(name="sampleDAO")로 bean을 수동으로 등록하였고, 거기서 사용된 빈이 방금 작성한 SampleDAO 클래스다. 그리고 AbstractDAO 클래스를 상속받았다. 굳이 따로 만들 필요는 없지만 작성자는 따로 만들었다.
- DAO는 데이터베이스에 접근하여 데이터를 조작하는 (가져오거나 입력하는 등) 역할만 수행한다.
우리는 MyBatis 프레임워크를 사용하기 때문에 JDBC 연결 및 쿼리 수행을 편하게 할 수 있다.
MyBatis는 프로그램의 소스 코드에서 SQL을 분리하여 별도의 XML 파일에 저장하고, 이 둘을 연결하는 방식으로 작동한다. 우리가 실행할 쿼리 이름과 해당 쿼리에 필요한 변수들을 매개변수로 MyBatis의 리스트 조회 메서드를 호출하였다. 여기서 사용한 selectList는 MyBatis의 기본 기능으로, 리스트를 조회할 때 사용한다. 지난 글에서 AbstractDAO를 생성할 때, MyBatis의 기본 기능과 동일한 이름으로 만들어놨는데, 필요에 따라서 이름을 변경하는 등, 자신에 맞게끔 변경하여 사용하면 된다.
- selectList 메서드의 인자는 두 가지이다. 첫번째는 쿼리 이름, 두번째는 쿼리가 실행되는데 필요한 변수들이다.
"sample.selectBoardList"가 쿼리 이름이고, Controller에서부터 계속 넘어온 Map<String,Object> map이 쿼리 실행시 필요한 변수들이다. 게시판 목록을 조회할 때 지금 당장 필요한 변수들이 없기 때문에, 이 인자는 무의미하게 느껴질 수 있지만, 추후 다른 기능 등에서 사용하게 될 것이다.
- 그리고 그 결과값은 List<Map<String,Object>> 형식으로 반환할 수 있도록 형변환을 하였다.
2.4 sample_SQL
- 게시판 목록을 조회할 쿼리를 작성할 것이다. 전 포스트에서 작성했던 sample_SQL을 밑과 같이 작성하면 된다.
<?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="sample"> <select id="sample.selectBoardList" resultType="hashmap" parameterType="hashmap" > <![CDATA[ SELECT IDX, TITLE, CONTENTS, HIT_CNT, CREA_DTM, CREA_ID FROM TB_BOARD WHERE DEL_GB='N' ORDER BY IDX DESC ]]> </select> </mapper>
이게 MyBatis에서 사용하는 XML의 모습이다.
- 첫번째로, <select> 태그를 이용하여 이 쿼리가 select문이라는 것을 명시하였다.
- id="selectBoardList" 부분은 이 쿼리의 id는 selectBoardList 라고 정의하였다.
- parameterType="hashmap" 부분은 이 쿼리가 실행될때 필요한 변수는 HashMap 형태를 의미한다.
- resultType="hashmap" 부분은 이 쿼리의 결과값은 HashMap에 담겨서 반환된다는 것을 의미한다.
parameterType과 resultType으로 모두 HashMap을 사용할 것인데, 다른 클래스를 사용할 경우 해당 클래스의 이름을 적어주면 된다.
원래는 HashMap을 사용하려고 하면 parameterType="java.util.HashMap"이라고 패키지 명까지 정확히 명시를 해야 하지만, MyBatis에서 우리가 많이 사용하는 변수형은 hashmap 과 같이 간단히 사용할 수 있도록 지원하고 있다.
2.5 boardList.jsp
마지막으로 jsp파일만 구성하면 된다.
- src/main/java/webapp/WEB-INF/jsp/sample/ 경로에 boardList.jsp 파일을 밑과 같이 작성한다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <title>first</title> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> </head> <body> <h2>게시판 목록</h2> <table style="border:1px solid #ccc"> <colgroup> <col width="10%"/> <col width="*"/> <col width="15%"/> <col width="20%"/> </colgroup> <thead> <tr> <th scope="col">글번호</th> <th scope="col">제목</th> <th scope="col">조회수</th> <th scope="col">작성일</th> </tr> </thead> <tbody> <c:choose> <c:when test="${fn:length(list) > 0}"> <c:forEach items="${list }" var="row"> <tr> <td>${row.IDX }</td> <td>${row.TITLE }</td> <td>${row.HIT_CNT }</td> <td>${row.CREA_DTM }</td> </tr> </c:forEach> </c:when> <c:otherwise> <tr> <td colspan="4">조회된 결과가 없습니다.</td> </tr> </c:otherwise> </c:choose> </tbody> </table> </body> </html>
전체 조회결과가 있으면 그 결과를 보여주고, 없으면 조회된 결과가 없다는 메시지를 보여주는 화면이다.
- <c:forEach item="${list}" var="row">
Controller에서 DB에서 조회된 결과 list를 mv.addObject를 이용하여 "list"라는 이름으로 mv에 값을 저장 했었던 것을 떠올려보자. (mv.addObject("list",list); 라고 작성했었다.)
JSTL의 forEach문을 통해서 테이블의 목록을 만드려고 하는데, 여기서 사용할 아이템은 ${list}라고 되어있다. 이게 바로 우리가 mv에서 추가를 해줬던 그 list를 의미한다.
- 그 다음으로 var="row"라고 되어있다. 우리는 List<Map<String,Object>> 라는 형식으로 list를 선언하고, DB에서 조회된 결과를 받았다.
이 list에서 하나의 데이터쌍을 가져오면 ( Java에서 list.get(index)를 의미한다.) 그 데이터는 Map<String,Object> 형식의 데이터 한줄이 나오게 되고, 그 데이터는 row라는 이름의 변수에 저장이 된다.
그 후, row에서 원하는 데이터를 뽑아서 사용하면 된다.
row.IDX, TITLE, HIT_CNT, CREA_DTM의 이름에서 볼 수 있듯이, 이는 우리가 select 쿼리를 실행하였을 때 뽑아온 데이터의 이름이다. (대소문자를 구분한다.)
쿼리의 select 문에서 뽑아온 이름이 Map의 키(key)로 사용되고, 화면에서는 그 키를 이용하여 데이터에 접근할 수 있다.
2.6 확인하기
여기까지 잘 따라왔다면 다음과 같은 화면이 뜰 것이다.
'코딩 > Spring' 카테고리의 다른 글
Spring 개발 - 게시판 만들기(10) - 게시글 쓰기 (0) | 2017.12.25 |
---|---|
Spring 개발 - 게시판 만들기(9) - HandlerMethodArgumentResolver 적용 (0) | 2017.12.25 |
Spring 개발 - 게시판 만들기(7) - Mybatis 연동하기 (0) | 2017.12.24 |
Spring 개발 - 게시판 만들기(6) - 로그 및 인터셉터 설정 (6) | 2017.12.23 |
Spring 개발 - 게시판 만들기(5) - Spring MVC 구조 및 설정 변경 (0) | 2017.12.23 |