Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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
Tags
more
Archives
Today
Total
관리 메뉴

dearbeany

[MyBatis] Spring 과 MyBatis 연동 및 세팅 | 게시판 CRUD 실습 본문

Spring

[MyBatis] Spring 과 MyBatis 연동 및 세팅 | 게시판 CRUD 실습

dearbeany 2022. 10. 21. 01:52
더보기

0. 라이브러리 세팅. 마이바티스, 마이바티스-스프링
1. 루트컨테이너에 dataSource빈 등록
2. SqlSessionFactory 빈 등록
- 1의 dataSource를 주입
- 매퍼위치
- dto들의 위치
3. Dao인터페이스의 풀패키지명과 mapper의 namespace는 일치해야함
- Dao인터페이스의 함수명과 그에 대응하는 mapper(board.xml)의 id와 일치해야함
=> mapper를 만들어서 자동으로 매핑해주려고.

4. 3의 조건을 만족할 경우 Mapper를 빈으로 등록하면 Dao의 구현체가 빈으로 만들어짐
- mybatis-spring:scan을 통해 인터페이스가 있는 패키지를 읽음

1. 라이브러리 추가 위해 pom.xml 세팅 

(1) MySql 연결

(2) 커넥션 자동 관리 위한 사용

(3) MyBatis 연결

(4) MyBatis-Spring 

(5) 트랜잭션 관리 위해 Spring-jdbc 추가 (spring-transaction을 이미 포함하고 있으므로)

// pom.xml
		<!-- MySql 연결 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.28</version>
		</dependency>

		<!-- 커넥션을 관리하기 위해서 사용 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>2.8.0</version>
		</dependency>

		<!-- MyBatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.9</version>
		</dependency>

		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>2.0.6</version>
		</dependency>
		
        	<!-- 트랜잭션 관리 위한 spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

 

 

2. root-context.xml에서 MyBatis 실행에 필요한 객체를 Spring Bean으로 등록해 사용 

(1) dataSource (2) sqlSessionFactory

// root-context.xml
	<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
		<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
		<property name="url" value="jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC"/>
		<property name="username" value="root"/>
		<property name="password" value="ssafy"/>
	</bean>
	
	<!-- MyBatis 를 사용하기 위한 SqlSessionFactory를 등록한다. -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="mapperLocations" value="classpath*:mapper/**/*.xml"/>
		<property name="typeAliasesPackage" value="com.ssafy.board.model.dto"/>
	</bean>
	
	<!-- mybatis에서 제공하는 scan 태그를 통해 dao interface들의 위치를 지정한다. -->
	<mybatis-spring:scan base-package="com.ssafy.board.model.dao"/>

 

 

3. dao와 service의 분리 

- dao는 DB와 소통하나, service는 기능에 집중하여 사용자와 보다 가깝다.

- 인터페이스를 통해 설계도(BoardService)를 만들고, 이를 implements하는 구현체 클래스(BoardServiceImpl)를 만들자.

 

dao와 service

 

 

BoardServiceImpl을 bean으로 등록하자. 

- @Service 어노테이션 추가와 root-context.xml에 component-scan 추가

- 정상적으로 bean으로 등록되면 클래스 아이콘에 s가 붙은 걸 확인할 수 있다.

@Service
public class BoardServiceImpl implements BoardService {
// root-context.xml
<context:component-scan base-package="com.ssafy.board.model.service" />

 

- service 안에서는 dao를 호출하여서 sql에 대한 작업을 모두 맡기도록 한다.

- 단, dao는 service가 직접 new해서 만드는 게 아니라 스프링컨테이너에 있는 걸 가져다 쓰는 것이다. → @Autowired 하자!

@Service
public class BoardServiceImpl implements BoardService {
	private BoardDao boardDao;

