190718_Day69 서플릿 필터, 리스너, 파일업로드

<서블릿 필터>

  • 사용자 요청에 따라 서블릿이나 JSP의 실행 전후, 필요에 따라 기능을 추가, 삭제해주는 역할

  • 보통 클라이언트의 요청을 서블릿이 받기 전에 가로채어 필터에 작성된 내용을 수행 하는 것

  • 인증, 로깅/감사, 이미지변환, 데이터압축, 암호화 등..

  • javax.servlet.Filter

  • util이라는 패키지에 넣어봤습니다~

  • 환경설정 필요

    • Web.xml (WEB-INF안에)

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app version="3.0" 
               xmlns="http://java.sun.com/xml/ns/javaee" 
               xmlns:xml="http://www.w3.org/XML/1998/namespace" 
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd ">
      
       <!-- 리스너 등록(0718오후) -->
       <listener>
           <listener-class>t0718.MyListener</listener-class>
       </listener>
      
       <!-- 전체 서블릿과 JSP에서 공유할 데이터 (text) 정의 -->
       <context-param>
           <param-name>common</param-name>
           <param-value>진꼬복 많이 받으세요 :)</param-value>
       </context-param>
      
       <!-- 경로 변경시 이미지 쉽게 루트 변경하려면! -->
        <context-param>
           <param-name>imgPath</param-name>
           <param-value>/TomTest/image</param-value> <!-- 이제 여기만 고치면 되네! -->
       </context-param>
      
       <context-param>
           <param-name>rootPath</param-name>
           <param-value>/TomTest</param-value>
       </context-param>
      
       <!-- 필터 클래스 등록 -->
       <filter>
           <filter-name>enc</filter-name> <!-- 아무거나! -->
           <filter-class>util.enc.EncFilter</filter-class>
           <init-param>
               <description>설명은 여기에 적어, encoding초기값</description>
               <param-name>encType</param-name>
               <!-- 얘를 EncFilter.java에서 가져다 씀 -->
               <param-value>UTF-8</param-value> 
               <!-- EncFilter 무시하고 이 값으로 감 -->
           </init-param>
       </filter>
       <filter-mapping>
           <filter-name>enc</filter-name> <!-- 아무거나! -->
           <url-pattern>*.jsp</url-pattern>
       </filter-mapping>              
      
        <!-- 서블릿 클래스 등록 -->
        <servlet>
          <servlet-name>my</servlet-name>
          <servlet-class>t0708.MyServlet</servlet-class>
          <init-param>
             <param-name>youName</param-name>
             <param-value>아무개</param-value>
          </init-param>
        </servlet>
      <!-- (서블릿 클래스에 매핑될) 가상의 경로 설정 -->
      <servlet-mapping>
        <servlet-name>my</servlet-name>
        <url-pattern>/gildong/my</url-pattern>
        <!-- url-pattern엘리먼트 내의 맨 앞의 '/'는  (컨텍스트)루트를 의미!!
                        예) /gildong
              ===> http://localhost:8282/TomTest/gildong
         -->
      </servlet-mapping>         


      <!-- 카운트 서블릿등록 -->
      <servlet>
         <servlet-name>cnt</servlet-name>
         <servlet-class>com.encore.t0708.CountServlet</servlet-class>
      </servlet>

      <!-- 카운트 서블릿에 매핑할 가상경로 정의 -->
      <servlet-mapping>
         <servlet-name>cnt</servlet-name>
         <url-pattern>/cnt</url-pattern>
      </servlet-mapping>

      <!-- 카운트 서블릿등록2 -->
      <servlet>
         <servlet-name>cnt2</servlet-name>
         <servlet-class>com.encore.t0708.CountServlet2</servlet-class>
      </servlet>

      <!-- 카운트 서블릿에 매핑할 가상경로 정의2 -->
      <servlet-mapping>
         <servlet-name>cnt2</servlet-name>
         <url-pattern>/cnt2</url-pattern>
      </servlet-mapping>

      <!-- 파라미터서블릿등록 -->  
      <servlet>
         <servlet-name>param</servlet-name>
         <servlet-class>com.encore.t0709.ParamServlet</servlet-class>
      </servlet>

      <!-- 파라미터서블릿에 대한 가상경로 등록 -->  
      <servlet-mapping>
         <servlet-name>param</servlet-name>
         <url-pattern>/0709/result</url-pattern>
      </servlet-mapping>


      <!-- 
        <error-page>는  에러발생동기와   ==>   <error-code>  또는  <exception-type>
                                         에러발생시 이동할 페이지의 정보를 저장   ==>  <location>
      -->

     <!-- 
      <error-page>
        <error-code>500</error-code>
        <exception-type>java.lang.ArithmeticException</exception-type>
        <location>/0711/error.jsp</location>
      </error-page> 
     -->

      <!-- 
          <welcome-file-list>에는 페이지 명시 없을 때 보여줄 화면 페이지를 설정

         - 페이지 명시하는 경우 : http://192.168.0.96:8282/TomTest/hello.jsp
         - 페이지 명시하지 않는 경우 : http://192.168.0.96:8282/TomTest

         <welcome-file>태그 중 위쪽에 명시된 페이지가 우선 순위가 높다.
                 만약 TomTest폴더 밑에 아래의 index.html, index.jsp, hello.jsp파일이 
                 전부 있다면 index.html이 화면에 자동 출력됨. 
       -->

      <session-config>
          <session-timeout>1</session-timeout>
          <!-- TomTest(WebContext) 안에 모든 페이지에 대해 '분' 단위의 세션유지 시간 설정 -->
      </session-config>

      <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>hello.jsp</welcome-file>
      </welcome-file-list>


    </web-app>

