서블릿

서현서현·2022년 6월 7일
0

서블릿 & JSP

목록 보기
22/26
  • 서블ㄹ릿 스펙
  • 리소스 분류기준

서블릿

  • 웹에서 발생하는 요청을 받고 그에 대한 응답을 생성할 수 있는 어플리케이션의 조건을 모아놓은 명세서
  • HttpServlet은 추상클래스이므로…
    • 서블릿 개발단계
      1. HttpServlet을 상속받은 소스 정의
      2. 컴파일(-d) : /WEB-INF/classes(어플리케이션의 classPath)에 클래스 배포
      3. WAS에 서블릿 등록(ver2.5 - web.xml, 그이상의 버전 - @WebServlet)
        • servlet → servlet-name (required) → servlet-class (required) load-on-startup, init-param (optional)
      4. 서블릿 매핑(ver2.5 - web.xml, 그이상의 버전 - @WebServlet)
        • servlet-mapping → servlet-name → url-pattern
      5. WAS restart (auto-reload 설정시 생략가능)
  • WAS = Web Application Container, Servlet Container, Servlet Container
  • 그렇다면 Container란 무엇일까? → 컴포넌트의 생명주기 관리자! → Servlet Container = 서블릿의 생명주기 관리자 → 생명주기 내에서 callback을 호출 → 콜백? $(”#button”).on(”click”,function(){}); → 특정 컨텍스트 내에서 어떤 이벤트가 발생했을때 (특정 조건이 만들어졌을때), 시스템 내부에서 자동으로 호출하는 구조
    • 생성 - init

    • 요청 - service, doXXX

    • 소멸 - destroy

      Container

      @Override
      	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      		// TODO Auto-generated method stub
      		super.doGet(req, resp);
      	}

      static이 없음 - 인스턴스 객체라는것

      근데 우리는 서블릿클래스의 객체를 생성한 적이 없다

      ⇒ 우리 외 누군가가 대신 생성해줬을것 = Container의 역할!!

Untitled

// url-pattern과 value라는 속성은 그 의미가 같다
@WebServlet(value= {"/desc.do"})

// 싱글밸류로 쓸수있다
@WebServlet({"/desc.do"})

// 엘리먼트가 하나면 이렇게 써도되는것
@WebServlet("/desc.do")

Untitled

모든 do 계열의 메소드는 405 메소드를 만든다. (지금은 super땜에 나오는중)

@WebServlet(value= {"/desc.do"})
public class DescServlet extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.getWriter().println("Desc Servlet");
	}
}

Untitled

이녀석의 객체를 WAS가 생성해준것

확인해볼까

@WebServlet(value= {"/desc.do"})
public class DescServlet extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.getWriter().println("Desc Servlet");
	}

	public DescServlet() {
		super();
		System.out.println(this.getClass().getName());
	}

}

this의 getClass로 접근한건 바로 여기

Untitled

WAS는 싱글톤으로 관리하니까 메모리상 올라가있는 객체를 가비지 컬렉션 시켜야 새 로그가 찍힐수있으니 리스타트

Untitled

이런식으로 출력되는 패스를 퀄리파이드 네임이라고 한다

근데 새로고침 많이해서 요청 여러번해도 저건 한번출력된더

→ 서블릿의 객체가 단한번 생성됐다 (= WAS가 싱글톤으로 관리한다)


콜백

@WebServlet(value= {"/desc.do"})
public class DescServlet extends HttpServlet{
	
	public DescServlet() {
		super();
		System.out.println(this.getClass().getName()+"생성");
	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		System.out.println(this.getClass().getName()+"초기화");
	}
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("요청처리시작");
		super.service(req, resp);
		System.out.println("요청처리종료");
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.getWriter().println("Desc Servlet");
	}
	
	@Override
	public void destroy() {
		super.destroy();
		System.out.println(this.getClass().getName()+"소멸");
	}

}

새로고침 한번

Untitled

새로고침 여러번

Untitled

띄어쓰기 하나 추가하고 콘솔창보면

Untitled

@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.getWriter().println("Desc Servlet");
		System.out.println("doGet() 실행");
	}

