서블릿

서현서현·2022년 5월 10일
0

서블릿 & JSP

목록 보기
11/26

서블릿

  • JSP표준에 앞서 자바에서 웹 어플리케이션 개발을 위해 만들어진 표준
  • 서블릿 프로그래밍, 웹프로그래밍시 중요한 4개의 객체 ⇒ resp, req, session, context
  • 표준을 지켜줘야 톰캣과같은 프로그램들이 코드를 이해해준다.
    1. 서블릿 규약에 따라 자바코드 작성(HttpServlet 상속 후 필요메소드 정의)
    2. 자바 코드를 컴파일하여 클래스파일 생성
    3. 클래스파일을 /WEB-INF/classes 디렉토리에 패키지 구조에 따라 저장
    4. web.xml 파일에 서블릿 클래스 등록 및 리퀘스트와의 매핑 (서블릿 3.0 규약부터 @WebServlet 어노테이션으로 대체)
    5. 톰캣등 컨테이너 재실행 (서블릿 리로딩 기능이 있는경우 생략)
    6. 웹브라우저에서 요청처리결과 확인
💡 그동안은 프로그램 진입을 위해 main을 작성했는데, 이제 사용자는 웹브라우저로 웹 어플리케이션에 접근하게 되어서 변화가 필요했다. 그래서 대신 실행해주는 서블릿 컨테이너나 WAS가 필요하다. 그 예시가 톰캣! 그래서 적절한 서블릿을 구동시켜 서비스를 제공해준다.

이제 서블릿 스펙에 맞게 개발을 해줘야겠다~

Untitled

톰캣의 라이브러리를 열어보면 서블릿을 사용하기위한 api가 있다

따라서 톰캣을 프로젝트에서 구동시켜주거나(아파치톰캣8.5 폴더 잡아서), 내 프로젝트의 WEB-INF폴더의 lib에 저 jar파일을 넣어주면 사용이 가능해진다.

Untitled

  • HttpServlet을 extends 하면 오버라이드 할 메소드가 뜬다!

톰캣 테스트 : 웹브라우저로 구동시켜보기

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class T01_ServletLifeCycle extends HttpServlet{
	
	@Override
	public void init() throws ServletException {
		// 초기화 코드 작성...
		System.out.println("init() 호출됨....");
	}
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 실제적인 작업이 실행되는 지점....(자바의 메인메서드 역할)
		System.out.println("service() 호출됨...");
		super.service(req, resp);
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 메소드 방식이 get인경우 호출됨...
		System.out.println("doGet() 호출됨...");
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 메서드 방식이 post인 경우 호출됨
		System.out.println("dpPost() 호출됨...");
	}
	
	@Override
	public void destroy() {
		// 객체 소멸시 (컨테이너로부터 서블릿객체 제거시) 필요한 코드 작성...
		System.out.println("destroy() 호출됨...");
	}
	
	

}

여러 WAS들은 lib에 넣어주면 알아서 인식한다!

Untitled

또한 프로젝트를 위한 설정정보를 넣어줄수 있다. WEB-INF폴더에 web.xml을 만들어준 후 거기에 넣어야만 한다.

셀프로 만들어도되고// 이클립스의 경우엔

Untitled

Untitled

이렇게 하면 생긴다

web.xml 작성

이름 간단히 바꾸기

<servlet>
		<servlet-name>T01_SLC</servlet-name>
		<servlet-class>kr.or.ddit.basic.T01_ServletLifeCycle</servlet-class>
	</servlet>

url정보 설정해주기

/T01_SLC 라는 url 요청이 사용자에게 오면 T01_SLC를 실행할거야

<servlet-mapping>
		<servlet-name>T01_SLC</servlet-name>
		<url-pattern>/T01_SLC</url-pattern>
	</servlet-mapping>

톰캣설정

Untitled

톰캣 더블클릭으로 들어가서 모듈을 보면 다음과 같이 설정되어있음

따라서 웹브라우저로 http://localhost/ServletTest/T01_SLC 라는 url로 접속하게되면

Untitled

  • GET은 요청, POST는 답신
  • HTTP 모델을 기억하면 , GET의 경우는 보내는 데이터가 없다 즉 바디가 없다 (쿼리스트링으로 해서 url에 포함해서 어쩌구는 가능) 즉, url 이나 하이퍼링크(a태그)는 다 GET방식이다
  • POST는 대표적으로 form태그가 있다
  • service()에서 들어온 url정보(?)를 보면 GET인지 POST인지 적혀있으니까 그거보고 GET이면 doGet()을 실행한다

Untitled

톰캣서버 종료시 (주의 : 콘솔창 종료 누르지말것)

Untitled

destroy()는 자원반납같은 내용을 넣어주기 좋은 메소드이다!

우리가 집중해야할건 doGet(), doPost()

HttpServletRequest req, HttpServletResponse resp

<< 톰캣이 만들어주는 객체, 요청처리 완료후 사라짐

