Java Web Programming 4일차
Hello World! Servlet만들기 WEB-INF의classes디렉토리에 HelloServlet.java파일을 생성해서 컴파일 HelloServlet.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println(“<html><body>”); out.println(“<h1> Hello World </h1>”); out.println(“</body></html>”); } } 실행 : http://localhost:8080/MySample/servlet/HelloServlet
서블릿이란? 서블릿은 Servlet인터페이스를 구현하여 GenericServlet을 만들고 이를 다시 Http프로토콜에 맞게 확장한 HttpServlet클래스를 상속한 후 내부 메서드를 재정의하여 사용
서블릿의 동작 서블릿의 동작 순서 클라이언트의 요청 서블릿 Handler 8080포트에서 요청 받음 서블릿 컨테이너에서 해당 서블릿 검색 해당 서블릿이 데이터 베이스 작업을 해야 한다면 DB연결, 작업 모든 작업이 완료 되었다면 응답으로 결과를 리턴한다.
서블릿의 상속구조 GenericServlet은 서블릿으로 클라이언트와 네트웍통신을 할 때 필요한 인터페이스. 그리고 구현된 GenericServlet을 Http프로토콜에 맞게 다시 확장시킨 것이 바로 HttpServlet
GenericServlet abstract 클래스 GenericServlet은, Servlet의 가장 기본이 되는 클래스로, 실제로 서블릿을 만들 때 상속받아 쓰는 HttpServlet도 이 GenericServlet을 상속받은 클래스이다. 웹 애플리케이션은 거의 모두가 Http프로토콜을 기반으로 하기 때문에, 이에 알맞게 만들어진 HttpServlet을 상속하여 서블릿을 작성하는것이 일반적이다.
GenericServlet의 예 GenericServletTest.java import java.io.*; import java.util.Enumeration; import javax.servlet.*; public class GenericServletTest extends GenericServlet { public void service(ServletRequest req, ServletResponse res) thro ws ServletException, IOException { String message = req.getParameter("message"); PrintWriter out=res.getWriter(); out.println("<html><body>"); out.println("<h1>" + message + "</h1>"); out.println("</body></html>"); } }
Servlet 인터페이스 서블릿 프로그램은 init, service, destroy 세가지 메서드에 의해서 초기화, 서비스, 파괴의 과정을 거친다. 로딩될 때 단 한번 init메서드를 호출 클라이언트의 요청이 있을 때마다 service메서드를 반복적으로 호출 service메서드는 클라이언트의 요청방식에 따라 Get방식이면 doGet메서드를 Post방식이면 doPost를 호출 이 세 메서드는 Servlet인터페이스의 가장 기본적인 메서드이며 서블릿의 생명 주기와 관련된 메서드들이다. 더이상 서비스를 하지 않고 있는 경우 메모리에서 제거되며 이때 호출되어지는 메서드는 destroy() destroy()메서드가 호출되면 가비지 콜렉터는 객체의 메모리를 제거 init과 destroy는 단 한번 호출하게 되며 클라이언트의 요청에 따라 service메서드는 요청이 있을 때 마다 호출
ServletConfig 인터페이스 ServletConfig 인터페이스에 포함된 메서드들은 서블릿을 초기화하는 동안에 해당 서블릿에 정보를 전달하기 위해서 사용 정보에는 서블릿의 서버와 관련된 정보를 나타내는 ServletContext, 이름과 값의 쌍으로 이루어진 초기화 매개변수 등이 있다.
HttpServlet abstract 클래스 HttpServlet은 일반적으로 웹 클라이언트로부터 온 요청을 받아서 처리하고, 그 결과를 다시 웹 클라이언트에게 되돌려 주는 작업을 수행 doGet과 doPost를 재정의하여 사용 클라이언트 요청 발생시 HttpServlet클래스의 service메소드 자동 호출 service메서드의 내부에서는 클라이언트의 요청방식에 따라서 doGet, doPost메서드가 자동으로 호출됨
클라이언트의 요청방식에 따라 service메서드가 호출하는 메서드 doGet 메소드: 서블릿이 HTTP GET 요청을 처리하기 위해서 재정의합니다. doPost 메소드: 서블릿이 HTTP POST 요청을 처리하기 위해서 재정의합니다. doPut 메소드: 서블릿이 HTTP PUT 요청을 처리하기 위해서 재정의합니다. doDelete 메소드: 서블릿이 HTTP DELETE 요청을 처리하기 위해서 재정의합니다
HttpServlet doGet HelloDoGet.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloDoGet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); String name = request.getParameter("name"); out.println("<html><body>"); out.println("<h1> Hello doGet Test</h1>"); if(name != null){ out.println("<h2>"+name+"</h2>"); }else{ out.println("<h2>nothing parameter</h2>"); } out.println("</body></html>"); } }
HttpServlet doPost HelloDoPost.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloDoPost extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); String name = request.getParameter("name"); out.println("<html><body>"); out.println("<h1> Hello doPost Test</h1>"); if(name != null){ out.println("<h2>"+name+"</h2>"); }else{ out.println("<h2>nothing parameter</h2>"); } out.println("</body></html>"); } }
HelloDoPost.html <HTML><HEAD><TITLE>doPost 테스트</TITLE></HEAD> <BODY> <h1>doPost 테스트</h1> <form action="/MySample/servlet/HelloDoPost" method="Post"> <input type="text" name="name"> <input type="submit" name="submit1"> </form> </BODY> </HTML>
서블릿 작업의 중심 protected void service(HttpServletRequest req, HttpServletResponse resp) protected void doGet(HttpServletRequest req, HttpServletResponse resp) protected void doPost(HttpServletRequest req, HttpServletResponse resp)
HttpServletRequest, HttpServletResponse의 개요 클라이언트의 모든 요청 정보 보유 request header form data, query parameter InputStream(클라이언트로부터 전송되어지는 데이터) 기타 클라이언트 정보얻기 세션 정보, 쿠키, path ... HttpServletResponse 클라이언트에게 보내지는 모든 정보 보유 response header OutputStream (클라이언트에게 보내지는 데이터) 쿠키 설정 세션 설정
get방식과 post방식 동시에 처리하기 GetPostTest.html <html><head><title>GetPostTest</title></head><body> <form action="/MySample/servlet/chap4.GetPostResult?age=20" method="post"> <input type="text" name="name" size="10"><br> <input type="submit"><input type="reset"> </form></body></html>
GetPostResult.java package chap4; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class GetPostResult extends HttpServlet{ public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ res.setContentType("text/html;charset=euc-kr"); PrintWriter pout=res.getWriter(); String name=req.getParameter("name"); String age=req.getParameter("age"); pout.println("<html><head>"); pout.println("<title>GetPostResult</title>"); pout.println("</head><body>"); pout.println("Name : "+name); pout.println("<br>Age : "+age); pout.println("</body></html>"); } }
HttpServletRequest–양식 데이터 전체 값 출력하기 ParaNamesValueTest.html <HTML><BODY> <h1> 입력양식테스트 </h1> <form action="/MySample/servlet/chap4.ParamsTest" method="post"> 1.텍스트필드 <input type=text name="tf1"><br><br> 2.히든 <input type=hidden name="h1" value="히든값"><br><br> 3.Radio버튼 테스트<br> <input type=radio name="r1" value="JSP" checked>JSP<br> <input type=radio name="r1" value="자바">자바<br> <input type=radio name="r1" value="자바스크립트">자바스크립트<br><br> 4.CheckBox버튼 테스트<br> <input type=CheckBox name="r2" value="서울">서울<br> <input type=CheckBox name="r2" value="대구">대구<br> <input type=CheckBox name="r2" value="대전" checked>대전<br><br> 5.select박스테스트<br> <select name="s1"> <option selected>홍길동</option> <option>김삿갓</option> <option>대발이</option> </select><br><br>
6.select박스 Multiple<br> <select name="s2" Multiple> <option selected>CGI</option> <option>JSP</option> <option>ASP</option> <option>Perl</option> </select><br><br> 7.TextArea테스트<br> <textarea name="ta1"></textarea> <br> <input type=submit value="전송"> </form> </BODY></HTML>
ParamsTest.java package chap4; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import org.jabook.util.*; public class ParamsTest extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=euc-kr"); PrintWriter out = response.getWriter(); String tf1 = request.getParameter("tf1"); String h1 = request.getParameter("h1"); String r1 = request.getParameter("r1"); String[] r2 = request.getParameterValues("r2"); String s1 = request.getParameter("s1"); String[] s2 = request.getParameterValues("s2"); String ta1 = request.getParameter("ta1"); out.println("1.Text:"+encodeString(tf1)+"<br>"); out.println("2.Hidden:"+encodeString(h1)+"<br>"); out.println("3.Radio:"+encodeString(r1)+"<br>"); out.println("4:CheckBox:"); for(int i=0; i<r2.length; i++) out.println(encodeString(r2[i])+" "); out.println("<br>5.Select:" + encodeString(s1) + "<br>"); out.println("6:Select Multipul:");
for(int i=0; i<s2. length; i++) out for(int i=0; i<s2.length; i++) out.println(encodeStrint(s2[i]) +" "); out.println("<br>7.TextArea:" + encodeString(ta1) +"<br>"); } public String encodeString(String str){ return HangulEncoder.toKSC5601(str); } }
HttpServletRequest – getParameterNames() RequestParameterNames.java package chap4; import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import org.jabook.util.*; public class RequestParameterNames extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=KSC5601"); PrintWriter out = response.getWriter(); out.println("<html><body>"); out.println("<h1>요청데이터의 모든 양식데이터 받기</h1>"); Enumeration enum = request.getParameterNames();
while(enum. hasMoreElements()){ String name = (String)enum while(enum.hasMoreElements()){ String name = (String)enum.nextElement(); out.println("<b>"+name+":</b>" +HangulEncoder.toKSC5601(request.getParameter(name))+"<br>"); } out.println("</body></html>"); out.close(); } }
HttpServletResponse –다른 페이지 보내기 ResponseRedirect.java package chap4; import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class ReponseRedirect extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=euc-kr"); PrintWriter out = response.getWriter(); String gopage = request.getParameter("gopage"); if(gopage!=null && gopage.equals("yahoo")){ response.sendRedirect("http://www.yahoo.co.kr"); }else { out.println("<html><body>"); out.println("<h1>Response의 sendRedirect</h1>"); out.println("다른페이지로 이동하기 위해서는<br>"); out.println("URL에 ?gopage=yahoo를 붙이시오"); out.println("</body></html>"); } out.close(); } }
모델1 구조와 모델2 구조 모델1 구조 모델2 구조 포워딩 1. 요청 웹 컨테이너 JSP 비즈니스 로직을 JSP에서 실행 로직 코드와 UI 코드가 혼합 클라이언트 요청이 JSP로 전달 로직처리 클래스 2. 응답 빈 빈 빈 모델2 구조 1. 요청 웹 컨테이너 서블릿에서 로직을 실행 JSP에서 UI를 생성 클라이언트 요청이 서블릿으로 전달 서블릿 로직클래스 포워딩 빈 빈 빈 JSP 2. 응답 JSP 2.0 Programming
Model-View-Controller 패턴 MVC 패턴의 구성 2. 비즈니스 로직처리 1. 요청 사용자 컨트롤러 (Controller) 모델 (Model) 3. 뷰선택 4. 응답 뷰 (View) 모델 - 비즈니스 영영역의 상태 정보를 처리한다. 뷰 - 뷰즈니스 영역에 대한 프리젠테이션 뷰 (즉, 사용자가 보게 될 결과 화면)를 담당한다. 컨트롤러 - 사용자의 입력 및 흐름 제어를 담당한다 MVC 패턴의 핵심 비즈니스 로직을 처리하는 모델과 결과 화면을 보여주는 뷰가 분리되어 있다. 어플리케이션의 흐름 제어나 사용자의 처리 요청은 컨트롤러에 집중된다. JSP 2.0 Programming
MVC 패턴과 모델2 구조의 매핑 컨트롤러 = 서블릿 모델 = EJB 내지 비즈니스 로직 클래스, 자바빈 뷰 = JSP 사용자 = 웹브라우저, 휴대폰과 같은 디바이스 JSP 2.0 Programming
MVC: 컨트롤러 서블릿의 동작 방식 웹 컨테이너 서블릿 HTTP 요청 1. HTTP 요청 받음 2. 클라이언트가 요구하는 과정1 - 웹 브라우저가 전송한 HTTP 요청을 받는다. 서블릿의 doGet() 메소드나 doPost() 메소드가 호출된다. 과정2 - 웹 브라우저가 어떤 기능을 요청했는 지 분석한다. 예를 들어, 게시판 목록을 요청했는 지, 글 쓰기를 요청했는 지 알아낸다. 과정3 - 모델을 사용하여 요청한 기능을 수행한다. 과정4 - 모델로부터 전달받은 결과물을 알맞게 가공한 후, request나 session의 setAttribute() 메소드를 사용하여 결과값을 속성에 저장한다. 이렇게 저장된 결과값은 뷰인 JSP에서 사용된다. 과정5 - 웹 브라우저에 보여질 JSP를 선택한 후, 해당 JSP로 포워딩한다. 경우에 따라서 리다이렉트를 하기도 한다. HTTP 요청 1. HTTP 요청 받음 2. 클라이언트가 요구하는 기능을 분석 3. 요청한 비즈니스로직을 처리하는 모델 사용 모델 4. 결과를 request 또는 session에 저장 5. 알맞은 뷰 선택 후, 뷰로 포워딩(또는 리다이렉트) HTTP 응답 JSP JSP 2.0 Programming
MVC: 컨트롤러와 모델의 연결 모델의 일반적 처리 순서 모델 서블릿 HTTP 요청 1. 컨트롤러로부터 요청 받음 웹 컨테이너 서블릿 모델 HTTP 요청 1. 컨트롤러로부터 요청 받음 2. 비즈니스 로직 수행 3. 수행 결과 컨트롤러에 리턴 JSP HTTP 응답 JSP 2.0 Programming
컨트롤러 서블릿의 기본 구현 Code public class ControllerServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { processRequest(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) private void processRequest(HttpServlet request, HttpServletResponse response) // 2단계, 요청 분석 // request 객체로부터 사용자의 요청을 분석하는 코드 ... // 3단계, 모델을 사용하여 요청한 기능을 수행한다. // 사용자에 요청에 따라 알맞은 코드 // 4단계, request나 session에 처리 결과를 저장 request.setAttribute("result", resultObject); // 이런 형태의 코드 // 5단계, RequestDispatcher를 사용하여 알맞은 뷰로 포워딩 RequestDispatcher dispatcher = request.getRequestDispatcher("/view.jsp"); dispatcher.forward(request, response); 1단계, 요청받음 GET/POST 방식으로 전달받은 웹브라우저의 요청을 하나의 메소드인 processRequest()로 전달한다. JSP 2.0 Programming
간단한 컨트롤러 서블릿 예제 Example 모델이 없으므로 직접 로직 코드 실행 private void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // 2단계, 요청 파악 // request 객체로부터 사용자의 요청을 파악하는 코드 String type = request.getParameter("type"); // 3단계, 요청한 기능을 수행한다. // 사용자에 요청에 따라 알맞은 코드 Object resultObject = null; if (type == null || type.equals("greeting")) { resultObject = "안녕하세요."; } else if (type.equals("date")) { resultObject = new java.util.Date(); } else { resultObject = "Invalid Type"; } // 4단계, request나 session에 처리 결과를 저장 request.setAttribute("result", resultObject); // 5단계, RequestDispatcher를 사용하여 알맞은 뷰로 포워딩 RequestDispatcher dispatcher = request.getRequestDispatcher("/simpleView.jsp"); dispatcher.forward(request, response); 모델이 없으므로 직접 로직 코드 실행 JSP 2.0 Programming
Command 패턴의 적용 (1) 각 요청을 처리하는 클래스를 별도로 작성한다. 이때 요청을 하나의 커맨드로 볼 경우, 각 커맨드를 처리하는 핸들러 클래스가 따로 존재한다. (Command 패턴) 커맨드와 커맨드 핸들러 클래스의 사이의 매핑 정보를 별도의 파일에 저장한다. JSP 2.0 Programming
<<인터페이스>> Command 패턴의 적용 (2) Command 패턴의 구현 <<인터페이스>> CommandHandler 요청을 처리하는 클래스가 구현해야 할 인터페이스 public String process() 각 요청을 처리해주는 클래스는 CommandHandler 인터페이스를 implements 한다. process() 메소드에 요청을 처리하는 코드가 위치한다. ListHandler WriteFormHandler public String process() public String process() JSP 2.0 Programming
Command 패턴의 적용 (3) Controller와 Command의 연결 관계 컨트롤러 서블릿 요청 HTTP 요청 받음 클라이언트가 요구하는 기능을 분석 로직을 처리할 명령어 핸들러를 생성 생성 CommandHandler 로직처리 명령어 핸들러를 통해 로직 처리 결과저장 명령어 핸들러가 리턴한 뷰로 포워딩 뷰리턴 뷰 JSP 2.0 Programming
Command 패턴의 적용 (4) 설정 파일의 구성 # <명령어, 핸들러 클래스>의 매핑 정보 저장 명령어1=핸들러클래스이름1 명령어2=핸들러클래스이름2 … 명령어3=핸들러클래스이름3 Example # <명령어, 핸들러 클래스>의 매핑 정보 저장 /hello.do=madvirus.command.HelloHandler /guestbook/writeForm.do=madvirus.guestbook.command.WriteFormHandler /guestbook/write.do=madvirus.guestbook.command.WriteHandler JSP 2.0 Programming
Command 선택 요청 URI로부터 Command를 선택 예) http://server/chap21/logic/process.do에서 /logic/process.do를 Command로 선택 특정 파라미터의 값을 Command로 선택 예) http://server/servlet/..?cmd=list&p=2 에서 cmd 파라미터 값인 list를 Command로 선택 JSP 2.0 Programming
모델1 구조와 모델2 구조의 선택 문제 모델 장점 단점 모델 1 -배우기 쉬움 -자바 언어를 몰라도 구현 가능 -기능과 JSP의 직관적인 연결. 하나의 JSP가 하나의 기능과 연결 -여전히 로직 코드와 뷰 코드가 혼합되어 JSP 코드가 복잡해짐 -뷰 변경시 논리코드의 빈번한 복사 즉, 유지보수 작업이 불편함 -통합 권한 인증 코드를 JSP 단위로 적용해야 함 모델 2 -로직 코드와 뷰 코드의 분리에 따른 유지 보수의 편리함 -컨트롤러 서블릿에서 집중적인 작업 처리 가능.(권한/인증 등) -확장의 용이함 -자바 언어에 친숙하지 않으면 접근하기가 쉽지 않음 -작업량이 많음(커맨드클래스+뷰JSP) -디버깅 작업의 어려움 JSP 2.0 Programming