Skip to content

Commit

Permalink
refactor(New, JobPosting): 채용공고, 뉴스 복원
Browse files Browse the repository at this point in the history
  • Loading branch information
limehee committed Aug 4, 2024
1 parent eaf0d5c commit d0d6ab4
Show file tree
Hide file tree
Showing 28 changed files with 677 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package page.clab.api.domain.community.jobPosting.adapter.in.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import page.clab.api.domain.community.jobPosting.application.dto.response.JobPostingDetailsResponseDto;
import page.clab.api.domain.community.jobPosting.application.port.in.RetrieveJobPostingDetailsUseCase;
import page.clab.api.global.common.dto.ApiResponse;

@RestController
@RequestMapping("/api/v1/job-postings")
@RequiredArgsConstructor
@Tag(name = "Community - Job Posting", description = "커뮤니티 채용 공고")
public class JobPostingDetailsRetrievalController {

private final RetrieveJobPostingDetailsUseCase retrieveJobPostingDetailsUseCase;

@Operation(summary = "[U] 채용 공고 상세 조회", description = "ROLE_USER 이상의 권한이 필요함")
@Secured({ "ROLE_USER", "ROLE_ADMIN", "ROLE_SUPER" })
@GetMapping("/{jobPostingId}")
public ApiResponse<JobPostingDetailsResponseDto> retrieveJobPostingDetails(
@PathVariable(name = "jobPostingId") Long jobPostingId
) {
JobPostingDetailsResponseDto jobPosting = retrieveJobPostingDetailsUseCase.retrieveJobPostingDetails(jobPostingId);
return ApiResponse.success(jobPosting);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package page.clab.api.domain.community.jobPosting.adapter.in.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import page.clab.api.domain.community.jobPosting.application.dto.response.JobPostingResponseDto;
import page.clab.api.domain.community.jobPosting.application.port.in.RetrieveJobPostingsByConditionsUseCase;
import page.clab.api.domain.community.jobPosting.domain.CareerLevel;
import page.clab.api.domain.community.jobPosting.domain.EmploymentType;
import page.clab.api.global.common.dto.ApiResponse;
import page.clab.api.global.common.dto.PagedResponseDto;
import page.clab.api.global.exception.InvalidColumnException;
import page.clab.api.global.exception.SortingArgumentException;
import page.clab.api.global.util.PageableUtils;

import java.util.List;

@RestController
@RequestMapping("/api/v1/job-postings")
@RequiredArgsConstructor
@Tag(name = "Community - Job Posting", description = "커뮤니티 채용 공고")
public class JobPostingsByConditionsRetrievalController {

private final RetrieveJobPostingsByConditionsUseCase retrieveJobPostingsByConditionsUseCase;
private final PageableUtils pageableUtils;

@Operation(summary = "[U] 채용 공고 목록 조회(공고명, 기업명, 경력, 근로 조건 기준)", description = "ROLE_USER 이상의 권한이 필요함<br>" +
"4개의 파라미터를 자유롭게 조합하여 필터링 가능<br>" +
"공고명, 기업명, 경력, 근로 조건 중 하나라도 입력하지 않으면 전체 조회됨<br>" +
"DTO의 필드명을 기준으로 정렬 가능하며, 정렬 방향은 오름차순(asc)과 내림차순(desc)이 가능함")
@Secured({ "ROLE_USER", "ROLE_ADMIN", "ROLE_SUPER" })
@GetMapping("")
public ApiResponse<PagedResponseDto<JobPostingResponseDto>> retrieveJobPostingsByConditions(
@RequestParam(name = "title", required = false) String title,
@RequestParam(name = "companyName", required = false) String companyName,
@RequestParam(name = "careerLevel", required = false) CareerLevel careerLevel,
@RequestParam(name = "employmentType", required = false) EmploymentType employmentType,
@RequestParam(name = "page", defaultValue = "0") int page,
@RequestParam(name = "size", defaultValue = "20") int size,
@RequestParam(name = "sortBy", defaultValue = "createdAt") List<String> sortBy,
@RequestParam(name = "sortDirection", defaultValue = "desc") List<String> sortDirection
) throws SortingArgumentException, InvalidColumnException {
Pageable pageable = pageableUtils.createPageable(page, size, sortBy, sortDirection, JobPostingResponseDto.class);
PagedResponseDto<JobPostingResponseDto> jobPostings = retrieveJobPostingsByConditionsUseCase.retrieveJobPostings(title, companyName, careerLevel, employmentType, pageable);
return ApiResponse.success(jobPostings);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package page.clab.api.domain.community.jobPosting.adapter.out.persistence;

import org.mapstruct.Mapper;
import page.clab.api.domain.community.jobPosting.domain.JobPosting;

@Mapper(componentModel = "spring")
public interface JobPostingMapper {

JobPostingJpaEntity toJpaEntity(JobPosting domain);

JobPosting toDomain(JobPostingJpaEntity entity);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package page.clab.api.domain.community.jobPosting.adapter.out.persistence;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import page.clab.api.domain.community.jobPosting.application.port.out.RetrieveJobPostingPort;
import page.clab.api.domain.community.jobPosting.domain.CareerLevel;
import page.clab.api.domain.community.jobPosting.domain.EmploymentType;
import page.clab.api.domain.community.jobPosting.domain.JobPosting;
import page.clab.api.global.exception.NotFoundException;

@Component
@RequiredArgsConstructor
public class JobPostingPersistenceAdapter implements
RetrieveJobPostingPort {

private final JobPostingRepository repository;
private final JobPostingMapper jobPostingMapper;

@Override
public JobPosting findByIdOrThrow(Long jobPostingId) {
return repository.findById(jobPostingId)
.map(jobPostingMapper::toDomain)
.orElseThrow(() -> new NotFoundException("[JobPosting] id: " + jobPostingId + "에 해당하는 채용 공고가 존재하지 않습니다."));
}

@Override
public Page<JobPosting> findByConditions(String title, String companyName, CareerLevel careerLevel, EmploymentType employmentType, Pageable pageable) {
return repository.findByConditions(title, companyName, careerLevel, employmentType, pageable).map(jobPostingMapper::toDomain);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package page.clab.api.domain.community.jobPosting.adapter.out.persistence;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;

@Repository
public interface JobPostingRepository extends JpaRepository<JobPostingJpaEntity, Long>, JobPostingRepositoryCustom, QuerydslPredicateExecutor<JobPostingJpaEntity> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package page.clab.api.domain.community.jobPosting.adapter.out.persistence;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import page.clab.api.domain.community.jobPosting.domain.CareerLevel;
import page.clab.api.domain.community.jobPosting.domain.EmploymentType;

public interface JobPostingRepositoryCustom {
Page<JobPostingJpaEntity> findByConditions(String title, String companyName, CareerLevel careerLevel, EmploymentType employmentType, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package page.clab.api.domain.community.jobPosting.adapter.out.persistence;

import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import page.clab.api.domain.community.jobPosting.domain.CareerLevel;
import page.clab.api.domain.community.jobPosting.domain.EmploymentType;
import page.clab.api.global.util.OrderSpecifierUtil;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class JobPostingRepositoryImpl implements JobPostingRepositoryCustom {

private final JPAQueryFactory queryFactory;

@Override
public Page<JobPostingJpaEntity> findByConditions(String title, String companyName, CareerLevel careerLevel, EmploymentType employmentType, Pageable pageable) {
QJobPostingJpaEntity jobPosting = QJobPostingJpaEntity.jobPostingJpaEntity;
BooleanBuilder builder = new BooleanBuilder();

if (title != null && !title.isEmpty()) builder.and(jobPosting.title.containsIgnoreCase(title));
if (companyName != null && !companyName.isEmpty())
builder.and(jobPosting.companyName.containsIgnoreCase(companyName));
if (careerLevel != null) builder.and(jobPosting.careerLevel.eq(careerLevel));
if (employmentType != null) builder.and(jobPosting.employmentType.eq(employmentType));

List<JobPostingJpaEntity> jobPostings = queryFactory.selectFrom(jobPosting)
.where(builder)
.orderBy(OrderSpecifierUtil.getOrderSpecifiers(pageable, jobPosting))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();

long total = queryFactory.query().from(jobPosting)
.where(builder)
.fetchCount();

return new PageImpl<>(jobPostings, pageable, total);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package page.clab.api.domain.community.jobPosting.application.dto.response;

import lombok.Builder;
import lombok.Getter;
import page.clab.api.domain.community.jobPosting.domain.CareerLevel;
import page.clab.api.domain.community.jobPosting.domain.EmploymentType;
import page.clab.api.domain.community.jobPosting.domain.JobPosting;

import java.time.LocalDateTime;

@Getter
@Builder
public class JobPostingDetailsResponseDto {

private Long id;
private String title;
private CareerLevel careerLevel;
private EmploymentType employmentType;
private String companyName;
private String recruitmentPeriod;
private String jobPostingUrl;
private LocalDateTime createdAt;

public static JobPostingDetailsResponseDto toDto(JobPosting jobPosting) {
return JobPostingDetailsResponseDto.builder()
.id(jobPosting.getId())
.title(jobPosting.getTitle())
.careerLevel(jobPosting.getCareerLevel())
.employmentType(jobPosting.getEmploymentType())
.companyName(jobPosting.getCompanyName())
.recruitmentPeriod(jobPosting.getRecruitmentPeriod())
.jobPostingUrl(jobPosting.getJobPostingUrl())
.createdAt(jobPosting.getCreatedAt())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package page.clab.api.domain.community.jobPosting.application.dto.response;

import lombok.Builder;
import lombok.Getter;
import page.clab.api.domain.community.jobPosting.domain.JobPosting;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@Builder
public class JobPostingResponseDto {

private Long id;
private String title;
private String recruitmentPeriod;
private String jobPostingUrl;
private LocalDateTime createdAt;

public static JobPostingResponseDto toDto(JobPosting jobPosting) {
return JobPostingResponseDto.builder()
.id(jobPosting.getId())
.title(jobPosting.getTitle())
.recruitmentPeriod(jobPosting.getRecruitmentPeriod())
.jobPostingUrl(jobPosting.getJobPostingUrl())
.createdAt(jobPosting.getCreatedAt())
.build();
}

public static List<JobPostingResponseDto> toDto(List<JobPosting> jobPostingList) {
return jobPostingList.stream()
.map(JobPostingResponseDto::toDto)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package page.clab.api.domain.community.jobPosting.application.port.in;

import page.clab.api.domain.community.jobPosting.application.dto.response.JobPostingDetailsResponseDto;

public interface RetrieveJobPostingDetailsUseCase {
JobPostingDetailsResponseDto retrieveJobPostingDetails(Long jobPostingId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package page.clab.api.domain.community.jobPosting.application.port.in;

import org.springframework.data.domain.Pageable;
import page.clab.api.domain.community.jobPosting.application.dto.response.JobPostingResponseDto;
import page.clab.api.domain.community.jobPosting.domain.CareerLevel;
import page.clab.api.domain.community.jobPosting.domain.EmploymentType;
import page.clab.api.global.common.dto.PagedResponseDto;

public interface RetrieveJobPostingsByConditionsUseCase {
PagedResponseDto<JobPostingResponseDto> retrieveJobPostings(String title, String companyName, CareerLevel careerLevel, EmploymentType employmentType, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package page.clab.api.domain.community.jobPosting.application.port.out;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import page.clab.api.domain.community.jobPosting.domain.CareerLevel;
import page.clab.api.domain.community.jobPosting.domain.EmploymentType;
import page.clab.api.domain.community.jobPosting.domain.JobPosting;

public interface RetrieveJobPostingPort {

JobPosting findByIdOrThrow(Long jobPostingId);

Page<JobPosting> findByConditions(String title, String companyName, CareerLevel careerLevel, EmploymentType employmentType, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package page.clab.api.domain.community.jobPosting.application.service;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import page.clab.api.domain.community.jobPosting.application.dto.response.JobPostingDetailsResponseDto;
import page.clab.api.domain.community.jobPosting.application.port.in.RetrieveJobPostingDetailsUseCase;
import page.clab.api.domain.community.jobPosting.application.port.out.RetrieveJobPostingPort;
import page.clab.api.domain.community.jobPosting.domain.JobPosting;

@Service
@RequiredArgsConstructor
public class JobPostingDetailsRetrievalService implements RetrieveJobPostingDetailsUseCase {

private final RetrieveJobPostingPort retrieveJobPostingPort;

@Transactional(readOnly = true)
@Override
public JobPostingDetailsResponseDto retrieveJobPostingDetails(Long jobPostingId) {
JobPosting jobPosting = retrieveJobPostingPort.findByIdOrThrow(jobPostingId);
return JobPostingDetailsResponseDto.toDto(jobPosting);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package page.clab.api.domain.community.jobPosting.application.service;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import page.clab.api.domain.community.jobPosting.application.dto.response.JobPostingResponseDto;
import page.clab.api.domain.community.jobPosting.application.port.in.RetrieveJobPostingsByConditionsUseCase;
import page.clab.api.domain.community.jobPosting.application.port.out.RetrieveJobPostingPort;
import page.clab.api.domain.community.jobPosting.domain.CareerLevel;
import page.clab.api.domain.community.jobPosting.domain.EmploymentType;
import page.clab.api.domain.community.jobPosting.domain.JobPosting;
import page.clab.api.global.common.dto.PagedResponseDto;

@Service
@RequiredArgsConstructor
public class JobPostingsByConditionsRetrievalService implements RetrieveJobPostingsByConditionsUseCase {

private final RetrieveJobPostingPort retrieveJobPostingPort;

@Transactional(readOnly = true)
@Override
public PagedResponseDto<JobPostingResponseDto> retrieveJobPostings(String title, String companyName, CareerLevel careerLevel, EmploymentType employmentType, Pageable pageable) {
Page<JobPosting> jobPostings = retrieveJobPostingPort.findByConditions(title, companyName, careerLevel, employmentType, pageable);
return new PagedResponseDto<>(jobPostings.map(JobPostingResponseDto::toDto));
}
}
Loading

0 comments on commit d0d6ab4

Please sign in to comment.