본문으로 바로가기

리뷰 게시판 구현

category Spring boot 2024. 11. 1. 11:27

 

데이터 베이스 설계

CREATE TABLE `company_review` (
  `id` int NOT NULL AUTO_INCREMENT,
  `company_id` int DEFAULT NULL, -- 클라이언트 ID
  `freelancer_id` int DEFAULT NULL, -- 프리랜서 ID
  `work_quality_score` int NOT NULL, -- 작업물 퀄리티 평가 (1~5)
  `timeliness_score` int NOT NULL, -- 개발 시간 준수 정도 (1~5)
  `feedback_score` int NOT NULL, -- 개발 의견 반영 정도 (1~5)
  `willingness_score` int NOT NULL, -- 함께 하고 싶은 정도 (1~5)
  `overall_score` int NOT NULL, -- 종합 평점 (1~5)
  `review_date` timestamp DEFAULT CURRENT_TIMESTAMP, -- 리뷰 작성 날짜
  `response_data` TEXT DEFAULT NULL, -- 평가 내용 (TEXT 형식)
  PRIMARY KEY (`id`),
  CONSTRAINT `clients_review_chk_1` CHECK (`work_quality_score` BETWEEN 1 AND 5),
  CONSTRAINT `clients_review_chk_2` CHECK (`timeliness_score` BETWEEN 1 AND 5),
  CONSTRAINT `clients_review_chk_3` CHECK (`feedback_score` BETWEEN 1 AND 5),
  CONSTRAINT `clients_review_chk_4` CHECK (`willingness_score` BETWEEN 1 AND 5),
  CONSTRAINT `clients_review_chk_5` CHECK (`overall_score` BETWEEN 1 AND 5)
);

 

 

