자바 서블릿(Java Servlet)
서블릿이란 웹페이지를 동적으로 생성하기 위해 서버측 프로그램을 말한다.
이는 자바 언어를 기반으로 만들지며 웹 어플리케이션 서버( Web Application Sever )
위에서 컴파일 되고 동작한다.
쉽게 말해, java만으로 자바소스코드안에 HTML태그를 작성해서
웹 페이지를 만드는 자바 프로그램이다.
이해를 쉽게 하기 위해 jsp와 비교해보겠다.
먼저 06sum.jsp를 다음과 같이 작성해보자
06sum.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<body>
<h2>1부터 10까지의 합</h2>
<%
StringBuffer result=new StringBuffer();
result.append("<ul>");
int sum=0;
for(int i=1;i<=10;i++){
sum+=i;
result.append("<li>"+i+"="+sum);
}
result.append("</ul>");
out.print(result.toString());
%>
</body>
</html>
사실 브라우저에서 url요청 후 06sum.jsp의 결과화면이 나온다.
그럼 jsp만이 브라우저에 결과화면을 응답할 수 있는 것인가?
아니다. java만으로도 가능하다. 물론 우리가 그냥 처음부터 브라우저에
요청을 받아 응답까지 하게해주는 클래스를 만들긴 쉽지않다.
하지만 그런 기능이 있는 클래스가 있다. 바로 Servlet클래스다.
이 Servlet클래스 자식 중 우리는 Http 통신을 하므로
HttpServlet을 상속받으면 브라우저의 요청을 받아 응답을 할 수 있게됩니다.
그리고 이 Servlet클래스를 상속받은 걸 일반적으로 우리가 'Servlet'이라고 부릅니다.
앞에서말한 Servlet의 정의는 바로 Servlet 클래스의 정의라고 할 수 있겠죠.
그럼 한번 Sum.java를 만들어 보겠습니다.
Sum.java
package study;
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 Sum extends HttpServlet{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
PrintWriter out=response.getWriter();
out.print("<html><body><h2>1부터 10까지의 합</h2>");
StringBuffer result=new StringBuffer();
result.append("<ul>");
int sum=0;
for(int i=1;i<=10;i++){
sum+=i;
result.append("<li>"+i+"="+sum);
}
result.append("</ul>");
out.print(result.toString());
out.print("</body></html>");
}
}
이렇게 만들어진 Sum 클래스는 '서블릿'이라 할 수 있죠.
참고로 doGet메소드는 get방식으로 온 요청만 처리하는 메소드입니다.
자 이렇게 만들어진 Sum은 실행하는게 아닙니다.
사실 지금까지 작성한 모든 jsp는 실행하는게 아닙니다.
서버만 실행합니다.
서버를 켠 후 브라우저에서 해당 jsp를 요청하면 서버가 결과물만
브라우저에 응답한 후 브라우저는 결과만 화면에 보여줍니다.
다만, 앞으로 편의를 위해 서버를 킨 상태에서
브라우저로 서버에 jsp요청하는거를 실행한다고하겠습니다.
jsp의 경우 WebContent 폴더가 /study와 대응되면서 url에
localhost:8080/study/02basic/06sum.jsp를 입력하면 요청을 할 수 있었지만,
서블릿 Sum은 어떻게 요청해야 할까요?
localhost:8080/study까지는 동일한 거 같은데 그 이후에 어떻게 요청할까요??
정답은 web.xml(서버설정 xml파일)에서 하시면 됩니다.
web.xml은 기본적으로 WebContent/WEB-INF 폴더에 있습니다. 혹시 없으시다면
프로젝트 우클릭-Java EE Tools-Generate Deployment Descripot Stub를 누르면 web.xml이 생성됩니다.
web.xml을 생성했으면 다음과 같이 web.xml을 작성해봅시다.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<!-- 톰캣10이라면 <web-app> 이면 충분하다 -->
<servlet>
<servlet-name>sum</servlet-name> <!-- 이름은 아무렇게나 -->
<servlet-class>study.Sum</servlet-class> <!-- 서블릿클래스 위치 -->
</servlet>
<servlet-mapping>
<servlet-name>sum</servlet-name> <!-- <servlet>에서 설정한 이름-->
<url-pattern>/servlet/sum.weekend</url-pattern><!--브라우저에서 요청할 url 주소 -->
</servlet-mapping>
</web-app>
이제 서버를 키고 url에 localhost:8080/study/servlet/sum.weekend 를 요청해봅시다.
참고 : url-패턴은 여러 종류가 있다.
- 확장자 매핑 : *.soju
- 경로 매핑 : /board/* , "/"로 시작하고 "*"로 끝나는 패턴
- 서블릿 매핑 : / 이미 등록된 매핑을 제외하고 모든 요청을 처리
- 완전매핑 : /admin/hello.do , "/"로 시작하고 완전한 하나의 url을 가지는 매핑
결과화면:
java만으로도 jsp처럼 똑같은 화면을 보여주는것이 가능하다는 걸 확인했습니다.
즉 모든 jsp는 자바부분은 그대로, <html>태그부분도 out.print("<html>") 등으로 사용하면
Servlet(.java 파일)으로 변경할 수 있습니다.
※ 사실 jsp가 나오기전에 먼저 개발자들이
'야, java만으로 http통신하게 하자. out.print() 해서 html 태그 그대로 사용하고'...
이런식으로 생각해서 servlet을 만들었습니다.
근데 servlet만 사용하다보니
'아 html태그 맨날 out.print() 하기 귀찮네...' 해서 다시
'아 그럼 html태그 쓰는 부분은 그냥 html태그 그대로 쓰고
java가 필요한 곳만 java로 사용하면 되잖아??'
해서 나온게jsp입니다.
물론 jsp가 나오고 나서 화면 만드는 곳에서는 servlet대신 jsp를 사용하지만
view역할 말고도 servlet의 역할이 남아있어 servlet도 잘 알아야됩니다.
나머지 servlet의 역할은 MVC패턴에서의 Controller역할로, 나중에 배우게 됩니다.
jsp 처리과정
- JSP에 해당하는 서블릿이 존재하지 않을 경우(과정 1.1)
- jsp 페이지로부터 자바 코드를 생성한다. (과정1.2 : 위에서 jsp는 java파일로 변환이 가능하다 했습니다)
- 자바 코드를 컴파일해서 서블릿 클래스를 생성한다(과정1.3)
- 서블릿에 클라이언트 요청을 전달한다. (과정 2.1)
- 서블릿이 요청을 처리한 결과를 으답으로 생성한다. (과정 2.2)
- 응답을 웹 브라우저에 전송한다. (과정 3)
- JSP에 해당하는 서블릿이 존재하는 경우(즉, 이미 과정1.1~1.3을 거친 경우)
- 서블릿에 클라이언트 요청을 전달한다. (과정 2.1)
- 서블릿이 요청을 처리한 결과를 으답으로 생성한다. (과정 2.2)
- 응답을 웹 브라우저에 전송한다. (과정 3)
버퍼
출력버퍼는 위 jsp처리과정의 3 응답전송부분에 해당한다.
JSP 페이지는 응답 결과를 곧바로 웹 브라우저에 전송하지 않는다.
대신 출력 버퍼라고 불리는 곳에
임시로 응답 결과를 저장했다가 한 번에 웹 브라우저에 전송한다.
버퍼를 사용하면 다음과 같은 장점이 있다.
- 데이터 전송 성능 향상
- JSP 실행 도중에 버퍼를 비우고 새로운 내용 전송 가능
- 버퍼가 다 차기 전까지 헤더 변경 가능
데이터 전송 성능 향상
벼퍼를 사용하면 성능이 향상되는데
그 이유는 작은 단위로 데이터를 전송하는 것이 아니라
한 번에 큰 단위로 데이터를 전송하는 것이 기능하기 때문이다.
네트워크를 비롯한 모든 데이터 교환에서는 작은 단위를 여러 차례 보내는 것보다,
큰 단위로 한 번에 묶어서 보내는 것이 더 높은 성능을 발휘하게 된다.
JSP 실행 도중에 버퍼를 비우고 새로운 내용 전송 가능
두 번째 장점은 버퍼를 사용함으로써
포워드(jsp: forward)기능과 에러 페이지 처리 기능이 가능하다는 점이다.
JSP 페이지가 생성한 결괴를 일단 벼퍼에 저장하기 때문에,
벼퍼에 보관된 데이터가 일정 크기가 될 때까지 웹 브라우저에 전송되는 데이터는 없다.
따라서, JSP 페이지가 생성한 내용이 있다 하더라도 벼퍼에 저장된 데이터가
웹 브라우저로 전송되기 전까지는 버퍼에 보관된 데이터를 지우고 새로운 내용을 전송할 수 있다.
예를 들어, JSP 실행 과정에서 에러가 발생하면,
지금까지 생성한 내용을 버퍼에서 지우고 에러 화면을 출력할수 있다.
버퍼가 다 차기 전까지 헤더 변경 가능
마지막으로 버퍼가 다 차기 전에는 헤더 정보를 변경할 수 있다.
HTTP프로토콜의 구조상 응답 상태 코드와 함께 헤더 정보를
가장 먼저 웹 브라우저에 전송해야 한다.
이런 이유로 WAS는 처음 버퍼의 내용을 웹 브라우저로 전송하기 전에 헤더 정보를 전송한다.
따라서 첫 번째로 버퍼의 내용을 웹 브라우저에
전송하기 전까지는 헤더 정보를 얼마든지 변경할 수 있다.
하지만, 일단 버퍼 내용이 웹 브라우저에 전송되면
그 이후로는 헤더 정보를 변경해도 적용되지 않게 된다.
out 기본 객체의 버퍼 관련 메소드
메소드 | 리턴타입 | 설명 |
getBufferSize() | int | 버프의 크기를 구합니다 |
getRemaining() | int | 현재의 버퍼의 남은 크기를 구합니다. |
clear() | void | 버퍼의 내용을 비웁니다. 만약 버퍼가 이미 플러시 되었다면 IOException을 발생시킵니다. |
clearBuffer() | void | 버퍼의 내용을 비웁니다. clear() 메소드와 달리 버퍼를 플러시 한 경우에도 IOException을 발생시키지 않습니다. |
flush() | void | 버퍼를 플러시 합니다. |
isAutoFlush() | boolean | 버퍼가 다찼을때 자동으로 플러시 할경우 true를 리턴합니다. |
isAutoFlush() 메소드의 값을 결정하는 것은 page 디렉티브의 autoFlush 속성입니다.