강좌/Spring @MVC

001. Servlet - HTML 로 개발자 피로감 상승 시키기

여름나라겨울이야기 2013. 2. 25. 17:32
728x90

선수 강좌: Spring 3.0 / 안 보신 분들은 다녀오세요.

http://expert0226.tistory.com/category/%EA%B0%95%EC%A2%8C/Spring%203.0
OR
http://expert0226.tistory.com/187 ~ 쭈욱

선수 지식: HTML

추천 서적: Head First Java / Head First JSP


사전 준비: JDK 5.0 이상, Tomcat v6.0 이상, STS 최신 설치본


이전 Spring 3.0 강좌 공개 후 Spring MVC 를 다루어달라고 하시는 몇몇 분들의 요청에 의거하여 작성하는 강좌는 아니고 역시 저의 야메(!) 지식 업그레이드와 댓글 놀이를 위해 작성하는 강좌입니다.  이 강좌를 우습게 보시기 위해 필요한 지식은 HTML, Java, JSP, Design Patten, Spring 3.0 지식이구요.  필수 지식은 HTML 약간, 그리고 Java 약간, 그리고 제 강좌 Spring 3.0 되겠습니다.  역시 야메(!)를 지향함으로 더 궁금하신 것은 토비의 스프링 3.0 기준으로 "10.1.4 웹 애플리케이션 IoC 컨테이너 구성", "12장 스프링 웹 기술과 스프링 MVC", "13장 스프링 @MVC" 를 보시면 되겠으나 그거 보실 능력이시면 이 강좌를 안 보시겠죠. 쿨락... 어찌 되었건 이 강좌 다 보시면 그 이후에는 "토비의 스프링" 또는 "최범균의 스프링 3.0" 등등 양서를 통해 좋은 지식을 확보하시길 바랍니다.


Java 언어에서의 웹구현: 그 첫번째 역사 Servlet


백문이 불여일타이니 일단 웹프로젝트를 구축해 보겠습니다.  STS 여시구요.  File > New > Dynamic Web Project 를 선택해 줍니다.




Project name: ExpertSpringMVC001

Target runtime: Apache Tomcat v6.0


으로 지정했습니다. 이제 과감하게 Next 버튼 클릭! 다시 Next 클릭! 이제 드디어 Finish 클릭! 잠시 기다리신 후에 팝업 창에서 과감히 Yes 버튼 클릭!



위와 같이 나오시면 성공적으로 프로젝트 생성이 완료되어진 겁니다.  이제 Java Resources/src 에서 우리가 가지고 놀 클래스 파일을 하나 생성하겠습니다.