여기만 수정하고 다시 실행

Untitled

@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("요청처리시작");
		**super.service(req, resp); <= 얘는 뭐하고 있는걸까?**
		System.out.println("요청처리종료");
	}

내부에소 doget을 호출하고있는것!

Untitled

do 계열 메소드는 7개나 되는데 저중 뭘 호출하는지 어케알지?

http 요청의 method(7개)를 파악하고 해당 callback을 호출

즉 요청을 열어서 보고 메소드를 파악해서 호출해주는것


http에서 요청이 어떤식으로 패키징 되느냐?


loadOnStartup

서블릿의 인스턴스 생성시점을 정함

보통 청이 처음 발생할때 생성되나 이걸 설정하면 서버 구동 즉시 인스턴스가 생성됨

@WebServlet(value= {"/desc.do"}, loadOnStartup=1)
// 숫자는 우선순위를 표시한다.

Untitled

새로고침 안했는데 생성

이걸로 나중에 데이터베이스와 연결을 수행할거임 (드라이버 로딩작업)

<servlet>
	  <servlet-name>DescServlet</servlet-name>
	  <servlet-class>kr.or.ddit.servlet01.DescServlet</servlet-class>
	  <init-param>
	  	<param-name>param1</param-name>
	  	<param-value>value1</param-value>
	  </init-param>
	  <load-on-startup></load-on-startup>
  </servlet>

<servlet-mapping>
  	<servlet-name>DescServlet</servlet-name>
  	<url-pattern>/desc.do</url-pattern>
</servlet-mapping>

작성에 제약이 많아서 사용 안하기 시작~

xml 대체 - JSON 또는 어노테이션인것임!

web.xml에 이러던걸 그냥 어노테이션으로 대체

@WebServlet(value= {"/desc.do"}, loadOnStartup=1, initParams= {@WebInitParam(name="param1",value="value1")})
@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		System.out.println(this.getClass().getName()+"초기화");
	}

어떤메소드를 쓰면 초기화 파라미터를 떠낼 수 있을까?

@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		System.out.println(this.getClass().getName()+"초기화");
		String initValue = config.getInitParameter("param1");
		System.out.println("param1의 값 - "+initValue);
	}

왜오류나 미친놈아


어노테이션과 xml 둘다 살려놓고 실행하면 오류뜸

urlpattern이 둘 다에 매핑되어있다는 오류 ~

어노테이션 지우고

Untitled

다른 서블릿도 같은 url 매핑시키면

url매핑이 같아서 오류난다고 콘솔에 나타난다!

이런 오류를 잡는 가장 좋은 방법

프로젝트 익스플로러에서

Untitled

매핑 쉽게 확인 가능


Untitled

Untitled

Untitled

알아서 어노테이션 달아서 만들어진다


멀까

package kr.or.ddit.servlet01;

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

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

@WebServlet("/korean.do")
public class KoreanServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String data = "한글 로우 데이터";
		StringBuffer html = new StringBuffer();
		html.append("<html>");
		html.append("<body>");
		html.append(String.format("<h4>%s</h4>",data));
		html.append("</body>");
		html.append("</html>");
		PrintWriter out = response.getWriter();
		out.println(html);
		out.close();
	}

}

Untitled

혀튼 나온 결과 인코딩이 안되어있다 개발자도구 켜서 네트워크의 request헤더 보면 특이하대

네이버를 보면 컨텐츠타입이 정의되어있는데 우린 이게 없어서그럼

Untitled

MIME (Multi-purpose Internet Mail Extension)

: P2P 사이에서 전송되는 컨텐츠의 타입(형식)

문법 - mainType/subType[;charset=encoding]

ex) text/javascript, text/html, text/css, text/plain;charset=utf-8, image/jpeg, video/mp4

1바이트의 아스키코드는 부호코드 하나 뺴고 7비트 사용가능, 2의 7승으로는 한글 표현 불가 최소 2바이트는 필요하다

Untitled

클라이언트의 브라우저한테 UTF-8로 설정된상태임을 알려줘야함

현재 응답데이터가 html 소스인 상태니까.. 그안에 utf-8로된 특수문자가 있고

