2015년 7월 15일 수요일

서블릿에서 Spring MVC까지

http://olc.oss.kr/main.jsp
백기선 님이 발표한
에서 가입 후 Spring 으로 검색시 뜨는 강의중 1번재 강의
'서블릿에서 Spring MVC까지' 내용을 듣고 작성한 게시물임
아는 내용일 경우 둘러보고 끝내고
 안오는 경우 해당 강의를 청취하는것도 하나의 방법입니다.
 (무료교육)


1. 서블릿 JSP 프로그램
웹에서 동적으로 생성되는 컨텐츠를 제공하는 방법
CGI 요청 당 프로세스 , 서블릿 요청당 쓰레드
서블릿을 쓰면서 동접자를 많이 유치할 수 있게됨

- STS에서 프로젝트를 생성한다.
   다이나믹 웹 프로젝트 - 이름 쓰고, web.xml 생성 체크

    ex02) servlet
-----------------------------------------
작성1 src 밑에 작성

package whiteship;

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 HelloServlet extends HttpServlet {
 
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  
  String name = req.getParameter("name");
  String result = "+name+";
  resp.getWriter().println("ex02 Hello "+name);
 }
}


작성2 web.xml 에 추가


 hello
 whiteship.HelloServlet



 hello
 /hello



실행시 url 을 다음과 같이 설정
http://localhost:8080/ServletToSpringMVC/hello?name=team
결과 : ex02.jpg


---------------------------------------------------


- 여기서 servlet 맵핑 우선순위를 볼 수 있다.
 1. 정확하게 일치한 맵칭
 2. 디렉토리까지 일치
 3. 확장자가 일치
  동일한 수준만 맵핑 될 경우 그중 가장 긴것으로 맵핑한다.
==> 서블릿만으로 구현시 html단 코딩이 불편함


1.2. jsp 코딩
==>html단은 쉽지만 서버단 코딩이 제한됨.

    ex02) ex01 프로젝트에서 jsp로 작성
----------------------------------------
작성01 WebContent 밑에 HelloJsp.jsp를 새로 생성 및 작성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1><%= "hello" %> JSP</h1>
</body>
</html>


실행시 url 을 다음과 같이 설정
http://localhost:8080/ServletToSpringMVC/HelloJsp.jsp
결과 : ex03.jpg

---------------------------------------------------


1.3 서블릿 + jsp 로 작성
views/hello.jsp 를 작성
ps.WEB-INF 밑의 jsp는 사용자 직접 접근이 불가함 web.xml 설정으로 서블릿을 통해서 접근 가능함
==> model1 : jsp로만 코딩
==> model2 : 이렇게 서블릿 +jsp 로 코딩

** MVC 모델과 흡사하게 접근이 가능
   M : Model - servelet
   V : View - jsp
   C : controller - web.xml

핵심은 비지니스 모델과 프리젠테이션 로직의 분리

    ex03) 기존 프로젝트에서 계속 작업 (JSP, Servlet 같이 사용)
----------------------------------------
작성01 - HelloServlet.java 파일을 수정

package whiteship;

import java.io.IOException;

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

public class HelloServlet extends HttpServlet {
 
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  String name = req.getParameter("name");
  req.setAttribute("hello", "ex04 JSP+Servlet : "+name);
  RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/views/hello.jsp");
  requestDispatcher.forward(req, resp);
 }
 
}


작성02 - WEB-INF 밑에 views 폴더를 만들고 그 밑에 hello.jsp 파일을 생성 및 아래와 같이 작성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>${hello04}</h1>
</body>
</html>


실행시 url 을 다음과 같이 설정
http://localhost:8080/ServletToSpringMVC/hello?name=Kim
결과 : ex04.jpg

http://localhost:8080/ServletToSpringMVC/WEB-INF/views/hello.jsp
결과 : ex04_2.jpg : WEB-INF 밑에 jsp 파일은 접근할 수 없다.

---------------------------------------------------


이렇게 작성해서 구현코저 할때 도출된 불편함
 (1) 서블릿 실행전, 후 작업을 추가하고자 함
 (2) 컨트롤러 하나로 모든 요청 처리하기
 (3) 뷰를 좀더 편하게 제공하자
==> J2EE 패턴으로 발전함

2. J2ee 패턴
 1) Decoration Filter 패턴 사용하여 기존 코드 수정없이 부가기능 추가가 가능함 (1) 해결
    ex04)
----------------------------------------
작성01 - src 밑에 filter를 새로 생성

package whiteship;

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;
import javax.servlet.annotation.WebFilter;

/**
 * Servlet Filter implementation class TimerFillter
 */
@WebFilter("/TimerFillter")
public class TimerFillter implements Filter {

    /**
     * Default constructor.
     */
    public TimerFillter() {
        // TODO Auto-generated constructor stub
    }

