1. 程式人生 > >JAVAWEB學習(12) - 實現一個簡單的MVC框架

JAVAWEB學習(12) - 實現一個簡單的MVC框架

實現一個簡單的MVC框架

1. 目標

SmartMVC核心是一個通用的控制器(DispatcherServlet)。利用SmartMVC,我們在開發一個web應用時,只需要新增相應的配置,通過該控制器就可以呼叫相應的模型或者檢視。也就是說,只需要寫模型和檢視,不再需要寫控制器了。

2. 架構

smartmvc

3. 開發步驟

1. 建立一個Maven工程(smartmvc)

專案結構如下:

目錄

2. 導包

<dependencies>
	<dependency>
		<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> </dependencies>

3. 新增一個JSP(/WEB-INF/hello.jsp)

<%@ page pageEncoding="utf-8" 
contentType="text/html; charset=utf-8" %>
<html>
	<head></head>
	<body style="font-size:30px;">
		Hello SmartMVC!
	</body>
</html>

4. 在base.annotation包下新增一個java註解(@RequestMapping)

@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
	public String value();
}

5. 在demo包下新增HelloController類(處理器)

//該類方法前新增@RequestMapping註解(指定請求路徑)
//方法返回值是一個字串(即檢視名)
public class HelloController {

@RequestMapping("/hello.do")
public
String hello(){ System.out.println("HelloController的hello方法"); return "hello"; } }

6. 在resources資料夾下新增smart-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<!-- 配置處理器:
			class屬性用於指定處理器類名。
	 -->
	<bean class="demo.HelloController"/>
	<bean class="demo.LoginController"/>
</beans>

7. 在base.web包下新增DispatcherServlet

/**
在初始化方法裡,讀取配置檔案中的處理器類名,將處理器例項化,
然後將處理器例項交給HandlerMapping來處理。
*/
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

private HandlerMapping handlerMapping;

@Override
/**
 * 讀取配置檔案(smartmvc.xml)的內容,將所有
 * 處理器例項化,然後將這些處理器例項交給
 * HandlerMapping來處理。
 * 注:
 * 	  HandlerMapping負責建立請求路徑與處理器的
 * 對應關係。
 */
public void init() throws ServletException {
	//讀取配置檔案位置及檔名
	String configLocation = getServletConfig().getInitParameter("configLocation");
	
	SAXReader sax = new SAXReader();
	
	InputStream in = getClass().getClassLoader().getResourceAsStream(configLocation);
	
	try {
		/*
		 * 利用dom4j讀取配置檔案的內容,
		 * SAXReader的read方法的返回值可以
		 * 想像一棵樹,我們可以從根節點開始,
		 * 一層一層遍歷。
		 */
		Document doc = sax.read(in);
		//找到根節點
		Element root = doc.getRootElement();
		//找出根節點的所有子節點
		List<Element> elements = root.elements();
		List beans = new ArrayList();
		//遍歷子節點,讀取處理器類名
		for(Element ele : elements){
			String className = ele.attributeValue("class");
			System.out.println("className:" + className);
			//將處理器例項化
			Object bean = Class.forName(className).newInstance();
			beans.add(bean);
		}
		System.out.println("beans:" + beans);
		
		//將處理器例項交給HandlerMapping來處理
		handlerMapping  = new HandlerMapping();
		handlerMapping.process(beans);
		
	} catch (Exception e) {
		e.printStackTrace();
		throw new ServletException(e);
	}
}

8. 配置web.xml檔案

<servlet>
	<servlet-name>DispatcherServlet</servlet-name>
	<servlet-class>base.web.DispatcherServlet</servlet-class>
	<!--
		指定配置檔案的位置及檔名 
 	-->
	<init-param>
		<param-name>configLocation</param-name>
		<param-value>smart-mvc.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>DispatcherServlet</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

9. 在base.common包下新增Handler類

public class Handler {
	private Method method;
	private Object obj;
	
	public Handler(Method method, Object obj) {
		this.method = method;
		this.obj = obj;
	}
	
	public Method getMethod() {
		return method;
	}
	public void setMethod(Method method) {
		this.method = method;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
}

10. 在base.common包下新增HandlerMapping類(對映處理器)

public class HandlerMapping {

//mappings用於存放請求路徑與處理器的對應關係
private Map<String,Handler> mappings = 
		new HashMap<String,Handler>();

/**
 * 依據請求路徑返回Handler物件。
 * 注:
 *   Handler物件封裝了處理器物件及方法物件,
 *  方便利用java反射來呼叫處理器的方法。
 */
public Handler getHandler(String path){
	return mappings.get(path);
}

public void process(List beans) {
	for(Object bean: beans){
		//獲得Class物件
		Class clazz = bean.getClass();
		//獲得所有方法
		Method[] methods = clazz.getDeclaredMethods();
		//遍歷所有方法
		for(Method mh : methods){
			//獲得@RequestMapping註解
			RequestMapping rm = mh.getDeclaredAnnotation(RequestMapping.class);
			//獲得請求路徑
			String path = rm.value();
			//存放請求路徑與處理器的對應關係
			mappings.put(path, new Handler(mh,bean));
		}
		
	}
	System.out.println("mappings:" + mappings);
	}
}

至此,一個簡單的MVC框架就設計完成了,最後附上設計圖:

s1