ㅎㅇ 이번 실습은 정말 이해를 잘 해야하는, 하고싶은 부분이다


MVC가 웹 에서 가장 활용이 많이된다던  그 분의 말씀, 이제야 이해가 되는것 같다



먼저 MVC의 흐름? 을 그림으로 한눈에 보자



용어 설명

Model무엇을 할지 정의합니다. 비지니스 로직에서의 알고리즘, 데이터 등의 기능을 처합니다.
Controller어떻게 할지를 정의합니다. 요청을 받아서 화면과 Model과 View를 연결시켜주는 역할을 하지요.
View무엇을 화면으로 보여주는 역할을 하지요. 웹이라면 웹페이지, 모바일이라면 어플의 화면의 보여지는 부분입니다.



용어 설명2

Model: 어플리케이션의 데이터, 자료를 의미합니다.
View: 사용자에게 보여지는 부분, 즉 유저 인터페이스(User interface)를 의미합니다.

Controller: Model과 View사이를 이어주는 브릿지(Bridge)역할을 의미합니다.



용어 설명3

모델(Model)

프로그램에 사용되는 데이터를 의미하며 데이터베이스(DB), 상수, 문자열과 같은 변수들, 비전 프로그램이라면 카메라 정보와 같은 것들이 해당됩니다. 모델에는 뷰나 컨트롤러의 정보가 전혀 없습니다. 단지, 정보만 반환하거나 설정할 수 있습니다.

뷰(View)

다이얼로그에 존재하는 텍스트박스, 라벨, 버튼 등 사용자 인터페이스(User interface) 요소들을 의미합니다. 사용자가 제어하고 데이터를 확인할 수 있는 영역입니다. 뷰에서는 별도의 데이터를 보관하지 않습니다. 뷰에서 입력받고 출력해주는 모든 데이터는 모델을 사용해야합니다.

컨트롤러(Controller)

모델과 뷰를 관장하는 브릿지(Bridge)역할을 수행합니다. 사용자가 버튼을 클릭하면 이벤트는 뷰에서 발생하지만 내부 처리는 컨트롤러에서 관리하는 것입니다. 또한, 입력이 발생하면 이에 대한 통지를 담당합니다.


용어 설명4

M (model, domain)

M은 Model을 가리킨다.
Model이란 프로그램이 작업하는 세계관의 요소들을 개념적으로 정의한 것이라고 볼 수 있다.
예를 들어 음식점 무인 포스기를 개발한다고 가정해보자. 무인포스기가 정상적으로 목표하는 작업을 수행하기 위해서는 우선 메뉴가 있어야하고, 메뉴를 담을 수 있는 장바구니, 해당 메뉴의 수량, 결제수단, 할인정책 등등이 필요할 것이다.

이처럼 프로그램이 목표하는 작업을 원활하게 수행하기 위해 필요한 물리적 개체, 규칙, 작업등의 요소들을 구분되는 역할로써 정의해놓은게 Model이 된다. Model은 DTO와 DAO로 분류할 수 있다.
두 개념에 대해서는 나중에 다른 세션에서 정리할 예정이므로 간단히 언급만하고 넘어가겠다.

결과적으로 Model을 잘 설계하는 것은, 해당 도메인 세계를 얼마만큼 이해하고 있는지와도 밀접한 연관이 있다. 꼭 물리적인 요소뿐만아니라 추상적인 요소 또한 해당 작업을 수행하는데 특정 책임과 역할로서 구분될 수 있다면 최대한 구체적이고 작은 entitiy를 유지하면서 Model을 설계하는 것이 중요하다.

V (view)

V는 View를 가리키고 사용자가 보는 화면에 입출력 과정 및 결과를 보여주기 위한 역할을 한다. 입출력의 순서나 데이터 양식은 컨트롤러에 종속되어 결정되고, 도메인 모델의 상태를 변환하거나, 받아서 렌더링하는 역할을 한다.

view를 구현할 때 주의할 점은 도메인 로직의 어떤 것도 알고 있으면 안된다는 것이다. 절대적으로 객체를 전달받아 상태를 바로 출력하는 역할만을 담당해야 한다. 그렇기 때문에 view에서는 도메인 객체의 상태를 따로 저장하고 관리하는 클래스 변수 혹은 인스턴스 변수가 있을 필요가 없다.

C (controller)

C는 Controller를 가리킨다. controller는 model과 view를 연결 시켜주는 다리 역할을 함과 동시에 도메인 객체들의 조합을 통해 프로그램의 작동 순서나 방식을 제어한다. controller는 view와 model이 각각 어떤 역할과 책임이 있는 지 알고 있어야 한다.

웹 프로그래밍에서는 Controller에서 service layer를 분리하여 domain 로직이 수행되는 곳과 view의 요청을 매핑하는 곳을 독립적으로 관리할 수 있다.


웹사이트 개발시 MVC 패턴을 적용하는 일반적인 목적

- 애플리케이션에 데이터 구조와 Model(비지니스 로직)은 전형적으로 자주 변경되지 않지만, 데이터의 View(프레젠테이션 로직)은 사실 자주 변경되기 때문에 Model(비즈니스 로직)과 View(프레젠테이션 로직)을 분리함으로써 이러한 요구의 변경에 따라 애플리케이션에 유지보수가 쉬워진다. 

