사용자가 채용공고에 지원하면 채용공고와 사용자 정보를 RequestBody로 넘기는 API이다 

사용자는 사용자대로, 채용공고는 채용공고대로 있기에 따로 Apply라는 객체로 만들어서 

사용자와 채용공고가 매치되게 했다. N : M 관계 구현을 의도한 것 같은데, 사실 사용자는 해당 채용공고에 한번만 지원가능하므로 사실상 1 : 1 을 구현한 건가싶다 

 

- User

위치 : /domain/user

@Table
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {

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

    private String userName;

    @Builder
    public User(String userName) {
        this.userName = userName;
    }

    public static User of(String userName) {
        User user = User.builder()
                .userName(userName)
                .build();

        return user;
    }
}

 

- UserRepository

위치 : /domain/user

public interface UserRepository extends JpaRepository<User, Long> {
}

 

- UserService

위치 : /service/user

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    public void createUser(CreateUserRequest request) {
        User created = User.of(request.getUserName());

        userRepository.save(created);
    }
}

 

- UserController

위치 : /web/user

@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class UserController {

    private final UserService userService;

    @PostMapping("/create")
    public ApiResponse<String> createUser(@RequestBody CreateUserRequest request) {
        userService.createUser(request);
        return ApiResponse.SUCCESS;
    }
}

 

- Apply

위치 : /domain/apply

@Table
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Apply {

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

    @OneToOne
    @JoinColumn(name = "USER_ID")
    private User user;

    @OneToOne
    @JoinColumn(name = "RECRUITMENT_ID")
    private Recruitment recruitment;

    @Builder
    public Apply(User user, Recruitment recruitment) {
        this.user = user;
        this.recruitment = recruitment;
    }

    public static Apply of(User user, Recruitment recruitment) {
        Apply apply = Apply.builder()
                .user(user)
                .recruitment(recruitment)
                .build();

        return apply;
    }
}

 

- ApplyRepository

public interface ApplyRepository extends JpaRepository<Apply, Long> {

    Optional<Apply> findByUser(User user);
}

 

- ApplyService

위치 : /domain/apply

@Service
@RequiredArgsConstructor
public class ApplyService {

    private final RecruitmentRepository recruitmentRepository;
    private final UserRepository userRepository;
    private final ApplyRepository applyRepository;

    public void createApply(CreateApplyRequest request) throws Exception {
        Optional<Recruitment> recruitment = recruitmentRepository.findById(request.getRecruitId());
        Optional<User> user = userRepository.findById(request.getUserId());

        Optional<Apply> apply = applyRepository.findByUser(user.get());
        if (apply.isPresent()) {
            // 사용자는 한 채용공고에 한번만 지원할 수 있다
            throw new Exception();
        }

        Apply created = Apply.of(user.get(), recruitment.get());
        applyRepository.save(created);
    }
}

 

- ApplyController

위치 : /web/apply

@RestController
@RequiredArgsConstructor
@RequestMapping("/apply")
public class ApplyController {

    private final ApplyService applyService;

    @PostMapping("/create")
    public ApiResponse<String> createApply(@RequestBody CreateApplyRequest request) throws Exception {
        applyService.createApply(request);
        return ApiResponse.SUCCESS;
    }
}

 

Postman

 

RequestBody

{
    "recruitId" : 1,
    "userId" : 1
}

 

ResponseBody

{
    "data": null
}

 

'개인프로젝트 > 과제' 카테고리의 다른 글

6. 채용 상세 페이지 조회 API  (0) 2022.08.25
5-2. 채용공고 검색 API (가산점 요소)  (0) 2022.08.25
5-1. 채용공고 목록 API  (0) 2022.08.24
4. 삭제 API  (0) 2022.08.23
3. 수정 API  (0) 2022.08.23

채용 공고에서 특정 객체를 선택했을 때 상세 정보를 조회하는 API이다 

여기서 가산점을 주는 요소는 채용공고를 올린 회사가 올린 다른 채용공고의 id 리스트도 같이 반환하는 것이다 

 

회사 엔티티와 관련 로직이 필요해 추가했다 

- Company

위치  : /domain/company

@Table
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Company {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String companyName;
    private String country;
    private String region;


    @Builder
    public Company(String companyName, String country, String region) {
        this.companyName = companyName;
        this.country = country;
        this.region = region;
    }

    public static Company of(String companyName, String country, String region) {
        Company company = Company.builder()
                .companyName(companyName)
                .country(country)
                .region(region)
                .build();

        return company;
    }
}

-CompanyRepository

위치  : /domain/company

