Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

우리마의 웹 개발

[Spring]학생들의 성적에 대한 CRUD기능 구현(데이터베이스 없이 DAO의 List로 DB대용) 본문

WEB/Spring

[Spring]학생들의 성적에 대한 CRUD기능 구현(데이터베이스 없이 DAO의 List로 DB대용)

우리마 2020. 2. 17. 17:22

Spring환경에서 간단한 예제를 통해 Spring 웹페이지의 백앤드 에서의동작과정에 대해서 Controller, Service, DAO, VO 각각의 역할들을 이해하는 예제로 글을 쓴다.

완성할 예제의 대략적인 흐름은 다음과 같다.

1. 학생들의 이름과 성적을 입력받는다.

2. 등록 성공 화면과 '전체 조회' , '개인 점수 조회' 버튼이 있다.

3. 전체 조회에서는 List의 index번호를 이용해 삭제할 수 있다.

4. 개인 조회에서는 index번호를 이용해 List에서 가져온 데이터를 출력한다.

 

프로젝트 구조

실무 같은 경우에는 DAO에서 SQL을 매핑하여 데이터를 조작 하지만 이번 예제에서는 DB를 연결하지 않고 DAO에서 List를 생성하여 DB를 대용한다

VO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class ScoreVO {
    private String stuName;
    private Integer kor;
    private Integer eng;
    private Integer math;
    private Integer total;
    private Double avg;
    
    
    //총점, 평균을 구하는 메서드
    /*math.round
     *  ex) 88.3453454 를 math.round -> 88
     *  88 *100 = 8834.53111 를 math.round ->8834
     *  88/100 = 88.34
     * */
    public void calcData() {
        this.total = this.kor + this.eng + this.math;
        this.avg = Math.round((this.total / 3.0* 100/ 100.0;
    }
    
    public String getStuName() {
        return stuName;
    }
    public void setStuName(String stuName) {
        this.stuName = stuName;
    }
    public Integer getKor() {
        return kor;
    }
    public void setKor(Integer kor) {
        this.kor = kor;
    }
    public Integer getEng() {
        return eng;
    }
    public void setEng(Integer eng) {
        this.eng = eng;
    }
    public Integer getMath() {
        return math;
    }
    public void setMath(Integer math) {
        this.math = math;
    }
    public Integer getTotal() {
        return total;
    }
    public void setTotal(Integer total) {
        this.total = total;
    }
    public Double getAvg() {
        return avg;
    }
    public void setAvg(Double avg) {
        this.avg = avg;
    }
    @Override
    public String toString() {
        return "ScoreVO [stuName=" + stuName + ", kor=" + kor + ", eng=" + eng + ", math=" + math + ", total=" + total
                + ", avg=" + avg + "]";
    }
    
    
}
 
cs

앞 선 글들에서 VO에 대해 설명한 바 있다. VO는 커맨드 객체로서 데이터베이스의 칼럼들을 변수명으로 하여 getter, setter를 생성하고 Controller에서 데이터를 받을 수 있게 Class화 해놓은 것이다. VO를 이용한 파라미터 테스트는 아래 글을 참고하길 바란다.

https://onecutwook.tistory.com/13

 

[Spring]JSP에서 요청 파라미터를 Controller에서 처리하는 방법(커맨드 객체 사용)

앞선 글 들에서 view단에서 java단으로 데이터를 넘기는 데에 있어서 원초적이 방법들을 소개하였다. 이번엔 마지막으로 진짜 SpringFramework에 걸맞게 데이터를 처리하는 방법을 내 머가리 속에 기억하려고 글..

onecutwook.tistory.com

또한 16 Line의 calcData 함수에서 점수 총합과 평균을 구하는데, 소수점 n번째 자리에서 반올림하고 싶을 때의 방법을 주석으로 적어 놨지만, 아래 링크에서 설명해놨다. 참고하시길..

https://onecutwook.tistory.com/15

 

[JAVA]소수점 n번째 자리 반올림(Math.round, String.format)

어떠한 값의 평균값 따위를 구할 때나 실수를 이용한 데이터를 원하는 소수점 자리 까지만 출력할 때 반올림을 해야 할 일이 있을 거다 Math.round() Math.round 함수는 무조건 소수 첫 번째 자리를 반올림하여..

onecutwook.tistory.com

 

Controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.training.bbs.controller;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
import com.training.bbs.VO.ScoreVO;
import com.training.bbs.service.IScoreService;
 
@Controller
@RequestMapping("/score")
public class ScoreController {
    
    @Autowired
    private IScoreService service;
    
    //점수 등록 화면을 열어주는 요청 메서드
    @GetMapping("/register")
    public String register() {
        System.out.println("/score/register : GET 요청!");
        return "score/write-form";
    }
 
    //점수 등록을 처리하는 요청 메서드
    @PostMapping("/register")
    public String register(ScoreVO scores) {
        System.out.println("/score/register : POST 요청!");
        System.out.println("Scontroller param: " + scores);
        service.insertScore(scores);
        return "score/write-result";
    }
    
    //점수 전체 조회를 처리하는 요청 메서드
    @GetMapping("/list")
    public void list(Model model) {
        System.out.println("/score/lsit : get 요청 !");
        model.addAttribute("sList",service.selectAllScores());
    }
    //학생 삭제 하기
    @GetMapping("/delete")
    public String delete(@RequestParam("stuNum"int stuNum, RedirectAttributes ra) { //get으로 넘어오는 key명과 메서드의 파라미터 변수 명이 같으면 @RequestParam과 같은 역할을 한다.
        System.out.println(stuNum + "<- 학생 삭제되었습니다");
        service.deleteScore(stuNum);
        ra.addFlashAttribute("message","delSuccess");
        return "redirect:/score/list";
    }
    //점수 개별 조회 화면 요청 메서드
    @GetMapping("/search")
    public void search() {
        System.out.println("/score/search get요청!");
    }
    
    
    
    //학번으로 요청한 점수 조회 요청 메서드
    @GetMapping("/selectOne")
    public String selectOne(String stuNum, Model model, RedirectAttributes ra) {
        //String으로 학번을 받아서 숫자말고 다른 문자 입력 하면 catch로가서 리다이렉트 메시지 출력
        String result="";
        List<ScoreVO> list = service.selectAllScores(); //리스트에 없는 숫자 인지 확인을 위해 selectAll 호출 해서 사이즈 구한다
        try {
            int n = Integer.parseInt(stuNum);//정상적으로 받았으면 stunum을 Integer.pareseint 형변환
            if(n > list.size()) {
                ra.addFlashAttribute("msg","학번 정보가 없다");
                result = "redirect:/score/search"//사이즈보다 크면 리다이렉트 메시지 
            }else {
                model.addAttribute("stu",service.selectOne(n));    
                model.addAttribute("stuNum",n);
                result = "score/selectOne"//아니면 정상 selectOne리턴
            }
            
        } catch (Exception e) {
            System.out.println("cath : "+e.getMessage());
            ra.addFlashAttribute("msg""숫자로만 입력하세요!");
            result =  "redirect:/score/search";
        }
        
        return result;
    }
}                                                                                                                                                                  
 
cs

Controller를 먼저 작성함으로써 본격적인 백앤드 서비스 개발의 시작이다. 

22 Line : Service클래스는 이따 바로 작성할 건데 @Autowired 어노테이션은 서비스 객체에 대한 자동 빈등 록 기능을 가진 어노테이션이다.

 

44 Line : model.addAttribute 메서드를 사용해서 jsp단에 데이터를 EL 식으로 쓰려고 하는데 Service단에서 selectAllScores함수를 호출해 리턴 값을 sList란 이름으로 넣는 것이다. 이는 selectAllScores함수의 return 타입이 List이기 때문에 jsp단에서 c:forEach 문으로 반복문을 돌려 데이터를 출력할 것이다.

 

48 Line : 파라미터로 RedirectAttributes 객체를 받는데 이것은 삭제 버튼을 눌렀을 때 화면에 메시지를 표시하기 위함인데 /score/list를 리다이렉트로 호출할 때만 속성을 추가해서 페이지를 띄움으로 addFlashAttribute함수를 이용해 model객체에 데이터를 담는 것과 같은 형식으로 사용한다. 

 

61 Line : 학번을 입력받아서 단건 조회를 하는 기능이 있는데 학번이라는 것은 사실 DAO에서 DB대용으로 List를 만들어서 데이터를 저장한다고 언급했었는데 List의 index값을 나타내는 것이다.  그러므로 index 값은 int형인데 파라미터를 String으로 받는 이유는 65 Line에서 Integer.parseInt() 메서드를 이용하는데 이 메서드는 문자열이 예를 들어 "3" 이런 식으로 들어왔을 때 3을 int로 변환해주는 것이다. 그러니까 숫자를 문자열로 입력받으면 숫자로 데이터 타입을 변경해주는 것이다. 그런데 숫자가 아닌 다른 문자를 Integer.parseInt() 안에 넣으면 에러가 나서 catch문으로 가게 된다. 이를 이용한 숫자만 입력받는 방법이다.

 

63 Line : selectAllScores메서드는 전체 학생의 리스트를 조회할 메서드인데,. size() 함수를 이용해 크기를 구해서 터무니없는 숫자를 입력했는지 안 했는지 체크할 수 있다.

 

70 Line : 입력값이 정상 일 때 Model 객체에다가 jsp단에서 EL 식으로 쓸 수 있게 값을 담고 return 하도록 한다.

 

Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.training.bbs.service;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.training.bbs.VO.ScoreVO;
import com.training.bbs.repository.IScoreDAO;
 
@Service
public class ScoreService implements IScoreService {
    
    @Autowired
    private IScoreDAO dao;
    
    //점수 등록 기능
    @Override
    public void insertScore(ScoreVO scores) {
        scores.calcData();
        dao.insertScore(scores);
    }
    
    //전체 점수 조회 기능
    @Override
    public List<ScoreVO> selectAllScores() {
        return dao.selectAllScores();
    }
    
    //점수 삭제 기능
    @Override
    public void deleteScore(int stuNum) {
        dao.deleteScore(stuNum-1);
 
    }
    
    //index로 학생 점수 조회 기능
    @Override
    public ScoreVO selectOne(int stuNum) {
        return dao.selectOne(stuNum-1);
        
    }
 
}
 
 
cs

이제 Service단이다 interface는 이 메서드들의 원형이니까 생략하겠다. 점수 삭제 기능과 점수 stuNum을 파라미터로 받고 dao로 보낼 때 -1을 하는 이유는 stuNum이 사실은 DAO에서 List의 index값이라고 했는데 jsp단에서 학생을 등록할 때 학생 번호를 1부터 넣을 것이기 때문이다. 파라미터를 전달받는 곳에서 데이터를 조작하는, 이것이 Service의 역할이다

DAO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.training.bbs.repository;
 
import java.util.ArrayList;
import java.util.List;
 
import org.springframework.stereotype.Repository;
 
import com.training.bbs.VO.ScoreVO;
 
@Repository
public class ScoreDAO implements IScoreDAO {
    
    //학생들의 점수정보를 저장할 리스트 생성(DB 대용)
    private List<ScoreVO> scoreList = new ArrayList<>();
 
    @Override
    public void insertScore(ScoreVO scores) {
        System.out.println("Repository param : "+ scores);
        scoreList.add(scores);
    }
 
    @Override
    public List<ScoreVO> selectAllScores() {
        return scoreList;
    }
 
    @Override
    public void deleteScore(int stuNum) {
        scoreList.remove(stuNum);
    }
 
    @Override
    public ScoreVO selectOne(int stuNum) {
        return scoreList.get(stuNum);
        
    }
 
}
 
 
cs

DAO도 마찬가지로 interface는 메서드 들의 원형이기 때문에 생략한다. 먼저 처음에 언급했듯이 List를 하나 선언해서 이곳에 저장한다 DB대용으로.. 그리고 각각의 기능에서 List의 내장 함수를 이용해 CRUD를 실행한다. 실질적인 데이터의 삽입 삭제가 이루어지는 곳이 DAO이다.

 

이제 JSP 코드들과 결과 화면을 공개하겠다.

JSP , 결과
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
-------------------------list.jsp----------------------------
<body>
    <h1>전체 성적 조회</h1>
    <c:forEach var="stu" items="${sList}" varStatus="stuNum">
        <p>
            #번호 : ${stuNum.index+1}<br>
            #이름 : ${stu.stuName}<br>
            #영어 : ${stu.eng}<br>
            #국어 : ${stu.kor}<br>
            #수학 : ${stu.math}<br>
            #총점 : ${stu.total}<br>
            #평균 : ${stu.avg}<br>
            <a href="/bbs/score/delete?stuNum=${stuNum.index+1}">[삭제]</a>
            ============================<br>
        </p>
    </c:forEach>
    <a href="/bbs/score/register">다른 점수 등록 하기~</a>
    
<script type="text/javascript">
    const msg = "${message}";
    if(msg === "delSuccess"){
        alert("삭제 완료");
    }
</script>
</body>
-------------------------write-form.jsp----------------------------
<body>
    <h1>시험 점수 등록</h1>
    <form method="post">
        <p>
            #name : <input name="stuName"><br>
            #kor : <input name="kor"><br>
            #eng : <input name="eng"><br>
            #math : <input name="math"><br>
            <input type="submit" value="전송">
        </p>
    </form>
</body>
-------------------------write-result.jsp----------------------------
<body>
    <h1>점수 등록 성공~</h1>
    <p>
        <a href="/bbs/score/register">다른 점수 등록 하기~</a>
        <a href="/bbs/score/list">점수 전체조회</a>
        <a href="/bbs/score/search">점수 개별 조회</a>
    </p>
</body>
-------------------------search.jsp----------------------------
<body>
<h1>학번으로 점수 조회</h1>
<form action="/bbs/score/selectOne" method="get">
    <p>
    # searchNum : <input name="stuNum">
    </p>
    <input type="submit" value="확인">
    </form>
    <p style="color:red;">${msg}</p>
</body>
-------------------------selectOne.jsp----------------------------
<body>
    <h1>${stuNum}번 ${stu.stuName} 학생 성적 조회</h1>
    #영어 : ${stu.eng}<br>
    #국어 : ${stu.kor}<br>
    #수학 : ${stu.math}<br>
    #총점 : ${stu.total}<br>
    #평균 : ${stu.avg}<br>
</body>
 
 
cs

여기까지.. 잘된다.. 

Comments