EncFilter.java

package util.enc;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class EncFilter implements Filter
{
    private String encType;

    @Override
    public void init(FilterConfig config) throws ServletException
    {
        // System.out.println("init()");
        // config 통해서 web.xml에 정의된 param을 읽기 가능
        encType = config.getInitParameter("encType");
    }

    @Override
    public void destroy()
    {
        // System.out.println("destroy()");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException
    {
        // System.out.println("doFilter()");

        if (encType != null) // web.xml에 encType이 정의되었다면
        {
            request.setCharacterEncoding(encType);
        } else
        {
            request.setCharacterEncoding("UTF-8");
        }
        // doFilter와 페이지 연결 하려면
        chain.doFilter(request, response);
        // 다른 필터 혹은 요청 페이지와의 연결 진행
    }
}

input.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>입력폼</title>
</head>
<%-- input.jsp  (입력폼) --%>
<body> 
   <h3>입력폼</h3>
   <hr>
   <%
     String youName =  getServletConfig().getInitParameter("youName");
     out.print("당신의 이름은 "+ youName+"<br>");

     //application == ServletContext
     String msg = application.getInitParameter("common");
     out.print("<font color=green>서버의 메시지 :["+msg+"]</font><br>");
   %>
   ${book }<br>
     책제목: ${book.title } <br>
   <form method="post" action="result.jsp"> 
          이름: <input type="text" name="username"><br>
      <button>전송</button>
   </form>

</body>
</html>

result.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파라미터 전송결과</title>
</head>
<%--result.jsp --%>
<body>
  <h3>파라미터 전송결과</h3>
  <hr>
    전달 이름: 
    <%= request.getParameter("username") %>
</body>
</html>

web.xml에서 t0708/MyServlet 부분 서블릿 추가

ServletConfig 는 하나

ServletContext 는 여러개!

MyServlet.java(t0708)

package t0708;

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

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

public class MyServlet extends HttpServlet{
  //서블릿 : 한개의 웹페이지 화면을 구성!!

   @Override
   public void init() throws ServletException {
      System.out.println("init()");
   }

   @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       System.out.println("service()");
       //서블릿 서비스 메소드 == 웹브라우저 서비스!! ==> HTML 서비스
       //request:클라이언트(사용자, 브라우저), response : 서버를 각각 의미


       // (한글)문자집합 설정
       response.setContentType("text/html;charset=UTF-8");
       // text/html => MIME형식
       // 입력:text 출력:html => out.print() 메소드를 통해 전달되는 text를 브라우저에게 html해석하시오!
       //text:plane; text:xml; 이런식으로 형식을 줄 수 있다!

       PrintWriter out = response.getWriter();
       //PrintWriter out ==> 브라우저 출력 객체를 의미함.
       //out.print("HTML코드(텍스트)");

       out.print("<html><head><title></title></head>");
       out.print("<body><h3>ServletTest</h3></hr>");

       //190708 여기 추가
       //web.xml에 등록된 initParam데이터 가져오기
       ServletConfig config = getServletConfig(); // 현재 서블릿
           String name = config.getInitParameter("youName");
           String name2 = getInitParameter("youName");
           out.print("name : " + name + ", name2 : " + name2 );
       ServletContext application = getServletContext();
       //TomTest와 같은 웹어플리케이션

       String commonTxt = application.getInitParameter("common");
       out.print("<font color=green>" + commonTxt + "</fong><br>");



       out.print(application.getAttribute("book" + "<br>"));
       //이 위까지 190708 추가

       for (int i = 0; i < 10; i++) {
           if(i%2==0)
           out.println("<b><font color = red>용진</font></b><br>");
           if(i%2==1)
            out.println("<b><font color = blue>진주</font></b><br>");
    }
       out.print("</body></html>");
    }

    @Override
    public void destroy() {
       System.out.println("destroy()");
    }

}