	@Autowired // Dao를 Autowired로 주입한다
	public void setBoardDao(BoardDao boardDao) {
		this.boardDao = boardDao;
	}

 

 

4. Controller 작성 

- servlet-context.xml 에 컨트롤러를 bean으로 등록해둔다.

- @Controller 어노테이션 추가하면 bean 등록완료!

// servlet-context.xml
<context:component-scan base-package="com.ssafy.board.controller" />
@Controller
public class BoardController {
	@Autowired
	private BoardService boardService;

- 컨트롤러는 BoardService를 필드로 가지고 있다.

 

 

 

 

* 리다이렉트 

리다이렉트 사용 전 문제점

① showIndex() : list.jsp로 이동. 즉, 프로젝트 Run > showIndex()로 메인페이지 실행 > 리스트에 아무 것도 안 뜬다. 

② list() : service를 거쳐서 list.jsp로 이동. 즉, 리스트에 데이터들이 출력된다.

 

→ 메인페이지에 ②처럼 뜨도록 하려면 어떻게 해야할까? "/" 요청이 들어왔을 때 다시 한 번 "list" 요청으로 보내는 건 어떨까? 

리다이렉트 사용

 

 

 

 

4. filter 추가 

- 데이터를 입력할 때 한글일 경우, 인코딩의 문제가 발생할 수 있다 ex) 게시글 등록 시 한글 사용..

- web.xml에 filter를 추가하자.

// web.xml
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

 

 

5. detail.jsp 

- ${board.title } 이런 식으로 출력이 가능한 건 Board 클래스가 title 필드를 가져서가 아닌, setter 라서 가져올 수 있는 것!

- <form> 태그 작성 시에 더이상 <input type="hidden">은 필요하지 않다. <form>의 action에 저장되는 값들은 컨트롤러에서 @RequestMapping을 통해 요청을 매핑해주도록 한다.

 

 

 

- 게시글을 등록하자마자 상세보기로 넘겨보자.

- 키값에 대한 세팅

<!-- board.xml -->
	<!-- 게시글 등록 -->
	<insert id="insertBoard" parameterType="Board" keyProperty="id" useGeneratedKeys="true">
		INSERT INTO board (title, writer, content)
		VALUES (#{title}, #{writer}, #{content})
	</insert>
// BoardController.java
	@RequestMapping("write")
	public String write(Board board) {
		System.out.println("등록 전 : " + board);
		boardService.writeBoard(board);
		System.out.println("등록 후 : " + board);
//		return "redirect:list";  // 키값을 몰라서 상세화면으로 사실 보낼 수가 없었어.. 
		return "redirect:detail?id=" + board.getId();
	}

 

 

6. 동적 SQL 사용 및 검색기능 구현 

list.jsp에서 넘길 값 <input>의 name들이 너무 많아지면 -> 이들을 컨트롤러에서 모두 파라미터명으로 받아오는 건 너무 많다.

dto라고 하는 바구니(SearchCondition)를 만들어서 바구니 안에 필드명과 name 이름 일치시키자.

컨트롤러에서 데이터 들어오면 알아서 넣어준다 (입을 쩍 벌려준다..)

 

 

resultType : 클래스를 쓰겠다 -> 코드에 풀패키지명 아닌 Board로 쓰는 게 가능한 이유는 typeAlias 때문에.

resultMap : 내가 정의한 걸 쓰겠다

 

동적 쿼리는 <if>문 사용가능 -> board.xml에서

 

${ } -> 따옴표 안 붙음 =>

#{ } -> 따옴표 붙음  => '뿅'

<!-- board.xml -->
	<!-- 검색기능 -->
	<select id="search" resultType="Board" parameterType="SearchCondition">
		SELECT id, writer, content, title, view_cnt as viewCnt, date_format(reg_date, '%Y-%M-%d') as regDate 
		FROM board
		<!-- 어떤기준으로 검색을 할거냐  -->
		<if test="key != 'none'">
			WHERE ${key} like concat('%', #{word}, '%')
		</if>
		<!-- 어떤기준으로 어느방향으로 정렬할거냐  -->
		<if test="orderBy != 'none'">
			order by ${orderBy} ${orderByDir}
		</if>
	</select>

 

 

서비스에 데이터를 변경하는 메소드에 @Transactional 을 붙이자. (BoardServiceImpl 클래스에서 수정하자.)

(추후 AOP개념과 이어짐. 데이터 변경 전후로 커밋/롤백 할 수 있도록 확인하자!)