Skip to content
This repository was archived by the owner on Jan 11, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ dependencies {

// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// P6spy
implementation 'p6spy:p6spy:3.9.1'
implementation 'com.github.gavlyukovskiy:datasource-decorator-spring-boot-autoconfigure:1.9.0'
}

sentry {
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/com/example/spot/config/ApiLoggingInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.example.spot.config;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class ApiLoggingInterceptor implements HandlerInterceptor {

private static final Logger logger = LoggerFactory.getLogger(ApiLoggingInterceptor.class);

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
long startTime = (Long) request.getAttribute("startTime");
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("[API LOG] {} {} took {} ms", request.getMethod(), request.getRequestURI(), elapsedTime);
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/example/spot/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.spot.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Autowired
private ApiLoggingInterceptor apiLoggingInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(apiLoggingInterceptor);
}
}
11 changes: 6 additions & 5 deletions src/main/java/com/example/spot/domain/enums/Reason.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
import com.example.spot.api.exception.GeneralException;

public enum Reason {
동기부여를_받고_싶어요(1),
스터디원이_필요해요(2),
혼자서_하기가_의지가_부족해요(3),
한_목표를_가진_사람들과_친해지고_싶어요(4),
다양한_정보를_공유하고_받고_싶어요(5);
꾸준한_학습_습관이_필요해요(1),
상호_피드백이_필요해요(2),
네트워킹을_하고_싶어요(3),
자격증을_취득하고_싶어요(4),
대회에_참가하여_수상하고_싶어요(5),
다양한_의견을_나누고_싶어요(6);

private final long code;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.springframework.data.repository.query.Param;

public interface StudyRepositoryCustom {
List<Study> searchByTitle(String keyword, StudySortBy sortBy, Pageable pageable);
List<Study> findAllStudyByConditions(Map<String, Object> search, StudySortBy sortBy, Pageable pageable);
List<Study> findAllStudy(StudySortBy sortBy, Pageable pageable);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,25 @@
import com.example.spot.domain.enums.StudySortBy;
import com.example.spot.domain.enums.StudyState;
import com.example.spot.domain.mapping.MemberStudy;
import com.example.spot.domain.mapping.QMemberStudy;
import com.example.spot.domain.mapping.QRegionStudy;
import com.example.spot.domain.mapping.QStudyTheme;
import com.example.spot.domain.mapping.RegionStudy;
import com.example.spot.domain.mapping.StudyTheme;
import com.example.spot.domain.study.QStudy;
import com.example.spot.domain.study.Study;
import com.example.spot.repository.querydsl.StudyRepositoryCustom;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import static com.example.spot.domain.study.QStudy.study;
Expand All @@ -24,6 +31,7 @@
public class StudyRepositoryCustomImpl implements StudyRepositoryCustom {

private final JPAQueryFactory queryFactory;
private final EntityManager entityManager;

@Override
public List<Study> findAllStudyByConditions(Map<String, Object> search, StudySortBy sortBy,
Expand Down Expand Up @@ -193,6 +201,26 @@ public List<Study> findStudyByConditionsAndRegionStudiesAndNotInIds(Map<String,
return query.fetch();
}

@Override
public List<Study> searchByTitle(String keyword, StudySortBy sortBy, Pageable pageable) {
QStudy study = QStudy.study;

// FULLTEXT SEARCH를 위한 서브쿼리 생성
String subQuery = """
SELECT id FROM study WHERE MATCH(title) AGAINST (:keyword IN NATURAL LANGUAGE MODE) ORDER BY created_at DESC LIMIT :offset, :limit """;

List<Long> ids = entityManager.createNativeQuery(subQuery)
.setParameter("keyword", keyword)
.setParameter("offset", pageable.getOffset())
.setParameter("limit", pageable.getPageSize())
.getResultList();

// QueryDSL로 해당 ID들을 조회
return queryFactory.selectFrom(study)
.where(study.id.in(ids))
.orderBy(study.createdAt.desc())
.fetch();
}

@Override
public List<Study> findAllByTitleContaining(String title, StudySortBy sortBy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ public StudyPreviewDTO findLikedStudies(Long memberId, Pageable pageable) {
public StudyPreviewDTO findStudiesByKeyword(Pageable pageable,
String keyword, StudySortBy sortBy) {
// 키워드로 스터디 조회
List<Study> studies = studyRepository.findAllByTitleContaining(keyword, sortBy, pageable);
List<Study> studies = studyRepository.searchByTitle(keyword, sortBy, pageable);

// 조회된 스터디가 없을 경우
if (studies.isEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,12 @@ public ApiResponse<MemberUpdateDTO> updateMemberInfo(
## [회원 정보 업데이트] 해당하는 회원의 스터디 이유를 입력 및 수정 합니다.
업데이트 할 회원의 정보를 입력 받습니다.

1. 동기부여를_받고_싶어요
2. 스터디원이_필요해요
3. 혼자서_하기가_의지가_부족해요
4. 한_목표를_가진_사람들과_친해지고_싶어요
5. 다양한_정보를_공유하고_받고_싶어요
꾸준한 학습, 습관이필요해요(1) \n
상호 피드백이 필요해요(2), \n
네트워킹을 하고 싶어요(3), \n
자격증을 취득하고 싶어요(4), \n
대회에 참가하여 수상하고 싶어요(5),\n
다양한 의견을 나누고 싶어요(6); \n

이유에 해당하는 숫자를 리스트 형식으로 입력 받습니다.

Expand Down Expand Up @@ -231,7 +232,7 @@ public ApiResponse<MemberResponseDTO.MemberRegionDTO> getRegions(){
security = @SecurityRequirement(name = "accessToken"))
public ApiResponse<MemberResponseDTO.MemberStudyReasonDTO> getStudyReasons(){
MemberStudyReasonDTO memberStudyReasonDTO = memberService.getStudyReasons(SecurityUtils.getCurrentUserId());
return ApiResponse.onSuccess(SuccessStatus._MEMBER_REGION_UPDATE, memberStudyReasonDTO);
return ApiResponse.onSuccess(SuccessStatus._MEMBER_FOUND, memberStudyReasonDTO);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.github.gavlyukovskiy.boot.jdbc.decorator.DataSourceDecoratorAutoConfiguration
4 changes: 4 additions & 0 deletions src/main/resources/spy.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
appender=com.p6spy.engine.spy.appender.Slf4JLogger
logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat
customLogMessageFormat=took %(executionTime) ms | %(sql)
excludecategories=info,debug,result,resultset
Original file line number Diff line number Diff line change
Expand Up @@ -1569,7 +1569,7 @@ void findStudiesByKeyword() {
String keyword = "English";
StudySortBy sortBy = StudySortBy.ALL;

when(studyRepository.findAllByTitleContaining(keyword, sortBy, pageable))
when(studyRepository.searchByTitle(keyword, sortBy, pageable))
.thenReturn(List.of(study1));
when(studyRepository.countAllByTitleContaining(keyword, sortBy))
.thenReturn(1L);
Expand All @@ -1592,7 +1592,7 @@ void findStudiesByKeyword() {
// then
assertNotNull(result);
assertEquals(1, result.getTotalElements());
verify(studyRepository).findAllByTitleContaining(keyword, sortBy, pageable);
verify(studyRepository).searchByTitle(keyword, sortBy, pageable);
}

@Test
Expand All @@ -1602,7 +1602,7 @@ void findStudiesByKeyword() {
String keyword = "English";
StudySortBy sortBy = StudySortBy.ALL;

when(studyRepository.findAllByTitleContaining(keyword, sortBy, pageable))
when(studyRepository.searchByTitle(keyword, sortBy, pageable))
.thenReturn(List.of());

// when & then
Expand Down