Skip to content

Commit

Permalink
Merge pull request #39 from RecruitUs/feat/#32-recruitingPostFiltering
Browse files Browse the repository at this point in the history
[FEAT]#32 채용공고 필터 검색기능 구현
  • Loading branch information
DryRains authored Sep 1, 2023
2 parents f69a509 + 8e07e5d commit ceac466
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 18 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies {

// jpa
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.hibernate:hibernate-core:5.5.6.Final' //use Hibernate for implementation of JPA

// Swagger
implementation 'io.springfox:springfox-boot-starter:3.0.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@
import com.example.rcp1.domain.user.domain.User;
import com.example.rcp1.domain.user.domain.repository.UserRepository;
import com.example.rcp1.global.config.security.util.JwtUtil;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.*;
import lombok.RequiredArgsConstructor;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
Expand All @@ -33,6 +35,7 @@ public class RecruitmentService {
private final FieldRepository fieldRepository;
private final HeartRepository heartRepository;
private final ModelMapper modelMapper = new ModelMapper();
private final EntityManager entityManager;

@Transactional
public Post createRecruitmentPost(String token, PostReqDTO postDTO) {
Expand All @@ -50,6 +53,7 @@ public Post createRecruitmentPost(String token, PostReqDTO postDTO) {
.compensation_applicant(postDTO.getCompensation_applicant())
.dueDate(postDTO.getDueDate())
.content(postDTO.getContent())
.required_career(postDTO.getRequired_career())
.working_address(postDTO.getWorking_address())
.status("A")
.build();
Expand All @@ -59,24 +63,22 @@ public Post createRecruitmentPost(String token, PostReqDTO postDTO) {
field.setName(fieldDTO.getName());
post.addField(field);
}
// Post 엔티티 저장
postRepository.save(post);
return post; // Post 엔티티 반환
// Post 엔티티 저장 & 반환
return postRepository.save(post);
}
return null;
}

public List<PostResDTO> retrieveAllRecruitmentPosts(){
List<Post> posts = postRepository.findByStatusNot("D");
if(posts!=null){
List<PostResDTO> postDTOs = new ArrayList<PostResDTO>();
for(Post post : posts){
List<PostResDTO> postDTOs = new ArrayList<PostResDTO>();
if(!posts.isEmpty()) {
for (Post post : posts) {
//ModelMapper.map : ENTITY -> DTO
postDTOs.add(modelMapper.map(post, PostResDTO.class));
}
return postDTOs;
}
return null;
return postDTOs;
}

public PostResDTO retrieveRecruitmentPostById(Long postId) {
Expand All @@ -90,20 +92,61 @@ public PostResDTO retrieveRecruitmentPostById(Long postId) {
}

public List<PostResDTO> retrieveRecruitmentPostsOfCurrentCompany(String token) {
//get email by user token
String email = JwtUtil.getUserEmail(token, secretKey);
//get user by user email
Optional<User> user = userRepository.findByEmail(email);
List<PostResDTO> postDTOs = new ArrayList<PostResDTO>();
if (user.isPresent()) {
List<Post> posts = postRepository.findByUser_IdAndStatusNot(user.get().getId(),"D");
List<PostResDTO> postDTOs = new ArrayList<PostResDTO>();
for(Post post : posts){
List<Post> posts = postRepository.findByUser_IdAndStatusNot(user.get().getId(), "D");

for (Post post : posts) {
//ModelMapper.map : ENTITY -> DTO
postDTOs.add(modelMapper.map(post, PostResDTO.class));
}
return postDTOs;
}
return null;
return postDTOs;
}

public List<PostResDTO> retrieveRecruitmentPostsByFilters(Set<String> fieldNames, Integer career) {
/**정적 필터링 로직**/
/**모든 필터 적용 경우의 수에 따른 조건과 repository 메소드 구현해야함**/
// List<Post> posts = new ArrayList<>();
// if(fieldNames!=null&&career!=null) posts = postRepository.findByFilters(fieldNames,career);
// else if(fieldNames!=null&&career==null) posts = postRepository.findByFilters(career);
// else if(fieldNames==null&&career!=null) posts = postRepository.findByFilters(career);
// //선택한 필터가 없을경우
// else if(fieldNames==null&&career==null) posts = postRepository.findAll();

/**동적 필터링 로직 - Criteria API를 사용하여 동적 쿼리 활용**/
/**이 방식을 이용하면 JPA Repository 사용할 필요 없음**/
/**하지만 여전히 복잡한 코드 -> 향후 queryDSL로 교체**/
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Post> query = criteriaBuilder.createQuery(Post.class);
Root<Post> root = query.from(Post.class);
List<Predicate> predicates = new ArrayList<>();
if (fieldNames != null && !fieldNames.isEmpty()) {
SetJoin<Post, Field> fields = root.joinSet("fields", JoinType.INNER);
predicates.add(fields.get("name").in(fieldNames));
}
if (career != null) {
predicates.add(criteriaBuilder.equal(root.get("required_career"), career));
}
if (!predicates.isEmpty()) {
query.where(predicates.toArray(new Predicate[0]));
}
TypedQuery<Post> typedQuery = entityManager.createQuery(query);
List<Post> posts = typedQuery.getResultList();

//Entity -> DTO
List<PostResDTO> postDTOs = new ArrayList<PostResDTO>();
if(!posts.isEmpty()){
for(Post post : posts){
postDTOs.add(modelMapper.map(post, PostResDTO.class));
}
}
return postDTOs;
}

@Transactional
public PostResDTO updateRecruitmentPostById(String token, PostReqDTO postReqDTO, Long postId) {
Expand Down Expand Up @@ -198,4 +241,6 @@ public Post deleteRecruitmentPostById(String token, Long postId) {
heartRepository.deleteByPost(post);//좋아요 테이블에서 삭제
return postRepository.save(post);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ public class Post extends BaseEntity {

@Column
private LocalDate dueDate;

@Column
private String content;

@Column
private int required_career;

@Column
private String working_address;

Expand All @@ -68,7 +72,7 @@ public class Post extends BaseEntity {
private int numOfHearts;

@Builder
public Post(Long id, User user, String title, String company_photo_url, int compensation_recommender, int compensation_applicant, LocalDate dueDate, String content, String working_address, LocalDateTime created, LocalDateTime updated, String status) {
public Post(Long id, User user, String title, String company_photo_url, int compensation_recommender, int compensation_applicant, LocalDate dueDate, String content, int required_career, String working_address, LocalDateTime created, LocalDateTime updated, String status) {
this.id = id;
this.user = user;
this.title = title;
Expand All @@ -77,6 +81,7 @@ public Post(Long id, User user, String title, String company_photo_url, int comp
this.compensation_applicant = compensation_applicant;
this.dueDate = dueDate;
this.content = content;
this.required_career = required_career;
this.working_address = working_address;
this.created = created;
this.updated = updated;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.example.rcp1.domain.recruitment.domain.Field;
import org.springframework.data.jpa.repository.JpaRepository;

public interface FieldRepository extends JpaRepository<Field,Long> {
import java.util.Optional;

public interface FieldRepository extends JpaRepository<Field,Long> {
Optional<Field> findByName(String fieldName);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.example.rcp1.domain.recruitment.domain.repository;


import com.example.rcp1.domain.recruitment.domain.Field;
import com.example.rcp1.domain.recruitment.domain.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;

@Repository
public interface PostRepository extends JpaRepository<Post,Long> {
Expand All @@ -20,4 +23,18 @@ public interface PostRepository extends JpaRepository<Post,Long> {

List<Post> findByUser_Id(Long userId);



/**정적 필터링 로직 사용시**/
@Query("SELECT p FROM Post p JOIN p.fields f WHERE f.name IN :fieldNames AND p.required_career = :career AND p.status <> 'D'")
List<Post> findByFilters(@Param("fieldNames") Set<String> fieldNames, @Param("career") Integer career);
//fieldNames의 요소 중 하나라도 일치하는게 있으면서 career가 일치하는 데이터들 반환(status not "D")

@Query("SELECT p FROM Post p JOIN p.fields f WHERE f.name IN :fieldNames AND p.status <> 'D'")
List<Post> findByFilters(@Param("fieldNames") Set<String> fieldNames);

@Query("SELECT p FROM Post p JOIN p.fields f WHERE p.required_career = :career AND p.status <> 'D'")
List<Post> findByFilters(@Param("career") Integer career);


}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.rcp1.domain.recruitment.dto;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
Expand Down Expand Up @@ -31,6 +32,10 @@ public class PostReqDTO {
@NotBlank
private String content;

@Min(0)
@Max(10)
private int required_career;

@NotBlank
private String working_address;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.rcp1.domain.recruitment.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
Expand Down Expand Up @@ -43,6 +44,10 @@ public class PostResDTO { //반환용 DTO
@NotBlank
private String content;

@Min(0)
@Max(10)
private int required_career;

@NotBlank
private String working_address;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Set;

@RequestMapping("/recruiting")
@RestController
Expand Down Expand Up @@ -83,6 +84,24 @@ public ResponseEntity<BaseResponse<List<PostResDTO>>> retrieveRecruitmentPostsOf
}
}

//선택된 필터들에 해당하는 채용공고 리스트 조회
@GetMapping("/posts/search/filters")
public ResponseEntity<BaseResponse<List<PostResDTO>>> retrieveRecruitmentPostsByFilters(@RequestParam(value = "field", required = false) Set<String> fields,
@RequestParam(value = "career", required = false) Integer career){
try {
List<PostResDTO> posts = recruitmentService.retrieveRecruitmentPostsByFilters(fields,career);
if (!posts.isEmpty()) {
return ResponseEntity.ok(BaseResponse.success(SuccessCode.POST_RETRIEVAL_SUCCESS, posts));
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(BaseResponse.error(ErrorCode.NOT_FOUND, "해당 조건에 맞는 채용공고를 찾을 수 없습니다."));
}
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(BaseResponse.error(ErrorCode.REQUEST_VALIDATION_EXCEPTION, "채용공고 조회에 실패했습니다."));
}
}

//특정 채용공고 수정
@PatchMapping("/posts/{postId}")
public ResponseEntity<BaseResponse<PostResDTO>> updateRecruitmentPostById(@RequestHeader("Authorization") String Authorization,
Expand Down Expand Up @@ -120,4 +139,5 @@ public ResponseEntity<BaseResponse<Post>> deleteRecruitmentPostById(@RequestHead
.body(BaseResponse.error(ErrorCode.REQUEST_VALIDATION_EXCEPTION, "채용공고 삭제에 실패했습니다."));
}
}

}

0 comments on commit ceac466

Please sign in to comment.