Skip to content

Commit ebc727e

Browse files
authored
메인 머지 (10/16) - Merge pull request #390
메인 머지 (10/16)
2 parents 63a1923 + 8c076fe commit ebc727e

File tree

8 files changed

+614
-45
lines changed

8 files changed

+614
-45
lines changed

back/src/main/java/com/back/domain/mentoring/mentoring/entity/Mentoring.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ public void updateTags(List<Tag> tags) {
5252

5353
if (tags != null) {
5454
tags.forEach(tag ->
55-
this.mentoringTags.add(new MentoringTag(this, tag))
55+
this.mentoringTags.add(
56+
MentoringTag.builder()
57+
.mentoring(this)
58+
.tag(tag)
59+
.build()
60+
)
5661
);
5762
}
5863
}

back/src/main/java/com/back/domain/mentoring/mentoring/entity/Tag.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
@Getter
1212
@NoArgsConstructor
1313
public class Tag extends BaseEntity {
14-
@Column(length = 50, nullable = false, unique = true)
14+
@Column(length = 50, nullable = false)
1515
private String name;
1616

1717
@Builder

back/src/main/java/com/back/domain/mentoring/mentoring/service/MentoringService.java

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import java.io.IOException;
2525
import java.util.ArrayList;
2626
import java.util.List;
27-
import java.util.Set;
27+
import java.util.Map;
2828
import java.util.stream.Collectors;
2929

3030
@Service
@@ -123,33 +123,51 @@ private List<Tag> getOrCreateTags(List<String> tagNames) {
123123
return new ArrayList<>();
124124
}
125125

126-
// 기존 태그 조회
127-
List<Tag> existingTags = tagRepository.findByNameIn(tagNames);
128-
129-
Set<String> existingNames = existingTags.stream()
130-
.map(Tag::getName)
131-
.collect(Collectors.toSet());
126+
// 1. 동일한 사용자의 태그 중복 제거
127+
List<String> distinctNames = tagNames.stream()
128+
.map(String::trim)
129+
.filter(name -> !name.isEmpty())
130+
.distinct()
131+
.toList();
132132

133-
// 신규 태그 생성
134-
List<Tag> newTags = createNewTags(tagNames, existingNames);
133+
// 2. 기존 태그 조회 - MySQL collation에 의해 대소문자 무시
134+
Map<String, Tag> tagMap = tagRepository.findByNameIn(distinctNames).stream()
135+
.collect(Collectors.toMap(
136+
Tag::getName,
137+
tag -> tag, (t1, t2) -> t1)
138+
);
135139

136-
// 기존 태그 + 신규 태그
137-
List<Tag> allTags = new ArrayList<>(existingTags);
138-
allTags.addAll(newTags);
140+
return buildTagList(distinctNames, tagMap);
141+
}
139142

140-
return allTags;
143+
/**
144+
* 기존 태그 + 신규 태그
145+
* - 정확히 일치하는 건 재사용 (대소문자 구분)
146+
* - 없을 경우 신규 태그 생성
147+
*/
148+
private List<Tag> buildTagList(List<String> distinctNames, Map<String, Tag> tagMap) {
149+
List<Tag> result = new ArrayList<>();
150+
for (String name : distinctNames) {
151+
Tag tag = tagMap.getOrDefault(name, createTagSafely(name));
152+
if (tag != null) {
153+
result.add(tag);
154+
}
155+
}
156+
return result;
141157
}
142158