input.jsp에 추가

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>입력폼</title>
</head>
<%-- input.jsp  (입력폼) --%>
<body> 
   <h3>입력폼</h3>
   <hr>
   <%
     String youName =  getServletConfig().getInitParameter("youName");
     out.print("당신의 이름은 "+ youName+"<br>");

     //application == ServletContext
     String msg = application.getInitParameter("common");
     out.print("<font color=green>서버의 메시지 :["+msg+"]</font><br>");
   %>
   ${book }<br>
     책제목: ${book.title } <br>
   <form method="post" action="result.jsp"> 
          이름: <input type="text" name="username"><br>
      <button>전송</button>
   </form>

</body>
</html>
  • 어디에 쓰는데 이걸? 이미지 한곳에 모아놨었는데, 그 폴더에 없고 예를 들어 coffee 폴더 안에 있어...경로가 달라졌어!

  • 그럼 그림 안나옴 ㅠㅠ

  • 이미지 수십개 썼으면, 해당 jsp 가서 다 수정할거야? 아니지?

  • 문제가 되는 페이지에 가서 수정하는게 아니라

    • web.xml에 등록하고

        <context-param>
           <param-name>imgPath</param-name>
           <param-value>/TomTest/image</param-value> <!-- 이제 여기만 고치면 되네! -->
       </context-param>
      • 해당하는 imgPath value값만 바꾸면 된다!

      • 0717에 service.jsp에서 사진을

        <img src="<%= application.getInitParameter("imgPath")%>/ebi.gif" width="400" height="300">
        
        <img src="${initParam.imgPath }/ebi.gif" width="400" height="300">
        • 이렇게 수정함, 적용 잘 됨!
        • 너무 길면 ${initParam.imgPath }

<리스너>

  • 특정 인터페이스를 구현하는 자바클래스
  • web.xml의 리스너 설정 항목에 기술해두면 웹 애플리케이션 시작 시 자동으로 실행되어 모든 애플리케이션에서 참조할 객체 생성등을 수행

web.xml 에 리스터 등록

 <listener>
     <listener-class>t0718.MyListener</listener-class>
 </listener>

MyListener.java

package t0718;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyListener implements ServletContextListener
{
    @Override
    public void contextDestroyed(ServletContextEvent sce)
    {
        // 끝날 때
        //System.out.println("contextDestroyed");
    }

    @Override
    public void contextInitialized(ServletContextEvent sce)
    {
        // 시작할 때
        //System.out.println("contextInitialized");

        //전체 웹어플리케이션에서 공유할 객체 저장
        ServletContext application = sce.getServletContext();
        application.setAttribute("book", new Book());
    }
}

<파일 업로드>

  • 사용자(클라이언트) PC내의 파일 -> 서버의 특정 디렉토리에 저장!
  • <파일업로드 규칙>
    1. form태그의 method속성은 반드시 post!
    2. form태그의 속성 enctype="multipart/form-data" 추가!
      • 폼내의 데이터들을 text가 아닌 stream으로 전송!
      • input.jsp
    • 참고) enctype = "application/x-www-form-urlencoded"
      • 기본값
      • form태그내의 name데이터들을 text로 전달!
  • <파일 업로드 구현>
    1. inputFile.jsp : 폼제공
    2. resultFile.jsp : inputstream을 통해 파일 업로드 구현, 실행

inputFile.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>입력폼</title>
</head>
<%--inputFile.jsp --%>
<body>
  <h3>입력폼</h3>
  <hr>
  <form action="resultFile.jsp" method="post"
        enctype="multipart/form-data" >
       이름: <input type="text" name="username"><br>
       파일: <input type="file" name="myfile"><br>
       <button>전송</button>
  </form>
