Skip to content

Commit

Permalink
Merge pull request #16 from Link-MIND/feature/#14
Browse files Browse the repository at this point in the history
feature: 카테고리 검색 구현, userId resolver 해결, querydsl 추가
  • Loading branch information
sss4920 authored Jan 3, 2024
2 parents 5d1fd3d + c21be53 commit 6fd6e70
Show file tree
Hide file tree
Showing 17 changed files with 244 additions and 2 deletions.
13 changes: 13 additions & 0 deletions linkmind/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
buildscript {
ext {
queryDslVersion = "5.0.0"
}
}

plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
Expand All @@ -21,6 +27,7 @@ repositories {
mavenCentral()
}


dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
Expand All @@ -42,6 +49,12 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.10.0' // Firebase 서버로 푸시 메시지 전송 시 필요

implementation 'org.springframework.boot:spring-boot-starter-actuator'

//Query DSL
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.app.toaster.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.querydsl.jpa.impl.JPAQueryFactory;

import jakarta.persistence.EntityManager;

@Configuration
public class JpaQueryFactoryConfig {

@Bean
JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}
}
21 changes: 21 additions & 0 deletions linkmind/src/main/java/com/app/toaster/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.app.toaster.config;

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {

private final UserIdResolver userIdResolver;

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userIdResolver);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public ApiResponse<TokenResponseDto> reissueToken(@RequestHeader String refreshT
@PostMapping("/sign-out")
@ResponseStatus(HttpStatus.OK)
public ApiResponse signOut(@UserId Long userId) {
System.out.println(userId);
authService.signOut(userId);
return ApiResponse.success(Success.SIGNOUT_SUCCESS);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.app.toaster.controller;

import java.util.List;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.app.toaster.common.dto.ApiResponse;
import com.app.toaster.domain.Category;
import com.app.toaster.infrastructure.CategoryRepository;
import com.app.toaster.service.search.SearchService;

import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/category")
public class CategoryController {
private final SearchService searchService;

@GetMapping("/search")
public ApiResponse searchProducts(@RequestHeader Long userId ,@RequestParam("query") String query){
return searchService.searchCategoryTitle(userId,query);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.app.toaster.controller;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.app.toaster.common.dto.ApiResponse;
import com.app.toaster.service.search.SearchService;
import com.app.toaster.service.toast.ToastService;

import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/main")
public class MainController {
private final SearchService searchService;

@GetMapping("/search")
public ApiResponse searchProducts(@RequestHeader Long userId ,@RequestParam("query") String query){
return searchService.searchMain(userId,query);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class ToastController {
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse createToast(
@RequestHeader("userId") Long userId,
@RequestBody @Valid SaveToastDto requestDto
@RequestBody SaveToastDto requestDto
) {
toastService.createToast(userId, requestDto);
return ApiResponse.success(Success.CREATE_TOAST_SUCCESS);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.app.toaster.controller.response.search;

public record CategoryResult(Long categoryId, String title) {
public static CategoryResult of(Long categoryId, String title){
return new CategoryResult(categoryId, title);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.app.toaster.controller.response.search;

import java.util.List;

import com.app.toaster.domain.Category;

public record SearchCategoryResult(List<CategoryResult> categories) {
public static SearchCategoryResult of(List<CategoryResult> categories){
return new SearchCategoryResult(categories);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.app.toaster.controller.response.search;

import java.util.List;

public record SearchMainResult(List<ToastResult> toasts, List<CategoryResult> categories) {
public static SearchMainResult of(List<ToastResult> toasts, List<CategoryResult> categories){
return new SearchMainResult(toasts,categories);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.app.toaster.controller.response.search;

public record ToastResult(Long toastId, String title) {
public static ToastResult of(Long toastId, String title){
return new ToastResult(toastId, title);
}
}
10 changes: 9 additions & 1 deletion linkmind/src/main/java/com/app/toaster/domain/Category.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@

import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import lombok.AccessLevel;
import lombok.Builder;
Expand All @@ -24,9 +26,15 @@ public class Category {

private String title;

@ManyToOne(fetch = FetchType.LAZY)
private User user;



@Builder
public Category(String title) {
public Category(String title, User user) {
this.title = title;
this.user = user;
}

}
2 changes: 2 additions & 0 deletions linkmind/src/main/java/com/app/toaster/exception/Success.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public enum Success {
SIGNOUT_SUCCESS(HttpStatus.OK, "로그아웃 성공"),
DELETE_USER_SUCCESS(HttpStatus.OK, "유저 삭제 성공"),
DELETE_TOAST_SUCCESS(HttpStatus.OK, "토스트 삭제 성공"),
SEARCH_SUCCESS(HttpStatus.OK, "검색 성공"),


UPDATE_ISREAD_SUCCESS(HttpStatus.OK, "열람여부 수정 완료"),
Expand All @@ -33,6 +34,7 @@ public enum Success {
/**
* 204 NO_CONTENT
*/
SEARCH_SUCCESS_BUT_IS_EMPTY(HttpStatus.NO_CONTENT, "검색에 성공했지만 조회된 내용이 없습니다.")

;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.app.toaster.infrastructure;

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -8,4 +9,10 @@
import com.app.toaster.domain.Category;

public interface CategoryRepository extends JpaRepository<Category, Long> {

@Query("SELECT c FROM Category c WHERE " +
"c.user.userId = :userId and " +
"c.title LIKE CONCAT('%',:query, '%')"
)
List<Category> searchCategoriesByQuery(Long userId,String query);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package com.app.toaster.infrastructure;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.app.toaster.domain.Category;
import com.app.toaster.domain.Toast;

public interface ToastRepository extends JpaRepository<Toast, Long> {

@Query("SELECT t FROM Toast t WHERE " +
"t.user.userId = :userId and " +
"t.title LIKE CONCAT('%',:query, '%')"
)
List<Toast> searchToastsByQuery(Long userId, String query);
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public SignInResponseDto signIn(String socialAccessToken, SignInRequestDto reque

User user = userRepository.findBySocialIdAndSocialType(socialId, socialType)
.orElseThrow(() -> new NotFoundException(Error.NOT_FOUND_USER_EXCEPTION, Error.NOT_FOUND_USER_EXCEPTION.getMessage()));
System.out.println(user);
System.out.println(user.getUserId());

// jwt 발급 (액세스 토큰, 리프레쉬 토큰)
String accessToken = jwtService.issuedToken(String.valueOf(user.getUserId()), TOKEN_EXPIRATION_TIME_ACCESS);
Expand Down Expand Up @@ -80,6 +82,8 @@ public TokenResponseDto issueToken(String refreshToken) {

@Transactional
public void signOut(Long userId) {
System.out.println("여기???");
System.out.println(userId);
User user = userRepository.findByUserId(userId)
.orElseThrow(() -> new NotFoundException(Error.NOT_FOUND_USER_EXCEPTION, Error.NOT_FOUND_USER_EXCEPTION.getMessage()));
user.updateRefreshToken(null);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.app.toaster.service.search;

import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.app.toaster.common.dto.ApiResponse;
import com.app.toaster.controller.response.search.CategoryResult;
import com.app.toaster.controller.response.search.SearchCategoryResult;
import com.app.toaster.controller.response.search.SearchMainResult;
import com.app.toaster.controller.response.search.ToastResult;
import com.app.toaster.domain.Category;
import com.app.toaster.domain.Toast;
import com.app.toaster.domain.User;
import com.app.toaster.exception.Error;
import com.app.toaster.exception.Success;
import com.app.toaster.exception.model.CustomException;
import com.app.toaster.exception.model.NotFoundException;
import com.app.toaster.infrastructure.CategoryRepository;
import com.app.toaster.infrastructure.ToastRepository;
import com.app.toaster.infrastructure.UserRepository;
import com.google.protobuf.Api;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class SearchService {
private final ToastRepository toastRepository;
private final UserRepository userRepository;
private final CategoryRepository categoryRepository;

public ApiResponse<SearchCategoryResult> searchCategoryTitle(Long userId, String searchParam){
User presentUser = userRepository.findByUserId(userId).orElseThrow(
()-> new NotFoundException(Error.NOT_FOUND_USER_EXCEPTION, Error.NOT_FOUND_USER_EXCEPTION.getMessage())
);
List<Category> searchCategoryList = categoryRepository.searchCategoriesByQuery(userId, searchParam);

if (searchCategoryList.isEmpty()){
return ApiResponse.success(Success.SEARCH_SUCCESS_BUT_IS_EMPTY,null);
}

return ApiResponse.success(Success.SEARCH_SUCCESS, SearchCategoryResult.of(
searchCategoryList.stream().map(
category -> CategoryResult.of(category.getCategoryId(), category.getTitle()))
.collect(Collectors.toList())));
}

public ApiResponse<SearchMainResult> searchMain(Long userId, String searchParam){
User presentUser = userRepository.findByUserId(userId).orElseThrow(
()-> new NotFoundException(Error.NOT_FOUND_USER_EXCEPTION, Error.NOT_FOUND_USER_EXCEPTION.getMessage())
);
List<Toast> searchToastList = toastRepository.searchToastsByQuery(userId, searchParam);
List<Category> searchCategoryList = categoryRepository.searchCategoriesByQuery(userId, searchParam);

if (searchToastList.isEmpty() && searchCategoryList.isEmpty()){
return ApiResponse.success(Success.SEARCH_SUCCESS_BUT_IS_EMPTY,null);
}
return ApiResponse.success(Success.SEARCH_SUCCESS, SearchMainResult.of(
searchToastList.stream().map(
toast -> ToastResult.of(toast.getId(), toast.getTitle()))
.collect(Collectors.toList()),
searchCategoryList.stream().map(
category -> CategoryResult.of(category.getCategoryId(), category.getTitle()))
.collect(Collectors.toList())
));
}

}

0 comments on commit 6fd6e70

Please sign in to comment.