 /**
  * @see Filter#destroy()
  */
 public void destroy() {
  // TODO Auto-generated method stub
 }

 /**
  * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
  */
 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
  long startTime = System.currentTimeMillis();
  chain.doFilter(req, resp);
  System.out.println("Process Time : " + (System.currentTimeMillis()-startTime));
 }

 /**
  * @see Filter#init(FilterConfig)
  */
 public void init(FilterConfig fConfig) throws ServletException {
  // TODO Auto-generated method stub
 }
}


작성02 - web.xml 에 filter 정의

  
   fillter
   whiteship.TimerFillter
  
  
   fillter
   /*
  


실행시 url 을 다음과 같이 설정
http://localhost:8080/ServletToSpringMVC/hello?name=Kim
결과 : ex05.jpg

---------------------------------------------------

- 여기서 filter 적용규칙을 알아본다.
  (1)<url-pattern> 대응은 web.xml 정의된 순서대로(중복 선언 가능) 적용됨
  (2) <servlet-pattern> 을 (1) 하단에 추가로 나열이 가능함. (이것도 여러개 가능)

- 사용시기 :
Request 필터링 :
보안 관련 내용 체크,
요청 헤더와 바디 포맷팅 수정,
요청 감시 또는 기록
Response 필터링 :
응답 스트림 압축
응답 스크림에  내용 추가 또는 수정
전혀 다른 응답으로 교체

 2) Front Controller 패턴
  컨트롤러 하나로 모든 요청을 처리 (web.xml에 여러개를 등록하는게 아닌 하나만 등록하고 처리하는 방식)
  REQ/RES -> FrontController(애만 web.xml에 추가) -> Controller -> (Dispatcher View)(FrontController 일부로 작성 또는 따로 작성 또는 생략) -> view
  기존 작성 내용에서 FrontController를 추가함 why?
  (반복성 코드를 분리하고 좀더 쉽게 작성하기 위해서)

    ex05) Controller 위에 front Controller를 추가하기
----------------------------------------
작성01 - src 밑에 WhiteshipServlet.java 생성 및 작성

package whiteship;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

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

public class WhiteshipServlet extends HttpServlet{

 @Override
 protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  handleRequest(req, resp);
 }

 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  handleRequest(req, resp);
 }

 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  handleRequest(req, resp);
 }

 @Override
 protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  handleRequest(req, resp);
 }
 
 private void handleRequest(HttpServletRequest req, HttpServletResponse resp) {
  try {
   Handler handle = handlerMapping(req);
   String viewName = handlerAdpter(handle, req , resp);
   
   dispatch(viewName, req, resp);
  } catch (Exception e){
   exceptionResolve(e);
   throw new RuntimeException();
  }
  
 }

 private void exceptionResolve(Exception e) {
  //이런식으로 처리 가능함 구현 하세요 알아서
  
 }

 private void dispatch(String viewName, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  String resultViewName = "/WEB-INF/views/"+viewName+ ".jsp";
  RequestDispatcher dispatcher = req.getRequestDispatcher(resultViewName);
  dispatcher.forward(req, resp);
 }

 private String handlerAdpter(Handler handler, HttpServletRequest req, HttpServletResponse resp) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
  Method handlerMethod = handler.getClass().getMethod("handle", HttpServletRequest.class, HttpServletResponse.class);
  return (String) handlerMethod.invoke(handler, req, resp);
 }

 private Handler handlerMapping(HttpServletRequest req) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
  String uri = req.getRequestURI();
  String handleName = "whiteship."+uri.substring(uri.lastIndexOf("/")+1)+"Handler";
  Class handlerClass = Class.forName(handleName);
  return (Handler) handlerClass.newInstance();
 }
}


작성02 - src 밑에 Handler.java 생성 및 interface 작성

package whiteship;

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

public interface Handler {
 public String handle(HttpServletRequest req , HttpServletResponse resp);
}


작성03 - HelloHandler.java 생성 및 작성

package whiteship;

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

public class HelloHandler implements Handler{

 @Override
 public String handle(HttpServletRequest req, HttpServletResponse resp) {
  String name = req.getParameter("name");
  req.setAttribute("hello04", "start J2ee");
  req.setAttribute("message", "ex05 J2ee"+name);
  return "hello";
 }
}


작성04 - web.xml에 다음 내용을 추가

  
   whiteship
   whiteship.WhiteshipServlet
  
  
   whiteship
   /app/*
  


실행시 url 을 다음과 같이 설정
http://localhost:8080/ServletToSpringMVC/app/Hello?name=team

결과 : ex06.jpg

---------------------------------------------------

    ===> 결과적으로 핸들러 맵핑시 과정이 복잡하고, 유연하지 않음
          예외처리에 대한 부분이 부족, 뷰를 찾는 부분이 경직되어 있음(변경이 힘듬)
          -> 스프링 MVC 쓰자 로 결론

댓글 없음:

댓글 쓰기