💡 **서블릿 동작 방식** 1. 사용자(클라이언트)가 URL을 클릭하면 HTTP Request를 Servlet Container로 전송(요청)한다. 2. 컨테이너는 web.xml에 정의된 url패턴을 확인하여 어느 서블릿을 통해 처리해야 할지를 검색한다(로딩이 안된경우에는 로딩함. 로딩시 init()메소드 호출됨) 3. 서블릿 컨테이너는 요청을 처리할 개별 스레드 객체를 생성하여 해당 서블릿 객체의 service()를 호출한다. (톰캣이 HttpServletRequest 및 HttpServletResponse 객체를 생성하여 파라미터로 넘겨준다) 4. service() 메소드는 메소드타입을 체크하여 적절한 메소드를 호출한다. (doGet, doPost, doPut, doDelete 등) 5. 요청처리 완료되면, HttpServletRequest 및 HttpServletResponse 객체는 소멸된다. 6. 컨테이너로 부터 서블릿이 제거되는 경우에 destroy()가 호출된다.

Request 객체의 메서드

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class T02_ServletTest extends HttpServlet {
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// Request 객체의 메서드 확인하기
		System.out.println("getCharacterEncoding() : "+req.getCharacterEncoding());
		System.out.println("getContentLength() : "+req.getContentLength());
		System.out.println("getQueryString() : "+req.getQueryString());
		System.out.println("getProtocol() : "+req.getProtocol());
		System.out.println("getMethod() : "+req.getMethod());
		System.out.println("getRequestURI() : "+req.getRequestURI());
		System.out.println("getRequestedSessionId() : "+req.getRequestedSessionId());
		System.out.println("getRequestDispatcher() : "+req.getRequestDispatcher("/"));
		System.out.println("getHeaderNames() : "+req.getHeaderNames());
		System.out.println("getRemoteAddr() : "+req.getRemoteAddr());
		System.out.println("getRemotePort() : "+req.getRemotePort());
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
	}
	
	
}
<servlet>
		<servlet-name>T02_ST</servlet-name>
		<servlet-class>kr.or.ddit.basic.T02_ServletTest</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>T02_ST</servlet-name>
		<url-pattern>/T02_ST</url-pattern>
	</servlet-mapping>

Untitled

url : http://localhost/ServletTest/T02_ST?name=apple&age=33을 넣는다면 (쿼리스트링)

Untitled

T03 HTML사용하기

java

으로 날라온 데이터를 어떻게 꺼내는지 이해하고 사용해보기!

get 특징 : 바디가 필요없다 url쓰고 엔터치는게 겟! 링크(a태그)도 get!

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class T03_ServletParameterTest extends HttpServlet {
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 요청객체로부터 파라미터 데이터를 가져오는 방법
		// -getParameter() : 파라미터값이 한개인 경우에 가져올때 사용함
		// -getParameterValues() : 파라미터값이 여러개인 경우에 가져올때 사용함. ex) checkBox
		// -getParameterNames() : request에 존재하는 모든 파라미터 정보를 가져올때 사용함
		
		// Post방식으로 넘어오는 Body데이터를 인코딩 처리함. get방식은 톰캣의 URIEncoding 설정을 이용하여 처리함
		// 반드시 request에서 값을 가져오기 전에 먼저 설정해야 적용됨
		req.setCharacterEncoding("UTF-8");
		
		String username = req.getParameter("username"); 
		String password = req.getParameter("password"); 
		String gender = req.getParameter("gender"); 
		String hobby = req.getParameter("hobby"); 
		String rlgn = req.getParameter("rlgn");
		String[] food = req.getParameterValues("food");

		////
		// 응답관련. response객체 이용해준다 body 정보를... 설정
		resp.setContentType("text/html");
		resp.setCharacterEncoding("UTF-8");
		
		PrintWriter pw = resp.getWriter();
		pw.print("<html>");
		pw.print("<body>");
		pw.print("<p>username : "+username+"</p>");
		pw.print("<p>password : "+password+"</p>");
		pw.print("<p>gender : "+gender+"</p>");
		pw.print("<p>hobby : "+hobby+"</p>");
		pw.print("<p>rlgn: "+rlgn+"</p>");
		
		if(food!=null) {
			for(String s : food) {
				pw.print("<p>food: "+s+"</p>");
			}
		}
		
		Enumeration<String> params = req.getParameterNames();
		
		while(params.hasMoreElements()) {
			String param = params.nextElement();
			pw.print("<p>파라미터이름: "+param+"</p>");
		}
		
		pw.print("</body>");
		pw.print("</html>");
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}

}

XML 추가

<servlet>
		<servlet-name>T03_SPT</servlet-name>
		<servlet-class>kr.or.ddit.basic.T03_ServletParameterTest</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>T03_SPT</servlet-name>
		<url-pattern>/T03_SPT</url-pattern>
	</servlet-mapping>

HTML 파일

파일은 WEB-CONTENT 하단에 있어야한다

