-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
Merge pull request #112 from Korea-Certified-Store/develop
Develop to Main 릴리즈 (#111)
Showing
21 changed files
with
707 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
src/main/java/com/nainga/nainga/domain/report/api/ReportApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package com.nainga.nainga.domain.report.api; | ||
|
||
import com.nainga.nainga.domain.report.application.ReportService; | ||
import com.nainga.nainga.domain.report.domain.Report; | ||
import com.nainga.nainga.domain.report.dto.SaveNewStoreReportRequest; | ||
import com.nainga.nainga.domain.report.dto.SaveSpecificStoreReportRequest; | ||
import com.nainga.nainga.global.util.Result; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.validation.Valid; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
public class ReportApi { | ||
private final ReportService reportService; | ||
|
||
//사용자의 신규 가게 등록 요청에 대한 제보를 저장 | ||
@Tag(name = "[New] 사용자 제보") | ||
@Operation(summary = "사용자의 신규 가게 등록 요청에 대한 제보를 서버에 저장", description = "사용자의 신규 가게 등록 요청에 대한 제보를 서버에 저장합니다.<br><br>" + | ||
"[Request Body]<br>" + | ||
"storeName: 등록 요청하는 가게 이름<br>" + | ||
"formattedAddress: 등록 요청하는 가게 주소<br>" + | ||
"certifications: 가게가 가지고 있는 인증제들의 이름을 담은 리스트. 착한가격업소, 모범음식점, 안심식당이 아닌 경우 예외 발생<br>" + | ||
"[Response Body]<br>" + | ||
"등록된 reportId<br>") | ||
@PostMapping("api/report/newStore/v1") | ||
public Result<Long> saveNewStoreReport(@Valid @RequestBody SaveNewStoreReportRequest saveNewStoreReportRequest) { | ||
Long reportId = reportService.saveNewStoreReport(saveNewStoreReportRequest); | ||
return new Result<>(Result.CODE_SUCCESS, Result.MESSAGE_OK, reportId); | ||
} | ||
|
||
//사용자의 특정 가게에 대한 수정, 삭제 요청 정보를 저장 | ||
@Tag(name = "[New] 사용자 제보") | ||
@Operation(summary = "사용자의 특정 가게에 대한 정보 수정 혹은 삭제 요청에 대한 제보를 서버에 저장", description = "사용자의 특정 가게에 대한 정보 수정 혹은 삭제 요청에 대한 제보를 서버에 저장합니다.<br><br>" + | ||
"[Request Body]<br>" + | ||
"dtype: 제보 종류를 구분하기 위한 값. fix는 수정 요청, del은 삭제 요청. fix나 del이 아닌 경우 예외 발생<br>" + | ||
"storeId: 수정 혹은 삭제를 요청하는 가게 id<br>" + | ||
"contents: 제보 내용<br>" + | ||
"[Response Body]<br>" + | ||
"등록된 reportId<br>") | ||
@PostMapping("api/report/specificStore/v1") | ||
public Result<Long> saveSpecificStoreReport(@Valid @RequestBody SaveSpecificStoreReportRequest saveSpecificStoreReportRequest) { | ||
Long reportId = reportService.saveSpecificStoreReport(saveSpecificStoreReportRequest); | ||
return new Result<>(Result.CODE_SUCCESS, Result.MESSAGE_OK, reportId); | ||
} | ||
|
||
//reportId를 가지고 사용자 제보 내용 조회 | ||
@Tag(name = "[New] 사용자 제보") | ||
@Operation(summary = "reportId를 가지고 사용자 제보 내용 조회", description = "reportId를 가지고 사용자 제보 내용을 조회합니다.<br><br>" + | ||
"[Request Body]<br>" + | ||
"reportId: 검색할 사용자 제보의 reportId. 유효하지 않은 reportId의 경우 예외 발생<br>" + | ||
"[Response Body]<br>" + | ||
"해당 reportId로 검색된 사용자 제보 내용<br>") | ||
@GetMapping("api/report/byId/v1") | ||
public Result<Report> findById(@NotNull @RequestParam(value = "reportId") Long reportId) { | ||
Report report = reportService.findById(reportId); | ||
return new Result<>(Result.CODE_SUCCESS, Result.MESSAGE_OK, report); | ||
} | ||
|
||
//DB에 있는 모든 사용자 제보 내용 조회 | ||
@Tag(name = "[New] 사용자 제보") | ||
@Operation(summary = "DB에 있는 모든 사용자 제보 내용 조회", description = "DB에 있는 모든 사용자 제보 내용을 조회합니다.<br><br>" + | ||
"[Response Body]<br>" + | ||
"DB에 있는 모든 사용자 제보 내용<br>") | ||
@GetMapping("api/report/all/v1") | ||
public Result<List<Report>> findAll() { | ||
List<Report> reports = reportService.findAll(); | ||
return new Result<>(Result.CODE_SUCCESS, Result.MESSAGE_OK, reports); | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
src/main/java/com/nainga/nainga/domain/report/application/ReportService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package com.nainga.nainga.domain.report.application; | ||
|
||
import com.nainga.nainga.domain.report.dao.ReportRepository; | ||
import com.nainga.nainga.domain.report.domain.DelSpecificStoreReport; | ||
import com.nainga.nainga.domain.report.domain.FixSpecificStoreReport; | ||
import com.nainga.nainga.domain.report.domain.NewStoreReport; | ||
import com.nainga.nainga.domain.report.domain.Report; | ||
import com.nainga.nainga.domain.report.dto.SaveNewStoreReportRequest; | ||
import com.nainga.nainga.domain.report.dto.SaveSpecificStoreReportRequest; | ||
import com.nainga.nainga.global.exception.GlobalException; | ||
import com.nainga.nainga.global.exception.ReportErrorCode; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class ReportService { | ||
private final ReportRepository reportRepository; | ||
|
||
@Transactional | ||
public Long saveNewStoreReport(SaveNewStoreReportRequest saveNewStoreReportRequest) throws GlobalException { //사용자의 신규 가게 등록 요청 | ||
List<String> certificationList = List.of("착한가격업소", "모범음식점", "안심식당"); //현재 App에서 사용중인 Certification 목록 | ||
for (String certification : saveNewStoreReportRequest.getCertifications()) { | ||
if (!certificationList.contains(certification)) { | ||
throw new GlobalException(ReportErrorCode.INVALID_CERTIFICATION); //잘못된 인증제 값이 들어온 것이므로 예외 발생 | ||
} | ||
} | ||
|
||
NewStoreReport newStoreReport = NewStoreReport.builder() | ||
.storeName(saveNewStoreReportRequest.getStoreName()) | ||
.formattedAddress(saveNewStoreReportRequest.getFormattedAddress()) | ||
.certifications(saveNewStoreReportRequest.getCertifications()) | ||
.build(); | ||
|
||
return reportRepository.save(newStoreReport); | ||
} | ||
|
||
@Transactional | ||
public Long saveSpecificStoreReport(SaveSpecificStoreReportRequest saveSpecificStoreReportRequest) throws GlobalException { //사용자의 특정 가게에 대한 수정, 삭제 요청 | ||
if (saveSpecificStoreReportRequest.getDtype().equals("fix")) { | ||
FixSpecificStoreReport fixSpecificStoreReport = FixSpecificStoreReport.builder() | ||
.storeId(saveSpecificStoreReportRequest.getStoreId()) | ||
.contents(saveSpecificStoreReportRequest.getContents()) | ||
.build(); | ||
|
||
return reportRepository.save(fixSpecificStoreReport); | ||
} else if (saveSpecificStoreReportRequest.getDtype().equals("del")) { | ||
DelSpecificStoreReport delSpecificStoreReport = DelSpecificStoreReport.builder() | ||
.storeId(saveSpecificStoreReportRequest.getStoreId()) | ||
.contents(saveSpecificStoreReportRequest.getContents()) | ||
.build(); | ||
|
||
return reportRepository.save(delSpecificStoreReport); | ||
} else { | ||
throw new GlobalException(ReportErrorCode.INVALID_DTYPE); //잘못된 DTYPE이 들어왔을 경우에 Custom GlobalException 처리 | ||
} | ||
} | ||
|
||
public Report findById(Long id) throws GlobalException { //reportId를 가지고 report를 DB에서 조회하는 로직 | ||
Optional<Report> report = reportRepository.findById(id); | ||
if (report.isEmpty()) { | ||
throw new GlobalException(ReportErrorCode.INVALID_REPORT_ID); //잘못된 reportId로 검색하는 경우에 Custom GlobalException 처리 | ||
} else { | ||
return report.get(); | ||
} | ||
} | ||
|
||
public List<Report> findAll() { //DB에 있는 모든 Report 조회 | ||
return reportRepository.findAll(); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
src/main/java/com/nainga/nainga/domain/report/dao/ReportRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.nainga.nainga.domain.report.dao; | ||
|
||
import com.nainga.nainga.domain.report.domain.Report; | ||
import jakarta.persistence.EntityManager; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class ReportRepository { | ||
|
||
private final EntityManager em; | ||
|
||
public Long save(Report report) { | ||
em.persist(report); | ||
return report.getId(); | ||
} | ||
|
||
public Optional<Report> findById(Long id) { | ||
List<Report> result = em.createQuery("select r from Report r where r.id = :id", Report.class) | ||
.setParameter("id", id) | ||
.getResultList(); | ||
return result.stream().findAny(); | ||
} | ||
|
||
public List<Report> findAll() { | ||
return em.createQuery("select r from Report r", Report.class) | ||
.getResultList(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/com/nainga/nainga/domain/report/domain/DelSpecificStoreReport.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.nainga.nainga.domain.report.domain; | ||
|
||
import jakarta.persistence.DiscriminatorValue; | ||
import jakarta.persistence.Entity; | ||
import lombok.*; | ||
|
||
@Entity | ||
@Getter | ||
@Builder | ||
@DiscriminatorValue("del") | ||
@AllArgsConstructor | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class DelSpecificStoreReport extends Report { | ||
private Long storeId; //가게 id | ||
private String contents; //신고 내용 | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/com/nainga/nainga/domain/report/domain/FixSpecificStoreReport.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.nainga.nainga.domain.report.domain; | ||
|
||
import jakarta.persistence.DiscriminatorValue; | ||
import jakarta.persistence.Entity; | ||
import lombok.*; | ||
|
||
@Entity | ||
@Getter | ||
@Builder | ||
@DiscriminatorValue("fix") | ||
@AllArgsConstructor | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class FixSpecificStoreReport extends Report { | ||
private Long storeId; //가게 id | ||
private String contents; //신고 내용 | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/com/nainga/nainga/domain/report/domain/NewStoreReport.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.nainga.nainga.domain.report.domain; | ||
|
||
import jakarta.persistence.DiscriminatorValue; | ||
import jakarta.persistence.ElementCollection; | ||
import jakarta.persistence.Entity; | ||
import lombok.*; | ||
|
||
import java.util.List; | ||
|
||
@Entity | ||
@Getter | ||
@Builder | ||
@DiscriminatorValue("new") | ||
@AllArgsConstructor | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class NewStoreReport extends Report { | ||
private String storeName; //가게 이름 | ||
private String formattedAddress; //가게 주소 | ||
@ElementCollection | ||
private List<String> certifications; //가게가 가지고 있는 인증제 이름 리스트 | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/com/nainga/nainga/domain/report/domain/Report.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.nainga.nainga.domain.report.domain; | ||
|
||
import jakarta.persistence.*; | ||
import lombok.*; | ||
|
||
@Entity | ||
@Getter | ||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) | ||
@DiscriminatorColumn(name = "dtype") | ||
public abstract class Report { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "report_id") | ||
private Long id; | ||
} |
27 changes: 27 additions & 0 deletions
27
src/main/java/com/nainga/nainga/domain/report/dto/SaveNewStoreReportRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.nainga.nainga.domain.report.dto; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import jakarta.validation.constraints.NotEmpty; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.Data; | ||
|
||
import java.util.List; | ||
|
||
@Data | ||
public class SaveNewStoreReportRequest { | ||
@NotEmpty | ||
@Schema(defaultValue = "가게 이름", description = "새로 등록하고자 하는 가게 이름") | ||
private String storeName; //가게 이름 | ||
@NotEmpty | ||
@Schema(defaultValue = "주소", description = "새로 등록하고자 하는 가게 주소") | ||
private String formattedAddress; //가게 주소 | ||
@NotEmpty | ||
@Schema(defaultValue = "[\"착한가격업소\", \"모범음식점\", \"안심식당\"]", description = "새로 등록할 가게가 가지고 있는 인증제들의 이름을 담은 리스트. 착한가격업소, 모범음식점, 안심식당이 아닌 경우 예외 발생") | ||
private List<String> certifications; //가게가 가지고 있는 인증제 이름 리스트 | ||
|
||
public SaveNewStoreReportRequest(String storeName, String formattedAddress, List<String> certifications) { | ||
this.storeName = storeName; | ||
this.formattedAddress = formattedAddress; | ||
this.certifications = certifications; | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/java/com/nainga/nainga/domain/report/dto/SaveSpecificStoreReportRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.nainga.nainga.domain.report.dto; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import jakarta.validation.constraints.NotEmpty; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.Data; | ||
|
||
@Data | ||
public class SaveSpecificStoreReportRequest { | ||
@NotEmpty | ||
@Schema(defaultValue = "fix/del", description = "제보 종류를 구분하기 위한 값. fix는 수정 요청, del은 삭제 요청.") | ||
private String dtype; //Report 종류를 구분하기 위한 type | ||
@NotNull | ||
@Schema(defaultValue = "0", description = "수정 혹은 삭제를 요청하는 가게 id") | ||
private Long storeId; //가게 id | ||
@NotEmpty | ||
@Schema(defaultValue = "제보 내용", description = "제보 내용") | ||
private String contents; //신고 내용 | ||
|
||
public SaveSpecificStoreReportRequest(String dtype, Long storeId, String contents) { | ||
this.dtype = dtype; | ||
this.storeId = storeId; | ||
this.contents = contents; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
src/main/java/com/nainga/nainga/domain/store/application/StoreService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package com.nainga.nainga.domain.store.application; | ||
|
||
import com.nainga.nainga.domain.store.dao.StoreRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class StoreService { | ||
private final StoreRepository storeRepository; | ||
|
||
public List<String> autocorrect(String keyword) { //검색어 자동 완성 로직 | ||
return storeRepository.findAllBySearchKeyword(keyword); | ||
} | ||
|
||
// private final RedisSortedSetService redisSortedSetService; | ||
// private final RedisHashService redisHashService; | ||
|
||
/* | ||
Redis Hash 자료 구조를 활용한 새로운 검색어 자동 완성 로직입니다. | ||
아래 로직은 Case insensitive하게 검색될 수 있도록 구현하였습니다. | ||
지금은 MySQL이 성능이 더 좋아서 사용하지 않습니다. | ||
*/ | ||
|
||
// @PostConstruct | ||
// public void init() { //이 Service Bean이 생성된 이후에 검색어 자동 완성 기능을 위한 데이터들을 Redis에 저장 (Redis는 인메모리 DB라 휘발성을 띄기 때문) | ||
// redisHashService.removeAllOfHash(); | ||
// saveAllDisplayName(storeRepository.findAllDisplayName()); //모든 가게명을 소문자로 변환한 것을 field, 원래 가게 이름을 value로 매핑시켜서 Redis Hash에 저장 | ||
// } | ||
|
||
// public void saveAllDisplayName(List<String> allDisplayName) { | ||
// ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //병렬 처리를 위한 스레드풀을 생성하는 과정 | ||
// | ||
// for (String displayName : allDisplayName) { | ||
// executorService.submit(() -> { //submit 메서드를 사용해서 병렬 처리할 작업 추가 | ||
// //Redis 내장 기능이 아닌 case insensitive 조회를 구현하기 위해 소문자로 변환한 field값과 원래 string인 value의 쌍을 Hash에 저장 | ||
// redisHashService.addToHash(displayName.toLowerCase(), displayName); //case insensitive하게 검색어 자동 완성 기능을 직접 구현하기 위해 소문자로 통일해서 저장 | ||
// }); | ||
// } | ||
// executorService.shutdown(); //작업이 모두 완료되면 스레드풀을 종료 | ||
// } | ||
|
||
// public List<String> autocorrect(String keyword) { //검색어 자동 완성 로직 | ||
// Set<String> allValuesContainingSearchKeyword = redisHashService.findAllValuesContainingSearchKeyword(keyword); //case insensitive하게 serachKeyword를 포함하는 가게 이름 최대 10개 반환 | ||
// if(allValuesContainingSearchKeyword.isEmpty()) | ||
// return new ArrayList<>(); | ||
// else | ||
// return new ArrayList<>(allValuesContainingSearchKeyword); //자동 완성 결과가 존재하면 ArrayList로 변환하여 리턴 | ||
// } | ||
|
||
/* | ||
아래 주석처리 된 코드는 초기 검색어 자동 완성 로직입니다. | ||
검색어 자동 완성에 대한 요구 사항이 앞에서부터 매칭되는 글자가 아닌 Contains 개념으로 바뀌어서 주석 처리하여 임시로 남겨놓았습니다. | ||
지금은 MySQL이 성능이 더 좋기 때문에 사용하지 않는 코드입니다. | ||
*/ | ||
|
||
// private String suffix = "*"; //검색어 자동 완성 기능에서 실제 노출될 수 있는 완벽한 형태의 단어를 구분하기 위한 접미사 | ||
// private int maxSize = 10; //검색어 자동 완성 기능 최대 개수 | ||
// | ||
// @PostConstruct | ||
// public void init() { //이 Service Bean이 생성된 이후에 검색어 자동 완성 기능을 위한 데이터들을 Redis에 저장 (Redis는 인메모리 DB라 휘발성을 띄기 때문) | ||
// redisSortedSetService.removeAllOfSortedSet(); | ||
// saveAllSubstring(storeRepository.findAllDisplayName()); //MySQL DB에 저장된 모든 가게명을 음절 단위로 잘라 모든 Substring을 Redis에 저장해주는 로직 | ||
// } | ||
// | ||
// public void saveAllSubstring(List<String> allDisplayName) { | ||
// ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //병렬 처리를 위한 스레드풀을 생성하는 과정 | ||
// | ||
// for (String displayName : allDisplayName) { | ||
// executorService.submit(() -> { //submit 메서드를 사용해서 병렬 처리할 작업 추가 | ||
// redisSortedSetService.addToSortedSet(displayName + suffix); | ||
// | ||
// for (int i = displayName.length(); i > 0; --i) { | ||
// redisSortedSetService.addToSortedSet(displayName.substring(0, i)); | ||
// } | ||
// }); | ||
// } | ||
// executorService.shutdown(); //작업이 모두 완료되면 스레드풀을 종료 | ||
// } | ||
// | ||
// public List<String> autocorrect(String keyword) { //검색어 자동 완성 기능 관련 로직 | ||
// Long index = redisSortedSetService.findFromSortedSet(keyword); //사용자가 입력한 검색어를 바탕으로 Redis에서 조회한 결과 매칭되는 index | ||
// | ||
// if (index == null) { | ||
// return new ArrayList<>(); //만약 사용자 검색어 바탕으로 자동 완성 검색어를 만들 수 없으면 Empty Array 리턴 | ||
// } | ||
// | ||
// Set<String> allValuesAfterIndexFromSortedSet = redisSortedSetService.findAllValuesAfterIndexFromSortedSet(index); //사용자 검색어 이후로 정렬된 Redis 데이터들 가져오기 | ||
// | ||
// return allValuesAfterIndexFromSortedSet.stream() | ||
// .filter(value -> value.endsWith(suffix) && value.startsWith(keyword)) | ||
// .map(value -> StringUtils.removeEnd(value, suffix)) | ||
// .limit(maxSize) | ||
// .toList(); //자동 완성을 통해 만들어진 최대 maxSize개의 키워드들 | ||
// } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
src/main/java/com/nainga/nainga/global/application/RedisHashService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
//package com.nainga.nainga.global.application; | ||
// | ||
//import org.springframework.data.redis.core.Cursor; | ||
//import org.springframework.data.redis.core.HashOperations; | ||
//import org.springframework.data.redis.core.RedisTemplate; | ||
//import org.springframework.data.redis.core.ScanOptions; | ||
//import org.springframework.stereotype.Service; | ||
// | ||
//import java.util.HashSet; | ||
//import java.util.Map; | ||
//import java.util.Set; | ||
//import java.util.TreeSet; | ||
// | ||
//@Service | ||
//public class RedisHashService { | ||
// private final HashOperations<String, String, String> hashOperations; | ||
// private final RedisTemplate<String, String> redisTemplate; | ||
// | ||
// public RedisHashService(RedisTemplate<String, String> redisTemplate) { | ||
// this.hashOperations = redisTemplate.opsForHash(); | ||
// this.redisTemplate = redisTemplate; | ||
// } | ||
// | ||
// private String key = "autocorrect"; //검색어 자동 완성을 위한 Redis 데이터 | ||
// | ||
// //Hash에 field-value 쌍을 추가하는 메서드 | ||
// public void addToHash(String field, String value) { | ||
// hashOperations.put(key, field, value); | ||
// } | ||
// | ||
// public Set<String> findAllValuesContainingSearchKeyword(String searchKeyword) { | ||
// //Redis에서는 case insensitive한 검색을 지원하는 내장 모듈이 없으므로 searchKeyword는 모두 소문자로 통일하여 검색하도록 구현 | ||
// //당연히 초기 Redis에 field를 저장할 때도 모두 소문자로 변형하여 저장했고 원본 문자열은 value에 저장! | ||
// Set<String> result = new HashSet<>(); //searchKeyword를 포함하는 원래 가게 이름들의 리스트. 최대 maxSize개까지 저장. 중복 허용하지 않고, 자동 사전순 정렬하기 위해 사용 | ||
// final int maxSize = 10; //최대 검색어 자동 완성 개수 | ||
// | ||
// ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + searchKeyword + "*").build(); //searchKeyword를 포함하는지를 검사하기 위한 scanOption | ||
// Cursor<Map.Entry<String, String>> cursor = hashOperations.scan(key, scanOptions); //기존 Redis Keys 로직의 성능 이슈를 해결하기 위해 10개 단위로 끊어서 조회하는 Scan 기능 사용 | ||
// | ||
// while (cursor.hasNext()) { //끊어서 조회하다보니 while loop로 조회 | ||
// Map.Entry<String, String> entry = cursor.next(); | ||
// result.add(entry.getValue()); | ||
// | ||
// if(result.size() >= maxSize) //maxSize에 도달하면 scan 중단 | ||
// break; | ||
// } | ||
// cursor.close(); | ||
// return result; | ||
// } | ||
// | ||
// public void removeAllOfHash() { | ||
// redisTemplate.delete(key); | ||
// } | ||
//} |
34 changes: 34 additions & 0 deletions
34
src/main/java/com/nainga/nainga/global/application/RedisSortedSetService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
//package com.nainga.nainga.global.application; | ||
// | ||
//import lombok.RequiredArgsConstructor; | ||
//import org.springframework.data.redis.core.RedisCallback; | ||
//import org.springframework.data.redis.core.RedisTemplate; | ||
//import org.springframework.data.redis.core.ZSetOperations; | ||
//import org.springframework.stereotype.Service; | ||
// | ||
//import java.util.List; | ||
//import java.util.Set; | ||
// | ||
//@Service | ||
//@RequiredArgsConstructor | ||
//public class RedisSortedSetService { //검색어 자동 완성을 구현할 때 사용하는 Redis의 SortedSet 관련 서비스 레이어 | ||
// private final RedisTemplate<String, String> redisTemplate; | ||
// private String key = "autocorrect"; //검색어 자동 완성을 위한 Redis 데이터 | ||
// private int score = 0; //Score는 딱히 필요 없으므로 하나로 통일 | ||
// | ||
// public void addToSortedSet(String value) { //Redis SortedSet에 추가 | ||
// redisTemplate.opsForZSet().add(key, value, score); | ||
// } | ||
// | ||
// public Long findFromSortedSet(String value) { //Redis SortedSet에서 Value를 찾아 인덱스를 반환 | ||
// return redisTemplate.opsForZSet().rank(key, value); | ||
// } | ||
// | ||
// public Set<String> findAllValuesAfterIndexFromSortedSet(Long index) { | ||
// return redisTemplate.opsForZSet().range(key, index, index + 200); //전체를 다 불러오기 보다는 200개 정도만 가져와도 자동 완성을 구현하는 데 무리가 없으므로 200개로 rough하게 설정 | ||
// } | ||
// | ||
// public void removeAllOfSortedSet() { | ||
// redisTemplate.opsForZSet().removeRange(key, 0, -1); | ||
// } | ||
//} |
19 changes: 19 additions & 0 deletions
19
src/main/java/com/nainga/nainga/global/exception/ReportErrorCode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.nainga.nainga.global.exception; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
|
||
/* | ||
Report와 관련된 도메인에서 발생할 수 있는 ErrorCode를 정의합니다. | ||
*/ | ||
@Getter | ||
@RequiredArgsConstructor | ||
public enum ReportErrorCode implements ErrorCode { | ||
INVALID_DTYPE(HttpStatus.NOT_FOUND, "There is a wrong dtype. You can only use a dtype such as fix or del."), | ||
INVALID_CERTIFICATION(HttpStatus.NOT_FOUND, "There is a wrong certification. You can only use certifications such as 착한가격업소, 모범음식점, 안심식당."), | ||
INVALID_REPORT_ID(HttpStatus.NOT_FOUND, "There is a wrong reportId."); | ||
|
||
private final HttpStatus httpStatus; | ||
private final String message; | ||
} |
Submodule backend-submodule
updated
from 864e24 to c741a7
109 changes: 109 additions & 0 deletions
109
src/test/java/com/nainga/nainga/domain/report/application/ReportServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package com.nainga.nainga.domain.report.application; | ||
|
||
import com.nainga.nainga.domain.report.dao.ReportRepository; | ||
import com.nainga.nainga.domain.report.domain.DelSpecificStoreReport; | ||
import com.nainga.nainga.domain.report.domain.FixSpecificStoreReport; | ||
import com.nainga.nainga.domain.report.domain.NewStoreReport; | ||
import com.nainga.nainga.domain.report.domain.Report; | ||
import com.nainga.nainga.domain.report.dto.SaveNewStoreReportRequest; | ||
import com.nainga.nainga.domain.report.dto.SaveSpecificStoreReportRequest; | ||
import com.nainga.nainga.global.exception.GlobalException; | ||
import org.assertj.core.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
import static org.junit.jupiter.api.Assertions.*; | ||
|
||
@SpringBootTest | ||
@Transactional | ||
class ReportServiceTest { | ||
@Autowired | ||
private ReportRepository reportRepository; | ||
|
||
@Autowired | ||
private ReportService reportService; | ||
|
||
@Test | ||
public void saveNewStoreReport() throws Exception { | ||
//given | ||
SaveNewStoreReportRequest saveNewStoreReportRequest1 = new SaveNewStoreReportRequest("가게1", "주소1", List.of("착한가격업소", "모범음식점")); //정상적인 테스트 케이스 | ||
SaveNewStoreReportRequest saveNewStoreReportRequest2 = new SaveNewStoreReportRequest("가게2", "주소2", List.of("착한가격업")); //인증제 이름이 잘못되었을 때 | ||
|
||
//when | ||
Long report1Id = reportService.saveNewStoreReport(saveNewStoreReportRequest1); | ||
NewStoreReport report = (NewStoreReport) reportService.findById(report1Id); | ||
|
||
//then | ||
assertArrayEquals(report.getCertifications().toArray(), saveNewStoreReportRequest1.getCertifications().toArray()); | ||
assertThat(report.getStoreName()).isEqualTo(saveNewStoreReportRequest1.getStoreName()); | ||
assertThat(report.getFormattedAddress()).isEqualTo(saveNewStoreReportRequest1.getFormattedAddress()); | ||
assertThatThrownBy(() -> reportService.saveNewStoreReport(saveNewStoreReportRequest2)) //잘못된 인증제라서 예외가 터져야함 | ||
.isInstanceOf(GlobalException.class); | ||
} | ||
|
||
@Test | ||
public void saveSpecificStoreReport() throws Exception { | ||
//given | ||
SaveSpecificStoreReportRequest saveSpecificStoreReportRequest1 = new SaveSpecificStoreReportRequest("del", 123L, "내용1"); //정상적인 테스트 케이스 | ||
SaveSpecificStoreReportRequest saveSpecificStoreReportRequest2 = new SaveSpecificStoreReportRequest("fix", 1234L, "내용2"); //정상적인 테스트 케이스 | ||
SaveSpecificStoreReportRequest saveSpecificStoreReportRequest3 = new SaveSpecificStoreReportRequest("xxx", 12345L, "내용3"); //잘못된 dtype | ||
|
||
//when | ||
Long report1Id = reportService.saveSpecificStoreReport(saveSpecificStoreReportRequest1); | ||
Long report2Id = reportService.saveSpecificStoreReport(saveSpecificStoreReportRequest2); | ||
DelSpecificStoreReport report1 = (DelSpecificStoreReport) reportService.findById(report1Id); | ||
FixSpecificStoreReport report2 = (FixSpecificStoreReport) reportService.findById(report2Id); | ||
|
||
//then | ||
assertThat(report1.getStoreId()).isEqualTo(saveSpecificStoreReportRequest1.getStoreId()); | ||
assertThat(report2.getContents()).isEqualTo(saveSpecificStoreReportRequest2.getContents()); | ||
assertThatThrownBy(() -> reportService.saveSpecificStoreReport(saveSpecificStoreReportRequest3)) //잘못된 dtype이라서 예외가 터져야함 | ||
.isInstanceOf(GlobalException.class); | ||
} | ||
|
||
@Test | ||
public void findById() throws Exception { | ||
//given | ||
SaveNewStoreReportRequest saveNewStoreReportRequest1 = new SaveNewStoreReportRequest("가게1", "주소1", List.of("착한가격업소", "모범음식점")); //정상적인 테스트 케이스 | ||
SaveSpecificStoreReportRequest saveSpecificStoreReportRequest1 = new SaveSpecificStoreReportRequest("del", 123L, "내용1"); //정상적인 테스트 케이스 | ||
|
||
//when | ||
Long report1Id = reportService.saveNewStoreReport(saveNewStoreReportRequest1); | ||
Long report2Id = reportService.saveSpecificStoreReport(saveSpecificStoreReportRequest1); | ||
NewStoreReport report1 = (NewStoreReport) reportService.findById(report1Id); | ||
DelSpecificStoreReport report2 = (DelSpecificStoreReport) reportService.findById(report2Id); | ||
|
||
//then | ||
assertThat(report1.getFormattedAddress()).isEqualTo(saveNewStoreReportRequest1.getFormattedAddress()); | ||
assertArrayEquals(report1.getCertifications().toArray(), saveNewStoreReportRequest1.getCertifications().toArray()); | ||
assertThat(report1.getStoreName()).isEqualTo(saveNewStoreReportRequest1.getStoreName()); | ||
assertThat(report2.getContents()).isEqualTo(saveSpecificStoreReportRequest1.getContents()); | ||
assertThat(report2.getStoreId()).isEqualTo(saveSpecificStoreReportRequest1.getStoreId()); | ||
} | ||
|
||
@Test | ||
public void findAll() throws Exception { | ||
//given | ||
SaveNewStoreReportRequest saveNewStoreReportRequest1 = new SaveNewStoreReportRequest("가게1", "주소1", List.of("착한가격업소", "모범음식점")); //정상적인 테스트 케이스 | ||
SaveSpecificStoreReportRequest saveSpecificStoreReportRequest1 = new SaveSpecificStoreReportRequest("del", 123L, "내용1"); //정상적인 테스트 케이스 | ||
|
||
//when | ||
Long report1Id = reportService.saveNewStoreReport(saveNewStoreReportRequest1); | ||
Long report2Id = reportService.saveSpecificStoreReport(saveSpecificStoreReportRequest1); | ||
|
||
List<Report> reports = reportService.findAll(); | ||
List<Long> reportIds = reports.stream().map(Report::getId).toList(); | ||
|
||
//then | ||
assertArrayEquals(reportIds.toArray(), List.of(report1Id, report2Id).toArray()); | ||
|
||
} | ||
|
||
} |
49 changes: 49 additions & 0 deletions
49
src/test/java/com/nainga/nainga/domain/store/application/StoreServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package com.nainga.nainga.domain.store.application; | ||
|
||
import com.nainga.nainga.domain.store.dao.StoreRepository; | ||
import com.nainga.nainga.domain.store.domain.Store; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
|
||
@SpringBootTest | ||
@Transactional | ||
class StoreServiceTest { | ||
|
||
@Autowired | ||
StoreService storeService; | ||
|
||
@Autowired | ||
StoreRepository storeRepository; | ||
|
||
@Test | ||
public void autocorrect() throws Exception { //검색어 자동 완성 기능에 대한 테스트 | ||
//given | ||
Store store1 = Store.builder() | ||
.displayName("^") | ||
.build(); | ||
Store store2 = Store.builder() | ||
.displayName("^^") | ||
.build(); | ||
Store store3 = Store.builder() | ||
.displayName("^*^") | ||
.build(); | ||
storeRepository.save(store1); | ||
storeRepository.save(store2); | ||
storeRepository.save(store3); | ||
|
||
//when | ||
List<String> result1 = storeService.autocorrect("^"); | ||
List<String> result2 = storeService.autocorrect("^^"); | ||
|
||
//then | ||
assertArrayEquals(result1.toArray(), List.of("^", "^^", "^*^").toArray()); | ||
assertArrayEquals(result2.toArray(), List.of("^^").toArray()); | ||
} | ||
} |
Submodule backend-submodule
updated
from 732770 to c741a7