마트철수
[065] MyBatis 비즈니스 계층의 CRUD 구현 본문
2024.08.08(목)
Spring 5일차
병가 사용으로 온라인으로 강의를 들었다..
앞으로는 강의 내용뿐만 아니라
수업 중간중간 내가 느꼈던 것들도 함께 작성하려고 한당.
나중에 복습할 때 MapperTamplet 꼭 만들어둬야함!
Spring
PART01
- CH02. 스프링의 특징과 의존성 주입
- CH03.1 스프링 MVC의 기본 구조
- CH03.2 스프링 MVC의 Controller 1
- CH03.3 스프링 MVC의 Controller 2
- CH03.4 SpringLegacy 업데이트
- CH04.1 스프링과 MySQL Database
- CH04.2 MyBatis와 스프링 연동
- CH05.1 영속, 비즈니스 계층의 CRUD 구현
- CH05.2 비즈니스 계층
CH05.1 영속, 비즈니스 계층의 CRUD 구현
영속 영역의 CRUD 구현
JDBC와 달리 MyBatis로 할 때 안 한 것은?
- 바로 예외 처리를 안 하고 있음!
- checked 예외 → 반드시 예외 처리해야했음
- MyBatis는 RuntimeException으로 예외 처리
CommonException
- 여기서 예외 처리를 다 해주고 있음
package org.scoula.exception;
import lombok.extern.log4j.Log4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;
@Controller
@Log4j
public class CommonExceptionAdvice {
@ExceptionHandler(Exception.class)
public String except(Exception ex, Model model){
log.error("Exception ......" + ex.getMessage());
model.addAttribute("exception", ex);
log.error(model);
return "error_page";
}
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handle404(NoHandlerFoundException ex){
return "custom404";
}
}
※ Spring이 왜 간편한지 알게 된 첫 번째 이유
@Transactional이 Test에 붙으면, 자동으로 Rollback !
rest api url
- GET | /api/board | getList()
- GET| /api/board/:no | get(no)
- POST | /api/board
- PUT | /api/board/:no
Mapper 템플릿 파일 만들기
- BoardMapper.xml 파일 선택하여 File > Save File As Template
- 아래 1번 이미지와 같이 패키지, 테이블 네임 변수 처리
→ key는 그대로 두고, 테이블 네임만 변수 처리!

CH05.2 비즈니스 계층
비즈니스 계층의 설정
- BoardDTO.java
- VO와 DTO 객체 간 변환하는 메서드 추가
- VO → DTO / DTO → VO 변환
public static BoardDTO of(Board vo)
// return 값: BoardDTO
// 매개변수: BoardVO vo
VO(Value Object)와 DTO(Data Transfer Object)의 차이는 뭘까?
- VO: 불변 객체(static)로, 동일성을 보장하며 주로 비즈니스 레벨에서 값 비교에 사용!
- DTO: 데이터 전송용 객체로, 주로 계층 간 데이터 전송을 목적으로 사용! (가변)
- 차이점: VO는 값의 동일성 비교에 초점이라면, DTO는 데이터 전송과 변환에 중점을 둔다!
- BoardServiceImpl.java
- 생성자가 1개 있는 경우, 그 생성자를 통해 주입해줌
- 누가? Spring
- @RequiredArgsConstuctor: final 멤버를 인자로 가지는 생성자 추가
@Log4j
@Service // Bean 등록
@RequiredArgsConstructor
public class BoardServiceImpl implements BoardService
{
final private BoardMapper mapper; // 생성자가 1개인 경우 생성자 주입으로 초기화
위 코드는 코드 과정 꼭 기억해두기!
생성자 추가하는 건?
- alt + Enter
해당 교육에서는 단위테스트에서만 @Autowired 사용
BoardServiceImpl.java
- List<BoardVO) => List<BoardDTO>
- map: 모형을 바꾸고 싶을 때 사용 (BoardVO → BoardDTO)
# Boardof로 준비해둠
# 자주 나오는 코드 형태
@Override
public List<BoardVO> getList() {
log.info("getList..........");
return mapper.getList().stream() // BoardVO의 스트림
.map(BoardDTO::of) // BoardDTO의 스트림
.toList(); // List<BoardDTO> 변환
}
위 코드는 이번 실습에서 굉장히 많이 다뤘다.
이 정도는 기억하고 스스로 작성할 수 있을 정도로
익숙해져야하지 않을까..
비즈니스 계층의 구현과 테스트
BoardServiceImpl.java
- ofNullable(): Null이면 리턴시켜라
- 만약 없는 값을 준다면? NoSuchElementException 오류가 뜨는지 확인 !
@Override
public BoardDTO get(Long no) {
log.info("get......" + no);
BoardDTO board = BoardDTO.of(mapper.get(no));
return Optional.ofNullable(board)
.orElseThrow(NoSuchElementException::new); // RuntimeException
}
BoardController의 작성
BoardController의 분석
| Task | URL | Method | Parameter | Form | URL 이동 |
| 전체 목록 | /board/list | GET | |||
| 등록 처리 | /board/create | POST | 모든 항목 | 입력화면 필요 | 이동 |
| 조회 | /board/get | GET | no=123 | ||
| 수정 처리 | /board/update | POST | no | 입력화면 필요 | 이동 |
| 삭제 처리 | /board/delete | POST | 모든 항목 | 입력화면 필요 | 이동 |
- 요청 흐름

