개발은 재밌어야 한다
article thumbnail
반응형

이제 본격적으로 게시판의 기능들을 구현해보려고 합니다.

src/main/java 에 패키지를 작성합니다.

- com.dream.controller : 웹에서 처리해야할 데이터를 받아서 해당 데이터를 담당할 service를 선택하여 호출합니다.

- com.dream.service : 데이터를 DAO를 통해 넘겨주거나 받으면서 비즈니스 로직을 수행하는 역할을 합니다.

- com.dream.mapper:  mapper에 기제된 SQL문을 호출하여 DB의 데이터에 접근합니다.

- com.dream.vo : DB에 있는 테이블 컬럼 값을 java에서 객체로 다루기 위해 사용합니다.

 

vo 패키지에 BoardVO 클래스를 생성합니다.

BoardVO클래스에 BOARD테이블에 맞게 VO객체를 생성합니다.

package com.dream.vo;

import java.util.Date;

import lombok.Data;

@Data
public class BoardVO {
/*
	BNO INT NOT NULL AUTO_INCREMENT,	-- 게시판 고유 번호 (자동증가)
	TITLE VARCHAR(100),	-- 게시글 제목
	CONTENT VARCHAR(1000),	-- 게시글 내용
	WRITER VARCHAR(100),	-- 글쓴이
	REGDATE TIMESTAMP DEFAULT NOW(),	-- 날짜(기본값 현재시각)
	PRIMARY KEY (BNO)	-- 게시판 번호 기본키 지정
*/
	int bno;
	String title;
	String content;
	String writer;
	Date regDate;
}

이때 lombok의 @Data를 사용하여 toString(), getter(), setter(), 생성자등을 자동으로 생성해줍니다.

lombok으로 자동으로 생성된 것을 확인할 수 있습니다

BoardMapper.XML파일을 작성해서 BOARD 테이블에서 게시물들을 불러 올 수 있는 SQL 쿼리문을 작성해서 BoardMapper 인터페이스를 통해서 Service 클래스에서 마이바티스를 통해 데이터를 불러 올 수 있도록 합니다.

getBoardList라는 id를 가진 select문의 쿼리를 작성해줍니다. 반환형은 BoardVO의 형태로 반환할 수 있도록 resultMap을 정의 해줍니다.

<?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="com.dream.mapper.BoardMapper">

	<resultMap type="com.dream.vo.BoardVO" id="boardMap">
		<id property="bno" column="bno"></id>
		<result property="title" column="title"/>
		<result property="content" column="content"/>
		<result property="writer" column="writer"/>
		<result property="regDate" column="regDate"/>
	</resultMap>
	
	<select id="getBoardList" resultMap="boardMap">
		SELECT * FROM BOARD
	</select>

</mapper>

 

다음에는 동일한 BoardMapper라는 이름을 가진 인터페이스를 작성해줍니다.

package com.dream.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.dream.vo.BoardVO;

@Mapper
public interface BoardMapper {

	public List<BoardVO> getBoardList();
	
}

XML파일에서 작성한 id가 getBoardList와 동일하게 getBoardList메소드를 인터페이스에 정의해주도록 합니다.

데이터의 return 값은 BoardVO가 리스트 형태로 있는 형태로 받아오도록 합니다.

 

이번에는 비즈니스 레이어를 담당하는 Service영역의 파일을 작성해보겠습니다.

서비스 파일에서 사용할 메소드를 미리 Interface로 정의하여 해당 인터페이스를 구현체의 형태로 정의하는 형태의 interface파일과 class파일을 쌍으로 만들도록 합니다.

 

우선 com.dream.service 패키지에 BoardServiceIF라는 이름의 인터페이스 파일을 생성해줍니다.

package com.dream.service;

import java.util.List;

import com.dream.vo.BoardVO;

public interface BoardServiceIF {
	
	public List<BoardVO> getBoardList();

}

getBoardList라는 메소드를 사용해서 service에서는 getBoardList 메소드를 사용해서 데이터를 호출하여 사용할 것이다라는 정의를 해주도록 합니다.

 

그리고 해당 인터페이스의 구현체인 BoardService.java파일을 작성하여 해당 파일을 implements를 하여 getBoardList()를 작성합니다.