form 데이터의 메소드를 post로 쓰면 post이다!

의 action 설정해주기!

form의 name속성은 서블릿에서 사용하기 때문에 매우 중요하다!

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>입력폼 예제</title>
</head>
<body>
   **<form method="post" action="T03_SPT">**
    <label for="username">유저명:</label><br>
    <input type="text" name="username" id="username"><br>
    <label for="password">패스워드:</label><br>
    <input type="password" name="password" id="password"><br>
    <hr>
    <input type="radio" id="male" name="gender" value="male">
    <label for="male">Male</label><br>
    <input type="radio" id="female" name="gender" value="female">
    <label for="female">Female</label><br>
    <input type="radio" id="other" name="gender" value="other">
    <label for="other">Other</label><br>
    <hr>
    <input type="checkbox" id="cb01" name="hobby" value="ch01">
    <label for="cb01">낚시</label>
    <input type="checkbox" id="cb02" name="hobby" value="ch02">
    <label for="cb02">등산</label>
    <input type="checkbox" id="cb03" name="hobby" value="ch03">
    <label for="cb03">하이킹</label>
    <input type="checkbox" id="cb04" name="hobby" value="ch04">
    <label for="cb04">독서</label><br>
    <hr>
    <label for="rlgn">종교</label>
    <select id="rlgn" name="rlgn">
    	<option value="01">불교</option>
    	<option value="02">기독교</option>
    	<option value="03">힌두교</option>
    	<option value="04">기타</option>
    </select>
    
    <hr>
    <label for="food">좋아하는 음식</label>
    <select id="food" name="food" multiple="multiple">
    	<option value="01">소고기</option>
    	<option value="02">돼지고기</option>
    	<option value="03">물고기</option>
    	<option value="04">채식</option>
    </select>
    
	<br>
	<br>
    <input type="submit" value="Submit">
   </form> 
</body>
</html>

Untitled

T04

html은 동적인 작업을 하지 못함.

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class T04_ErrorHandler extends HttpServlet {
	// get이 있으니 당연히 set도있음
	req.setAttribute("name",new String("홍길동));
	System.out.println(:name: )+req.getAttribute("name");

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 서블릿 예외정보 가져오기
		Throwable throwable = (Throwable) req.getAttribute("javax.servlet.error.exception"); // 예외객체
		Integer statusCode = (Integer) req.getAttribute("javax.servlet.error.status_code"); //에러상태코드
		String message = (String) req.getAttribute("javax.servlet.error.message"); //에러메세지
		String servletName = (String) req.getAttribute("javax.servlet.error.servlet_name"); //에러발생한 서블릿 이름
		
		if(servletName == null) {
			servletName = "알 수 없는 서블릿 이름";
		}
		
		String requestURI = (String) req.getAttribute("javax.servlet.error.request_uri"); // 에러발생 url정보
		
		if(requestURI == null) {
			requestURI="알 수 없는 URI";
		}
		
		//////////////////////////////
		
		resp.setCharacterEncoding("UTF-8");
		resp.setContentType("text/html");
		PrintWriter out = resp.getWriter(); //문자기반이기 때문에 writer사용
																				//바이트기반이면 getOutputStream()사용
	
		
		String title = "에러/예외정보";
		
		out.println("<!doctype html><html><head><title>"+title+"</title></head>"+"<body>");
		if(throwable == null && statusCode == null) {
			out.println("<h2>에러정보 없음</h2>");
		}else {
			out.println("<h2>예외/에러정보 없음</h2>");
			out.println("상태코드 : "+statusCode+"<br><br>");
			out.println("에러(예외메세지) : "+message+"<br><br>");
			out.println("서블릿 이름 : "+servletName+"<br><br>");
			out.println("요청 URI : "+requestURI+"<br><br>");
			
			if(statusCode != null) {
				out.println("예외타입: "+throwable.getClass().getName()+"<br><br>");
				out.println("예외(에러) 메세지:"+throwable.getMessage());
			}
		}
		
		out.println("</body>");
		out.println("</html>");
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}

}
	<servlet>
		<servlet-name>T04_EH</servlet-name>
		<servlet-class>kr.or.ddit.basic.T04_ErrorHandler</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>T04_EH</servlet-name>
		<url-pattern>/T04_EH</url-pattern>
	</servlet-mapping>

Untitled

404에러 발생하면 이동해라

<error-page>
		<error-code>404</error-code>
		<location>/T04_EH</location>
	</error-page>

Untitled

서블릿예외 발생하면 이동해라

<error-page>
		<exception-type>javax.servlet.ServletException</exception-type>
		<location>/T04_EH</location>
	</error-page>
T01 예제에 추가
@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 메소드 방식이 get인경우 호출됨...
		System.out.println("doGet() 호출됨...");
		
		throw new ServletException("서블릿 예외 발생");
	}

Untitled

예외정보 꺼내고 싶으면 req에서 꺼낸대

0개의 댓글