public interface CompanyRepository extends JpaRepository<Company, Long> {
}

- CompanyService

위치 : /service/company

@Service
@RequiredArgsConstructor
public class CompanyService {

    private final CompanyRepository companyRepository;

    public void createCompany(CreateCompanyRequest request) {

        Company created = Company.of(request.getCompanyName(), request.getCountry(), request.getRegion());

        companyRepository.save(created);
    }
}

 

- CompanyController

위치 : /web/company

@RestController
@RequiredArgsConstructor
@RequestMapping("/company")
public class CompanyController {

    private final CompanyService companyService;

    @PostMapping("/create")
    public ApiResponse<String> createCompany(@RequestBody CreateCompanyRequest request) {
        companyService.createCompany(request);
        return ApiResponse.SUCCESS;
    }
}

 

- getRecruitDetail()

위치 : /web/recruitment/RecruitmentController.class

@GetMapping("/detail/{id}")
public ApiResponse<GetRecruitDetailResponse> getRecruitDetail(@PathVariable Long id) {
    GetRecruitDetailResponse response = recruitmentService.getRecruitDetail(id);
    return ApiResponse.success(response);
}

 

-getRecruitDetail()

위치 : /service/recruitment/RecruitmentService.class

public GetRecruitDetailResponse getRecruitDetail(Long id) {
        Optional<Recruitment> findRecruit = recruitmentRepository.findById(id);
        Company company = findRecruit.get().getCompany();
        Long companyId = company.getId();

        List<Long> companyRecruits = new ArrayList<>();
        List<Recruitment> recruits = recruitmentRepository.findByCompanyId(companyId);
        for (Recruitment recruit : recruits) {
            if (!recruit.getId().equals(id)) {
                companyRecruits.add(recruit.getId());
            }
        }

        GetRecruitDetailResponse response = GetRecruitDetailResponse.of(company, findRecruit.get(), companyRecruits);

        return response;
    }

 

- GetRecruitDetailResponse

@ToString
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class GetRecruitDetailResponse {

    private Long recruitId;
    private String companyName;
    private String country;
    private String region;
    private String position;
    private Integer reward;
    private String techInfo;
    private String contents;
    private List<Long> companyRecruits = new ArrayList<>();

    @Builder
    public GetRecruitDetailResponse(Long recruitId, String companyName, String country, String region, String position, Integer reward, String techInfo, String contents, List<Long> companyRecruits) {
        this.recruitId = recruitId;
        this.companyName = companyName;
        this.country = country;
        this.region = region;
        this.position = position;
        this.reward = reward;
        this.techInfo = techInfo;
        this.contents = contents;
        this.companyRecruits = companyRecruits;
    }

    public static GetRecruitDetailResponse of(Company company, Recruitment recruitment, List<Long> companyRecruits) {
        GetRecruitDetailResponse response = GetRecruitDetailResponse.builder()
                .recruitId(recruitment.getId())
                .companyName(company.getCompanyName())
                .country(company.getCountry())
                .region(company.getRegion())
                .position(recruitment.getPosition())
                .reward(recruitment.getReward())
                .techInfo(recruitment.getTechInfo())
                .contents(recruitment.getContents())
                .companyRecruits(companyRecruits)
                .build();

        return response;
    }
}

Postman

RequestParam

ResponseBody

여기에서 조회한 채용공고까지 중복으로 포함되는데 이 부분은 수정해야할 것 같다 

{
    "data": {
        "recruitId": 1,
        "companyName": "wanted",
        "country": "korea",
        "region": "seoul",
        "position": "Backend Developer 1",
        "reward": 125000000,
        "techInfo": "Java",
        "contents": "now wanted is hiring for ,,,",
        "companyRecruits": [
            2,
            3
        ]
    }
}
{
    "data": {
        "recruitId": 5,
        "companyName": "naver",
        "country": "korea",
        "region": "seoul",
        "position": "backend junior developer",
        "reward": 25000000,
        "techInfo": "Java",
        "contents": "now naver is hiring for,,,",
        "companyRecruits": [
            4
        ]
    }
}
 

 

'개인프로젝트 > 과제' 카테고리의 다른 글

7. 사용자가 채용공고에 지원 API (가산점 요소)  (0) 2022.08.25
5-2. 채용공고 검색 API (가산점 요소)  (0) 2022.08.25
5-1. 채용공고 목록 API  (0) 2022.08.24
4. 삭제 API  (0) 2022.08.23
3. 수정 API  (0) 2022.08.23

특정 단어를 입력하면 해당 단어를 포함하는 모든 공고를 리스트로 응답하는 API이다 