음음 Dynamic Web Project 안 만들어 본지 어언... 범어동대장님의 DWP 셋팅/구동하기(http://blog.naver.com/asjgi?Redirect=Log&logNo=70131541795)를 추천하오니 DWP 구성 잘 안되시는 분들은 다녀오사이다.


package com.heaven.spring;

public class Member {
	public static final boolean FEMALE = true;
	public static final boolean MALE = false;
	
	private String name;
	private boolean gender;
	private int age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public boolean isGender() {
		return gender;
	}
	public void setGender(boolean gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	public String toString() {
		String msg = null;
		
		if(gender == FEMALE) {
			switch(age / 10) {
				case 0: 	msg = "귀엽냐?"; break;
				case 1: 	msg = "이쁘냐?"; break;
				case 2: 	msg = "이쁘냐?"; break;
				case 3: 	msg = "이쁘냐?"; break;
				case 4: 	msg = "이쁘냐?"; break;
				case 5: 	msg = "이쁘냐?"; break;
				case 6: 	msg = "곱냐?"; break;
				default: 	msg = "곱냐?"; break;
			}
		} else {
			switch(age / 10) {
				case 0: 	msg = "귀엽냐?"; break;
				case 1: 	msg = "잘 생겼냐?"; break;
				case 2: 	msg = "잘 생겼냐?"; break;
				case 3: 	msg = "돈 잘 버냐?"; break;
				case 4: 	msg = "밤에.. 음..?"; break;
				case 5: 	msg = "밤에.. 음..?"; break;
				case 6: 	msg = "재산 많냐?"; break;
				default: 	msg = "재산 많냐?"; break;
			}			
		}
		return msg;
	}
}

음!.. 예제는 예제일뿐 오해하지 말자.  간단하게 테스트해볼 드라이버 클래스도 하나 만들어 주겠습니다.


package com.heaven.spring;


public class MemberDriver {
	public static void main(String[] args) {
		Member juliet = new Member();
		juliet.setName("줄리엣");
		juliet.setGender(Member.FEMALE);
		juliet.setAge(18);
		
		Member romeo = new Member();
		romeo.setName("놈임요");
		romeo.setGender(Member.MALE);
		romeo.setAge(19);
		
		Member seoyoung = new Member();
		seoyoung.setName("이서영");
		seoyoung.setGender(Member.FEMALE);
		seoyoung.setAge(32);
		
		Member samjae = new Member();
		samjae.setName("이삼재");
		samjae.setGender(Member.MALE);
		samjae.setAge(62);
		
		showMember(juliet);
		showMember(romeo);
		showMember(seoyoung);
		showMember(samjae);
	}

	private static void showMember(Member member) {
		System.out.println(member.getName() + " " + member.toString());
	}
}

여기까지 만드셨으면 MemberDriver.java 우클릭 Run As > Java Application 하시고,  이상이 없다면 Console 창에 아래와 같이 예쁘게 결과가 나오겠죠.


줄리엣 이쁘냐?
놈임요 잘 생겼냐?
이서영 이쁘냐?
이삼재 재산 많냐?



자 이 프로그램의 교훈은 무엇일까요?  Member.java 를 보시면 아시겠지만 남자는 10대, 즉 사춘기부터 꾸준히 여성을 바라보는 마음이 한결같지만 여자는 갈대처럼 연령대별로 바뀌어간다능... 응? 응? 이건 아닌가요?  예제는 예제일 뿐 오해하지 마시라니깐요.


Console 화면에 텍스트 형태로 출력되는 것이 영 마음에 들지 않습니다.  AWT / SWING / Eclipse RCP 등을 이용해서 능력되시는 분은 GUI 로 구성해 보셔도 좋을 듯 합니다.  저는 Java GUI 만들 일이 없었음으로 패스...

자 더 나아가서 Web Broswer 상에서 보여달라는 요구가 생겼다고 가정해 보겠습니다.  그래서 등장하는 것이 Servlet.. 이게 무엇이 약자이냐?  저는 몰라요.  알면 좀 알려주세요(아무도 안 알려주셔서 결국 제가 찾아봤어요.  Servlet: 브라우저상이 아니고 서버상에서 움직이는 애플릿!!! ?.? 애플릿의 정의가 헷갈리기 시작했습니다.  제가 아는 Applet 는 브라우저 상에서 구동되는 자바 프로그램인데.. ㅡㅡ?  그래서 다시 꼬리 물기를 했습니다. Applet :다른 프로그램 내에서 실행되는 프로그램.  흠흠 제가 Applet 을 오해하고 있었군요.  Applet 미안....). 그냥 구현하라고 해서 구현합니다.  Sevlet 인터페이스를 implements 해주면 된다고 하네요.  그런데 기왕 웹브라우저에서 보여줄꺼면 Servlet 인터페이스를 직접 구현하기 보다는, Servlet 을 이미 구현한 HttpServlet 클래스를 상속해서 확장하는게 정신 건강에 좋다고 하는군요.  저는 체제 순응형 입니다.  시키면 합니다.  그래서 했습니다.  아래 소스는 모르셔도 Spring MVC 공부하는데는 별반 지장은 없습니다.  ^^  Spring MVC 는 완소 존재인 Servlet 에 의존하지 않는 POJO 를 지향하니까요.  알아서 나쁠 것도 없지만... 저도 백만년 만에 Servlet 코딩이라 사실 삽질 좀 했습니다.

package com.heaven.spring;

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 MemberServlet extends HttpServlet {
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {		
		Member juliet = new Member();
		juliet.setName("줄리엣");
		juliet.setGender(Member.FEMALE);
		juliet.setAge(18);
		
		Member romeo = new Member();
		romeo.setName("놈임요");
		romeo.setGender(Member.MALE);
		romeo.setAge(19);
		
		Member seoyoung = new Member();
		seoyoung.setName("이서영");
		seoyoung.setGender(Member.FEMALE);
		seoyoung.setAge(32);
		
		Member samjae = new Member();
		samjae.setName("이삼재");
		samjae.setGender(Member.MALE);
		samjae.setAge(62);
	
		resp.setContentType("text/html; charset=UTF-8");
		resp.setCharacterEncoding("UTF-8");
		PrintWriter out = resp.getWriter();
		
		out.println("<html>");
		out.println("<body>");
		showMember(out, juliet);
		showMember(out, romeo);
		showMember(out, seoyoung);
		showMember(out, samjae);
		out.println("</body>");
		out.println("</html>");
	}

	private void showMember(PrintWriter out, Member member) {		
		out.println("<b>" + member.getName() + "</b> " + member.toString() + "</br>");
	}
}

그래도 위 코드를 이해하고 알고 싶으시다구요?  Head First Servlet & JSP 를 추천합니다.  추천서적의 2장까지 읽으시면 위 코드를 이해하실 수 있습니다. ^^  서블릿을 만들었으니 서블릿을 호출할 수 있도록 web.xml 즉, 배포 설정자(Deploy Descriptor, 일명 DD)를 셋팅해 주셔야 겠죠.

<!--?xml version="1.0" encoding="UTF-8"?-->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemalocation="http://java.sun.com/xml/ns/javaee
				      http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID"
	version="2.5">
	<servlet>
		<servlet-name>MemberServlet</servlet-name>
		<servlet-class>com.heaven.spring.MemberServlet</servlet-class>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>MemberServlet</servlet-name>
		<url-pattern>/Member</url-pattern>
	</servlet-mapping>
</web-app>

브라우저를 열고 주소를 조심스럽게 타이핑 해줍니다.



URL 주소의 앞 부분은 각자가 조금 다르시겠죠.  아마도 http://localhost:8080/ExpertSpringMVC001/Member 라고 치시면 웹페이지가 잘 올라올 겁니다.  다 아시는 내용이겠지만 혹시나 해서 설명 좀 보태고 가도록 하죠.  먼저 살펴볼 부분은 MemberServlet.java 의 doGet() 메소드 입니다.


인자값:
HttpServletRequest rep - 사용자의 브라우저가 서버로 보내온 요청(request) 내용을 보관하는 객체입니다.

HttpServletResponse resp - 서버가 사용자의 브라우저로 보내는 응답(response) 내용을 보관하는 객체입니다.


// 응답이 Text 형태의 HTML 문서이며,

// 다국어(한국어) 지원을 위해 문자(들)는 UTF-8 로 인코딩했다는 사실을 브라우저에게 알려줍니다.

resp.setContentType("text/html; charset=UTF-8");


// UTF-8 인코딩 확인 사살입니다.  사실 바로 위에 것 하나로 끝내서도 됩니다.

resp.setCharacterEncoding("UTF-8");


PrintWriter out = resp.getWriter();


위와 같이 작성하시고 out 객체의 println() 메소드를 이용해서 Console 프로그램에 System.out.println() 메소드를 사용하듯 HTML 문서를 작성하시면 doGet() 메소드가 종료될 때 그 응답이 사용자의 브라우저로 전송 됩니다.  잘 모르시겠다구요?  좌절하거나 낙망하지 마십시요.  Spring MVC 로 넘어가면 다 필요없어집니다.


그럼 이제 WebContent/WEB-INF/web.xml 을 보도록 하겠습니다.  기존에 작성된 내용을 지우고 아래 내용으로 수정했습니다.  이건 Spring MVC 로 넘어가셔도 기억해 두셔야 합니다.


<servlet>
    <servlet-name>MemberServlet</servlet-name>
    <servlet-class>com.heaven.spring.MemberServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>MemberServlet</servlet-name>
    <url-pattern>/Member</url-pattern>
</servlet-mapping>


사용자 브라우저 입장에서부터 시작하겠습니다.  Tomcat(웹서버 - 서블릿 컨테이너) 은 자신의 주소(http://localhost:8080)와 프로젝트명(/ExpertSpringMVC001) 그리고 url-pattern 에 지정된 정보(/Member)가 결합된 주소를 받게 됩니다.  글로 설명하면 길고 그림으로 설명하면 그림 그리는 시간 걸리고.. ㅡㅜ 말로 설명할 수 있게 술값 들고 오세요.  선 긋기가 제일 힘들었어요.




자 그럼 D&C 해 보겠습니다.  D&C 기억 안 나시면 Spring 3.0 강좌 다시 보고 오세용.  사용자의 브라우저 주소에 URL 정보를 입력하는 것에서 부터 사용자 브라우저가 웹화면을 띄우는 과정까지를 D&C 로 쭈욱 나열해 봤습니다.


1. 사용자가 브라우저 주소창에 http://localhost:8080/ExpertSpringMVC001/Member 를 입력한다.


2. (떵색) 웹서버는 브라우저가 요청한 주소를 보고 웹서버의 ip(또는 도메인 네임), 포트, 프로젝트 이름을 제외한 후, 일치하는 url-pattern 을 찾는다.(/Member)

url-pattern 은 역시 여러분이 원하시는 것으로 작명하시면 됩니다.  어차피 실제 서블릿의 물리적 경로가 아닌 가상의 경로이기 때문에 맘껏 작명하시면 됩니다.  단, URL 규격에는 맞아야 겠죠.


3. (빨갱) <servlet-mapping> 의 servlet-name 과 일치하는 <servlet> 의 servlet-name 을 찾습니다(MemberServlet).

servlet-name 에 부여한 이름은 여러분이 원하는 무엇으로 주셔도 됩니다.  사용자에게 노출되지 않은 DD 내부에서만 사용하는 이름입니다.

<servlet-mapping> 과 <servlet> 내부의 servlet-name 이 서로 일치하기만 하면 됩니다.


4. (퍼렁) <servlet> 의 servlet-class 와 일치하는 자바 클래스(서블릿)를 찾아서 브라우저의 요청 정보를 처리한다.

<servlet-class> 내부에는 Servlet 인터페이스(여기서는 Servlet 인터페이스를 구현한 HttpServlet 을 상속)를 구현한 Java 클래스를 패키지명까지 포함해서 전부 적어 줍니다.


5. (중략) MemberServlet.java 의 doGet() 메소드가 브라우처의 요청(HttpServletRequest) 정보를 처리한 후 브라우저에게 응답(HttpServletResponse)을 전송합니다.


더 깊은 내용은 어디?  Head First Servlet & JSP!!!  하지만 Servlet 관련 내용은 Spring MVC 오면서 깊이 볼 필요가 있긔? 없긔?  그렇다 하더라도 웹프로그래밍의 전반적인 내용을 이해하기 위해 꼭 읽어보시길 권합니다.  최신판이 나오면 좋겠지만 이제는 절판까지 됬었네요(이런 2009 년에 개정판이 나왔군요.  거 보세요. 개정판 나와도 모를 정도로 Servlet 에 신경 안 쓰고도 웹개발자로 살아갈 수 있다는 증거입니다).  정말 좋은 책인데.. 차마 말로 할 수는 없고.. 남자한테 정말 좋은데.. 아니 웹개발자에게 정말 좋은데...  서점 등에서 구하셔서라도 꼭 읽어 보세요.  전체 내용을 다 열심히 보실 필요는 없구요.  현재의 웹개발에서도 필요한 내용만을 잘 선별해서 보시길 바랍니다.  잘 선별하는 법이요?  선배 개발자에게 물어보세요 ^^;


음 여기서 여러분은 이런 생각을 꼭 하셨어야 합니다.  <servlet> 과 <servlet-mapping>을 왜 분리하였는가?  합쳐도 될 것 같지 않나요?  아래와 같이요.


<servlet>
    <servlet-class>com.heaven.spring.MemberServlet</servlet-class>
    <url-pattern>/Member</url-pattern>
</servlet>


정답은 역시 책에... 퍼~~억!!!  알았어요 알았어.. 알려드리면 되잖아요. 폭력적이시긴... 정답은 아래의 사각형 안에 있습니다.  제 강좌 보신 분들은 내용 보시는 법은 아시죠.. ^^


<servlet>
    <servlet-name>MemberServlet</servlet-name>
    <servlet-class>com.heaven.spring.MemberServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>MemberServlet</servlet-name>
    <url-pattern>/Member</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>MemberServlet</servlet-name>
    <url-pattern>/회원</url-pattern>
</servlet-mapping>


딱 보시고 감이 안 오시면 조금 더 유심히 보세요(힌트:  일석이조, 1 타 쌍피!!! 1 타 7피!!!).


자 그럼 이런 Servlet 를 통해 웹 페이지를 개발하게 되면 문제가 뭘까요?  역시 고민 좀 해보시죠.  정답은 역시 숨겨져 있습니다.


스파케티 코드의 문제가 있습니다.  Java 코드 안에 HTML 태그가 들어가 있게 되는데 위의 예제는 짧으니까 그나마 스파케티 코드를 참아내며 개발할만 하지만 쓸만한 웹 페이지 하나를 out.println() 메소드 안에 인자로 구현하는 방식은 개발자들을 쉬 늙게 만드는 요인이 됩니다.


위에 숨겨진 답에 더해서 기존 Java 개발자도 Servlet 형태의 프로그램을 배우는데 어려운데, 웹 페이지를 제작하던 사람들은 Java 프로그래머가 주가 아니었고 정적 HTML 을 만들던 HTML 코더들이었습니다.  그 코더들에게 Servlet 프로그래밍을 가르치는 건 차량 구매자에게 차량 설계와 조립/정비, 운동 역학을 가르치는 것과 같은 당혹스러운 일이었습니다.   Java 중심의 HTML 웹 프로그래밍 (Servlet 안에 HTML 꾸겨넣었던) 개발의 시대가 가고, HTML 중심의 Java 웹 프로그래밍 (HTML 태그 사이에 Java 코드를 꾸겨넣는) 개발의 시대가 도래하게 되는데.. 두둥 바로 JSP 입니다.  Java Server Page 라고 공식적으로 소개되어 있습니다만 제가 현장에서 겪어본 웹 개발자들은 "저런 Si 8" 의 약자라고 하시는 분도 있습니다.  주의 깊게 읽으셔야합니다.  욕처럼 들릴 수 있습니다.  ^^  물론 ASP 에 대한 평가도 "에이 Si 8", PHP 는 "피나고 힘들고 피하고 싶은" 뭐 이런 우스개 소리가 있긴 합니다.


그럼 다음 강좌는 JSP 를 통해 위의 예제를 다시 작성해 보도록 하겠습니다.


그럼 모두 모두 저의 더위 사세요.  호산나... ^^/


STS 프로젝트 파일: ExpertSpringMVC001.zip


P.S 댓글 달리면 다음 강좌가 빨리 올라올껄요.  믿거나 말거나.. 쿨락

반응형