ㅎㅇ!!

 

 

juso.go.kr 에 접속해서 우측  상단 '개발자 센터'로 이동합니다~

 

 

 

 

그리고 API신청하기 클릭

 

 

 

업체 아무거나 쓰셔도 됩니다

URL 저는 localhost:8080 썼습니다

어짜피 인증키는 즉시나오는거라 상관없는거같기도

 

 

그다음 본인인증 해주시고 인증키를 발급받습니다. (빨간색 글자로 되있음)

인증키만 복사하고 어디 메모장에 적어두세요. 다시 보려면 또 본인인증 해야합니다

guidePopupApiJSP.zip
1.72MB

juso.go.kr 홈페이지에서 제공하는 API 사용 가이드 샘플 jsp파일 입니다. 다운받아주세요.

 

새로운 Dynamic Web Project를 만드시고 다운받은 파일 안에있는 Sample.jsp , jusoPopup.jsp를 붙여넣기 해주세요

 

1. Sample.jsp 에서 jusoPopup을 불러오는 경로부분을 자신의 프로젝트 경로에 맞게 바꿔주셔야합니다

 

2. jusoPopup.jsp 에 발급받았던 인증키를 넣어줍니다.

 

 

 

 

Sample.jsp를 Run on Server 하여 체험해봅니다!!!!!!!! 

 

 

이것을 개인프로젝트에 적용하는 방법을 설명 해드리겠습니다

 

제 임시 프로젝트입니다. jusoPopup.jsp는 그대로 가져와서 사용해야합니다.

 

주소검색 버튼을 누르면, jusoPopup.jsp 이(가) 나오게 해야합니다.

 

주소검색 버튼의 속성값에 onClick="goPopup()" 을 추가해줍니다. 

 

주소입력란(?)(input)의 속성값에 임의의 id="address" 를 추가해줍니다.

어렵지 않습니다

 

 

 

Sample.jsp 의 script 내부에있는 함수 goPopup() , jusoCallBack을 복사해옵니다.

저는 jusoCallBack함수에서 하나의 필드만 사용했기 때문에 하나만 인자로 가져왔습니다

 

체험판에서 했던거랑 똑같이 jusoPopup.jsp 를 찾아주는 경로를 설정해주시면?

 

 

주소검색 버튼클릭 -> 주소 검색( jusoPopup.jsp ) -> input창에 주소검색결과 삽입됨

 

이렇게 실행 될것입니다~~

 

 

 

 

 

 

 

- 웹 서버 (Web Server)

클라이언트가 서버에 페이지 요청을 하면 요청을 받아 정적 컨텐츠(.html, .png, .css등)를 제공하는 서버

클라이언트에서 요청이 올 때 가장 앞에서 요청에 대한 처리를 한다.

클라이언트의 요청을 기다리고 요청에 대한 데이터를 만들어서 응답하는 역할 (정적 데이터)

CASE

정적 컨텐츠를 요청(request)했나?

1. 정적 컨텐츠구나! 내가 제공해줄게 => .html, .png 등 응답(response)

2. 정적 컨텐츠가 아니구나.. 웹서버에서 간단히 처리 못하겠군. WAS에게 처리를 부탁해야겠다! => 결국 WAS가 처리해준 컨텐츠를 받은 웹서버는 응답(response)을 해줌

대표 : Apache, nginx







- WAS (Web Application Server)

동적 컨텐츠를 제공하기 위해 만들어진 애플리케이션 서버 (DB조회, 로직처리가 요구되는 컨텐츠)

JSP,Servlet 구동 환경 제공

컨테이너, 웹컨테이너, 서블릿 컨테이너라고도 부름

* JSP, servlet을 실행시킬 수 있는 소프트웨어 = 컨테이너

동작 프로세스

1. 웹서버로부터 요청이 오면 컨테이너가 받아서 처리

2. 컨테이너는 web.xml을 참조하여 해당 서블릿에 대한 쓰레드 생성하고 httpServletRequest와 httpServletResponse 객체를 생성하여 전달한다.

3. 컨테이너는 서블릿을 호출한다.

4. 호출된 서블릿의 작업을 담당하게 된 쓰레드(2번에서 만든 쓰레드)는 doPost()또는 doGet()을 호출한다.