</body>
</html>

resultFile.jsp

<%@page import="java.io.FileWriter"%>
<%@page import="java.io.InputStreamReader"%>
<%@page import="java.io.BufferedReader"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>결과페이지</title>
</head>
<%--resultFile.jsp --%>
<body>
  <h3>결과페이지</h3>
  <hr>

     이름: <%=request.getParameter("username") %> <br>
     파일: <%=request.getParameter("myfile") %> <br>
  <hr color="red">
  <%
     ServletInputStream sis = request.getInputStream();

     BufferedReader  br = new BufferedReader
                         (new InputStreamReader(sis,"UTF-8"));

     String delimiter = br.readLine();//구분자역할을 하는 문자열
     //"------WebKitFormBoundarys29EFHDUPZj87Yvt"

     String str;
     int count=0;
     while( (str=br.readLine())  !=  null ){
         count++;
        // out.print(str+"<br>");
        if(str.contains("name=\"myfile\"")){
            System.out.println(count+"째줄에서 myfile을 찾았다!!");

            //파일명 찾기
            int startIdx = str.lastIndexOf("=")+2;
            int endIdx = str.length()-1;

            String fileName = str.substring(startIdx, endIdx);
                  //"애국가.txt"
            FileWriter fw = new FileWriter
                (application.getRealPath("/upload/")+ fileName);
                  //e:/jaelee/workspace2/TomTest2/upload/애국가.txt

            br.readLine();
            br.readLine();//두줄 skip


            while( (str=br.readLine()) != null  ){
                if(str.contains(delimiter)) break;
                out.print(str+"<br>");//브라우저화면 출력
                fw.write(str+"\r\n");//파일 출력
            }//while
             fw.close();
        }//if
     }//while

     //애국가.txt파일의 내용을 브라우저 화면에 출력하자!!
     //애국가.txt파일을  upload폴더에 생성하고 내용을 파일출력하자!!

  %>

</body>
</html>

<파일 업로드 툴>

http://www.servlets.com

  • cos-20.08.zip

위의 툴을 사용해서 만들어 보자!

압축 풀고 lib 폴더에 jar 파일 넣고 빌드패스!

inputFile2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>입력폼</title>
</head>
<%--inputFile.jsp --%>
<body>
  <h3>입력폼(파일업로드 : COS.jar - MultipartRequest 객체 사용 )</h3>
  <hr>
  <form action="resultFile2.jsp" method="post"
        enctype="multipart/form-data" >
       이름: <input type="text" name="username"><br>
       파일: <input type="file" name="myfile"><br>
       <button>전송</button>
  </form>
</body>
</html>

resultFile2.jsp

<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h3>결과페이지(파일업로드)</h3>

  <%
   //MultipartRequest(HttpServletRequest request, String saveDirectory)
   //MultipartRequest(HttpServletRequest request, String saveDirectory, 
                   //String encoding)
   //MultipartRequest(HttpServletRequest request, String saveDirectory, 
            //int maxPostSize, String encoding, FileRenamePolicy policy)

    String saveDir=application.getRealPath("/upload");
    //---> "e:/jaelee/workspace2/TomTest/upload"
    int maxSize=  5     * 1024   * 1024; //업로드 될 파일의 크기 제한, 단위:byte
          //     5byte    5Kb       5Mb 

    MultipartRequest mreq = new MultipartRequest
    (request,saveDir, maxSize, "UTF-8", new DefaultFileRenamePolicy());
        //MultipartRequest생성자 호출 == 파일업로드 !

        out.print("파일 업로드 성공 ~ !");
        String name = mreq.getParameter("username");


    %>
    <br>
    이름 : <%= name %><br>
    원본파일명 : <%= mreq.getOriginalFileName("myfile") %><br> 
    저장파일명 : <%= mreq.getFilesystemName("myfile") %><br> 

</body>
</html>

궁금상자
context-param
init-param

context-param(컨텍스트 초기화 파라미터)
    - <web-app> 항목내 작성
    - 범위 : 웹 애플리케이션 내에 모든 서블릿, jsp


init-param(서블릿 초기화 파라미터)
    - <servlet> 항목내 작성
    - 범위 : <init-param>항목을 포함하는 서블랏만

+ Recent posts