본문 바로가기

programming/Gukbi

국비 교육 65일차 - mvc구조, controller 만들기, xml parsing

728x90
반응형

어제에 이어서 mvc 구조를 제대로 파헤져보는 시간이었다. 어제 한 controller는 controller 내부에서 직접 자바 코딩을 했었는데, 오늘은 xml 파일에서 구조를 만든 뒤에, 그걸 파싱해와서 사용하는 코드를 만들어봤다. 

 

일단 톰캣의 web.xml 파일은 아래와 같이 만들어 줬다. 

 

<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>JSPMiddleProject3</display-name>
  <servlet>
  	<servlet-name>mvc</servlet-name>
  	<servlet-class>com.sist.controller.DispatcherServlet</servlet-class>
  	<init-param>
  	 <param-name>contextConfigLocation</param-name>
  	 <param-value>C:\webDev\webStudy\JSPMiddleProject3\WebContent\WEB-INF\applicationContext.xml</param-value>
  	</init-param>
  </servlet>
  <servlet-mapping>
   <servlet-name>mvc</servlet-name>
   <url-pattern>*.do</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

 servlet-name을 mvc로 지정하고, servlet-class에 컨트롤러 경로를 지정한다. 

그리고 param에 contextConfigLocation이라고 이름을 준 뒤에, 사용할 xml 파일의 경로값을 준다. 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans><!-- 클래스를 등록하는 애플리케이션 -->
  <bean id="list"  class="com.sist.model.BoardListModel"/>
  <bean id="insert"  class="com.sist.model.BoardInsertModel"/>
  <bean id="insert_ok"  class="com.sist.model.BoardInsertOkModel"/>
  <bean id="detail"  class="com.sist.model.BoardDetailModel"/>
</beans>
<!-- xml은 문서형 데이터 베이스 -->

 그리고 applicationContext.xml에 위와 같이 태그를 만들어서 값을 지정해준다. 

id는 Controller의 Map에서 key값으로 등록하고, class는 메모리 할당을 위해 패키지명+클래스명까지 함께 등록해준다. 

 

 

package com.sist.controller;

import java.io.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import com.sist.model.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
// 생성자 : 메모리 할당, init():web.xml의 데이터 => service(): 사용자 요청 처리 => destroy(): 메모리해제
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private Map clsMap=new HashMap(); 
	
	public void init(ServletConfig config) throws ServletException {
		String path=config.getInitParameter("contextConfigLocation");
		//System.out.println(path);
		try
		{
			// XML을 읽어 온다
			DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); // newInstance() -> 싱글턴 패턴
			// Factory 패턴 => 한번만 생성 => 싱글턴 
			// HTML, XML, WML, VML, HDML 번역가능함 => 드라이버 매니저와 비슷함
			DocumentBuilder db=dbf.newDocumentBuilder(); //파싱기
			Document doc=db.parse(new File(path));
			// table 읽기
			Element beans=doc.getDocumentElement();
			//System.out.println("root:"+beans.getTagName());
			NodeList list=beans.getElementsByTagName("bean");
			for(int i=0; i<list.getLength(); i++)
			{
				Element bean=(Element)list.item(i);
				String id=bean.getAttribute("id");
				String cls=bean.getAttribute("class"); // 메모리할당 할때 항상 패키지명까지 같이 있어야 클래스를 읽어올 수 있음
				System.out.println("ID:"+id+",class:"+cls);
				
				Class clsName=Class.forName(cls); // 클래스 이름 읽기 => 전체 제어, 정보를 읽어 온 것
				// 메모리 할당을 클래스 이름으로 하는 것 (new를 쓰지않고 메모리 할당을 하지 않기 위해서)
				Object obj=clsName.getDeclaredConstructor().newInstance(); // new 해서 메모리 할당을 하는 것 
				// 클래스 이름으로 메모리 할당, 메소드호출이 가능, 변수값 설정, 생성자 제어 가능 
				// 리플렉션 
				System.out.println("id:"+id+",memory:"+obj);
				clsMap.put(id, obj);
			}
			
		} catch (Exception ex) {}
	}

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

}

 그리고 Controller에 해당하는 DispatcherSerlvet 파일에 해당하는 내용이다. 

일단 xml을 파싱해와야 하기 때문에 값을 넣어줄 Map을 하나 생성한다. 이름은 clsMap으로 생성을 해줬다. 

 

그리고 경로를 읽어올 변수가 하나 필요했기 때문에 

String path=config.getInitParameter("contextConfigLocation");

으로 경로값을 읽어서 path 변수에 저장을 하고 시작을 했다. 

 

path 값은 아래와 같이 저장된다. 

C:\webDev\webStudy\JSPMiddleProject3\WebContent\WEB-INF\applicationContext.xml

그럼 이제 만들어준 xml 파일을 읽어와서 newInstance()를 통해서 메모리를 새로 할당해준다. 

 