5. 호출된 doPost(), doGet() 메소드는 생성된 동적 페이지를 Response객체에 담아 컨테이너에 전달한다.

6. 컨테이너는 전달받은 Response객체를 HTTPResponse형태로 바꿔 웹서버에 전달하고 생성되었던 쓰레드를 종료하고 httpServletRequest, httpServletResponse 객체를 소멸시킨다.

대표 : Tomcat, Jeus, JBoss



WAS와 웹 서버 차이

- 동적 컨텐츠 처리를 수행 가능한가 아닌가.

WAS는 정적,동적 처리 둘다 가능하지만 정적처리를 WAS가 하게되면 부하가 많이 걸려서 좋지 않음


* 톰캣(WAS)에는 아파치(웹서버)의 기능(웹서비스데몬, Httpd)를 포함하고 있다.

- 일반적인 WAS, Web Server 구조가 아닌 걸로 알고 있음.


* WAS, Web Server를 따로 두고 쓰는 이유가 성능때문이라고 하는 건 잘못되었다.

톰캣5.5 이상부터는 httpd의 native모듈을 사용해서 정적파일을 처리하는 기능을 제공하는데 이것이 순수 아파치 Httpd만 사용하는 것과 비교해서 성능이 전혀 떨어지지 않기 때문이다.

그럼에도 톰캣앞에 아파치를 두는 이유는 하나의 서버에서 php애플리케이션과 java애플리케이션을 함께 사용하거나, httpd 서버를 간단한 로드밸런싱을 위해서 사용해야 할 때 필요하기 때문.



출처: https://jeong-pro.tistory.com/84 [기본기를 쌓는 정아마추어 코딩블로그]

이전 버전의 hello 프로젝트에는

일단 흐름을 계속 보면서 익힙시다 (가능하다면)


기능소개



로그인 

1. 서비스에서 req.getParameter로 input값을 저장할 String 변수 두 개를 만듬. (username , password)

2. UserDao의 login(Users uesrs) 함수의 매개변수를 만들어주기위해 Users 객체의 틀을 만든다.

3. UserDao 에서 DB연결 후 Users 객체 userEntity 에 DB에서 get해온값으로 build 한다. userEntity를 반환한다.

4. 다시 서비스로 돌아와, if(UserEntity != null) 이라면 



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
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 해서 확인
        // login함수 의 매개변수를 만들어주기위한 빌드업 (Users 틀 만들기)
        Users user = Users.builder()
                .username(username)
                .password(password)
                .build();
 
        // login 함수 실행 (sql로 데이터베이스에 select)
        UsersDao usersDao = new UsersDao();
        //login 의 반환형이 Users
        Users userEntity = usersDao.login(user);       // UserDao
        
        if(userEntity != null) {
            // session에는 사용자 패스워드 절대넣지않기
            // 3번 세션 키 발급
 
            // session 두 줄 이 무슨 역할 하는건가요??
            HttpSession session = req.getSession();
            //setAttribute : name으로 지정한 이름에 value값을 할당합니다.
            session.setAttribute("sessionUser", userEntity); // name , Object(value)
            
            Script.href(resp, "index.jsp""로그인 성공123");
            //한글처리를 위해 resp객체를 건드린다.
            // mime타입
            // http header 에 context-type
            
//            resp.sendRedirect("index.jsp"); 데이터를 들고 이동하는게 아니고 그냥 페이지이동만하는 기능.(필요없음)
            return user;
        }else {
            Script.back(resp, "로그인실패 -1");
            resp.sendRedirect("auth/login.jsp");
        }
        return null;
    }
cs





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
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()) { //출력할 행이 여러개면 while
                Users userEntity = Users.builder()
                        .id(rs.getInt("id"))  //Resultset rs 에서 가져오는중 = DB에서 가져오는중
                        .username(rs.getString("username"))
                        .password(rs.getString("password"))
                        .build();
                System.out.println("로그인 성공");
                return userEntity;
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("로그인 실패");
        return null;
    }
cs





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


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



ㅎㅇ 다이나믹 웹 프로젝트   프로젝트 이름 hello 를 만들어 놓으세요 ~


hello2 는 제가 삽질하느라 잘못 만든 프로젝트입니다 ~~~~