▶ 맵퍼 MyBatis 사용

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.damoa.repository.interfaces.CompanyReviewRepository">

    <!-- 모든 기업 리뷰 list 데이터 및 user_tb username 요청 쿼리 -->
    <select id="findAllByCompanyReviews" resultType="com.damoa.dto.review.CompanyMainDTO">
        SELECT cr.*, u.username AS freelancer_name
        FROM company_review cr
        LEFT JOIN user_tb u ON cr.freelancer_id = u.id
        ORDER BY cr.id DESC
    </select>

    <!-- {id}를 기준으로 상세 리뷰 데이터 및 user_tb username 요청 쿼리 -->
    <select id="findByCompanyReviewId" parameterType="com.damoa.dto.review.CompanyMainDTO">
        SELECT cr.*, u.username As freelancer_name
        FROM company_review cr
        JOIN user_tb u ON cr.freelancer_id = u.id
        WHERE cr.id = #{id}
    </select>

    <!-- GCP company 리뷰 데이터 MySQL로 insert-->
    <insert id="insertCompanyReview" parameterType="com.damoa.repository.model.CompanyReview">
        INSERT INTO company_review (writer_id, freelancer_id, work_quality_score,
        timeliness_score, feedback_score, willingness_score,
        overall_score, review_date, response_data)
        VALUES (#{writerId}, #{freelancerId}, #{workQualityScore},
        #{timelinessScore}, #{feedbackScore}, #{willingnessScore},
        #{overallScore}, #{reviewDate}, #{responseData})
    </insert>

    <select id="findCompanyReview" resultType="com.damoa.dto.admin.CompanyReviewDTO">
        select c.id, u.username, p.project_name, p.main_tasks, c.overall_score, c.response_data
        from company_review as c
        join user_tb as u on u.id = c.company_id
        join freelancer_tb as f on c.freelancer_id = f.id
        join project_tb as p on p.user_id = c.company_id
        limit #{limit} offset #{offset}
    </select>

    <select id="countCompanyReview" resultType="int">
        select count(*)
        from company_review as c
        join user_tb as u on u.id = c.company_id
        join freelancer_tb as f on c.freelancer_id = f.id
        join project_tb as p on p.user_id = c.company_id;
    </select>

    <select id="companyReviewDetail" resultType="com.damoa.dto.admin.CompanyReviewDetailDTO">
        select * from company_review where id = #{id}
    </select>

    <delete id="delete">
        delete from company_review where id = #{id}
    </delete>

    <select id="getDailyCompanyReviewData" resultType="com.damoa.dto.DailyCompanyReviewDTO">
        SELECT DATE_FORMAT(review_date, '%m-%d') AS date, COUNT(*) AS count
        FROM company_review
        WHERE review_date BETWEEN #{startDate} AND #{endDate}
        GROUP BY DATE_FORMAT(review_date, '%m-%d')
    </select>



</mapper>

 

▶ 레포지토리

package com.damoa.repository.interfaces;

import com.damoa.dto.admin.CompanyReviewDTO;
import com.damoa.dto.admin.CompanyReviewDetailDTO;
import com.damoa.dto.review.CompanyMainDTO;
import com.damoa.repository.model.CompanyReview;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.web.bind.annotation.RequestParam;
import com.damoa.dto.DailyCompanyReviewDTO;
import com.damoa.repository.model.CompanyReview;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Optional;

/*
* company 리뷰 기능
* */
@Mapper
public interface CompanyReviewRepository {

    // company 리뷰 데이터 호출
    List<CompanyMainDTO> findAllByCompanyReviews();

    // company 리뷰 id pk 호출
    Optional<CompanyMainDTO> findByCompanyReviewId(int id);

    // GCP company 리뷰 데이터 호출 후 MySQL로 데이터 insert
    void insertCompanyReview(CompanyReview companyReview);

    List<CompanyReviewDTO> findCompanyReview(@Param("limit") int limit, @Param("offset") int offset);

    int countCompanyReview();

    CompanyReviewDetailDTO companyReviewDetail(int id);
    // 일별 기업 리뷰 등록 수 데이터 가져오기
    List<DailyCompanyReviewDTO> getDailyCompanyReviewData(@Param("startDate") String startDate, @Param("endDate") String endDate);

    int delete(int id);
}

 

기업 리뷰 서비스 및 프리랜서 리뷰 서비스

package com.damoa.service;

import com.damoa.dto.admin.CompanyReviewDTO;
import com.damoa.dto.admin.CompanyReviewDetailDTO;
import com.damoa.dto.admin.FreelancerReviewDTO;
import com.damoa.dto.DailyCompanyReviewDTO;
import com.damoa.dto.DailyFreelancerReviewDTO;
import com.damoa.dto.admin.FreelancerReviewDetailDTO;
import com.damoa.dto.review.CompanyMainDTO;
import com.damoa.dto.review.FreelancerMainDTO;
import com.damoa.repository.interfaces.CompanyReviewRepository;
import com.damoa.repository.interfaces.FreelancerReviewRepository;
import com.damoa.repository.interfaces.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Log4j2
@Service
@RequiredArgsConstructor    // DI : 의존성 주입 & final
public class ReviewService {

    private final UserRepository userRepository;
    private final CompanyReviewRepository companyReviewRepo;
    private final FreelancerReviewRepository freelancerReviewRepo;

    // 클라이언트 && 프리랜서 리뷰 데이터 렌더링
    public void getAllReviews(Model model) {
        // 1. 클라이언트와 프리랜서 데이터 가져옴
        List<CompanyMainDTO> companyReviews = companyReviewRepo.findAllByCompanyReviews();
        List<FreelancerMainDTO> freelancerReviews = freelancerReviewRepo.findAllByFreelancerReviews();

        model.addAttribute("companyReviews", companyReviews);
        model.addAttribute("freelancerReviews", freelancerReviews);
        log.info("companyReviews: {}, freelancerReviews: {}", companyReviews, freelancerReviews);
    }

    // 프리랜서 리뷰 데이터 호출 메서드
    public void getFreelancerReviews(Model model) {
        List<FreelancerMainDTO> freelancerReview = freelancerReviewRepo.findAllByFreelancerReviews();
        model.addAttribute("freelancerReview", freelancerReview);
        model.addAttribute("totalReviews", freelancerReview.size());
    }

    // 회사 리뷰 데이터 호출 메서드
    public void getCompanyReviews(Model model) {
        List<CompanyMainDTO> companyReview = companyReviewRepo.findAllByCompanyReviews();
        model.addAttribute("companyReview", companyReview);
        model.addAttribute("totalReviews", companyReview.size());
    }

    // 프리랜서 리뷰 상세 조회 기능
    public void getByFreelancerId(int id, Model model) {
        Optional<FreelancerMainDTO> freelancerReview = freelancerReviewRepo.findByFreelancerReviewId(id);

        model.addAttribute("freelancerReview", freelancerReview.get()); // Optional에서 값 추출
    }

    // 회사 리뷰 상세 조회 기능
    public void getByCompanyId(int id, Model model) {
        Optional<CompanyMainDTO> companyReview = companyReviewRepo.findByCompanyReviewId(id);

        model.addAttribute("companyReview", companyReview.get()); // Optional에서 값 추출 .get() 안쓰면 내부 객체 접근 불가
        log.info("companyReview: {}", companyReview);
    }

    public List<CompanyReviewDTO> getComapanyReviews(int limit, int offset){
        List<CompanyReviewDTO> companyReviews = companyReviewRepo.findCompanyReview(limit,offset);
        return  companyReviews;

    }

    public int countReview(){
        return companyReviewRepo.countCompanyReview();
    }

    public List<FreelancerReviewDTO> findFreelancerReview(int limit, int offset){
        List<FreelancerReviewDTO> freelancerReviews = freelancerReviewRepo.findFreelancerReview(limit, offset);
        return freelancerReviews;

    }

    public int countFreelancerReview(){
        return freelancerReviewRepo.countFreelancerReview();
    }

    public CompanyReviewDetailDTO getCompanyDetails(int id){
       CompanyReviewDetailDTO companyReviewDetailDTO = companyReviewRepo.companyReviewDetail(id);
        return companyReviewDetailDTO;

    }


    // 일별 기업 리뷰 등록 수 데이터
    public List<DailyCompanyReviewDTO> getDailyCompanyReviewData() {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusMonths(1);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        return companyReviewRepo.getDailyCompanyReviewData(startDate.format(formatter), endDate.format(formatter));
    }

    // 일별 프리랜서 리뷰 등록 수 데이터
    public List<DailyFreelancerReviewDTO> getDailyFreelancerReviewData() {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusMonths(1);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        return freelancerReviewRepo.getDailyFreelancerReviewData(startDate.format(formatter), endDate.format(formatter));
    }

    public int deleteCompanyReview(int id){
        return companyReviewRepo.delete(id);
    }

    public int deleteFreelancerReview(int id){
        return freelancerReviewRepo.delete(id);
    }

    public FreelancerReviewDetailDTO getFreelancerDetails(int id){
        return freelancerReviewRepo.freelancerReviewDetail(id);
    }

}

 

▶ 어드민 컨트롤러

 

@Controller
@RequestMapping("/admin")
@RequiredArgsConstructor
public class AdminController {
  /**
     * http://localhost:8080/admin/list/company
     *
     * @param model
     * @return
     */
    @GetMapping("/list/company/{currentPageNum}") // URL의 {type} 부분을 변수로 처리
    public String companyReviewList(@PathVariable(required = false) Integer currentPageNum, Model model) {
        int pageSize = 6;
        int offset;

        int totallist = reviewService.countReview(); // 총몇개의 row 인지 확인
        int totalPages = (int) Math.ceil((double) totallist / (double) pageSize); // 2.1 = 13 / 6

        if (currentPageNum == null || currentPageNum <= 1) {
            currentPageNum = 2;
            offset = 0;
        } else {
            offset = (currentPageNum - 1) * pageSize;
        }
        int nextPageNum;
        int beforePageNum;

        if (currentPageNum >= totalPages - 1 && totalPages > 3) {
            currentPageNum = totalPages - 1;
            nextPageNum = currentPageNum + 1;
            beforePageNum = currentPageNum - 1;
        } else if (currentPageNum >= totalPages - 1) {
            currentPageNum = 2;
            nextPageNum = 3;
            beforePageNum = 1;
        }

        List<CompanyReviewDTO> list = reviewService.getComapanyReviews(pageSize, offset);

        model.addAttribute("list", list);
        model.addAttribute("totallist", totallist);
        model.addAttribute("totalPages", totalPages);
        model.addAttribute("currentPageNum", currentPageNum);
        model.addAttribute("beforePageNum", currentPageNum - 1);
        model.addAttribute("nextPageNum", currentPageNum + 1);

        return "admin/company_list";
    }
    
}

'Spring boot' 카테고리의 다른 글

Service 레이어 만들기  (0) 2024.11.06
JPARepository 란?  (3) 2024.11.05
Service 레이어 만들기  (3) 2024.10.23
JPARepository 란?  (0) 2024.10.23
리팩토링  (1) 2024.10.23