채널톡 아이콘

인프런 커뮤니티 질문&답변

Link님의 프로필 이미지

작성한 질문수 14

코드로 배우는 React with 스프링부트 API서버

todo list 검색 기능 문의

해결된 질문

작성

·

38

0

todo list 에서 검색어를 입력하여 검색된 결과를 화면에 출력하려면 어떻게 구현해야 하는지요?

예제에는 이런 것이 없는 거 같은데 제가 대충봐서 잘못 이해하고 있는 건가요?

전체적인 흐름으로 설명해주시면 감사하겠습니다.

답변 2

0

구멍가게코딩단님의 프로필 이미지
구멍가게코딩단
지식공유자

좋은 질문 감사합니다.

우선 라우팅 환경에서 검색이란 URL에 검색 관련 키워드 등이 쿼리 스트링으로 처리되어야 합니다.

/list?page=1&size=10&keyword=AAA 와 같은 형식으로 만들어져야 합니다.

 

따라서 검색 조건을 담당하는 컴포넌트를 작성하고 키워드를 입력한 후에 검색 버튼을 클릭하면 URL에 검색 조건이 포함되도록 해야 합니다.

 

 

실제 리스트를 출력하는 컴포넌트는 추가적으로 키워드를 받아서 서버를 호출하고 해당 결과를 출력하는 형태가 되면 됩니다.

 

 

 

 

Link님의 프로필 이미지
Link
질문자

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

@Data
@SuperBuilder  // - **상속 관계가 있는 클래스**에서 부모 클래스의 빌더 패턴을 지원하기 위해 사용된다.
@AllArgsConstructor  // 모든 필드에 대해 값을 받아 전체 매개변수 생성자를 자동으로 생성한다.
@NoArgsConstructor
public class PageRequestDTO {

    @Builder.Default  // 값을 명시적으로 설정하지 않을 때만 기본값을 부여
    private int page = 1;

    @Builder.Default
    private int size = 10;

    private Integer blockSize;  // Integer로 변경 (null 체크 가능하게)

    private String where; // 검색 KEY 추가
    private String keyword; // 검색어

    public int getBlockSize() {
        // blockSize가 null이면 size와 동일하게 처리
        return (blockSize != null) ? blockSize : size;
    }
}
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QueryDslConfig {

    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }
}
@Service
@Transactional
@Log4j2
@RequiredArgsConstructor // 생성자 자동 주입
public class TodoServiceImpl implements TodoService {

    // 자동 주입 대상은 final 로
    private final ModelMapper modelMapper;
    private final TodoRepository todoRepository;

    @Override
    public PageResponseDTO<TodoDTO> searchList(PageRequestDTO pageRequestDTO) {
        Page<Todo> result = todoRepository.search1(pageRequestDTO);

        Pageable pageable =
                PageRequest.of(
                        pageRequestDTO.getPage() - 1 ,  // 1페이지가 0이므로 주의
                        pageRequestDTO.getSize(),
                        Sort.by("tno").descending());

        List<TodoDTO> dtoList = result.getContent().stream()
                .map(todo -> modelMapper.map(todo, TodoDTO.class))
                .collect(Collectors.toList());

        log.info("dtoList: " + dtoList);

        long totalCount = result.getTotalElements();
        log.info("totalCount: " + totalCount);

        PageResponseDTO<TodoDTO> responseDTO = PageResponseDTO.<TodoDTO>withAll()
                .dtoList(dtoList)
                .pageRequestDTO(pageRequestDTO)
                .totalCount(totalCount)
                .build();

        return responseDTO;
    }

}
@Service
@Transactional
@Log4j2
@RequiredArgsConstructor // 생성자 자동 주입
public class TodoSearchImpl implements TodoSearch {
    private final JPAQueryFactory queryFactory;

    @Override
    public Page<Todo> search1(PageRequestDTO pageRequestDTO) {
        QTodo qTodo = QTodo.todo;

        BooleanBuilder builder = new BooleanBuilder();

        String keyword = pageRequestDTO.getKeyword();
        String where = pageRequestDTO.getWhere();

        // 검색 조건 적용
        if (keyword != null && !keyword.trim().isEmpty()) {
            switch (where) {
                case "title":
                    builder.and(qTodo.title.containsIgnoreCase(keyword));
                    break;
                case "writer":
                    builder.and(qTodo.writer.containsIgnoreCase(keyword));
                    break;
                default:
                    builder.and(
                            qTodo.title.containsIgnoreCase(keyword)
                                    .or(qTodo.writer.containsIgnoreCase(keyword))
                    );
            }
        }

        Pageable pageable = PageRequest.of(
                pageRequestDTO.getPage() - 1,
                pageRequestDTO.getSize(),
                Sort.by("tno").descending()
        );

        JPAQuery<Todo> query = queryFactory
                .selectFrom(qTodo)
                .where(builder)
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .orderBy(qTodo.tno.desc());

        List<Todo> resultList = query.fetch();

        long totalCount = queryFactory
                .select(qTodo.count())
                .from(qTodo)
                .where(builder)
                .fetchOne();

        return new PageImpl<>(resultList, pageable, totalCount);
    }
}

위와 같이 해서 해결했습니다.

감사합니다.

0

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다.

Link님께서 물어보신 Todo List 검색 기능 구현에 대한 질문은 React와 Spring Boot의 통합 과정에서 필수적인 부분입니다. 아래에서는 검색 기능을 구현하기 위한 간단한 흐름을 설명드리겠습니다.

전체적인 흐름

  1. 입력 필드 만들기

    • 사용자로부터 검색어를 입력받을 수 있도록 React 컴포넌트 내에 입력 필드를 만듭니다.
  2. 검색어 상태 관리

    • 입력 필드의 값을 useState 등을 사용해 상태로 관리하여, 상태 변화를 실시간으로 감지할 수 있도록 준비합니다.
  3. API 요청

    • Spring Boot에서 검색어를 받아 Todo List를 반환하는 엔드포인트를 구현합니다. 이를 위해 JPQL이나 QueryDSL을 사용하여 검색어가 포함된 Todo 항목을 찾는 쿼리를 작성합니다. 예를 들어, title이나 content가 검색어를 포함하는지를 조건으로 검색할 수 있습니다.
  4. 검색 버튼 클릭 이벤트 핸들러

    • 검색 버튼이 클릭될 때마다 API 서버로 현재 입력된 검색어를 전달하고, 해당 검색어에 맞는 Todo List를 가져오는 함수를 구현합니다. 이때 fetchaxios 같은 HTTP 클라이언트를 활용할 수 있습니다.
  5. 검색 결과 출력

    • API 서버로부터 받은 데이터를 React 컴포넌트를 통해 화면에 출력합니다. 이 과정에서 상태 관리와 조건부 렌더링을 활용하여 효과적으로 데이터를 표시합니다.

참고 링크

비슷한 질문이 있는 게시물을 통해 검색 기능에 대한 이해를 더욱 높이실 수 있습니다:

각 링크에서는 사용자가 마주할 수 있는 예외 상황과 그 해결책이 소개되어 있으니 참고하시기 바랍니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.