- BoardController.java
- Controller가 의존하는 객체는? Service
- final로 private 객체 생성
package org.scoula.board.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.log4j.Log4j;
@Controller
@Log4j
@RequestMapping("/board")
@RequiredArgsConstructor
public class BoardController {
final private BoardService service;
}
- ServletConfig.java
- "org.scoula.board.controller" 꼭 추가해야한다.
- 본래 controller도 단위테스트를 해야하지만 다르게 함 ??
- 컨트롤러 테스트
- 웹 요청을 실제로 하는 것이 아님
- MockMvc → 목업으로 수행
- 테스트마다 새로운 MockMvc 생성해야함

- 요청을 받아주는 것: mockMvc.perform
- 요청을 만드는 것: MockMvcRequestBuilders.get (GET 요청)
- 실제 보낼 url: ("/board/list") // ResultActions 리턴
- 다음 .이 붙은 메서드들은 ResultActions의 메서드
@Test
public void list() throws Exception {
log.info(
mockMvc.perform(MockMvcRequestBuilders.get("/board/list")) // ResultActions 리턴
.andReturn() // MvcResult 리턴
.getModelAndView() // ModelAndView 리턴
.getModelMap() // Model 리턴
);
}
}
GET 요청은 단위테스트가 필요할까?
- 없다.
- Spring이 다 구현해주기 때문에 POST 부분만 단위테스트 하면 된다.
MockMvc로 Post 요청 테스트하기
- 어떻게 단위테스트? 이용자가 body 파트의 form에 쓴건데?
- 세 가지 파라미터(title, content, writer이 뭔지, body 파트가 정해짐)
MockMvcRequestBuilders.post(url 문자열)
.param(키1, 값1) // form 요소
.param(키2, 값2)
- model은 쓰이지 않고, view만 쓰임 → /rediret: ...
Selvlet과 JSP를 배울 때,
강사님께서 불편한 점에 대해 고민해보라고 하신
이유를 하나하나 알아가고 있다.
이렇게 간편한 기능을 활용하려면,
그만큼 내가 많이 알고 있어야 가능하겠지?
Spring 만큼은 이론부터 실습까지
집중해서 듣고, 확실히 활용해보고 싶다.
'KB IT's Your Life > 교육' 카테고리의 다른 글
| [066] Spring: 서버로 화면 처리 (0) | 2024.08.12 |
|---|---|
| [TIL_3] KB 부트캠프: 스프링 MVC의 Controller (0) | 2024.08.11 |
| [064] MyBatis와 스프링 연동 + CRUD 연동 (0) | 2024.08.07 |
| [063] MyBatis와 스프링 연동 !! (0) | 2024.08.06 |
| [062] 스프링 MVC의 Controller (1) | 2024.08.05 |