예를 들어 웹사이트가 보여주는 데이터 구조에는 변함이 없지만, 국내외의 사용자에게 다양한 언어로 데이터를 보여주어야 할 경우 또는 PC/스마트폰/스마트TV 등과 같은 해상도가 다른 장치에서 동일한 데이터를 보여주어야 할 경우 Model(비즈니스 로직)은 유지하고, View(프레젠테이션 로직)만 수정하면 된다. 즉 MVC 패턴을 사용하면 웹사이트의 유지보수가 쉽다.

Model(비지니스 로직)을 담당하는 웹 개발자와 View(프레젠테이션 로직)을 담당하는 웹 디자이너 분리된 작업이 가능하다.





추가 설명

JSP 에서 JAVA로 데이터를 전송하려면 그냥 form action="" 을 이용하면 되지만


JAVA의 데이터를 JSP로 넣으려면 Dispatcher 에 데이터를 담아서 보내야한다.

보내주는 사람(?)은 Request 객체 이다.




실습한 코드 


UsersController.java

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
package com.cos.hello.controller;
 
import java.io.IOException;
import java.sql.SQLException;
 
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
//javax 로 시작하는 패키지는 톰캣이 갖고있는 라이브러리이다.
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
import com.cos.hello.model.Users;
import com.cos.hello.service.UsersService;
 