143-
private List<Tag> createNewTags(List<String> tagNames, Set<String> existingNames) {
144-
List<Tag> newTags = tagNames.stream()
145-
.filter(name -> !existingNames.contains(name))
146-
.map(name -> Tag.builder().name(name).build())
147-
.toList();
159+
private Tag createTagSafely(String name) {
160+
// 생성 전 재조회로 중복 방지
161+
Tag existing = tagRepository.findByNameIn(List.of(name)).stream()
162+
.filter(tag -> tag.getName().equals(name))
163+
.findFirst()
164+
.orElse(null);
148165

149-
if (!newTags.isEmpty()) {
150-
tagRepository.saveAll(newTags);
166+
if (existing != null) {
167+
return existing;
151168
}
152-
return newTags;
169+
170+
return tagRepository.save(Tag.builder().name(name).build());
153171
}
154172

155173

back/src/main/java/com/back/domain/mentoring/reservation/service/ReservationService.java

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,24 +71,28 @@ public ReservationResponse getReservation(Member member, Long reservationId) {
7171

7272
@Transactional
7373
public ReservationResponse createReservation(Mentee mentee, ReservationRequest reqDto) {
74-
Mentoring mentoring = mentoringStorage.findMentoring(reqDto.mentoringId());
75-
MentorSlot mentorSlot = mentoringStorage.findMentorSlot(reqDto.mentorSlotId());
74+
try {
75+
Mentoring mentoring = mentoringStorage.findMentoring(reqDto.mentoringId());
76+
MentorSlot mentorSlot = mentoringStorage.findMentorSlot(reqDto.mentorSlotId());
7677

77-
DateTimeValidator.validateStartTimeNotInPast(mentorSlot.getStartDateTime());
78-
validateMentorSlotStatus(mentorSlot, mentee);
79-
validateOverlappingTimeForMentee(mentee, mentorSlot);
78+
DateTimeValidator.validateStartTimeNotInPast(mentorSlot.getStartDateTime());
79+
validateMentorSlotStatus(mentorSlot, mentee);
80+
validateOverlappingTimeForMentee(mentee, mentorSlot);
8081

81-
Reservation reservation = Reservation.builder()
82-
.mentoring(mentoring)
83-
.mentee(mentee)
84-
.mentorSlot(mentorSlot)
85-
.preQuestion(reqDto.preQuestion())
86-
.build();
87-
reservationRepository.save(reservation);
82+
Reservation reservation = Reservation.builder()
83+
.mentoring(mentoring)
84+
.mentee(mentee)
85+
.mentorSlot(mentorSlot)
86+
.preQuestion(reqDto.preQuestion())
87+
.build();
88+
reservationRepository.save(reservation);
8889

89-
mentorSlot.updateStatus(MentorSlotStatus.PENDING);
90+
mentorSlot.updateStatus(MentorSlotStatus.PENDING);
9091

91-
return ReservationResponse.from(reservation);
92+
return ReservationResponse.from(reservation);
93+
} catch (OptimisticLockException e) {
94+
throw new ServiceException(ReservationErrorCode.CONCURRENT_RESERVATION_CONFLICT);
95+
}
9296
}
9397

9498
@Transactional

back/src/main/java/com/back/domain/roadmap/roadmap/service/JobRoadmapIntegrationServiceV3.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,6 @@ public class JobRoadmapIntegrationServiceV3 {
4444
private static final double QUALITY_NODE_COUNT_WEIGHT = 0.3; // 품질 점수: 노드 개수 가중치
4545
private static final double QUALITY_STANDARDIZATION_WEIGHT = 0.7; // 품질 점수: 표준화율 가중치
4646

47-
48-
// ========================================
49-
// Public API
50-
// ========================================
51-
5247
/**
5348
* 직업 로드맵 통합 (DB 커넥션 점유 시간 감소를 위해 AI 호출을 트랜잭션 밖에서 수행)
5449
*
@@ -67,7 +62,7 @@ public JobRoadmap integrateJobRoadmap(Long jobId) {
6762
// 3. Task prefetch (트랜잭션 외부, 읽기만 수행)
6863
Map<Long, Task> taskMap = prefetchTasks(aggregation);
6964

70-
// 4. 트리 구성 및 AI 호출 (트랜잭션 외부, 6-10분 소요)
65+
// 4. 트리 구성 및 AI 호출 (트랜잭션 외부)
7166
// 이 시간 동안 DB 커넥션은 사용하지 않음
7267
RoadmapTreeBuilder.TreeBuildResult treeResult = roadmapTreeBuilder.build(aggregation, taskMap);
7368

back/src/main/java/com/back/domain/roadmap/roadmap/service/RoadmapTreeBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ private Map<String, RoadmapNode> buildNodesFromIntegratedTexts(
149149
.learningAdvice(integratedTexts != null ? integratedTexts.learningAdvice() : null)
150150
.recommendedResources(integratedTexts != null ? integratedTexts.recommendedResources() : null)
151151
.learningGoals(integratedTexts != null ? integratedTexts.learningGoals() : null)
152-
.difficulty(avgDifficulty != null ? avgDifficulty.intValue() : null)
153-
.importance(avgImportance != null ? avgImportance.intValue() : null)
152+
.difficulty(avgDifficulty != null ? (int) Math.round(avgDifficulty) : null)
153+
.importance(avgImportance != null ? (int) Math.round(avgImportance) : null)
154154
.estimatedHours(avgEstimatedHours)
155155
.task(aggNode.task != null ? taskMap.get(aggNode.task.getId()) : null)
156156
.roadmapId(0L) // 임시 값

0 commit comments

Comments
 (0)