미니프로젝트 1단계
프로젝트 설정
dependencies {
// Data JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// WEB
implementation 'org.springframework.boot:spring-boot-starter-web'
// Lombok
implementation 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
// MySQL
runtimeOnly 'com.mysql:mysql-connector-j'
// Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// MockMvc
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
// Valid
implementation 'org.springframework.boot:spring-boot-starter-validation'
//QueryDSL
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
//QClass
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}
구현 기능
- 팀 등록 기능
- 직원 등록 기능
- 팀 조회 기능
- 직원 조회 기능
팀 기능 구현
팀 등록
회사에 있는 팀을 등록할 수 있습니다.
팀 이름은 필수 값입니다.
POST http://localhost:8080/api/v1/team
Content-Type: application/json
{
"name": "팀명"
}
팀 조회
팀 조회기능은 아래 API를 통해서 조회가 가능합니다.
GET http://localhost:8080/api/v1/team/list
DTO
@Getter
public class EmployeeCreateRequest {
private String name;
private ROLE role;
private LocalDate joinDate;
private LocalDate birthday;
private String teamName;
public EmployeeCreateRequest() {
}
@Builder
private EmployeeCreateRequest(final String name, final ROLE role, final LocalDate joinDate, final LocalDate birthday, String teamName) {
this.name = name;
this.role = role;
this.joinDate = joinDate;
this.birthday = birthday;
this.teamName = teamName;
}
public boolean hasTeam() {
if (teamName == null || teamName.isBlank()) {
return false;
}
return true;
}
}
Controller
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
private final EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@GetMapping("/employee/list")
public ApiResponse<List<EmployeeProfileResponse>> getEmployeeProfileAll() {
return ApiResponse.ok(employeeService.getEmployeeProfileAll());
}
@PostMapping("/employee")
public ApiResponse<Long> joinEmployee(@RequestBody EmployeeCreateRequest request) {
return ApiResponse.ok(employeeService.joinEmployee(request));
}
}
Service Dto
@Getter
@NoArgsConstructor
@ToString
public class TeamProfileResponse {
private String name;
private String manager;
private Long memberCount;
public TeamProfileResponse(final String name, final String manager, final Long memberCount) {
this.name = name;
this.manager = manager;
this.memberCount = memberCount;
}
}
Service
@Service
public class EmployeeService {
private final EmployeeRepository employeeRepository;
private final TeamRepository teamRepository;
EmployeeService(EmployeeRepository employeeRepository, TeamRepository teamRepository) {
this.employeeRepository = employeeRepository;
this.teamRepository = teamRepository;
}
public long joinEmployee(EmployeeCreateRequest request) {
Employee employee = Employee.create(request.getName(), request.getRole(), request.getJoinDate(), request.getBirthday());
ifHasTeamThenJoinTeam(request, employee);
return employeeRepository.save(employee);
}
private void ifHasTeamThenJoinTeam(EmployeeCreateRequest request, Employee employee) {
if (request.hasTeam()) {
Team team = teamRepository.findByName(request.getTeamName())
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 팀명입니다."));
employee.joinTeam(team.getId());
}
}
public List<EmployeeProfileResponse> getEmployeeProfileAll() {
return employeeRepository.getEmployeeProfileAll();
}
}
Team Repository
public interface TeamJpaRepository extends JpaRepository<Team, Long>{
Optional<Team> findByName(String name);
@Query("select " +
"new org.example.miniinflearn.api.team.service.response.TeamProfileResponse(" +
"t.name, " +
"function('listagg', case when e.role = MANAGER then e.name else null end,','),"+
"SUM(CASE WHEN e.teamId is not null then 1L ELSE 0L END)) " +
"from Team as t " +
"left join Employee as e on t.id = e.teamId GROUP BY t.name")
List<TeamProfileResponse> getTeamProfile();
}
TestCode
Service
@SpringBootTest
public class EmployeeServiceTest {
@Autowired
private EmployeeService employeeService;
@Autowired
private TeamService teamService;
@Test
@DisplayName("직원을 등록할 수 있다.")
void joinEmployee() {
// given
String name = "둘리";
ROLE role = ROLE.MANAGER;
LocalDate joinDate = LocalDate.now();
LocalDate birthday = LocalDate.of(2000, 3, 4);
EmployeeCreateRequest request = getEmployeeCreateRequest(name, role, joinDate, birthday);
// when
long joinEmployeeId = employeeService.joinEmployee(request);
// then
Assertions.assertThat(joinEmployeeId).isEqualTo(1L);
}
private EmployeeCreateRequest getEmployeeCreateRequest(String name, ROLE role, LocalDate joinDate, LocalDate birthday) {
return EmployeeCreateRequest.builder()
.name(name)
.role(role)
.joinDate(joinDate)
.birthday(birthday)
.build();
}
@Test
@DisplayName("팀원 정보를 모두 조회할 수 있다.")
void getMemberAll() {
//given
teamService.addTeam("팀A");
teamService.addTeam("팀B");
employeeService.joinEmployee(getEmployeeCreateRequest("팀A", "매니저-둘리", ROLE.MANAGER, LocalDate.of(1998, 8, 1), LocalDate.of(2024, 1, 1)));
employeeService.joinEmployee(getEmployeeCreateRequest("팀A", "직원-둘리", ROLE.MEMBER, LocalDate.of(1997, 8, 1), LocalDate.of(2024, 3, 1)));
//when
List<EmployeeProfileResponse> responses = employeeService.getEmployeeProfileAll();
for (EmployeeProfileResponse respons : responses) {
System.out.println("respons = " + respons);
}
//then
Assertions.assertThat(responses).hasSize(2);
Assertions.assertThat(responses)
.extracting("name", "teamName", "role", "birthday", "workStartDate")
.containsExactlyInAnyOrder(
Assertions.tuple("매니저-둘리", "팀A", "MANAGER", "1998-08-01", "2024-01-01"),
Assertions.tuple("직원-둘리", "팀A", "MEMBER", "1997-08-01", "2024-03-01")
);
}
private EmployeeCreateRequest getEmployeeCreateRequest(String teamName, String name, ROLE role, LocalDate birthday, LocalDate workStartDate) {
return EmployeeCreateRequest.builder()
.teamName(teamName)
.name(name)
.role(role)
.birthday(birthday)
.joinDate(workStartDate)
.build();
}
}
Controller
@WebMvcTest(controllers = TeamController.class)
class TeamControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private TeamService teamService;
@Test
@DisplayName("팀 이름은 필수 값이다.")
void c1() throws Exception {
//given
CreateTeamRequest request = new CreateTeamRequest("팀");
//when
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/team")
.content(objectMapper.writeValueAsString(request))
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value("200"));
}
@Test
@DisplayName("팀 이름이 공백일 경우 예외가 발생한다.")
void c2() throws Exception {
//given
CreateTeamRequest request = new CreateTeamRequest("");
//when
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/team")
.content(objectMapper.writeValueAsString(request))
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value("400"))
.andExpect(MockMvcResultMatchers.jsonPath("$.body").value("FAIL"))
.andExpect(MockMvcResultMatchers.jsonPath("$.message").value("팀명은 공백이나 null이 들어올 수 없습니다."));
}
}
직원 기능 구현
직원 조회
직원 조회 기능은 아래 API를 통해서 조회가 가능합니다.
GET http://localhost:8080/api/v1/employee/list
직원 등록
직우너 등록 기능은 아래 API를 통해서 등록이 가능합니다.
POST http://localhost:8080/api/v1/employee
Content-Type: application/json
{
"name": "직원이름",
"teamName": "소속 팀 이름"
"role": "MANAGER",
"birthday": "1998-01-01",
"workStartDate": "2024-01-01",
}
DTO
@Getter
public class EmployeeCreateRequest {
private String name;
private ROLE role;
private LocalDate joinDate;
private LocalDate birthday;
private String teamName;
public EmployeeCreateRequest() {
}
@Builder
private EmployeeCreateRequest(final String name, final ROLE role, final LocalDate joinDate, final LocalDate birthday, String teamName) {
this.name = name;
this.role = role;
this.joinDate = joinDate;
this.birthday = birthday;
this.teamName = teamName;
}
public boolean hasTeam() {
if (teamName == null || teamName.isBlank()) {
return false;
}
return true;
}
}
Controller
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
private final EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@GetMapping("/employee/list")
public ApiResponse<List<EmployeeProfileResponse>> getEmployeeProfileAll() {
return ApiResponse.ok(employeeService.getEmployeeProfileAll());
}
@PostMapping("/employee")
public ApiResponse<Long> joinEmployee(@RequestBody EmployeeCreateRequest request) {
return ApiResponse.ok(employeeService.joinEmployee(request));
}
}
Service Dto
@Getter
@AllArgsConstructor
@ToString
public class EmployeeProfileResponse {
private String name;
private String teamName;
private String role;
private String birthday;
private String workStartDate;
}
Service
@Service
public class EmployeeService {
private final EmployeeRepository employeeRepository;
private final TeamRepository teamRepository;
EmployeeService(EmployeeRepository employeeRepository, TeamRepository teamRepository) {
this.employeeRepository = employeeRepository;
this.teamRepository = teamRepository;
}
public long joinEmployee(EmployeeCreateRequest request) {
Employee employee = Employee.create(request.getName(), request.getRole(), request.getJoinDate(), request.getBirthday());
ifHasTeamThenJoinTeam(request, employee);
return employeeRepository.save(employee);
}
private void ifHasTeamThenJoinTeam(EmployeeCreateRequest request, Employee employee) {
if (request.hasTeam()) {
Team team = teamRepository.findByName(request.getTeamName())
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 팀명입니다."));
employee.joinTeam(team.getId());
}
}
public List<EmployeeProfileResponse> getEmployeeProfileAll() {
return employeeRepository.getEmployeeProfileAll();
}
}
Repository
public interface EmployeeJpaRepository extends JpaRepository<Employee, Long> {
@Query("select " +
"new org.example.miniinflearn.api.employee.service.EmployeeProfileResponse(" +
"e.name,t.name,str(e.role),cast(e.birthday as String),cast(e.workStartDate as String))" +
"from Employee as e left join Team as t on e.teamId = t.id")
List<EmployeeProfileResponse> getEmployeeProfileAll();
}
Employee Test Code
@SpringBootTest
public class EmployeeServiceTest {
@Autowired
private EmployeeService employeeService;
@Autowired
private TeamService teamService;
@Test
@DisplayName("직원을 등록할 수 있다.")
void joinEmployee() {
// given
String name = "둘리";
ROLE role = ROLE.MANAGER;
LocalDate joinDate = LocalDate.now();
LocalDate birthday = LocalDate.of(2000, 3, 4);
EmployeeCreateRequest request = getEmployeeCreateRequest(name, role, joinDate, birthday);
// when
long joinEmployeeId = employeeService.joinEmployee(request);
// then
Assertions.assertThat(joinEmployeeId).isEqualTo(1L);
}
private EmployeeCreateRequest getEmployeeCreateRequest(String name, ROLE role, LocalDate joinDate, LocalDate birthday) {
return EmployeeCreateRequest.builder()
.name(name)
.role(role)
.joinDate(joinDate)
.birthday(birthday)
.build();
}
@Test
@DisplayName("팀원 정보를 모두 조회할 수 있다.")
void getMemberAll() {
//given
teamService.addTeam("팀A");
teamService.addTeam("팀B");
employeeService.joinEmployee(getEmployeeCreateRequest("팀A", "매니저-둘리", ROLE.MANAGER, LocalDate.of(1998, 8, 1), LocalDate.of(2024, 1, 1)));
employeeService.joinEmployee(getEmployeeCreateRequest("팀A", "직원-둘리", ROLE.MEMBER, LocalDate.of(1997, 8, 1), LocalDate.of(2024, 3, 1)));
//when
List<EmployeeProfileResponse> responses = employeeService.getEmployeeProfileAll();
for (EmployeeProfileResponse respons : responses) {
System.out.println("respons = " + respons);
}
//then
Assertions.assertThat(responses).hasSize(2);
Assertions.assertThat(responses)
.extracting("name", "teamName", "role", "birthday", "workStartDate")
.containsExactlyInAnyOrder(
Assertions.tuple("매니저-둘리", "팀A", "MANAGER", "1998-08-01", "2024-01-01"),
Assertions.tuple("직원-둘리", "팀A", "MEMBER", "1997-08-01", "2024-03-01")
);
}
private EmployeeCreateRequest getEmployeeCreateRequest(String teamName, String name, ROLE role, LocalDate birthday, LocalDate workStartDate) {
return EmployeeCreateRequest.builder()
.teamName(teamName)
.name(name)
.role(role)
.birthday(birthday)
.joinDate(workStartDate)
.build();
}
}
'스터디공부 > 인프런 워밍업' 카테고리의 다른 글
인프런 워밍업 스터디 일곱 번째 과제! (진도표 7일차) (0) | 2024.02.27 |
---|---|
인프런 워밍업 0기 여섯 번째 과제! (진도표 6일차) (0) | 2024.02.26 |
인프런 워밍업 5일차 과제 (0) | 2024.02.23 |
인프런 워밍업 4일차 과제 제출 (0) | 2024.02.22 |
인프런 워밍업 3일차 과제 (0) | 2024.02.21 |