public class UserController extends HttpServlet {
    // 12월 21알 월요일
    // req , res는 톰캣이 만들어줌. (클라이언트의 요청이 있을 때 마다)
    // req는 Reader 할 수 있는 ByteStream 요청
    // res는 Writer 할 수 있는 ByteStream 응답
    // http://localhost:8000/hello/user?gubun=login
 
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        String gubun = req.getParameter("gubun");
//        route(gubun, req, resp);
        System.out.println("doGet실행됨");
        doProcess(req, resp);
    }
 
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost실행됨");
        doProcess(req, resp);
    }
 
    protected void doProcess(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//      super.doGet(req, resp);
        System.out.println("UserController 실행됨");
 
        String gubun = req.getParameter("gubun");
        System.out.println(gubun);
        try {
            route(gubun, req, resp);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
 
    private void route(String gubun, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException, SQLException {
        UsersService usersService = new UsersService();
        
        if (gubun.equals("login")) {
            resp.sendRedirect("auth/login.jsp"); //loginProc 버튼
        } else if (gubun.equals("join")) {
            resp.sendRedirect("auth/join.jsp"); // joinProc 버튼
        } else if (gubun.equals("selectOne")) {
            usersService.유저정보보기(req, resp);
        } else if (gubun.equals("updateOne")) {
            usersService.유저정보수정페이지(req, resp);
        } else if (gubun.equals("joinProc")) { 
            usersService.회원가입(req, resp);
        } else if (gubun.equals("loginProc")) {
            usersService.로그인(req, resp);
            //SELECT id, username, email From users where username = ? and password = ?
            //DAO 함수명 : login() , return -> Users Object
            //정상 -> 세션을 담고 index.jsp , 비정상 -> login.jsp
        }
    }
}
 
cs

UsersService 객체를 만들어서 route에서 열심히 일하고있다.




UsersService.java

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.cos.hello.service;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
 
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
import com.cos.hello.dao.UsersDao;
import com.cos.hello.model.Users;
 
public class UsersService {
    public void 회원가입(HttpServletRequest req, HttpServletResponse resp) throws SQLException, IOException {
        //input 에서 값을 받아옴
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String email = req.getParameter("email");
 
        System.out.println("=========joinProc Start=========");
        System.out.println(username);
        System.out.println(password);
        System.out.println(email);
        System.out.println("=========joinProc End=========");
        // 2번 DB에 연결해서 3가지 값을 INSERT하기
        // input 값을 토대로 Users 빌드
        Users user = Users.builder()
                .username(username)
                .password(password)
                .email(email)
                .build();
        
        // insert 함수 실행 (sql로 데이터베이스에 insert)  
        UsersDao usersDao = new UsersDao();
        int result = usersDao.insert(user); //pstmt
        
        if(result == 1) {
               resp.sendRedirect("auth/login.jsp");
            } else {
               resp.sendRedirect("auth/join.jsp");
            }
    }
    
    public Users 로그인(HttpServletRequest req, HttpServletResponse resp) throws SQLException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("=========loginPorc Start=========");
        System.out.println(username);
        System.out.println(password);
        System.out.println("=========loginPorc End=========");
        // 2번 DB값이 있는지 select 해서 확인 (생략)
        Users user = Users.builder()
                .username(username)
                .password(password)
                .build();
 
        // login 함수 실행 (sql로 데이터베이스에 select)
        UsersDao usersDao = new UsersDao();
        Users userEntity = usersDao.login(user);
        
        if(userEntity != null) {
            // session에는 사용자 패스워드 절대넣지않기
            // 3번 세션 키 발급
            HttpSession session = req.getSession();
            
            //setAttribute : name으로 지정한 이름에 value값을 할당합니다.
            session.setAttribute("sessionUser", userEntity); // name , value
            
            resp.sendRedirect("index.jsp");
            return user;
        }else {
            resp.sendRedirect("auth/login.jsp");
        }
        return null;
    }
    
    public void 유저정보보기(HttpServletRequest req, HttpServletResponse resp) throws SQLException, IOException, ServletException {
        HttpSession session = req.getSession();
        
        Users users = (Users)session.getAttribute("sessionUser");
        UsersDao usersDao = new UsersDao();
        if(users != null) {
            Users userEntity = usersDao.selectById(users.getId());
            req.setAttribute("users", userEntity); // name , Object
            
            // xxx.jsp로 이동할겁니다 라는 객체
            RequestDispatcher dis = req.getRequestDispatcher("user/selectOne.jsp");
            
            // 덮어쓰기
            dis.forward(req, resp);
        }else {
            System.out.println("유저정보보기() 실패");
        }
    }
    
    public void 유저정보수정페이지(HttpServletRequest req, HttpServletResponse resp) throws SQLException, IOException, ServletException {
        HttpSession session = req.getSession();
        Users users = (Users)session.getAttribute("sessionUser");
        UsersDao usersDao = new UsersDao();
        if(users != null) {
            Users userEntity = usersDao.selectById(users.getId());
            req.setAttribute("user", userEntity); // name , Object
            
            // xxx.jsp로 이동할겁니다 라는 객체
            RequestDispatcher dis = req.getRequestDispatcher("user/updateOne.jsp");
            
            // 덮어쓰기
            dis.forward(req, resp);
        }
    }
}
 
cs

Model (User 객체) , UserDao , MySQL 셋을 모두 활용하고 있다.

정확하게는 Model, UserDao 두가지. (UserDao 안에 MySQL Query가 있다.)



UserDao.java

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package com.cos.hello.dao;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import com.cos.hello.config.DBConnMySQL;
import com.cos.hello.model.Users;
 
public class UsersDao {
    //(String username,String password,String email)
    public int insert(Users users) throws SQLException {// 회원가입수행해줘
        // 1번 form의 input태그에 있는 3가지 값 username, passeword, email받기
            
        StringBuffer sb = new StringBuffer();
        sb.append("INSERT INTO users(username, password, email)");
        sb.append("VALUES(?,?,?)");
        String sql = sb.toString();
        Connection conn = DBConnMySQL.getInstance();
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, users.getUsername());
            pstmt.setString(2, users.getPassword());
            pstmt.setString(3, users.getEmail());
            int result2 = pstmt.executeUpdate(); // 변경된 row count를 리턴, 오류 시 -1를 리턴
            
//            pstmt.executeUpdate();
             
//            return pstmt.executeUpdate();
            if(result2 == 1) {
                System.out.println("result2 : " + result2);
                System.out.println("회원가입 성공");
                return 1;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 3번 INSERT가 정상적으로 되었다면 index.jsp
        
        return -1;
    }
    
    public Users login(Users users) throws SQLException {
        StringBuffer sb = new StringBuffer();
        sb.append("SELECT id, username, password, email FROM users WHERE username = ? AND password = ?");
        String sql = sb.toString();
        Connection conn = DBConnMySQL.getInstance();
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, users.getUsername());
            pstmt.setString(2, users.getPassword());
//            int result2 = pstmt.executeQuery(sql); // 변경된 row count를 리턴, 오류 시 -1를 리턴
//            System.out.println("result2 : " + result2);
            
            
            ResultSet rs = pstmt.executeQuery();
            if(rs.next()) {
                Users userEntity = Users.builder()
                        .id(rs.getInt("id"))
                        .username(rs.getString("username"))
                        .password(rs.getString("password"))
                        .build();
                
                return userEntity;
            }
            System.out.println("로그인 성공");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("로그인 실패");
        return null;
    }
    
    public Users selectById(int id) throws SQLException {
        StringBuffer sb = new StringBuffer(); //간단한 문장은 String 으로 , 복잡한 문장은 Buffer로
        sb.append("SELECT id, username, password, email FROM users WHERE id = ?");
        String sql = sb.toString();
        
        Connection conn = DBConnMySQL.getInstance();
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, id);            
//            int result2 = pstmt.executeQuery(sql); // 변경된 row count를 리턴, 오류 시 -1를 리턴
//            System.out.println("result2 : " + result2);        
            ResultSet rs = pstmt.executeQuery();
            if(rs.next()) {
                Users userEntity = Users.builder()
                        .id(rs.getInt("id"))
                        .username(rs.getString("username"))
                        .password(rs.getString("password"))
                        .email(rs.getString("email"))
                        .build();
                System.out.println("SelectById 성공");
                return userEntity;
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("SelectById 실패");
        return null;
    }
}
 
cs



UsersService 에서 사용할 수 있도록 반환형이 Users 객체나 , success 인 정보를 함수로 반환한다.







hello 프로젝트 참고


https://github.com/tony6303/jspwork



+ Recent posts