dearbeany
[MyBatis] Spring 과 MyBatis 연동 및 세팅 | 게시판 CRUD 실습 본문
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)를 만들자.
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개념과 이어짐. 데이터 변경 전후로 커밋/롤백 할 수 있도록 확인하자!)
'Spring' 카테고리의 다른 글
[Spring] Spring ~ REST 과목평가 예상문제 (1) | 2022.10.25 |
---|---|
[REST] REST API @Annotation별 실습 (0) | 2022.10.24 |
[Tomcat] starting tomcat v9.0 server at localhost has encountered a problem in mac (0) | 2022.10.20 |
[MyBatis] MyBatis와 Java 초기세팅 (Mapper, typeAlias, $과 #의 차이) (0) | 2022.10.20 |
[Spring] SpringMVC 요청처리흐름 | 파일업로드와 다운로드 실습 (0) | 2022.10.19 |