필드가 정해져있지 않아서 어떻게 해야하나 여러 시도를 해봤다 

repository에서 in 쿼리 사용해서 해당 단어를 가지고 있는 객체 리스트 반환(컴파일 에러 발생함)

각 필드마다 find하는 시그니처 만들어서 각자 진행하는 것(실패)

 

그러던 중 모든 recruitment를 찾은 다음 각 recruiment의 필드에서 해당 단어를 가지고 있으면 그걸 리스트에 추가한 후 

반환하는 로직을 생각했다 

 

- getSearchRecruitList()

위치 : /web/recruitment/RecruitmentController.class

@GetMapping("/search")
public ApiResponse<List<GetSearchRecruitResponse>> getSearchRecruitList(@RequestParam String search) {
    List<GetSearchRecruitResponse> response = recruitmentService.getSearchRecruitList(search);
    return ApiResponse.success(response);
}

 

- getSearchRecruitList()

Java에선 != 로 문자열을 비교하면 에러가 발생하므로, .equals()를 이용해야한다 

문제에선 원티드로 검색했을 때 원티드와 원티드코리아의 채용공고가 조회되었으므로, 해당 단어와 정확히 일치하는 것뿐만 아니라 

포함하는 것도 조회해야한다고 생각해서 .contains()를 이용했다 

코드가 아직 단순하고 문제가 많을 것 같지만 일단 지금까지의 최선이다 

하나의 채용공고에 서로 다른 필드가 중복되는 단어를 가지고 있는 경우 같은 공고가 여러개 반환되는 문제가 발생한다 

 

public List<GetSearchRecruitResponse> getSearchRecruitList(String search) {
    List<Recruitment> all = recruitmentRepository.findAll();

    List<GetSearchRecruitResponse> result = new ArrayList<>();
    for (Recruitment recruitment : all) {
        if (recruitment.getCompany().getCompanyName().contains(search) || recruitment.getCompany().getCountry().contains(search) || recruitment.getCompany().getRegion().contains(search)) {
            GetSearchRecruitResponse response = GetSearchRecruitResponse.of(recruitment);

            result.add(response);
        }

        if (recruitment.getPosition().contains(search) || recruitment.getTechInfo().contains(search)) {
            GetSearchRecruitResponse response = GetSearchRecruitResponse.of(recruitment);

            result.add(response);
        }
    }
    return result;
}

 

- GetSearchRecruitResponse

위치 : /web/recruitment/dto/response

@ToString
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class GetSearchRecruitResponse {

    private Long recruitId;
    private String companyName;
    private String country;
    private String region;
    private String position;
    private Integer reward;
    private String techInfo;

    @Builder
    public GetSearchRecruitResponse(Long recruitId, String companyName, String country, String region, String position, Integer reward, String techInfo) {
        this.recruitId = recruitId;
        this.companyName = companyName;
        this.country = country;
        this.region = region;
        this.position = position;
        this.reward = reward;
        this.techInfo = techInfo;
    }

    public static GetSearchRecruitResponse of(Recruitment recruitment) {
        GetSearchRecruitResponse response = GetSearchRecruitResponse.builder()
                .recruitId(recruitment.getId())
                .companyName(recruitment.getCompany().getCompanyName())
                .country(recruitment.getCompany().getCountry())
                .region(recruitment.getCompany().getRegion())
                .position(recruitment.getPosition())
                .reward(recruitment.getReward())
                .techInfo(recruitment.getTechInfo())
                .build();

        return response;
    }
}

 

Postman

RequestParam 

key = search, value = naver

 

ResponseBody

naver를 포함한 모든 회사의 채용공고 리스트를 반환하는 것을 볼 수 있다 

{
    "data": [
        {
            "recruitId": 1,
            "companyName": "naverwebtoon",
            "country": "korea",
            "region": "seoul",
            "position": "Backend Developer 1",
            "reward": 125000000,
            "techInfo": "Java"
        },
        {
            "recruitId": 2,
            "companyName": "naverwebtoon",
            "country": "korea",
            "region": "seoul",
            "position": "Backend Developer 2",
            "reward": 125000000,
            "techInfo": "Java"
        },
        {
            "recruitId": 3,
            "companyName": "naverwebtoon",
            "country": "korea",
            "region": "seoul",
            "position": "Backend Developer 3",
            "reward": 125000000,
            "techInfo": "Python"
        },
        {
            "recruitId": 4,
            "companyName": "naver",
            "country": "korea",
            "region": "seoul",
            "position": "Backend Developer 1",
            "reward": 125000000,
            "techInfo": "Python"
        },
        {
            "recruitId": 5,
            "companyName": "naver",
            "country": "korea",
            "region": "seoul",
            "position": "Backend Developer 2",
            "reward": 125000000,
            "techInfo": "Java"
        }
    ]
}

 