마임으로 표현하면 text/html;charset=utf-8;

@WebServlet("/korean.do")
public class KoreanServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String mime = "text/html;charset=utf-8";
		response.setContentType(mime);
		String data = "한글 로우 데이터";
		StringBuffer html = new StringBuffer();
		html.append("<html>");
		html.append("<body>");
		html.append(String.format("<h4>%s</h4>",data));
		html.append("</body>");
		html.append("</html>");
		PrintWriter out = response.getWriter();
		out.println(html);
		out.close();
	}

}

Untitled


응답데이터 내보내보기 예제

파일리소스를 웹 리소스인것처럼 스트리밍 해주기………

내보내려는 컨텐츠는 html이 아닌 이미지데이터임

  • D://contents/cheezDug.png
  • 이미지파일을 읽고(input)
  • stream copy
  • 스트리밍 컨텐츠로 출력 (output)
  • Content-Type(MIME)설정 필요
  1. 소스 확보 (D://contents/cheezDug.png)
  2. 소스 대상 input스트림 개방 (FileInputStream 이미지니까 캐릭터아니고 바이트스트림, 그중에서도 인풋)
  3. destination 확보(resp)
  4. dest 대성 output스트림 개방 (프린트라이터는 문자열 출력위한 캐릭터 스트림, 이번엔 아웃풋 스트림이 필요함 - resp.getOutputStream)
  5. in/out stream copy
// 내가 푼 풀이
@WebServlet("/image.do")
public class ImageStreamingServlet extends HttpServlet{
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		// 클라이언트에 이미지파일 전달하는 서블릿
		resp.setContentType("image/png");
		
		// 클라이언트에게 원시데이터를 전달할 수 있는 출력스트림을 반환받아 저장
		ServletOutputStream out = resp.getOutputStream();
		
		// 이미지파일의 경로 저장
		String filePath ="D:/contents/cheezDug.png";
		
		// 이미지파일을 읽기위한 입력스트림 생성및 저장
		FileInputStream in = new FileInputStream(filePath);
		
		// 입력스트림에서 원시데이터를 읽어 출력스트림으로 저장 (파일전송)
		while(true) {
			int readByte = in.read();
			if(readByte==-1) break;
			out.write(readByte);
		}
		
		// 입력스트림 제거
		in.close();
		
	}
	
}
@WebServlet("/image.do")
public class ImageStreamingServlet extends HttpServlet{
	
	private ServletContext application;
	
	@Override
		public void init(ServletConfig config) throws ServletException {
			super.init(config);
			application = getServletContext();
		}
	
	@Override
	// 서블릿 컨텍스트는 싱글톤
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		File source = new File("D://contents/cheezDug.png");
		
		String mime = application.getMimeType(source.getName());
		resp.setContentType(mime);
		
		FileInputStream fis = new FileInputStream(source);
		OutputStream os = resp.getOutputStream();
		byte[] buffer = new byte[1024];
		int length = -1;
		while((length = fis.read(buffer))!=-1){
			os.write(buffer,0,length);
		}
		fis.close();
		os.close();
	}
}

Untitled


프로젝트 안에 있는 이미지파일

Untitled

이렇게 했더니

Untitled

클래스에도 생긴다

배포 후 남아있는건 코드가 아니라 빌드 안의 클래시스임 그래서 저거를 쓰는거…

또 붙여넣기 한판 해주고

Untitled

Untitled

독베이스

Untitled

저 붙여넣기 한게 아닌 이 경로의 파일들을 사용하는것!!!!

그래서 저 이미지를 쓰려면 주소가 필요

Untitled

혀튼 같은파일이 세군데 있음

