Spring

★ Spring _ 점수 관리 app - 문제점 [서비스 컨트롤러 만들기]_22.07.14_7일차

양빵빵 2022. 7. 14. 12:17
package com.spring.webmvc.springmvc.chap02.Controller;

import com.spring.webmvc.springmvc.chap02.domain.Score;
import com.spring.webmvc.springmvc.chap02.repository.ScoreRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@Controller
@Log4j2
@RequiredArgsConstructor
public class ScoreController {

    private final ScoreRepository repository;

    //    @Autowired
    //    public ScoreController(ScoreRepository repository) {
    //        this.repository = repository;
    //    }

    // 점수 등록 및 조회 화면 열기 요청
    @RequestMapping("/score/list")
    public String list(
            //클라이언트가 sort를 보내지 않을 경우
            @RequestParam(defaultValue = "num") String sort,
            Model model) {
        log.info("/score/list GET 요청!! - param1: {}", sort);

        // jsp에게 점수 정보 리스트를 전달해야 함.
        List<Score> scoreList = repository.findAll(sort);

        // 이름 마킹 처리
        for (Score s : scoreList) {
            String original = s.getName();
            StringBuilder markName = new StringBuilder(String.valueOf(original.charAt(0)));
            for (int i = 0; i < original.length() - 1; i++) {
                markName.append("*");
            }
            s.setName(markName.toString());
        }


        model.addAttribute("scores", scoreList);

        // jsp 에게 1등인 학생의 정보를 전달
        List<Score> firstScoreList = repository.findFirst();
        model.addAttribute("firstScores", firstScoreList);

        // jsp 에게 꼴등인 학생의 정보를 전달
        List<Score> lastScoreList = repository.findlast();
        model.addAttribute("lastScores", lastScoreList);


        return "chap02/score-list";
    }

    // 점수 신규등록 요청
    @RequestMapping("/score/register")
    public String register(Score score) {
        score.calcTotalAndAvg();
        score.calcGrade();
        log.info("/score/register POST! -" + score);

        if (repository.save(score)) {
            return "redirect:/score/list";
        } else {
            return "redirect:/";
        }
    }


/*        @RequestMapping("score/detail")
        public ModelAndView detail(int sutNum) {
            log.info("score/detail GET - param1: {}", sutNum);
            Score score = repository.findOne(sutNum);

            ModelAndView mv = new ModelAndView("chap02/score-detail");
            mv.addObject("s",score);

            return mv;
        }*/

    @RequestMapping("/score/detail")
    public String detail(int stuNum, Model model) {
        log.info("/score/detail GET 요청!! - ");

        Score s = repository.findOne(stuNum);

        model.addAttribute("s", s);
        //      model.addAttribute("name", s.getName());
        //      model.addAttribute("kor", s.getKor());
        //      model.addAttribute("eng", s.getEng());
        //      model.addAttribute("math", s.getMath());
        //      model.addAttribute("total", s.getTotal());
        //      model.addAttribute("average", s.getAverage());
        //      model.addAttribute("grade", s.getGrade());

        log.info(s);

        return "chap02/score-detail";
    }

    @RequestMapping("/score/delete")
    public String delete(@RequestParam("stuNum") int sn) {
        log.info("score/delete GET - param1: {}", sn);

        return repository.remove(sn) ? "redirect:/score/list" : "redirect:/";
    }


}

 

적당한 요청을 받아서 요청 데이터를 처리해줘서 비즈니스 로직을 실행한 다음 뷰를 안내 하는 것 -> 컨트롤러의 역할

하지만 ScoreController는 이름 마킹처리 등 많은 일들을 하고 있다.

 

컨트롤러와 레파지토리 사이의 서비스라는 레이어를 둬서 잡다한일들을 처리하도록 하려고 한다.

 

클라이언트 ->

 

디스패쳐서블릿 [프론트 컨트롤러 url 분석]

-> 핸들러맵핑 을 통해 요청을 수행할 컨트롤러를 찾아준다.