'개인프로젝트 > 과제' 카테고리의 다른 글

7. 사용자가 채용공고에 지원 API (가산점 요소)  (0) 2022.08.25
6. 채용 상세 페이지 조회 API  (0) 2022.08.25
5-1. 채용공고 목록 API  (0) 2022.08.24
4. 삭제 API  (0) 2022.08.23
3. 수정 API  (0) 2022.08.23

채용 공고 리스트를 조회하는 API이다 

채용 공고 등록할 때는 회사 정보를 입력하지 않아서 회사 엔티티를 만들지 않았는데, 목록의 각 개체에 회사정보가 있길래 회사 관련 정보도 추가해서 진행했다 

 

-getRecruitList()

위치 : /web/recruitment/RecruitmentController.class

채용공고 목록만 확인하는 것이므로 따로 requestbody가 필요하지 않다고 생각했다 

@GetMapping("/list")
public ApiResponse<List<GetRecruitListResponse>> getRecruitList() {
    List<GetRecruitListResponse> responses = recruitmentService.getRecruitList();
    return ApiResponse.success(responses);
}

-getRecruitList()

위치 : /service/RecruitmentService.class

public List<GetRecruitListResponse> getRecruitList() {

    List<Recruitment> all = recruitmentRepository.findAll();

    List<GetRecruitListResponse> recruitList = new ArrayList<>();
    for (Recruitment recruitment : all) {
        Company recruitCompany = recruitment.getCompany();

        GetRecruitListResponse response = GetRecruitListResponse.of(recruitCompany, recruitment);

        recruitList.add(response);
    }

    return recruitList;
}

 

- GetRecruitListResponse

위치 : /web/recruitment/dto/response

@ToString
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class GetRecruitListResponse {

    private Long recruitId;
    private String companyName;
    private String country;
    private String region;
    private String position;
    private Integer reward;
    private String techInfo;

    @Builder
    public GetRecruitListResponse(Long recruitId, String companyName, String country, String region, String position, Integer reward, String techInfo) {
        this.recruitId = recruitId;
        this.companyName = companyName;
        this.country = country;
        this.region = region;
        this.position = position;
        this.reward = reward;
        this.techInfo = techInfo;
    }

    public static GetRecruitListResponse of(Company company, Recruitment recruitment) {
        GetRecruitListResponse response = GetRecruitListResponse.builder()
                .recruitId(recruitment.getId())
                .companyName(company.getCompanyName())
                .country(company.getCountry())
                .region(company.getRegion())
                .position(recruitment.getPosition())
                .reward(recruitment.getReward())
                .techInfo(recruitment.getTechInfo())
                .build();

        return response;
    }

Postman

company 생성 (두 개의 회사)

{
    "companyName" : "wanted",
    "country" : "korea",
    "region" : "seoul"
}
{
    "data": null
}

 

company에서 recruitment 생성 

{
    "companyId" : 2,
    "position" : "backend junior developer",
    "reward" : 225000000,
    "contents" : "now wanted is hiring for,,,",
    "techInfo" : "Java"
}
{
    "data": {
        "id": 3,
        "position": "backend junior developer",
        "reward": 225000000,
        "contents": "now wanted is hiring for,,,",
        "techInfo": "Java"
    }
}

 

사용자가 recruitment list 조회 

{
    "data": [
        {
            "recruitId": 1,
            "companyName": "naver",
            "country": "korea",
            "region": "seoul",
            "position": "backend senior developer",
            "reward": 325000000,
            "techInfo": "Java"
        },
        {
            "recruitId": 2,
            "companyName": "naver",
            "country": "korea",
            "region": "seoul",
            "position": "backend jenior developer",
            "reward": 125000000,
            "techInfo": "Java"
        },
        {
            "recruitId": 3,
            "companyName": "wanted",
            "country": "korea",
            "region": "seoul",
            "position": "backend junior developer",
            "reward": 225000000,
            "techInfo": "Java"
        }
    ]
}

'개인프로젝트 > 과제' 카테고리의 다른 글

6. 채용 상세 페이지 조회 API  (0) 2022.08.25
5-2. 채용공고 검색 API (가산점 요소)  (0) 2022.08.25
4. 삭제 API  (0) 2022.08.23
3. 수정 API  (0) 2022.08.23
2. 등록 API 생성  (0) 2022.08.23

+ Recent posts