순서대로

  1. 파일 시스템 리소스 : 파일시스템상의 절대경로(D:\contents\cat1.jpg)
  2. class path 리소스 : classpath((/WebStudy01/res) 이후의 절대 경로(/kr/or/ddit/images/cat1.jpg)
  3. web 리소스 : 서버에 의해서 사용되고 서버에 의해서 경로 결정, URL 갖고있음 (http://IP[domain]:port/WebStudy01/resources/images/cat1.jpg)

웹리소스는 웹을 통해 바로 서비스되는 리소스이다

Untitled

웹에서 주소를 통해 다이렉트로 접근 (왜? url 가지고있으니까)

크라이언트는 url을 이용해서 was에 접귾래서,… 웹리소스를 받아옴…

1본이나 3번에 존재하는 자원을 서비스하려면 그를 대신 읽어줄 수있느 어플맅케ㅣㅇ션이 핋요하다(WAS)

@WebServlet("/image.do")
public class ImageStreamingServlet extends HttpServlet{
	
	private ServletContext application;
	
	@Override
		public void init(ServletConfig config) throws ServletException {
			super.init(config);
			application = getServletContext();
		}
	
	@Override
	// 서블릿 컨텍스트는 싱글톤
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		String srcPath = "/kr/or/ddit/images/cat1.jpg";
		String filePath = this.getClass().getResource(srcPath).getFile(); // 파일시스템상 절대경로
		File source = new File(filePath);
		String mime = application.getMimeType(source.getName());
		resp.setContentType(mime);
		
		FileInputStream fis = new FileInputStream(source);
		OutputStream os = resp.getOutputStream();
		byte[] buffer = new byte[1024];
		int length = -1;
		while((length = fis.read(buffer))!=-1){
			os.write(buffer,0,length);
		}
		fis.close();
		os.close();
	}
또는 이렇게
@WebServlet("/image.do")
public class ImageStreamingServlet extends HttpServlet{
	
	private ServletContext application;
	
	@Override
		public void init(ServletConfig config) throws ServletException {
			super.init(config);
			application = getServletContext();
		}
	
	@Override
	// 서블릿 컨텍스트는 싱글톤
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		String srcPath = "/kr/or/ddit/images/cat1.jpg";
/*		String filePath = this.getClass().getResource(srcPath).getFile(); // 파일시스템상 절대경로
		File source = new File(filePath);*/
		String mime = application.getMimeType(srcPath);
		resp.setContentType(mime);
		
		InputStream is = ImageStreamingServlet.class.getResourceAsStream(srcPath);
		
		//FileInputStream fis = new FileInputStream(source);
		OutputStream os = resp.getOutputStream();
		byte[] buffer = new byte[1024];
		int length = -1;
		while((length = is.read(buffer))!=-1){
			os.write(buffer,0,length);
		}
		is.close();
		os.close();
	}
}

Untitled

Untitled

웹리소스인 얘네들은 중가 ㄴ서블릿 필요없음

Untitled

새로 만들기

얘도 웹 리소스에 해당한다

근데 위의 웹리소스와는 다르게 외부클라이언트의 접근이 불가능하다(web-inf아래에있어서)

웹리소스일지라도 중간객체가 필요한 부분도 있으 수 있다

inner안의걸 서비스 해보자

@WebServlet("/image.do")
public class ImageStreamingServlet extends HttpServlet{
	
	private ServletContext application;
	
	@Override
		public void init(ServletConfig config) throws ServletException {
			super.init(config);
			application = getServletContext();
		}
	
	@Override
	// 서블릿 컨텍스트는 싱글톤
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		//String srcPath = "/kr/or/ddit/images/cat1.jpg";
		String webPath = "/WEB-INF/inner/cat1.jpg";
		// => 웹리소스... 근데 얘는 web-inf라서 접근불가... 접근 가능한애들도 있지 당연~

		/*String filePath = this.getClass().getResource(srcPath).getFile(); // 파일시스템상 절대경로
		File source = new File(filePath);*/
		
		String mime = application.getMimeType(webPath);
		resp.setContentType(mime);
		
		//InputStream is = ImageStreamingServlet.class.getResourceAsStream(srcPath);
		InputStream is = application.getResourceAsStream(webPath);
		//FileInputStream fis = new FileInputStream(source);
		OutputStream os = resp.getOutputStream();
		byte[] buffer = new byte[1024];
		int length = -1;
		while((length = is.read(buffer))!=-1){
			os.write(buffer,0,length);
		}
		is.close();
		os.close();
	}
}

0개의 댓글