서비스 계층과 DTO 구현

강상은·2023년 12월 4일

서비스 계층과 DTO의 구현

개요

  • Spring Data JPA를 이용해서 영속 계층 처리
  • Thymeleaf를 이용해서 화면 처리
  • 스프링 부트를 이용한 컨트롤러와 서비스 처리

ModelMapper 설정

  • 서비스 계층에서 엔티티 객체를 DTO로 변환하거나 반대의 작업을 처리하기 위해 ModelMapper를 이용(엔티티 객체는 영속 컨텍스트에서 관리되므로 가능하면 많은 계층에서 사용되지 않는 것이 좋음)
  • ModelMapper 라이브러리 주입(build.gradle)
implementation 'org.modelmapper:modelmapper:3.1.0'
  • Config 디렉토리를 구성하고 RootConfig 클래스를 생성
    • @Configuration을 이용해서 스프링의 설정 클래스임을 명시
      • Configuration 어노테이션 : 싱글톤을 보장하고 스프링 컨테이너에서 Bean을 관리 가능
@Configuration
public class RootConfig {
		//@Bean을 통해 ModelMapper 객체를 스프링 컨테이너에 빈으로 등록
    @Bean
    public ModelMapper getMapper() {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration() 
                .setFieldMatchingEnabled(true)
								//소스와 대상 객체간 필드 이름을 기준으로 매핑 -> 즉 필드 이름 일치 시 자동으로 매핑
                .setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE)
                //기본적으로 ModelMapper는 public 필드만 매핑에 사용하나, private 필드도 매핑에 쓰겠단 얘기
							 .setMatchingStrategy(MatchingStrategies.STRICT);
								//매핑시 정확한 일치만 허용(교재는 LOOSE)

        return modelMapper;
    }
}

CRUD 작업 처리

  • DTO 디렉토리 생성 후 DTO 클래스 구현 및 servic 디렉토리에 BoardService 인터페이스와 Impl클래스 추가
  • BoardServiceImpl은 ModelMapper와 BoardRepository를 주입받도록 구현
등록 작업 처리

@Service
@Log4j2
@RequiredArgsConstructor
@Transactional //일관성을 유지하고 글 등록에서 예외가 발생했을때 롤백시키기 위해 트랜잭션 처리를 해줌
public class BoardServiceImpl implements BoardService{

    private final ModelMapper modelMapper;

    private final BoardRepository boardRepository;

    @Override
    public Long register(BoardDTO boardDTO) {

        Board board = modelMapper.map(boardDTO, Board.class); //modelMapper의 특성을 이용해서 BoardDTO 객체를 Board 객체로 변환

        Long bno = boardRepository.save(board).getBno();

        return bno;
    }
조회 작업 처리

@Override
    public BoardDTO readOne(Long bno) {
				
				//Optional<> 타입으로 리턴하여 result에 저장
        Optional<Board> result = boardRepository.findById(bno);

        Board board = result.orElseThrow(); //Optional 객체가 비어있을때 예외를 던짐

        BoardDTO boardDTO = modelMapper.map(board, BoardDTO.class);

        return boardDTO;
    }
수정 작업 처리

@Override
    public void modify(BoardDTO boardDTO) {

        Optional<Board> result = boardRepository.findById(boardDTO.getBno());

        Board board = result.orElseThrow();
				
				//Board 클래스에 정의되어있는 change 메서드의 Title과 Content만 가져옴
        board.change(boardDTO.getTitle(), boardDTO.getContent());

        boardRepository.save(board);

    }
//테스트 할 때는 반드시 실제 데이터베이스에 존재하는 번호를 이용해서 확인

@Test
    public void testModify() {

        //변경에 필요한 데이터만
        BoardDTO boardDTO = BoardDTO.builder()
                .bno(101L)
                .title("Updated....101")
                .content("Updated content 101...")
                .build();

        boardService.modify(boardDTO);

    }
삭제 작업 처리

@Override
    public void remove(Long bno) {

        boardRepository.deleteById(bno);

    }

목록/검색 처리

PageRequestDTO, PageResponseDTO와 같이 클래스를 작성 후 반환 타입은 PageResponseDTO로 활용

PageRequestDTO

페이징 관련 정보(page/size) 및 검색의 종류(type)와 키워드(keyword)를 지정

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageRequestDTO {

    @Builder.Default
    private int page = 1;

    @Builder.Default
    private int size = 10;

    private String type; // 검색의 종류 t,c, w, tc,tw, twc

    private String keyword;

//현재 검색 조건들을 BoardRepository에서 String[]로 처리하기 때문에 type이라는 문자열을 배열로 반환해주는 기능
public String[] getTypes(){
        if(type == null || type.isEmpty()){
            return null;
        }
        return type.split("");
    }

//페이징 처리를 위해 Pageable 타입을 반환하는 기능
public Pageable getPageable(String...props) {
        return PageRequest.of(this.page -1, this.size, Sort.by(props).descending());
    }
//Spring Data JPA는 페이지 번호를 1부터 시작하도록 기본 설정되어 있습니다. 그래서 PageRequest.of 메서드에 전달되는 this.page - 1는 내부적으로 페이지 번호를 1부터 시작하는 인덱스로 조정하는 역할을 합니다.
//따라서 1페이지는 0이고 2페이지는 1.. 이런 식으로 인덱싱되는것

0개의 댓글