ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 학원 day53. 서블릿, 필터, 첨부파일 업로드
    기록 2022. 11. 18. 09:58

    서블릿

    - 서버에서 실행되는 자바프로그램

    - javaEE 웹 애플리케이션의 핵심 컴포넌트

    - 클라이언트의 HTTP 요청을 수신하고 응답하는 역할을 하는 자바클래스

    - 클라이언트의 HTTP요청에 동적으로 작동하는 JAVA EE 웹 애플리케이션 컴포넌트

    - jsp는 html문서안에 자바코드를 포함하고 있는 반면, 서블릿은 자바 코드 안에 html을 포함하고 있다

    jakarta.servlet.Servlet <interface>

    - 모든 서블릿 클래스가 반드시 구현해야하는 인터페이스.

    - 서블릿의 라이프사이클 메소드가 정의되어 있다.

    - 주요 메소드

    void init(ServletConfig config)

    - 서블릿 객체가 초기화될 때 실행되는 메소드다.

    void destroy()

    - 서블릿 객체가 폐기될 때 실행되는 메소드다.

    void service(ServletRequest request, ServletResponse response)

    - 서블릿 객체가 클라이언트의 요청을 처리할 때 실행되는 메소드다.

     

    jakarta.servlet.GenericServlet<Abstract Class>

    - Servlet 인터페이스의 구현하는 추상클래스.

    - Servlet 인터페이스의 주요 메소드를 대부분 구현하고 있다.

    - Servlet 인터페이스에 정의되어 있지 않은 추가 메소드를 제공한다.

    - 주요 메소드

    void init(){...}

    String getInitParameter(String name){...}

    - 서블릿 초기화파라미터값을 반환한다.

    ServletConfig getServletConfig(){...}

    - ServletConfig 객체를 반환한다.

    ServletContext getServletContext(){...}

    - ServletContext 객체를 반환한다.

     

    jakarta.servlet.http.HttpServlet <Abstract Class>

    - HttpServlet은 제너릭서블릿을 상속받아 만든 것임.

    - http프로토콜에 특화되어 있는 서블릿을 만들 수 있는 서블릿이다.

    주요 메소드

    void doGet(HttpServletRequest request, HttpServletResponse response){...}

    GET방식의 요청은 이 메소드를 재정의해서 처리한다.

    void doPut(HttpServletRequest request, HttpServletResponse response){...}

    PUT방식의 요청은 이 메소드를 재정의해서 처리한다.

    void doPost(HttpServletRequest request, HttpServletResponse response){...}

    POST방식의 요청은 이 메소드를 재정의해서 처리한다.

    void doDelete(HttpServletRequest request, HttpServletResponse response){...}

    DELETE방식의 요청은 이 메소드를 재정의해서 처리한다.

    void service(HttpServletRequest request, HttpServletResponse response){...}

    클라이언트의 요청을 분석해서 요청방식에 맞는 doXXX 메소드를 실행한다.

    * 요청방식에 상관없이 항상 실행되는 메소드다.

    * service() 메소드의 본래 기능을 버리고, 클라이언트의 요청을 처리하는 코드로 재정의한다.

    서블릿이 실행되는 과정
    jsp가 실행되는 과정

    - 톰캣에서 서비스라는 메소드는 클라이언트 요청이 올 때마다 계속적으로 실행된다.

    - init와 destroy메소드는 서블릿의 일생동안 한번만 실행된다.

    - 객체가 만들어지면 또다른 hello라는 URL요청이 와도 새로 만들지 않고 유지하고 있는다.

     

    * 싱글턴 객체 : 클라이언트의 요청(로직)을 수행하는 객체, 한번만 만들어서 재사용한다.

    * 프로토타입 객체 : 데이터(정보)를 담는 객체, 필요할 때마다 계속 만들어진다.


    서블릿 배포방법 2가지

     

    1. 어노테이션으로 배포하기 

     - Servelte을 상속한 java 클래스에 어노테이션 (@WebServlet)을 작성해주면 된다. 이 경우, web.xml(배포설명자 파일)에 작성해주었던 <servlet>태그와 <servlet-mapping> 태그를 지워야한다.

     

    @WebServlet("/hello")
    public class HelloServlet extends HttpServlet {

    }

     

    2. web.xml(배포설명자 파일)에서 <servlet>, <servlet-mapping>태그로 배포하기

    - web.xml은 웹어플리케이션과 관련된 설정정보를 지정하는 파일로 배포설명자 파일이라고 불린다.

     

    <servlet>

             <servlet-name>별칭</servlet-name>

             <servlet-class>서블릿 클래스의 전체 이름(패키지경로와 클래스명)</servlet-class>

    </servlet>
    <servlet-mapping>
            <servlet-name>별칭</servlet-name>
            <url-pattern>매핑할 URL</url-pattern>

    </servlet-mapping>

     

    < HelloServlet.java >

    package com.sample.servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import jakarta.servlet.ServletConfig;
    import jakarta.servlet.ServletException;
    import jakarta.servlet.annotation.WebServlet;
    import jakarta.servlet.http.HttpServlet;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    
    //@WebServlet("/hello")
    public class HelloServlet extends HttpServlet {
    	
    	@Override
    	public void init() throws ServletException {
    		System.out.println("HelloServlet의 init() 메소드 실행됨...");
    	}
    	
    	@Override
    	public void destroy() {
    		System.out.println("HelloServlet의 destroy() 메소드 실행됨...");		
    	}
    
    	@Override
    	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		System.out.println("HelloServlet의 service() 메소드 실행됨...");	
    		
    		// 초기화 파라미터 정보를 제공하는 ServletConfig 객체를 획득한다.
    		ServletConfig config = getServletConfig();
    		
    		// String getInitParameter(String name) 메소드로 초기화 파라미터값을 조회한다.
    		String emailValue = config.getInitParameter("email");
    		String telValue = config.getInitParameter("tel");		
    		
    		response.setContentType("text/html; charset=utf-8");
    		PrintWriter out = response.getWriter();
    		out.println("<!doctype html>");
    		out.println("<html lang='ko'>");
    		out.println("<head>");
    		out.println("<meta charset='utf-8'>");
    		out.println("<title>헬로 서블릿</title>");
    		out.println("</head>");
    		out.println("<body>");
    		out.println("<h1>헬로 서블릿</h1>");
    		out.println("<p>나는 서블릿입니다.</p>");
    		out.println("<p>서블릿의 라이프 사이클 메소드를 확인하세요</p>");
    		out.println("<p>이메일 : " + emailValue + "</p>");
    		out.println("<p>연락처 : " + telValue + "</p>");
    		out.println("</body>");
    		out.println("</html>");
    		
    	}
    }

    < web.xml >

    <!-- 
       /hello URL 요청이 오면 hello-servlet이라는 별칭으로 배포된 com.sample.servlet.HelloServlet을 실행하라.
    -->
          
    <servlet>
          <servlet-name>hello-servlet</servlet-name>
          <servlet-class>com.sample.servlet.HelloServlet</servlet-class>
    <!-- 
        HelloServlet에게 전달할 초기화 파라미터 값 설정하기
    -->
          <init-param>
          	<param-name>email</param-name>
          	<param-value>admin@sample.com</param-value>
          </init-param>
          <init-param>
          	<param-name>tel</param-name>
          	<param-value>02) 1234-5678</param-value>
          </init-param>
    </servlet>
    <servlet-mapping>
          <servlet-name>hello-servlet</servlet-name>
          <url-pattern>/hello</url-pattern>
          <url-pattern>/hi</url-pattern>
          <url-pattern>/ye</url-pattern>
    </servlet-mapping>

     

    톰캣

    - 웹 애플리케이션 서버(Web Application Server : WAS)다.

    - 서블릿/JSP 엔진이다. (서블릿/JSP를 실행시킨다.)

    - 서블릿/JSP 컨테이너이다.(서블릿/JSP객체를 생성, 관리, 유지, 저장한다.)

     

    초기화 파라미터 

    - 초기화 파라미터로 서블릿 실행에 필요한 값을 전해줄 수 있다.

    - 외부(web.xml)에서 설정한 값을 서블릿에서 이용할 수 있다. (설정정보를 외부에 정의해놓을 수 있다.)

    - <init-param> 태그에 정의해 놓는다.

    - <param-name>태그 사이 적은 이름으로 경로를 알려줄 수 있다.

    서블릿에서 초기화 파라미터값을 꺼내는 방법 

    < HelloServlet.java > 서블릿에서 아래처럼 코드를 작성한다.

    // 서블릿의 초기화 파라미터 정보를 제공하는 ServletConfig 객체를 획득한다.
    ServletConfig config = getServletConfig();

    // String getInitParameter(String name)메소드를 초기화 파라미터값을 조회한다.
    String emailValue = config.getInitParameter("email");
    String telValue = config.getInitParameter("tel");


    필터 (Filter)

    - Filter는 JSP 혹은 Servlet이 실행되기 전에, 실행된 후에 실행된다. 

    - Filter는 JSP 혹은 Servlet이 실행되기 전에, 실행된 후에 실행할 작업을 정의한다.

    - 필터의 목적은 공통으로 사용되는 코드를 처리하기 위함이다. 로깅필터, 인증필터, 인가필터, 압축 및 암호화필터, 오류처리 필터 등이 있다.

      * 인증 필터 : 로그인한 사용자인지 아닌지 구현

      * 인가 필터 : 이 요청을 할 수 있는 권한을 갖고 있는 사용자인지 아닌지 구현

      * 스프링 시큐리티라는 프레임워크는 필터를 통해 웹어플리케이션 보안을 구현할 수 있음.

    - 클라이언트의 요청이 오면 request객체, response객체, filterChain객체가 만들어진다.

    - 필터체인은 필터의 순서를 알고있는 객체이다. 

    - 클라이언트의 요청이 들어오면 FirstFilter, SecondFilter순으로 실행된다. 

    - doFilter라는 메소드가 있다. 매개변수로 servletRequest, sevletResponse, FilterChain을 전달받는다.

    메소드 안에는 filterChain.doFilter(request, response)메소드가 반드시 존재해야 한다. 다음에 있는 필터를 실행시키는 메소드다.

    - 더이상 실행할 필터가 없으면 jsp 또는 servlet를 실행한다. 

     

    /* : 모든 url요청에 대해서 실행하겠다는 의미이다.


    필터에서도 마찬가지로 web.xml에 초기화파라미터를 넣고 서블릿에서 값을 꺼낼 수 있다.

    web.xml
    
    <filter>
        <filter-name>second</filter-name>
        <filter-class>com.sample.filter.SecondFilter</filter-class>
        <init-param>
            <param-name>secret-key</param-name>
            <param-value>1a2cb5fde675caed3</param-value>
        </init-param>
    </filter>
    secondFilter.java
    
    public class SecondFilter implements Filter {
    	
    	private String secretKey;
    	private String companyName;
    	
    	@Override
    	public void init(FilterConfig filterConfig) throws ServletException {
    		System.out.println("SecondFilter의 init() 메소드 실행됨");
    		
    		// 필터의 초기화 파라미터값 조회하기
    		this.secretKey = filterConfig.getInitParameter("secret-key");
    	}
    	
    	
    	
    	@Override
    	public void destroy() {
    		System.out.println("SecondFilter의 destroy() 메소드 실행됨");
    	}
    
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
    			throws IOException, ServletException {
    		
    		System.out.println("SecondFilter의 doFilter() 메소드의 전처리 작업 수행됨");
    		
    		// 필터의 초기화 파라미터값 사용하기
    		System.out.println("SecondFilter의 비밀키 : " + secretKey);
    		
    		filterChain.doFilter(request, response);
    		
    		System.out.println("SecondFilter의 doFilter() 메소드의 후처리 작업 수행됨");
    	}
    
    }

    실행결과

    - Config라는 객체는 필터가 만들어지면 쌍으로 같이 만들어진다.

    - Config라는 객체는 필터마다 하나씩 있다.

    - Config는 내부에 초기화 파라미터라는 값을 갖고 있다.

    - SecondConfig에 설정되어 있는 초기화파라미터는 first filter에서는 못꺼내가고 second filter에서만 꺼내갈 수 있다.

     

    웹 애플리케이션 전체에서 사용가능한 초기화 파라미터

    web.xml
    <!-- 
    		웹 애플리케이션 전체에서 사용가능한 초기화 파라미터를 설정한다.
    		모든 서블릿/JSP/필터/리스너에서 사용가능하다.
    		<context-param />으로 설정한 초기화파라미터 값은 ServeletContext 객체의 초기화파라미터로 저장된다.
    		
    		ServletContext는 웹 애플리케이션 프로젝트 당 하나 생성되는 객체다.
    		WAS가 켜질 때 ServletContext 객체가 생성되고, WAS가 종료될 때 ServletContext 객체는 폐기된다.
    		ServletContext 객체는 서블릿의 여러 객체 중에서 가장 오랫동안 유지되는 객체다.
    		ServletContext 객체에는 속성과 초기화 파라미터를 저장할 수 있다.
    		ServletContext 객체에 저장된 속성과 초기화 파라미터는 모든 서블릿/jsp/필터/리스너에게 공유된다.
    -->
    	<context-param>
    		<param-name>company-name</param-name>
    		<param-value>중앙Hta 학원</param-value>
    	</context-param>

    - ServletContex의 초기화파라미터는 어플리케이션 전체에서 사용가능한 초기화파라미터이다.(스프링에서 사용된다.)

    - 메모리를 많이 차지 하기때문에 프로젝트에서 협의하에 값을 넣어야 한다.

    - 파라미터값을 서블릿에서 가져올때는 아래와 같이 코드를 작성한다.

    - JSP에서는 내부에 이미 ServletContext객체가 들어있기 때문에 객체를 만들 필요 없이

    String companyName = application.getInitParameter("company-name");만 작성하면 된다.

    HelloServlet.java
    
        // 애플리케이션의 초기화 파라미터 정보를 제공하는 ServletContext객체를 획득한다.
        ServletContext application = getServletContext();
        // String getInitParameter(String name)메소드를 초기화 파라미터값을 조회한다.
        String companyNameValue = application.getInitParameter("company-name");


    첨부파일 업로드하기

    1. <form /> 속성에 속성 추가하기

               <form method="post" enctype="multipart/form-data" action="register.jsp">

               * method=post

                     post방식의 요청만 첨부파일 업로드를 지원한다.

     

                     enctype은 요청메세지의 바디부에 포함되는 데이터의 인코딩 방식을 지정하는 속성이다.

     

                    enctype의 기본값은 enctype="application/x-www-form-urlencoded" 이다.

                    * <form />의 기본 enctype이다.

                    * 폼입력요소의 값을 url의 쿼리스트링과 같은 형식으로 변환해서 요청메세지의 바디부에 포함시킨다.

                    * 이 방식은 첨부파일 업로드가 불가능하다. 첨부파일 업로드가 없는 폼에서 사용하는 인코딩 방식이다.

                    * 요청헤더의 컨텐츠 타입이 이와 같이 지정된다.

                                    Content-Type: application/x-www-form-urlencoded

                    * 요청메세지의 바디부 예시)

                                    title=연습&writer=홍길동&content=게시글 작성 연습입니다.

                  

                    enctype="multipart/form-data"

                    * 첨부파일 업로드가 있는 폼에서 사용하는 인코딩 방식이다.

    2. <input type="file" /> 태그 추가하기

     

    3. Multipart요청(첨부파일 업로드가 포함된 요청)을 처리하는 API 사용

            서블릿

                     jakarta.servlet.http.Part 

                     주요 메소드

                              String getContentType()

                                    업로드된 첨부파일의 컨텐츠 타입을 반환한다.

                              String getSubmittedFileName()

                                    업로드된 첨부파일의 이름을 반환한다.

                             InputStream getInputStream()

                                      업로드된 첨부파일을 읽어오는 객체를 반환한다.

                             long getSize()

                                      업로드된 첨부파일의 사이즈를 반환한다.

                            * Part는 JSP에서는 사용불가, HttpServlet을 상속받은 사용자정의 서블릿 클래스에서만 사용가능하다.

           

            사용자 정의 유틸 클래스 (스프링에서는 사용할 일이 없음)

                     com.sample.MultipartRequest

                     생성자

                                  MultipartRequest(HttpServletRequest request, String directory)

                                        * 요청객체와 첨부파일을 저장할 디렉토리 경로를 전달받아서 MultipartRequest 객체를 초기화한다.

                                        * 요청메세지를 분석한다.

                                                 * 첨부파일을 지정된 디렉토리에 저장한다.

                                                 * 폼입력값을 분석해 놓는다. 

                     주요 메소드

                              String getParameter(String name)

                              String[] getParameterValues(String name)

                              String getFilename(String name)

     

             Spring framework의 MultipartFile
                      주요 메소드
                             String getContentType()
                             업로드된 첨부파일의 컨텐츠 타입을 반환한다.
                             String getOriginalFileName()
                             업로드된 첨부파일의 이름을 반환한다.
                             InputStream getInputStream()
                             업로드된 첨부파일을 읽어오는 객체를 반환한다.
                             long getSize()
                             업로드된 첨부파일의 사이즈를 반환한다.
                             boolean isEmpty()
                             업로드된 첨부파일이 없으면 true를 반환한다.
                             byte[] getBytes()
                             업로드된 첨부파일 데이터를 반환한다.

     

    => 아래는 이중에서 유틸클래스를 사용한 코드이다.

    register.jsp 내부에 다음과 같은 코드를 작성한다.

        // 멀티파트 요청처리를 지원하는 MultipartRequest 객체를 생성한다.
        // MultipartRequest는 multipart/form-data 요청처리를 지원하는 클래스다.
        
        
        // MultipartRequest객체를 아래의 생성자를 실행해서 객체생성하고, 초기화한다.
        // MultipartRequest mr = new MultipartRequest(요청객체, 첨부파일저장디렉토리);
        MultipartRequest mr = new MultipartRequest(request, "C:\\app\\web-workspace\\temp");
       
        // 요청객체에 저장된 요청파라미터값을 가져온다.
        String title = mr.getParameter("title");
        String content = mr.getParameter("content");
        String filename = mr.getFilename("attachedFile");
       
        System.out.println("게시글 제목: " + title);
        System.out.println("게시글 내용: " + content);
        System.out.println("게시글 첨부파일명: " + filename);
    
    	// Board객체를 생성해서 board정보를 담는다.
    	Board board = new Board();
    	board.setTitle(title);
    	board.setWriter(user.getId());   // 작성자에 로그인한 사용자의 아이디를 저장한다.
    	board.setContent(content);
    	board.setFileName(filename);

    detail.jsp

        <tr>
            <th>첨부파일</th>
            <td colspan="3">
                <%=board.getFileName() != null ? board.getFileName() : "없음" %>
    <%
            if (board.getFileName() != null) {
    %>					
                <a href="../download?no=<%=board.getNo() %>" class="ms-5 btn btn-success"
                style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .4rem; --bs-btn-font-size: .65rem;">다운로드</a>
    <%
            }
    %>
            </td>
        </tr>


    +) escape문자

     

    : \t

    줄바꿈문자 : \n

    백스페이스 : \b

    \ : \\

    ‘ : \’

    “ : \”

     

    경로를 나타내는 역슬래시임을 나타내기 위해 역슬래시를 하나 더 표시한다.

    \escape문자를 나타내는게 아니라는 걸 표시하기 위해 역슬래시를 2개 붙인다.

    댓글

Designed by Tistory.