Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package com.econovation.third_project;

import com.econovation.second_project.HellStudyApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ThirdStudyApplication {
public static void main(String[] args) {
SpringApplication.run(ThirdStudyApplication.class, args);
}
public static void main(String[] args) {}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,79 @@
package com.econovation.third_project.controller;

import com.econovation.third_project.dto.*;
import com.econovation.third_project.service.*;
import com.econovation.third_project.database.Database;
import com.econovation.third_project.database.Registration;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Controller
@RequiredArgsConstructor
public class AdminQueryController {
private final Database database;
private final ApplicantQueryService applicantQueryService;
private final MajorQueryService majorQueryService;
private final SupportPathQueryService supportPathQueryService;
private final HopeFieldQueryService hopeFieldQueryService;
private final DesiredTimeQueryService desiredTimeQueryService;

// 예시 코드
@PostMapping("/registration")
public ResponseEntity<Object> postRegistrate(@RequestBody Registration registration) {
database.register(registration);
return ResponseEntity.ok().build();
}
@GetMapping("/registration")
public ResponseEntity<Registration> getRegistration(String userId) {
return ResponseEntity.ok().body(database.getRegistration(userId));


@GetMapping("/admin/{applicants}/{majors}/{programmers}/{path}/{desiredTime}")
public ResponseEntity<AdminQueryResponse> getAdmin(
@PathVariable(required = false) String applicants,
@PathVariable(required = false) String majors,
@PathVariable(required = false) String programmers,
@PathVariable(required = false) String path,
@PathVariable(required = false) String desiredTime) throws ExecutionException, InterruptedException {
Comment on lines +38 to +44
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

값을 여러개 받아올 때는 PathVariable보다 RequestParam이 더 낫지않나요?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

url이 너무 어지러워요~~ 특히나 앞에 리소스 명시도 없이 계속 데이터를 받으면 그게 무슨 데이터인지 알 수가 없습니다.
최소한 /admin/applicants/{applicants}/majors/{majors}/programmers/{programmers}/path ... 이런식으로 하셔야합니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그러네요. 프론트 입장에서 어떤 데이터인지 알기 힘들 것 같네요. RequestParam을 사용하는 게 더 나은 선택지 같습니다.


CompletableFuture<List<ApplicantDTO>> applicantFuture = applicants.isEmpty()
? null
: CompletableFuture.supplyAsync(() -> applicantQueryService.execute());

CompletableFuture<List<MajorDTO>> majorFuture = majors.isEmpty()
? null
: CompletableFuture.supplyAsync(() -> majorQueryService.execute());

CompletableFuture<List<ProgrammerFieldDTO>> programmerFuture = programmers.isEmpty()
? null
: CompletableFuture.supplyAsync(() -> hopeFieldQueryService.execute());

CompletableFuture<List<PathDTO>> pathFuture = path.isEmpty()
? null
: CompletableFuture.supplyAsync(() -> supportPathQueryService.execute());

CompletableFuture<List<DesiredTimeDTO>> desiredTimeFuture = desiredTime.isEmpty()
? null
: CompletableFuture.supplyAsync(() -> desiredTimeQueryService.execute());

CompletableFuture<AdminQueryResponse> completableFuture = CompletableFuture.allOf(applicantFuture, majorFuture, programmerFuture, pathFuture, desiredTimeFuture)
.thenApply(Void -> AdminQueryResponse.builder()
.applicants(applicantFuture.join())
.majors(majorFuture.join())
.programmers(programmerFuture.join())
.path(pathFuture.join())
.desiredTime(desiredTimeFuture.join())
.build());
Comment on lines +46 to +73
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컨트롤러에서 집계를 하지 마세요 집계 클래스를 따로 만드시는게 좋겠습니다.
Future를 이용한 집계를 도입한 부분이 인상적입니다.
future null join이 가능한가요? NPE가 발생하지 않나요?

최대한 nul을 대놓고 바인딩하는 것은 정말 위험합니다.
이런 경우 코드가 좀 길어질 수는 있겠지만 .handler 로 null 을 만날 경우 별도의 처리를 해주는 것도 방법이겠죠.

이렇게 코드를 짠 궁극적인 원인은 이미 response 클래스가 고정적으로 변수를 선언됐기 때문이겠죠. 거기부터 다시 생각해봅시다.

Copy link
Collaborator Author

@hwangdaesun hwangdaesun May 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

집계 관련 유틸 클래스를 만드는 게 좋을 것 같네요 감사합니다!

allOf 메서드에서 null을 만나면 NPE가 발생합니다. 말씀하신 것처럼 null일 경우 allOf 메서드에 해당 객체가 가지 않도록 코드를 수정해야겠네요.

response 클래스를 Map 을 사용하지 않은 이유는 아래와 같습니다.

https://www.inflearn.com/questions/626856/api-%EC%9D%91%EB%8B%B5%EC%9C%BC%EB%A1%9C-map-%EC%82%AC%EC%9A%A9%EC%9D%84-%EC%A7%80%EC%96%91%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0

위의 이유들로 인해 Map을 사용하지 않고 DTO 응답 클래스를 생성하였습니다.


return ResponseEntity.ok().body(completableFuture.get());
}


}
34 changes: 31 additions & 3 deletions src/main/java/com/econovation/third_project/database/Database.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.econovation.third_project.database;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*;

import org.springframework.stereotype.Component;

/**
Expand All @@ -25,4 +24,33 @@ public void register(Registration registrationRequest) {
public Registration getRegistration(String userId) {
return registration.get(userId);
}

public List<Registration> getAllRegistration(){
return registration.keySet().stream().map(
key -> registration.get(key)
).toList();
}

public List<PersonalInformation> getAllPersonalInformation(){
return personalInformation.keySet().stream().map(
key -> personalInformation.get(key)
).toList();
}

public List<PersonalInformation> getPersonalInformation(List<String> keys){
return keys.stream().map(key -> personalInformation.get(key)).toList();
}

public List<Path> getAllPath(){
return path.keySet().stream().map(
key -> path.get(key)
).toList();
}

public List<DesiredTime> getAllDesiredTime(){
return desiredTime.keySet().stream().map(
key -> desiredTime.get(key)
).toList();
}

Comment on lines +28 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map의 values 함수를 사용하면 stream을 사용하지 않고 모든 Registration, Path, DesiredTime 등을 불러올 수 있을 것 같네요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 그러네요!! 감사합니다

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.econovation.third_project.database;

import java.util.List;

import com.econovation.third_project.domain.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class DesiredTime {
String registrationId;
private String personalInfoId;
// 희망 시간 (11 * 3)의 테이블 형태를 준수합니다.
private List<int[]> desiredTime;
private List<Table> desiredTime;

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.econovation.third_project.database;

import com.econovation.third_project.domain.SupportPath;
import lombok.AllArgsConstructor;
import lombok.Getter;

Expand All @@ -8,5 +9,5 @@
public class Path {
String registrationId;
// 지원 경로
private String supportPath;
private SupportPath supportPath;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.econovation.third_project.database;

import com.econovation.third_project.domain.Major;
import lombok.AllArgsConstructor;
import lombok.Getter;

Expand All @@ -24,12 +25,12 @@ public class PersonalInformation {
private Integer semester;

// 전공
private String major;
private Major major;

// 복수전공
private String doubleMajor;
private Major doubleMajor;
// 부전공
private String minor;
private Major minor;



Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
package com.econovation.third_project.database;

import com.econovation.third_project.domain.HopeField;
import com.econovation.third_project.domain.ProgrammerField;
import lombok.Getter;

@Getter
public class Registration {

private Long registrationId;
// 희망분야
private String hopeField;
private HopeField hopeField;

// 1지망
private String firstPriority;
private ProgrammerField firstPriority;

// 2지망
private String secondPriority;
private ProgrammerField secondPriority;

public Registration(String hopeField, String firstPriority, String secondPriority) {
this.hopeField = hopeField;
this.firstPriority = firstPriority;
this.secondPriority = secondPriority;
this.hopeField = HopeField.valueOf(hopeField);
this.firstPriority = ProgrammerField.valueOf(firstPriority);
this.secondPriority = ProgrammerField.valueOf(secondPriority);
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/econovation/third_project/domain/HopeField.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.econovation.third_project.domain;

public enum HopeField {

개발자,기획자,디자이너;

public Boolean isProgrammer(HopeField hopeField){
return hopeField.name().equals(HopeField.개발자);
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/econovation/third_project/domain/Major.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.econovation.third_project.domain;

public enum Major {
산업공학과,소프트웨어공학과,컴퓨터정보통신공학과,Iot인공지능융합전공,디자인학과
}
Comment on lines +3 to +5
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전공무관인 만큼 다양한 전공이 있을 수 있는데 이것을 enum으로 관리하는건 적절하지 않다고 봐요
미처 enum으로 정의하지 않은 학과에서 동아리 지원을 한다면...?

Copy link
Collaborator Author

@hwangdaesun hwangdaesun May 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum으로 전공을 관리하였을 때 제가 생각하는 장단점은 아래와 같습니다.

장점

  • Enum을 이용하여 Validation을 할 수 있다. 즉, 존재하지 않는 학과를 걸러낼 수 있습니다.
  • 싱글톤이라 메모리를 절약할 수 있다.

만약 정의 되어 있지 않거나 잘못된 학과(산업공학과가 아닌 산ㅋ공ㅋ업과) 이런 식으로 온다면, 잘못된 값이 저장되는 것도 문제고 이를 집계하는 것 또한 어렵다고 판단해서, Enum으로 명시적으로 관리하는 게 좋다고 생각했습니다.

단점

  • Enum으로 정의할 학과들이 너무 많다.
  • 너무 많아서 정의하지 못한 학과들이 있을 수 있다.
  • 확장에 취약하다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.econovation.third_project.domain;

public enum ProgrammerField {
WEB,APP,AI,GAME,IoT,AR_VR
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.econovation.third_project.domain;

public enum SupportPath {
홍보_포스터,학교_공지사항,지인소개,인스타그램,에브리타임
}
Comment on lines +3 to +5
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

경로에 제 기억으로는 기타가 있었던 걸로 기억합니다.. 기타에 유튜브 보고 왔음 라고 했을 때 어떻게 하실거죠?

Copy link
Collaborator Author

@hwangdaesun hwangdaesun May 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

�음.. 문제에서 기타라는 항목은 찾지 못 했습니다.
다만, 확장에 취약하네요.

만약, 기타를 선택할 수 있고, 기타를 문자열로 무언가를 적을 수 있을 경우는 지원 경로는 enum으로 관리하고 기타 유튜브 보고 왔음은 따로 저장해야할 것 같네요.

24 changes: 24 additions & 0 deletions src/main/java/com/econovation/third_project/domain/Table.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.econovation.third_project.domain;

import lombok.Getter;

@Getter
public enum Table {
zerozero(0,0),zeroone(0,1),zerotwo(0,2),zerothree(0,3),zerofour(0,4),zerofive(0,5),zerosix(0,6),zeroseven(0,7),zeroeight(0,8),zeronine(0,9),zeroten(0,10),
onezero(1,0),oneone(1,1),onetwo(1,2),onethree(1,3),onefour(1,4),onefive(1,5),onesix(1,6),oneseven(1,7),oneeight(1,8),onenine(1,9),oneten(1,10),
twozero(2,0),twoone(2,1),twotwo(2,2),twothree(2,3),twofour(2,4),twofive(2,5),twosix(2,6),twoseven(2,7),twoeight(2,8),twonine(2,9),twoten(10,10),
;

private Integer row;
private Integer column;


Table(Integer row, Integer column) {
this.row = row;
this.column = column;
}

public int[] toArray(){
return new int[]{this.getRow(), this.getColumn()};
}
}
Comment on lines +7 to +24
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DesiredTime을 int[]로도 적용할 수 있는데 Enum을 채택하신 이유가 있을까요?? Enum으로 했을 때 어떤 장점이 있을까요?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

뭔가 싱글톤 개념으로 이점이 있을 것 같았는데 아래 코드들을 더 읽어보니 toArray를 호출하면서 새로운 int[]배열을 만들어 주고 있네요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FlyWeight 패턴을 적용해서 메모리를 절약하는 게 목표였습니다.

코드를 좀 수정해서 아래처럼 작성해야할 것 같네요

  @Getter
  public enum Table {
      zerozero(new int[]{1,1})
      ;
  
      private int[] time;
  
      Table(int[] time) {
          this.time = time;
      }
   }

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.econovation.third_project.dto;

import lombok.Builder;

import java.util.List;

public record AdminQueryResponse(
List<ApplicantDTO> applicants,
List<MajorDTO> majors,
List<ProgrammerFieldDTO> programmers,
List<PathDTO> path,
List<DesiredTimeDTO> desiredTime
) {

@Builder
public AdminQueryResponse {
}


}
19 changes: 19 additions & 0 deletions src/main/java/com/econovation/third_project/dto/ApplicantDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.econovation.third_project.dto;

import lombok.Builder;

public record ApplicantDTO(
String hopeField,
Integer count
) {
@Builder
public ApplicantDTO {
}

public static ApplicantDTO of(String type, Integer count){
return ApplicantDTO.builder()
.hopeField(type)
.count(count)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.econovation.third_project.dto;

import com.econovation.third_project.database.PersonalInformation;
import com.econovation.third_project.domain.Table;
import lombok.Builder;
import java.util.List;

public record DesiredTimeDTO(
int[] table,
Integer countOfTime,
List<PersonalInformation> personalInformations
) {
@Builder
public DesiredTimeDTO {
}

public static DesiredTimeDTO of(Table table, Integer countOfTime, List<PersonalInformation> personalInformations){
return DesiredTimeDTO.builder()
.table(table.toArray())
.countOfTime(countOfTime)
.personalInformations(personalInformations)
.build();
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/econovation/third_project/dto/MajorDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.econovation.third_project.dto;

import lombok.Builder;

public record MajorDTO(
String major,
Integer count
) {
@Builder
public MajorDTO {
}

public static MajorDTO of(String major, Integer count){
return MajorDTO.builder()
.count(count)
.major(major)
.build();
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/econovation/third_project/dto/PathDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.econovation.third_project.dto;

import lombok.Builder;

public record PathDTO(
String pathName,
Integer count
) {

@Builder
public PathDTO {
}

public static PathDTO of(String pathName, Integer count){
return PathDTO.builder()
.pathName(pathName)
.count(count)
.build();
}
}
Loading