->스펙을 맞춰주기위해 핸들러 어댑터도 찾는다.

-> ex) scoreController에 연결 메서드 수행

-> 스코어컨트롤러는 데이터베이스 정보가 필요하면 스코어 레파지토리에 요청

-> 스코어 레파지토리는 db에 요청 

-> 응답 받은 스코어 컨트롤러는 -> 뷰에 요청

-> 뷰는 클라이언트에게 보여주기

 

[ 스코어컨트롤러와 스코어레파지토리 사이에 서비스객체를 둔다. ]

 

 

 

===> 따라 쓰면서 캡처하니까 놓쳤음 ㅠ

 

리팩토링 완성본

 

-- 컨트롤러

package com.spring.webmvc.springmvc.chap03;

import com.spring.webmvc.springmvc.chap02.domain.Score;
import com.spring.webmvc.springmvc.chap02.repository.ScoreRepository;
import com.spring.webmvc.springmvc.chap03.service.ScoreService;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@Controller
@Log4j2
@RequiredArgsConstructor
public class ScoreControllerV2 {

    private final ScoreService service;


    // 점수 등록 및 조회 화면 열기 요청
    @RequestMapping("/score/list")
    public String list(
            @RequestParam(defaultValue = "num") String sort
            , Model model) {
        log.info("/score/list GET 요청!! - param1 : {}", sort);

        List<Score> scoreList = service.listService(sort);

        model.addAttribute("scores", scoreList);
        return "chap02/score-list";
    }

    // 점수 신규 등록 요청
    @RequestMapping("/score/register")
    public String register(Score score) {
        log.info("/score/register POST! - " + score);

        return service.saveService(score) ? "redirect:/score/list" : "redirect:/";
    }

    // 점수 삭제 요청
    @RequestMapping("/score/delete")
    public String delete(@RequestParam("stuNum") int sn) {
        log.info("/score/delete GET - param1: {}", sn);
        return service.deleteService(sn) ? "redirect:/score/list" : "redirect:/";
    }

    // 점수 상세 조회 요청
    @RequestMapping("/score/detail")
    public ModelAndView detail(int stuNum) {
        log.info("/score/detail GET - param1: {}", stuNum);
        Score score = service.detailService(stuNum);
        ModelAndView mv = new ModelAndView("chap02/score-detail");
        mv.addObject("s", score);

        return mv;
    }

}

 

 

-- 서비스

package com.spring.webmvc.springmvc.chap03.service;

import com.spring.webmvc.springmvc.chap02.domain.Score;
import com.spring.webmvc.springmvc.chap02.repository.ScoreRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

// 컨트롤러와 레파지토리 중간 로직 처리
@Service // 스프링 빈 등록
@RequiredArgsConstructor
public class ScoreService {

    private final ScoreRepository repository;

    // 점수 목록 요청 중간 처리 메서드
    public List<Score> listService(String sort) {
        // jsp에게 점수 정보 리스트를 전달해야 함.
        List<Score> scoreList = repository.findAll(sort);

        // 이름 마킹 처리
        processMarkName(scoreList);
        return scoreList;
    }

    // 점수 저장 요청 중간 처리
    public boolean saveService(Score score) {
        score.calcTotalAndAvg();
        score.calcGrade();
        return repository.save(score);
    }

    // 점수 삭제 중간처리
    public boolean deleteService(int stuNum) {
        return repository.remove(stuNum);
    }
    // 점수 개별조회 중간처리
    public Score detailService(int stuNum) {
        return repository.findOne(stuNum);
    }

    private void processMarkName(List<Score> scoreList) {
        for (Score s : scoreList) {
            String original = s.getName();
            StringBuilder markName = new StringBuilder(String.valueOf(original.charAt(0)));
            for (int i = 0; i < original.length() - 1; i++) {
                markName.append("*");
            }
            s.setName(markName.toString());
        }
    }
}

 

테스트를 위한 충돌 방지