Servers 가 Tomcat 관련 파일이 들어있는곳인데 , web.xml에서 내용 일부를 복붙해서 hello 프로젝트에 새로 만들어 줄겁니다 ~


web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="4.0"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee                       http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
    <servlet>
        <servlet-name>userController</servlet-name>
        <servlet-class>com.cos.hello.controller.UserController</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>boardController</servlet-name>
        <servlet-class>com.cos.hello.controller.BoardController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>userController</servlet-name>
        <url-pattern>/user</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>boardController</servlet-name>
        <url-pattern>/board</url-pattern>
    </servlet-mapping>
</web-app>
cs




WEB-INF 폴더에 저장   ( new - xml file 로 직접 만들어서 코드만 복붙하세요 )






(미완성)



서블릿을 동작하게 만들려면 web.xml 에 필터를 만들어야함 , 서블릿 맵핑을 해야함


URL 패턴을 쓰지않고 URI 패턴을 사용하기위해서임


모든 요청을 한 곳 으로 모으고싶어서 쓰는것 ( 입구를 하나로)





ㅎㅇ 일단  톰캣을 설치하셈


https://tomcat.apache.org/download-90.cgi




9.0버전 , installer 로 다운받으시고






저는 셧다운포트 8005  연결포트 8000 으로 했습니다


연결포트 8080은 oracle의 포트와 충돌이 있을수도 있다고...


톰캣 설치 끝



STS 실행하세요


FIle > New > other > web > 다이나믹 웹 프로젝트 만드세요




타겟 런타임을 톰캣 9.0으로 설정해주세요

설치경로는 기본값으로 하셨다면 

C:\Program Files\Apache Software Foundation\Tomcat 9.0


여기 있을겁니다







이제 jsp 파일을 만들 수 있습니다



jsp 파일은 항상 WebContent 폴더에 작성해주세요


META-INF , WEB-INF 는  외부접근 불가 구역입니다. 주로 프로젝트의 설정파일을 저장하는곳입니다.


뜬금없지만 JSP관련 기초 설명을 하겠습니다


JSP는 쉽게 말하면 html 파일에서 자바코드를 작성할 수 있게 해주는 파일입니다.

톰캣은 하나의 자바 컴파일러 라고 할 수 있어요.



웹서버(아파치)

내 하드디스크의 특정 폴더를 http주소 방식으로 접근할 수 있게 열어둔 것


접근 방법

프로토콜://ip주소:포트번호/컨텍스트루트/자원명

ex) http://localhost:8000/test1/a.html


jsp

html파일안에 java코드를 넣을 수 있는 파일


톰켓

아파치가 처리할 수 없는 .jsp 파일 요청시 동작함. html파일은 그대로

두고 java코드만 컴파일하여 html코드와 그 결과를 .html파일로 만들

어서 응답해줌.


WebContent

프로젝트 폴더내에 유일하게 외부에서 접근할 수 있게 열어둔 영역


컨텍스트루트

웹서버내에 많은 프로젝트들을 구분하기 위해서 필요


URL

자원에 접근하는 법

URI

식별자로 접근하는 법





MySQL에 있는 데이터를 웹에 뿌려봅시다

아까 만든 다이나믹 웹 프로젝트에서 WEB-INF 폴더에, lib폴더에 >  jar파일 하나 추가하고 add 빌드패스 합니다


https://mvnrepository.com/artifact/mysql/mysql-connector-java



저는 8.0.16 버전 썼습니다







그리고 MySQL에 연결을 시켜줄 자바 파일을 하나 만듭니다

패키지명 com.cos.test1.config


얇은 지식으로 말씀드리자면 패키지명(유일해야함) = 도메인(유일함)

그러므로 도메인을 거꾸로 쓴거같은 양식이 유일하기때문에 그렇게 작성한다고 하네요



new > class > DBConn.java 생성




DBConn.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
package com.cos.test1.config;
 
import java.sql.Connection;
import java.sql.DriverManager;
 
