ToBe끝판왕

[ 프로젝트 ] Mybatis 프레임워크 게시판 적용 (1) 본문

■ 프로젝트/팀프로젝트 수정 2

[ 프로젝트 ] Mybatis 프레임워크 게시판 적용 (1)

업그레이드중 2022. 6. 15. 01:48
반응형

 


 

Mybatis 프레임워크 적용

 

▶  Mybatis 구조 파악하기

 

•  기존 프로젝트 내 게시판 디렉터리 구조이다.

< 기존 프로젝트 게시판 디렉터리 구조 >

src
├── controller
│	└── CommController.java
├── model
│	├── BoardTO.java
│	├── BoardDAO.java
│	└── BoardListTO.java
└── webapp
	└── WEB-INF
    		└── views
            		└── community
                    		└── .jsp 파일들

 

 

•  게시판에 Mybatis를 적용시켜 디렉터리 구조를 아래와 같이 만들 것이다.

< Mybatis 프레임워크 적용 디렉터리 구조 >

src
 ├── community
 │ 	├── controller
 │	│	└── CommController.java
 │	├── mapper
 │	│	└── CommMapper.java
 │	├── model
 │	│	└── BoardTO.java
 │	│	└── PagingVO.java
 │	└── service
 │		├── impl
 │		│	└── CommServiceImpl.java
 │		└── CommService.java	
 └── resources
 	└── mybatis
        	└── commMapper.xml

 

•  디렉터리 구조를 파악해보면

   CommMapper.java / CommServiceImpl.java / CommService.java / commMapper.xml 4개의 파일을 만들어야 한다.

 

 

 

▶  pom.xml 에 스프링 부트 myBatis dependency를 추가한다.

<!-- mybatis -->
<dependency>
		<groupId>org.mybatis.spring.boot</groupId>
		<artifactId>mybatis-spring-boot-starter</artifactId>
		<version>2.2.2</version>
</dependency>

 

 

 

▶  application.properties 에서 mapper.xml 위치 관련 설정을 한다.

