Skip to content

Commit

Permalink
Merge pull request #53 from Tave100Shot/46-feat-추천-문제-정보-추가하여-반환
Browse files Browse the repository at this point in the history
46 feat 추천 문제 정보 추가하여 반환
  • Loading branch information
wjd4204 authored Jan 22, 2024
2 parents 7c8b49d + f6c930c commit 74fb6fb
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
package com.api.TaveShot.domain.recommend.controller;

import com.api.TaveShot.domain.post.post.dto.response.PostResponse;
import com.api.TaveShot.domain.recommend.dto.RecProRequestDto;
import com.api.TaveShot.domain.recommend.dto.RecProResponseDto;
import com.api.TaveShot.domain.recommend.dto.RecResponseDto;
import com.api.TaveShot.domain.recommend.service.RecommendService;
import com.api.TaveShot.global.success.SuccessResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
Expand All @@ -30,9 +33,7 @@ public class RecommendController {
@Operation(summary = "사용자 기반 문제 추천", description = "해당 유저가 푼 문제들을 바탕으로" +
" 같은 티어의 사용자가 푼 문제들을 관련성이 높은 순으로 추천합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "추천 성공",
content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
schema = @Schema(implementation = PostResponse.class)))
@ApiResponse(responseCode = "200", description = "추천 성공")
})
@GetMapping("/rival")
public SuccessResponse<RecResponseDto> getUserBasedProList() throws IOException {
Expand All @@ -42,13 +43,11 @@ public SuccessResponse<RecResponseDto> getUserBasedProList() throws IOException

@Operation(summary = "태그 관련 문제 추천", description = "원하는 문제와 태그가 같은 관련성이 높은 문제를 추천합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "추천 성공",
content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
schema = @Schema(implementation = PostResponse.class)))
@ApiResponse(responseCode = "200", description = "추천 성공")
})
@GetMapping("/problem")
public SuccessResponse<RecResponseDto> getSolvedProList() throws IOException {
RecResponseDto responseDto = recommendService.getListByProblem();
public SuccessResponse<RecResponseDto> getSolvedProList(@RequestParam(value = "solvedRecentId") int solvedNumber) throws IOException {
RecResponseDto responseDto = recommendService.getListByProblem(solvedNumber);
return new SuccessResponse<>(responseDto);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.api.TaveShot.domain.recommend.converter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;

import java.util.List;

@Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {

private final ObjectMapper mapper = new ObjectMapper();

@Override
public String convertToDatabaseColumn(List<String> dataList){
try{
return mapper.writeValueAsString(dataList);
} catch(JsonProcessingException e){
throw new RuntimeException(e);
}
}

@Override
public List<String> convertToEntityAttribute(String data) {
try{
return mapper.readValue(data, List.class);
} catch (JsonProcessingException e){
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.api.TaveShot.domain.recommend.domain;

import com.api.TaveShot.domain.recommend.converter.StringListConverter;
import jakarta.persistence.*;
import lombok.*;

import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "Problem")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@AllArgsConstructor
@Builder
public class ProblemElement {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Integer problemId;

private String title;
private Integer acceptedUserCount;
private Integer bojLevel;

private String bojKey;
private String bojTagId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.api.TaveShot.domain.recommend.dto;

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;

import java.util.List;

@Getter
@ToString
@Builder
public class RecProDetailResponseDto {

private String title;
private String problemId;
private String tier;
private List<String> bojTag;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.api.TaveShot.domain.recommend.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
public class RecProRequestDto {

private int solvedRecentId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
@Builder
public class RecResponseDto {

private List<String> result;
private List<RecProDetailResponseDto> result;

private String rightCnt;
private String wrongCnt;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.api.TaveShot.domain.recommend.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
Expand All @@ -10,9 +11,19 @@
@Builder
@ToString
public class UserCrawlingDto {

@Schema(description = "유저 순위")
private String rank;

@Schema(description = "맞은 문제 수")
private String rightCnt;

@Schema(description = "틀린 문제 수")
private String wrongCnt;

@Schema(description = "유저 레벨")
private String tier;

@Schema(description = "맞은 문제 리스트")
private List<String> solvedProblemList;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.api.TaveShot.domain.recommend.repository;

import com.api.TaveShot.domain.recommend.domain.ProblemElement;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface ProblemElementRepository extends JpaRepository<ProblemElement, Long> {

@Query("select p from ProblemElement as p where p.problemId=:problemId")
ProblemElement findByProblemId(Integer problemId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

import com.api.TaveShot.domain.Member.domain.Member;
import com.api.TaveShot.domain.Member.repository.MemberRepository;
import com.api.TaveShot.domain.recommend.domain.TierCount;
import com.api.TaveShot.domain.recommend.dto.RecResponseDto;
import com.api.TaveShot.domain.recommend.dto.UserCrawlingDto;
import com.api.TaveShot.domain.recommend.dto.RecProResponseDto;
import com.api.TaveShot.domain.recommend.domain.ProblemElement;
import com.api.TaveShot.domain.recommend.dto.*;
import com.api.TaveShot.domain.recommend.repository.ProblemElementRepository;
import com.api.TaveShot.domain.recommend.repository.TierCountRepository;
import com.api.TaveShot.global.exception.ApiException;
import com.api.TaveShot.global.exception.ErrorType;
Expand All @@ -18,6 +17,10 @@
import org.springframework.web.reactive.function.client.WebClient;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
Expand All @@ -27,6 +30,7 @@ public class RecommendService {
private final CrawlingService crawlingService;
private final MemberRepository memberRepository;
private final TierCountRepository tierCountRepository;
private final ProblemElementRepository problemElementRepository;

@Value("${lambda.secret.url1}")
private String lambda1;
Expand All @@ -36,10 +40,7 @@ public class RecommendService {

// 사용자 기반 추천 서비스
public RecResponseDto getListByUser() throws IOException {
Member currentMember1 = getCurrentMember();
String bojName = currentMember1.getBojName();

UserCrawlingDto dto = crawlingService.getUserInfo(bojName);
UserCrawlingDto dto = getUserInfo();

WebClient webClient = WebClient.builder()
.baseUrl(lambda1)
Expand All @@ -53,54 +54,128 @@ public RecResponseDto getListByUser() throws IOException {

Integer tierCount = tierCountRepository.findByTier(Integer.parseInt(dto.getTier()));

List<RecProDetailResponseDto> proDetailResponseDtos = getProblemDetail(proList);

RecResponseDto responseDto = RecResponseDto.builder()
.rivalCnt(Integer.toString(tierCount))
.rightCnt(dto.getRightCnt())
.wrongCnt(dto.getWrongCnt())
.userRank(dto.getRank())
.result(proList.getResult())
.result(proDetailResponseDtos)
.build();

return responseDto;
}

// 문제 기반 추천 서비스
public RecResponseDto getListByProblem() throws IOException {
Member currentMember2 = getCurrentMember();
String bojName = currentMember2.getBojName();
public RecResponseDto getListByProblem(int solvedRecentId) throws IOException {

UserCrawlingDto dto = crawlingService.getUserInfo(bojName);
UserCrawlingDto dto = getUserInfo();

WebClient webClient = WebClient.builder()
.baseUrl(lambda2)
.build();

RecProRequestDto requestDto = RecProRequestDto.builder()
.solvedRecentId(solvedRecentId)
.build();

RecProResponseDto proList = webClient.post()
.body(BodyInserters.fromValue(dto))
.body(BodyInserters.fromValue(requestDto))
.retrieve()
.bodyToMono(RecProResponseDto.class)
.block();

Integer tierCount = tierCountRepository.findByTier(Integer.parseInt(dto.getTier()));

List<RecProDetailResponseDto> proDetailResponseDtos = getProblemDetail(proList);

RecResponseDto responseDto = RecResponseDto.builder()
.rivalCnt(Integer.toString(tierCount))
.rightCnt(dto.getRightCnt())
.wrongCnt(dto.getWrongCnt())
.userRank(dto.getRank())
.result(proList.getResult())
.result(proDetailResponseDtos)
.build();

return responseDto;
}

private Member getCurrentMember(){
public UserCrawlingDto getUserInfo() throws IOException {
Member currentMember2 = getCurrentMember();
String bojName = currentMember2.getBojName();
// String bojName = "wjdrhs3473";

UserCrawlingDto dto = crawlingService.getUserInfo(bojName);

return dto;
}

private Member getCurrentMember(){
Member currentMember = SecurityUtil.getCurrentMember();
Long currentMemberId = currentMember.getId();
return memberRepository.findById(currentMemberId)
.orElseThrow(() -> new ApiException(ErrorType._USER_NOT_FOUND_DB));
}

private String getTierName(Integer bojLevel){
String[] tiers = {"BRONZE", "SILVER", "GOLD", "PLATINUM", "DIAMOND", "RUBY", "MASTER"};
if(bojLevel <= 5)
return tiers[0];
else if(bojLevel <= 10)
return tiers[1];
else if(bojLevel <= 15)
return tiers[2];
else if(bojLevel <= 20)
return tiers[3];
else if(bojLevel <= 25)
return tiers[4];
else if(bojLevel <= 30)
return tiers[5];

return tiers[6];
}

private List<String> extractWords(String bojTags){
List<String> tags = new ArrayList<>();

Pattern pattern = Pattern.compile("\\b\\w+\\b");
Matcher matcher = pattern.matcher(bojTags);

while(matcher.find()){
tags.add(matcher.group());
}

return tags;
}

private List<RecProDetailResponseDto> getProblemDetail(RecProResponseDto proList){
List<String> result = proList.getResult();
List<RecProDetailResponseDto> proDetailResponseDto = new ArrayList<>();

// 문제 세부 정보 찾기
for(int i=0;i<15;i++){
Integer num = Integer.parseInt(result.get(i));
log.info("num:{}", num);
try {
ProblemElement problemElement = problemElementRepository.findByProblemId(num);
log.info("{}, {}, {}", problemElement.getProblemId(), problemElement.getBojLevel(), problemElement.getBojKey());
String tierName = getTierName(problemElement.getBojLevel());
List<String> tags = extractWords(problemElement.getBojKey());
RecProDetailResponseDto detailResponseDto = RecProDetailResponseDto.builder()
.title(problemElement.getTitle())
.problemId(String.valueOf(num))
.tier(tierName)
.bojTag(tags)
.build();
proDetailResponseDto.add(detailResponseDto);
} catch(Exception e){
continue;
}

}

return proDetailResponseDto;
}

}
Loading

0 comments on commit 74fb6fb

Please sign in to comment.