public class DBConn {
    public static Connection getConnection() {
        Connection conn = null;
        //localhost 뒤 = DB이름?
        String url = "jdbc:mysql://localhost:3306/ssar?serverTimezone=Asia/Seoul";
        String username = "ㅇㅎㅇㅀㅇㅀㅇㅀ";
        String password = "ㅇㅎㅇㅎㅎㄱㅎ";
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(url, username, password);
            
            System.out.println("DB 연결성공");
            return conn;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
 
cs


String url = "jdbc:mysql://localhost:3306/ssar?serverTimezone=Asia/Seoul";
String username = "ㅇㅀㄷㄱㅎㄷㅎr";
String password = "둃ㅇㅀㅇㅀ";


url = 포트번호뒤에 있는 ssar 은 제 계정에있는 데이터베이스 이름입니다. 각자 환경에 맞게 바꿔주세요

username = 사용자 계정 아이디 입니다.

password = 사용자 계정 비밀번호 입니다.




webcontent > new jsp file


select.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
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="com.cos.test1.config.DBConn"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>찾아보기</title>
</head>
<body>
<%
    String sql = "SELECT * FROM users WHERE id=1";
    Connection conn = DBConn.getConnection();
    PreparedStatement pstmt = 
            conn.prepareStatement(sql);
    ResultSet rs = pstmt.executeQuery();
    
    rs.next();
    int id = rs.getInt("id");
    String username = rs.getString("username");
    String password = rs.getString("password");
    String email = rs.getString("email");
%>
<h3>id : <%=id %></h3>
<h3>username : <%=username %></h3>
<h3>password : <%=password %></h3>
<h3>email : <%=email %></h3>
</body>
</html>
cs

<% %> 로 감싸진 부분에서는 자바코드를 작성해도 되는 곳입니다.


아까 java resource에 만들었던 DBConn을 import 해서 사용하고있습니다.


executeQuery()의 반환값이 Resultset 이기 때문에 새로 변수를 만들어서 저장해줍니다.


rs,next() : 커서를 한 번 이동시켜줍니다 (안하면 안됨)


rs.get@@@ : 새로만든 변수에 get해서 데이터를 넣습니다 .    변수명은 웬만하면 필드명이랑 일치하게 작성합니다 


<%=id %> : 표현식 태그 라고하네요 결과값을 출력합니다.



실행하기전에~~~


크롬으로 바꿔주시고 (알아서 하셈)




프로젝트 폴더를 Run As > Run On Server 를 하신다면 welcome page (기본값 index.jsp , index.html) 을 실행할 것입니다.


그래서 저희는 그냥  select.jsp 를 Run On Server 할겁니다


TomCat 9.0  확인하고 Finish ㄱㄱ







잘 작동하고있네요 다행입니다




1편에서 한 내용


Oracle 사용자 계정만들기 , DB연결하기 , INSERT랑 DELETE 하기




INSERT , DELETE , UPDATE , SELECT (SELECT는 scott 계정에 맞게 작성하였음)

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
 
import config.DBConnection;
import model.Dept;
 
public class MainApp {
 
    public static void main(String[] args) {
//        추가(9);
//        삭제(1);
        찾기(10);
    }
 
    // 함수로 모듈화
    public static void 추가(int id) {
//        String sql = "INSERT INTO test1(id) VALUES("+id+")"; //이렇게하면 인젝션 뚫림
        String sql = "INSERT INTO test1(id) VALUES(?)";
        Connection conn = DBConnection.getinstance();
        // Byte Stream (?)
 
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, id); // 첫번째 '?' 부분에 id를 넣겠다.
            int result = pstmt.executeUpdate(); // 변경된 row count를 리턴, 오류 시 -1를 리턴
            System.out.println("result : " + result);
            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
 
    // 함수로 모듈화
    public static void 삭제(int id) {
        String sql = "DELETE FROM test1 WHERE id = ?";
        Connection conn = DBConnection.getinstance();
        // Byte Stream (?)
 
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, id); // 첫번째 '?' 부분에 id를 넣겠다.
            int result = pstmt.executeUpdate(); // 변경된 row count를 리턴, 오류 시 -1를 리턴
            System.out.println("result : " + result);
//            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
 
    // 함수로 모듈화
    public static void 수정(int id) {
        String sql = "UPDATE test1 SET 4 WHERE id = ?";
        Connection conn = DBConnection.getinstance();
        // Byte Stream (?)
 
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, id); // 첫번째 '?' 부분에 id를 넣겠다.
            int result = pstmt.executeUpdate(); // 변경된 row count를 리턴, 오류 시 -1를 리턴
            System.out.println("result : " + result);
//            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
 
    // 함수로 모듈화 , 사용자 scott으로 변경해야함
    // return값 Dept
    public static Dept 찾기(int deptno) {
        String sql = "SELECT deptno, dname, loc FROM dept WHERE deptno=?";
        Connection conn = DBConnection.getinstance();
        // Byte Stream (?)
 
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, deptno); // 첫번째 '?' 부분에 id를 넣겠다.
            ResultSet rs = pstmt.executeQuery();
            if(rs.next()) {
                Dept dept = Dept.builder()
                        .deptno(rs.getInt("deptno"))
                        .dname(rs.getString("dname"))
                        .loc(rs.getString("loc"))
                        .build();
                System.out.println(dept);
                return dept;
//                int deptno2 = rs.getInt("deptno");
//                String dname = rs.getString("dname");
//                String loc = rs.getString("loc");
//                System.out.println(deptno2);
//                System.out.println(dname);
//                System.out.println(loc);
            }
 
//            int result = pstmt.executeUpdate(); // 변경된 row count를 리턴, 오류 시 -1를 리턴
//            System.out.println("result : " + result);
//            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
 
    
    
    // 함수로 모듈화 , 사용자 scott으로 변경해야함
    // return값 Dept
    public static List<Dept> 전체찾기() {
        String sql = "SELECT deptno, dname, loc FROM dept WHERE deptno=?";
        Connection conn = DBConnection.getinstance();
        // Byte Stream (?)
 
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
//            pstmt.setInt(1, deptno); // 첫번째 '?' 부분에 id를 넣겠다.
            ResultSet rs = pstmt.executeQuery();
            if(rs.next()) {
                Dept dept = Dept.builder()
                        .deptno(rs.getInt("deptno"))
                        .dname(rs.getString("dname"))
                        .loc(rs.getString("loc"))
                        .build();
                System.out.println(dept);
                
//                return dept;
//                int deptno2 = rs.getInt("deptno");
//                String dname = rs.getString("dname");
//                String loc = rs.getString("loc");
//                System.out.println(deptno2);
//                System.out.println(dname);
//                System.out.println(loc);
            }
 
//            int result = pstmt.executeUpdate(); // 변경된 row count를 리턴, 오류 시 -1를 리턴
//            System.out.println("result : " + result);
//            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}
 
cs


모델 먼저 만드세요. [ 만드는이유 : 관리하기 편하기위해서 ? ]


참고로 올리는 scott 스키마 사진


▼Dept 클래스를 모델 패키지에 만든 모습

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package model;
 
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
 
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Dept {
    private int deptno;
    private String dname;
    private String loc;
}
 
cs


lombok.jar 다운로드


https://mvnrepository.com/artifact/org.projectlombok/lombok

알아서 빌드패스




이번에 해볼 일 : 전체찾기 (SELECT)


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
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
import config.DBConnection;
import model.Dept;
 
public class MainApp {
 
    // 함수로 모듈화 , 사용자 scott으로 변경해야함
    // return값 List<Dept>
    public static List<Dept> 전체찾기() {
        String sql = "SELECT deptno, dname, loc FROM dept";
        Connection conn = DBConnection.getinstance();
        // Byte Stream (?)
 
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();
            
            //List 하위에 vector , ArrayList가 있음, 선언은 반복문위에
            List<Dept> listDept = new ArrayList<Dept>();
            while(rs.next()) {
                Dept dept = Dept.builder()
                        .deptno(rs.getInt("deptno"))
                        .dname(rs.getString("dname"))
                        .loc(rs.getString("loc"))
                        .build();
                System.out.println(dept); //toString() 작동 ?
                
                //컬렉션에 담기
                listDept.add(dept);
            }
            return listDept;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    
    public static void main(String[] args) {
//        추가(9);
//        삭제(1);
//        찾기(10);
//        Dept dept = 찾기(10);
        List<Dept> listDept = 전체찾기();
    }
}
 
cs

메서드 전체찾기()만 보면 됩니다.

예제 준비물 : Oracle sqldeveloper , sts tool , ojdbc6.jar


1. sqldeveloper 에 존재하는 데이터베이스에 연동을 할것이기 때문에 사용자계정이 있어야한다.

만들어보자.


먼저 모든 권한을 갖고있는 system 계정에 로그인을 한 뒤 아래 명령어를 실행한다.


-- 앞으로 사용할 사용자이름 , 비밀번호

CREATE USER superuser IDENTIFIED BY 1234; -- 사용자를 만들면 데이터베이스가 같이 만들어짐

GRANT CREATE SESSION TO superuser;

GRANT CREATE TABLE TO superuser;

GRANT CREATE TABLESPACE TO superuser;

GRANT UNLIMITED TABLESPACE TO superuser;



2. Ojdbc6.jar를 다운받아서 buildpath를 한다.


https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc6/11.2.0.4 


여기서 다운받으면 아마 될 지도 ?


oracle developer 가있다면 이 경로에 가면 jar파일이 있을것이다. 나는 여기 있는걸 복붙해서 썼다.

C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib



Build Path 성공한 사진







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
package config;
 
import java.sql.Connection;
import java.sql.DriverManager;
 
public class DBConnection {
    //커넥션을 리턴하는게 목적입니다
    //PC의 서버에 연결할것입니다
    public static Connection getinstance() {
        Connection conn = null;
        String url = "jdbc:oracle:thin:@localhost:1521:xe"; //고정
        String user = "superuser"; //사용자계정
        String password = "1234";
        
        //OracleDriver 클래스를 메모리에 로드, 알집파일 안에 있음
        //패키지 경로
        try {
            //문자열에 오류가 있을수도있으니 자체적으로 try문을 권장함
            //reflection 메모리에떠있는 타입을 찾아낸다 (getconnection 컨트롤 클릭 해보시오)
            Class.forName("oracle.jdbc.driver.OracleDriver");
            conn = DriverManager.getConnection(url, user, password);
            System.out.println("DB연결 성공이요");
            return conn;
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("연결 실패");
        return null;
    } // end of getinstance 
}
 
cs


문자열에서 오타가 발생하거나 인터넷이 끊겨있지 않은 이상 연결 성공 할것이다.




3. 자바로 데이터 INSERT 해보기


새 클래스를 만들고 메인함수를 만듭니다.


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
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
 
import config.DBConnection;
 
public class MainApp {
 
    public static void main(String[] args) {
        String sql = "INSERT INTO test1(id) VALUES(1)";
        Connection conn = DBConnection.getinstance();
        // Byte Stream  (?)
        
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        
    }
 
}
 
cs


아 지금 보니 id필드를 갖고있는 test1 이라는 테이블이 있어야한다 알아서 만드십쇼



4. 함수로 모듈화

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
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
 
import config.DBConnection;
 
public class MainApp {
 
    public static void main(String[] args) {
        추가(9);
        삭제(1);
    }
    //함수로 모듈화
    public static void 추가(int id) {
//        String sql = "INSERT INTO test1(id) VALUES("+id+")"; //이렇게하면 인젝션 뚫림
        String sql = "INSERT INTO test1(id) VALUES(?)";
        Connection conn = DBConnection.getinstance();
        // Byte Stream  (?)
        
        try {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, id); // 첫번째 '?' 부분에 id를 넣겠다.
            int result = pstmt.executeUpdate(); // 변경된 row count를 리턴, 오류 시 -1를 리턴
            System.out.println("result : " + result);
//            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    //함수로 모듈화
        public static void 삭제(int id) {
//            String sql = "INSERT INTO test1(id) VALUES("+id+")"; //이렇게하면 인젝션 뚫림
            String sql = "DELETE FROM test1 WHERE id = ?";
            Connection conn = DBConnection.getinstance();
            // Byte Stream  (?)
            
            try {
                PreparedStatement pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, id); // 첫번째 '?' 부분에 id를 넣겠다.
                int result = pstmt.executeUpdate(); // 변경된 row count를 리턴, 오류 시 -1를 리턴
                System.out.println("result : " + result);
//                pstmt.executeUpdate();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
 
}
 
cs



ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

pstmt를 알고있다면 코드이해에 조금 도움이 될것입니다...

하지만 저는 아직 모르겠네요 알게되면 추가하겠습니다.


+ Recent posts