mybatis.mapper-locations: mybatis/*.xml
# mybatis.type-aliases-package=com.camper.mapper


=> 물론 데이터베이스로 사용한 AWS RDS 연결설정도 필요하다.

 

 

 

▶  mapper.xml 파일 만들기

•  Mybatis 사용목적 중 하나는 DAO로부터 SQL문을 분리하는 것이다.

•  분리된 SQL문은 SQL mapper 파일에 작성하며 DAO에서 SqlSession 객체가 SQL mapper 파일을

   참조하게 된다.

 

 

 

•  SQL mapper 파일은 XML이기 때문에 XML 선언을 먼저 해준다.

<?xml version="1.0" encoding="UTF-8"?>

 

•  태그 규칙을 정의한 DTD 선언을 한다.

<!DOCTYPE mapper 
	PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

 

•  Root Element - <mapper>

-  SQL mapper 파일은 루트 엘리먼트 <mapper>을 작성하는 것으로 시작한다.

-  <mapper>의 namespace 속성은 자바의 패키지처럼 여러 개의 SQL문을 묶는 용도로 사용된다.

-  mapper 파일에 작성하는 모든 SQL문은 <mapper> 하위에 놓여야 한다.

<mapper namespace="com.camper.mapper.CommMapper">

 

•  SQL 문 작성 - <select> , <insert> , <update> , <delete>

< select / insert / update / delete id = " " parameterType=" " resultType/resultyMap= " " >
속성 설명
id 각 SQL문을 구분한다.
resultyType SELECT문 실행 결과를 담을 객체
패키지 이름을 포함한 클래스 이름 or 객체 alias 지정
( alias는 Mybais 설정파일에 설정한다. )
resultMap SELECT문 실행 결과를 담을 객체를 resultMap으로 지정
<resultMap> 따로 선언해줘야 한다.
resultType , resultMap 중 하나를 택해서 설정한다.
parameterType 이 속성에 지정한 객체의 프로퍼티값이 SQL문의
입력 파라미터에 지정된다.

 

-  resultType 속성 : myBatis는 SELECT 결과를 저장하기 위해 resultType에 지정된 클래스의 인스턴스를 생성한다.

                                 그리고 각 칼럼에 대응하는 Setter를 호출한다.

                                 칼럼에 맞는 Setter가 없으면 그 칼럼의 값은 객체에 저장되지 않는다.

                                 이름이 달라서 값이 저장되지 않는 문제를 해결하기 위해선, SELECT문의 각 칼럼에 as로 alias를

                                 붙이면 된다.

 

-  resultMap 속성 : resultType를 사용하면 Setter와 매칭되지 않는 경우 각 칼럼마다 alias를 붙여야 하는 번거로움이 있다.

                                resultMap 속성은 이문제를 해결할 수 있다.            

 

 

• CommMapper.xml 작성

<?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.camper.community.mapper.CommMapper">

	<!-- 게시판 Mapper.xml -->
	
	<!-- 커뮤니티 캠핑로그 / 캠핑꿀팁 / 캠핑가자 List -->
	<select id="boardList" parameterType="com.camper.community.model.BoardTO" resultType="com.camper.community.model.BoardTO">
		SELECT PSEQ
	    		, TITLE
	            , NICK
	            , TYPE
	            , DATE_FORMAT( WDATE, '%y-%m-%d' ) AS WDATE
	    FROM p_table
	    WHERE TYPE = #{type}
	    ORDER BY PSEQ DESC
	    LIMIT 5 OFFSET #{offset}
	</select>
	
	<!-- 페이징 위한 게시글 count -->
	<select id="boardListCount" parameterType="com.camper.community.model.BoardTO" resultType="int" >
		SELECT COUNT(1)
		FROM p_table
		WHERE TYPE = #{type}
	</select>
	
	
	<!-- 커뮤니티 게시물 보기 -->
	<select id="viewBoard" parameterType="com.camper.community.model.BoardTO" resultType="com.camper.community.model.BoardTO">
		SELECT TITLE
	    		, NICK
	            , DATE_FORMAT( WDATE, '%y-%m-%d' ) AS WDATE
	            , CONTENT
	            , TYPE
	            , PSEQ 
	    FROM p_table 
	    WHERE PSEQ = #{pseq}
	</select>
	    
	    
	<!-- 커뮤니티 게시물 등록 -->
	<insert id="writeBoard" parameterType="com.camper.community.model.BoardTO">
		INSERT INTO p_table 
	    VALUES( 0, #{title}, #{nick}, #{pwd}, #{content}, #{type}, now(), #{heart}, #{preply} )
	</insert>
	
	
	<!--  커뮤니티 게시물 삭제 확인 -->
	<delete id="deleteOkBoard" parameterType="com.camper.community.model.BoardTO">
		DELETE FROM p_table 
	    WHERE PSEQ = #{pseq}
	</delete>
	
	
	<!-- 커뮤니티 게시물 수정 -->
	<select id="modifyBoard" parameterType="com.camper.community.model.BoardTO" resultType="com.camper.community.model.BoardTO">
		SELECT TITLE
				, NICK
				, CONTENT
				, TYPE
				, PSEQ
		FROM p_table 
		WHERE PSEQ = #{pseq}
	</select>
	
	
	<!-- 커뮤니티 게시물 수정 확인 -->
	 <update id="modifyOkBoard" parameterType="com.camper.community.model.BoardTO">
		UPDATE p_table SET TITLE = #{title}, CONTENT = #{content} 
	    WHERE PSEQ = #{pseq}
	</update>   
	    
	    
	<!-- 공지사항 List -->
	<select id="noticeList" parameterType="com.camper.community.model.BoardTO" resultType="com.camper.community.model.BoardTO">
		SELECT NSEQ
	    		, TITLE
	            , NICK
	            , TYPE
	            , DATE_FORMAT( WDATE, '%y-%m-%d' ) AS WDATE 
	    FROM n_board 
	    WHERE TYPE = #{type}
	    ORDER BY NSEQ DESC 
	</select>
	    
	    
	<!-- 공지사항 게시물 보기 -->
	<select id="noticeView" parameterType="com.camper.community.model.BoardTO" resultType="com.camper.community.model.BoardTO">
		SELECT TITLE
	    		, NICK
	            , DATE_FORMAT( WDATE, '%y-%m-%d' ) AS WDATE
	            , CONTENT
	            , TYPE
	            , NSEQ
	    FROM n_board 
	    WHERE NSEQ = #{nseq}
	</select>
	    
	    
	<!-- FAQ List -->
	<select id="faqList" parameterType="com.camper.community.model.BoardTO" resultType="com.camper.community.model.BoardTO">
		SELECT NSEQ
	    		, TITLE
	            , NICK
	            , CONTENT
	            , DATE_FORMAT(WDATE, '%Y-%m-%d' ) AS WDATE
	    FROM n_board 
	    WHERE TYPE = #{type}
	    ORDER BY NSEQ DESC  
	</select>
	
</mapper>

 

 

※ #{ } 사용

•  Mybatis에서는 입력 파라미터를 #{프로퍼티}로 표시한다.

•  #{ } 사용 시, PreparedStatement 생성

•  PreparedStatement가 제공하는 Set 계열 메서드를 사용하여 물음표(?)를 대체할

   값을 지정한다.

•  ' 값 ' 형태로 쿼리가 수행된다.

 

 

 

▶  CommMapper.java 인터페이스 만들기

 

•  Mapper 인터페이스

-  개발자가 작성한다.

Mybatis 3.0 이후 생긴 방식이다.

Mapper.xml 파일에 기재된 SQL문을 호출하기 위한 인터페이스이다.

Mapper.xml 파일에 있는 SQL을 자바 인터페이스를 통해 지정한다.

Mapper 인터페이스를 사용하지  않으면, SQL 호출하는 프로그램은 SqlSession의 메서드의 인수에

   문자열로 namespace.SQL_ID를 지정해야 한다.

 

•  Mapper 인터페이스 작성

-  반드시 Interface로 선언한다.

-  메서드명은 mapper.xml의 namespace ID랑 맞춘다.

-  @Mapper 어노테이션은 단순히 Mybatis의 mappers를 위한 Mapper등록을 위해 사용한다.

package com.camper.community.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.camper.community.model.BoardTO;


@Mapper
public interface CommMapper {
	
	// 커뮤니티 메인페이지 3개 List
	public List<BoardTO> boardList( BoardTO to );
	
	// 페이징 위한 게시글 count
	public int boardListCount( BoardTO to );

	// 커뮤니티 게시글 보기
	public BoardTO viewBoard( BoardTO to );
	
	// 커뮤니티 게시글 등록
	public int writeBoard( BoardTO to );
	
	// 커뮤니티 게시글 삭제
	// public BoardTO deleteBoard( BOardTO to );

	// 커뮤니티 게시글 삭제 확인
	public int deleteOkBoard( BoardTO to );
	
	// 커뮤니티 게시글 수정
	public BoardTO modifyBoard( BoardTO to );
	
	// 커뮤니티 게시글 수정 확인
	public int modifyOkBoard( BoardTO to );
	
	// 공지사항 게시글 List
	public List<BoardTO> noticeList( BoardTO to );
	
	// 공지사항 게시글 보기
	public BoardTO noticeView( BoardTO to );
	
	// FAQ 게시글 List
	public List<BoardTO> faqList( BoardTO to);
}

 

 

 

▶  CommService.java / CommServiceimpl.java 만들기

 

•  Service / Serviceimpl

-  추상화 , OOP 원칙의 예시로 볼 수 있다.

-  Service는 Controller의 요청에 맞추어 데이터를 가공하고 Controller에게 넘겨주는 비즈니스 로직이다.

-  비즈니스 로직을 수행하기 위해 Service는 Interface파일로. Serviceimpl은 class파일로 작성한다.

-  MVC 패턴에서 Serviceimpl은 비즈니스 로직 즉, 기능을 구현하는 구현부를 수행하는 역할을 맡는다.

-  Interface와 구현체 class를 분리함으로써 구현체를 독립적으로 확장할 수 있으며, 구현체 클래스를 변경하거나

   확장해도 이를 사용하는 클라이언트 코드에는 영향을 주지 않는다.

-  인터페이스와 클래스로 분리하기 때문에 의존관계를 최소화하고 기능의 변화에도 최소한의 수정으로

   개발할 수 있는 유연함을 가질 수 있다.

-  모듈화를 통해 어디서든 사용할 수 있도록 재사용성을 높인다.

 

 

• CommService.java( Interface ) 작성

-  객체의 사용방법을 정의한 타입( = 해당 서비스에서 수행하는 기능들을 먼저 정의해 둔 것이다. )

-  Controller는 화면에서 넘어오는 매개변수들을 이용해 Service객체를 호출한다.

package com.camper.community.service;

import java.util.List;

import com.camper.community.model.BoardTO;
import com.camper.model.NboardTO;

public interface CommService {

		// 커뮤니티 메인페이지 3개 List
		public List<BoardTO> boardList( BoardTO to ) throws Exception;
		
		// 페이징 위한 게시글 count
		public int boardListCount( BoardTO to ) throws Exception;
		
		// 커뮤니티 게시글 보기
		public BoardTO viewBoard( BoardTO to ) throws Exception;
		
		// 커뮤니티 게시글 등록
		public int writeBoard( BoardTO to ) throws Exception;
		
		/*
		// 커뮤니티 게시글 삭제
		public BoardTO deleteBoard( BoardTO to ) throws Exception;
		*/
		
		// 커뮤니티 게시글 삭제 확인
		public int deleteOkBoard( BoardTO to ) throws Exception;
		
		// 커뮤니티 게시글 수정
		public BoardTO modifyBoard( BoardTO to ) throws Exception;
		
		// 커뮤니티 게시글 수정 확인
		public int modifyOkBoard( BoardTO to ) throws Exception;
		
		// 공지사항 게시글 List
		public List<BoardTO> noticeList( BoardTO to ) throws Exception;
		
		// 공지사항 게시글 보기
		public BoardTO noticeView( BoardTO to ) throws Exception;
		
		// FAQ 게시글 List
		public List<BoardTO> faqList( BoardTO to ) throws Exception;
}

 

 