동일하게 com.dream.service 패키지에 작성하도록 합니다.

빈객체를 생성하기 위해서 빈객체임을 명시하도록 어노테이션을 넣어야하는데, 해당 파일은 Service 파일임을 명시해주기 위해서 @Serivce라는 이름의 어노테이션을 작성하도록 합니다. 

BoardServiceIF 인터페이스에서 정의한 메소드를 구현하기 위해서 implements 를 작성해서 넣어줍니다.

 

Ctrl + 1 단축키를 통해서 구현되지 않은 메소드를 추가해줍니다.
getBoardList메소드에 대한 Override를 작성할 수 있다.

SqlSessionFactory는 데이터베이스와 연결을 SQL의 실행에 대한 객체입니다. 

sqlSessionFactory에서 openSession 메소드를 통해서 session을 담아주고 세션에서 사용할 매퍼(BoardMapper)를 지정해서 해당 매퍼에서 BoardMapper 인터페이스에서 정의한 getBoardMapper를 사용하여 데이터를 불러와 리스트형태의 boardList객체를 생성해서 담아주도록 합니다.

package com.dream.service;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dream.mapper.BoardMapper;
import com.dream.vo.BoardVO;

@Service
public class BoardService implements BoardServiceIF {

	@Autowired
	private SqlSessionFactory sqlSessionFactory;

	@Override
	public List<BoardVO> getBoardList() {
		// TODO Auto-generated method stub
		List<BoardVO> boardList = new ArrayList<BoardVO>();

		try (SqlSession session = sqlSessionFactory.openSession()) {
			BoardMapper mapper = session.getMapper(BoardMapper.class);

			boardList = mapper.getBoardList();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return boardList;
	}

}

이번에는 Controller에 파일을 작성해서 작성한 Service파일을 불러오도록 하겠습니다.

마찬가지로 @Controller 어노테이션을 추가하여 컨트롤러임을 명시하여 bean 객체가 생성되도록 합니다.

@RequestMapping을 통해서 ViewResolver를 통해서 컨트롤러에 들어오는 URI를 명시하도록 합니다.

LOG를 찍어서 해당 URI에 들어 올 때 로그를 남기도록 하기 위해서 Controller에 대한 로그를 선언해줍니다.

 

BoardService에 대한 객체를 @Autowired 어노테이션을 사용해서 해당 객체에 대한 의존성을 자동으로 주입할 수 있도록 해줍니다.

조회할 URI 에 대해서 JSON 형태로 데이터를 REST하게 응답하기 위해서 @ResponseBody 어노테이션과 최종적으로 매핑될 주소인 (board/get-board-list.do)를 작성하고 method응답 형태를 GET임을 명시해주도록 합니다.

 

응답에 대한 결과값을 담아 JSON형태의 결과를 보여줄 ResultVO라는 클래스파일을 com.dream.vo 패키지에 작성합니다.

com.dream.vo 패키지에 객체에 대한 결과값을 담을 ResultVO클래스 작성

결과 데이터를 담을 객체인 result와 성공, 실패여부를 알려 줄  수 있는 success값을 생성자를 통해서 세팅할 수 있도록 선언 해주도록 합니다. 

그러면 실패하게 되면 생성자를 만들때의 형태 그대로인 false와 null값이 들어가는 형태가 됩니다.

package com.dream.vo;

import lombok.Data;

@Data
public class ResultVO {
	
	Object result;
	boolean success;
	
	// 생성자
	public ResultVO(boolean success, Object result) {
		this.result = result;
		this.success = false;
	}
}

 

다시 Controller로 돌아와서 메소드를 마저 작성해보겠습니다.

해당 메소드를 호출했다면 호출을 알리는 로그와 

생성자를 통해 ResultVO를 생성하는데 기본값을 result는 null로, success는 false로 세팅하고 에러시에는 그대로 null 값과 false값이 나오고 성공시에는 데이터를 담고 true값으로 세팅합니다.

실패시에는 실패에 대한 로그와 실패 메세지에 대한 값을 로그로 남깁니다.

package com.dream.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.dream.service.BoardService;
import com.dream.vo.ResultVO;

@Controller
@RequestMapping("board/")
public class BoardController {