// XML을 읽어 온다
			DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); // newInstance() -> 싱글턴 패턴
			// Factory 패턴 => 한번만 생성 => 싱글턴 
			// HTML, XML, WML, VML, HDML 번역가능함 => 드라이버 매니저와 비슷함
			DocumentBuilder db=dbf.newDocumentBuilder(); //파싱기
			Document doc=db.parse(new File(path));
			// table 읽기
			Element beans=doc.getDocumentElement();
			//System.out.println("root:"+beans.getTagName());
			NodeList list=beans.getElementsByTagName("bean");

DocumentBuilderFactory를 이용해서 dbf라는 변수에 xml 메모리 할당을 해준다. (여러개가 저장되어 있기 때문에, 그 여러개를 다 저장해주기 위해서 Factory패턴을 써준다)

 

그러면 이제 파싱을해서 doc에 파일의 경로를 저장해준다. 

경로를 doc를 통해 저장해서 들어오면 getDocumentElement()를 통해 beans에 있는 Element들을 읽어 올 수 있다. 

이것을 다시 beans 아래에 있는 bean 태그 안에 있는 내용들을 list 안에 담아준 다음, 

 

for문을 사용해서 각각의 id에 해당하는 class명을 가져온다. 

for(int i=0; i<list.getLength(); i++)
			{
				Element bean=(Element)list.item(i);
				String id=bean.getAttribute("id");
				String cls=bean.getAttribute("class"); // 메모리할당 할때 항상 패키지명까지 같이 있어야 클래스를 읽어올 수 있음
				//System.out.println("ID:"+id+",class:"+cls);
				
				Class clsName=Class.forName(cls); // 클래스 이름 읽기 => 전체 제어, 정보를 읽어 온 것
				// 메모리 할당을 클래스 이름으로 하는 것 (new를 쓰지않고 메모리 할당을 하지 않기 위해서)
				Object obj=clsName.getDeclaredConstructor().newInstance(); // new 해서 메모리 할당을 하는 것 
				// 클래스 이름으로 메모리 할당, 메소드호출이 가능, 변수값 설정, 생성자 제어 가능 
				// 리플렉션 
				//System.out.println("id:"+id+",memory:"+obj);
				clsMap.put(id, obj);
			}

 list에 있는 i 번째의 item들을 받아서 bean에 저장후, id와 class값들을 각각 getAttribute로 받아온다. 

 

그리고 나서 Class clsName=Class.forName(cls)로 클래스의 이름을 읽어온다.

그러고 나서 받아온 클래스 이름으로 메모리 할당을 obj 변수에 받아온다. 

 

그렇게 메모리 할당을 해주고, clsMap에는 id와 새로 할당한 주소값을 넣어주고 for문을 마무리 한다. 

 

String cmd=request.getRequestURI();
		//System.out.println(cmd);
		cmd=cmd.substring(cmd.lastIndexOf("/")+1, cmd.lastIndexOf("."));
		Model model=(Model)clsMap.get(cmd);
		//System.out.println(model); null
		String jsp=model.execute(request);
		// 지정된 jsp에 request를 전송해라
		RequestDispatcher rd=request.getRequestDispatcher(jsp);
		rd.forward(request, response);

 

아래에서는 사용자가 보내준 uri 으로부터 값을 읽어와서 cmd라는 변수에 담아준다. 

/JSPMiddleProject3/insert.do

 위가 cmd에 변수에 담긴 값이다. 그러면 이것을 필요한 만큼 잘라와 주기 위해서 가장 마지막 /의 뒤부터, .까지 잘라온다. 

그게 위 에서는 insert에 해당한다. 

그러면 이 cmd를 맵에서 키로 넣어서 해당하는 model의 주소값을 저장해준다. 

com.sist.model.BoardInsertModel@271559c9

 그리고 나서 jsp라는 변수에 model에 request값을 넣어서 리턴값을 호출하여 가져온다. 

그 리턴값을 RequestDispatcher 라는 클래스의 변수로 넣어서 jsp에서 실행할 수 있도록 request,response를 매개변수로 넘겨주고 forward를 하면 controller의 역할이 마무리 된다. 

 

**RequestDispatcher라는 클래스는 현재 request에 담긴 정보를 저장하고 있다가, 그 다음페이지에도 해당 정보를 계속 저장하는 기능이다. 원래 request는 한번만 넘어가고 저장이 되지 않는다. 

 

즉 RequestDispatcher를 사용하면 파라미터 정보가 계속 유지될 수 있는 것이다. 

 

 

근데 이건 최종이 아니다.

 

 

정말 스프링에서 사용하는 구조를 이용하려면 따로 xml에 코딩을 하는게 아니라 어노테이션을 이용해서 하나의 클래스들에 있는 메소드들을 각각 호출해와야 하기 때문이다. 

 

일단 LastProject와 현재 위에서 코딩한 프로젝트의 차이점을 정리해보자면..

 

 

1. 하나의 클래스 - 여러개 메소드
2. 어노테이션 사용
3. applicationContext.xml 에서 패키지 명만 추가해온다. 
4. cmd 변수에 폴더명까지 함께 가져와서 저장

 일단 지금 기억나는건 이정도. 너무 길어질 것 같아서 그냥 같은 날이지만 다음 포스팅에서 어노테이션까지 활용하여 컨트롤러를 만드는 방법을 정리해서 올리도록 하겠다. 

728x90
반응형