• CommServiceimpImpl.java( class) 작성

CommService.java를 부모로 상속받아 구현하게 된다.

-  @Service 어노테이션은 해당 클래스가 비즈니스 로직을 담은 Service클래스임을 명시한다.

-  @Autowired 어노테이션은 필드 / 생성자 / 수정자 메서드에 사용한다. ( 객체에 대한 의존성을 주입한다. )

package com.camper.community.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.camper.community.mapper.CommMapper;
import com.camper.community.model.BoardTO;
import com.camper.community.service.CommService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CommServiceImpl implements CommService {

	@Autowired
	CommMapper commMapper;
	
	// 커뮤니티 게시글 List
	@Override
	public List<BoardTO> boardList(BoardTO to) throws Exception {
		
		List<BoardTO> list = null;
		
		try {
			list = commMapper.boardList( to );
		} catch (Exception e) {
			log.error( "[게시판 리스트 조회 에러]" + e.getMessage() );
		}
		
		return list;
	}
	
	// 페이징 위한 게시글 count
	public int boardListCount( BoardTO to ) throws Exception {
		// 게시판 카운트
		return commMapper.boardListCount( to );
		
	}
	
	// 게시판 게시글 상세보기
	@Override
	public BoardTO viewBoard(BoardTO to) throws Exception {
		
		BoardTO board = null;
		
		try {
			board = commMapper.viewBoard( to );
		} catch (Exception e) {
			log.error( "[게시글 상세 보기 에러]" + e.getMessage() );
		}
		
		return board;
	}
	
	// 게시판 게시글 등록
	@Override
	public int writeBoard(BoardTO to) throws Exception {
		
		int flag = 1;
		
		try {
			if( commMapper.writeBoard( to ) == 1 ) {
				flag = 0;
			}
		} catch (Exception e) {
			log.error( "[게시판 게시글 등록 에러]" + e.getMessage() );
		}
		return flag;
	}
	
	/*
	// 게시판 게시글 삭제
	@Override
	public BoardTO deleteBoard(BoardTO to) throws Exception {
		BoardTO board = null;
		
		try {
			board = commMapper.deleteBoard( to );
		} catch (Exception e) {
			log.error( "[게시판 게시글 삭제 에러]" + e.getMessage() );
		}
		
		return board;
		
	}
	*/
	
	// 게시판 게시글 삭제 확인
	@Override
	public int deleteOkBoard(BoardTO to) throws Exception {
		
		int flag = 1;
		
		try {
			if( commMapper.deleteOkBoard( to ) == 1 ) {
				// 정상
				flag = 0;
			}
		} catch (Exception e) {
			log.error( "[게시판 게시글 삭제 확인 에러]" + e.getMessage() );
		}
		return flag;
	}
	
	// 게시판 게시글 수정
	@Override
	public BoardTO modifyBoard(BoardTO to) throws Exception {
		
		BoardTO board2 = null;
		
		try {
			board2 = commMapper.modifyBoard( to );
		} catch (Exception e) {
			log.error( "[게시판 게시글 수정 에러]" + e.getMessage() );
		}
		
		return board2;
		
	}
	
	// 게시판 게시글 수정 확인
	@Override
	public int modifyOkBoard(BoardTO to) throws Exception {
		
		int flag = 1;
		
		try {
			if( commMapper.modifyOkBoard( to ) == 1 ) {
				// 정상
				flag = 0;
			}
		} catch (Exception e) {
			log.error( "[게시판 게시글 수정 확인 에러]" + e.getMessage() );
		}
		
		return flag;
	}

	// 공지사항 List
	@Override
	public List<BoardTO> noticeList(BoardTO to) throws Exception {
		
		List<BoardTO> list = null;
		
		try {
			list = commMapper.noticeList( to );
		} catch (Exception e) {
			log.error( "[공지사항 리스트 에러]" + e.getMessage() );
		}
		
		return list;
	}

	// 공지사항 글보기
	@Override
	public BoardTO noticeView(BoardTO to) throws Exception {
		
		BoardTO board3 = null;
		
		try {
			board3 = commMapper.noticeView( to );
		} catch (Exception e) {
			log.error( "[공지사항 글보기 에러]" + e.getMessage() );
		}
		return board3;
	}

	// FAQ List
	@Override
	public List<BoardTO> faqList(BoardTO to) throws Exception {
		
		List<BoardTO> list = null;
		
		try {
			list = commMapper.faqList( to );
		} catch (Exception e) {
			log.error( "[문의응답 리스트 에러]" + e.getMessage() );
		}
		
		return list;
	}

}

 

 

 

반응형
Comments