	private static final Logger LOG = LoggerFactory.getLogger(BoardController.class);

	@Autowired
	BoardService service;

	@ResponseBody
	@RequestMapping(value = "get-board-list.do", method = RequestMethod.GET)
	public ResultVO getBoardList() 
	{	
		// 호출 시 찍히게 될 로그
		LOG.info("[GET] getBoardList");
		// 결과 값을 담을 ResultVO를 선언한 생성자를 통해서 만드는데 기본값은 success는 false, result는 null로 세팅
		ResultVO result = new ResultVO(false, null);

		try {
			result.setResult(service.getBoardList());
			result.setSuccess(true);
		} catch (Exception e) {
			// TODO: handle exception
			LOG.error("[Board] getBoardList : " + e.getMessage(), e);
		}

		return result;

	}
}

 

이제 위에서 만든 것들을 스프링에서 Bean 객체를 생성하기 위해서 component-scan 을 통해서 위에서 선언한 @Controller, @Service등의 Bean 객체들을 생성 할 수 있도록 합니다.

servlet-context.xml 파일을 수정합니다.

servlet-context.xml

이미 controller패키지에 대한 선언은 되어 있습니다. 새롭게 생성한 service, mapper, vo패키지에 대한 component-scan을 작성해줍니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="com.dream.controller" />
	<context:component-scan base-package="com.dream.service" />
	<context:component-scan base-package="com.dream.mapper" />
	<context:component-scan base-package="com.dream.vo" />
	
	
</beans:beans>

다음으로 BoardMapper를 사용하기 위해서 Mapper를 스캔할 수 있도록 root-context.xml도 수정합니다.

mapperLocations인자에 대해서 dream의 mapper패키지 하위에  모든 Mapper.xml로 끝나는 파일에 대해서 mapper를 스캔하여 사용하도록 해서 sqlSessionFactory가 사용 할 수 있도록 합니다.

 

자 이제 실행해서 데이터를 정상적으로 받아 오는지 확인하도록 하겠습니다.

서버를 디버깅 모드로 실행하도록 합니다

저는 초기에 생성했던 HomeController.java를 삭제했기 대문에 /에 대한 주소를 찾지 못한다고 나와있습니다.

설정했던 board/get-board-list.do를 호출하여 정상적으로 데이터를 가져오는지 breaking point를 잡아 확인해보겠습니다.

보시는것 처럼 34번째 라인을 더블클릭하여 breaking point를 잡아줍니다.

그리고 http://localhost:8080/board/get-board-list.do를 접속해보면 해당 breaking point에 멈춰집니다.

해당 라인에 디버깅을 할 수 있게 되었습니다.

오른쪽에 보시면 해당라인에서는 33번째 라인의 result.setResult(service.getBoardList());을 통해서 result변수에 데이터를 세팅했기때문에 해당 변수안에 결과값을 보면

이렇게 변수가 담긴것을 볼 수 있습니다.

이렇게 정상적으로 담긴 변수들을 이제 화면에 json형태로 response하여 프론트엔드에서 사용할 수 있게 됩니다.

 

다음에는 이런 결과값들을 활용하여 프론트엔드영역을 vue를 이용하여 화면에 보이게 하도록 하겠습니다.

 

 

2시간 걸려서 글 작성했는게 다 날아가서 다시 작성하기 싫어서 차일피일 미루다가 이제서야 올리게 되네요.

앞으로의 게시글에서는 캡쳐는 좀 최소화하고 빠르게 완성까지 하는걸 목표로 해야겠어요... 

저도 그랬듯이 한번 따라하다가 끊기면 따라 할 수 있는 방향이 없어지기 때문에 최대한 끝까지 빠르게 올리도록 하겠습니다.

감사합니다.

 

 

해당 프로젝트 파일은 GitHub에서 다운 받으실 수 있습니다.

https://github.com/skarbgud/Board-Project

 

skarbgud/Board-Project

Contribute to skarbgud/Board-Project development by creating an account on GitHub.

github.com

 

반응형
profile

개발은 재밌어야 한다

@ghyeong

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!