实现一个MVC框架
(1)java反射基础
(2)java注解
代码
package base.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
*Java注解默认只保留到源代码里面(即编译时,java注解会被抹掉。
*使用@Retention告诉编译器,编译时不抹掉该注解)
*/
@Retention(RetentionPolicy.RUNTIME)//该注解保留到运行时
public @interface RequestMapping {
public String value();
}
package base.common;
import java.lang.reflect.Method;
/**
* 为了方便利用java反射进行方法的调用,
* 将处理器实例和方法对象进行了封装。
*
*/
public class Handler {
private Method mh;
private Object obj;
public Handler(Method mh, Object obj) {
this.mh = mh;
this.obj = obj;
}
public Method getMh() {
return mh;
}
public void setMh(Method mh) {
this.mh = mh;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
package base.common;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import base.annotation.RequestMapping;
/**
* 映射处理器:
* 负责提供请求路径与处理器的对应关系
*
*/
public class HandlerMapping {
//存放请求路径与处理器的对应关系。
private Map<String,Handler> handlerMap =
new HashMap<String,Handler>();
/**
* 依据请求路径,返回Handler对象。
* 注:
* Handler对象包含了Method对象和处理器实例。
*/
public Handler getHandler(String path){
return handlerMap.get(path);
}
/**
* process方法遍历整个集合,将处理器实例
* 取出来,通过java反射技术读取@RequestMapping
* 注解中的路径信息,建立请求路径与处理器的
* 对应关系。
*/
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();
System.out.println("path:" + path);
//建立请求路径与处理器的对应关系
handlerMap.put(path,
new Handler(mh,bean));
}
}
System.out.println("handlerMap: "
+ handlerMap);
}
}
package base.web;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import base.common.Handler;
import base.common.HandlerMapping;
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
//HandlerMapping负责提供请求路径与处理器的对应关系
private HandlerMapping handlerMapping;
@Override
/**
* 读取配置文件(smartmvc.xml)中的处理器的
* 配置信息,然后将处理器实例化并存放到一个
* 集合里面。接下来,将这个集合交给
* HandlerMapping来处理。
* 注:
* HandlerMapping处理流程:
* (通过java反射读取处理器中的
* @RequestMapping注解信息,建立请求路径与处理器
* 方法的对应关系,比如 "/hello.do"应该由
* HelloController的hello方法来处理)。
*
*/
public void init() throws ServletException {
/*
* 使用dom4j读取配置文件的内容
*/
SAXReader reader =
new SAXReader();
InputStream ins =
getClass().getClassLoader()
.getResourceAsStream(
"smartmvc.xml");
try {
//解析配置文件
Document doc = reader.read(ins);
//找到根节点
Element root = doc.getRootElement();
//找到根节点下面的所有的子节点
List<Element> eles = root.elements();
//遍历所有子节点
List beans = new ArrayList();
for(Element ele : eles){
//读取class属性值
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);
}
}
protected void service(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException,
IOException {
//获得请求资源路径
String uri = request.getRequestURI();
//获得应用名
String contextPath =
request.getContextPath();
//截取请求资源路径的一部分
String path =
uri.substring(
contextPath.length());
System.out.println("path:" + path);
//依据请求路径(path)找到对应的处理器来处理
Handler handler =
handlerMapping.getHandler(path);
System.out.println("handler:"
+ handler);
//获得要调用的Method对象
Method mh = handler.getMh();
//获得处理器实例
Object bean = handler.getObj();
//returnVal是方法的返回值
Object returnVal = null;
try {
//调用处理器的方法
returnVal = mh.invoke(bean);
System.out.println("returnVal:"
+ returnVal);
//将视图名转换成对应的jsp
String jspPath =
"/WEB-INF/" + returnVal
+ ".jsp";
//转发
request.getRequestDispatcher(
jspPath).forward(
request, response);
} catch (Exception e) {
e.printStackTrace();
throw new ServletException(e);
}
}
}
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_2_5.xsd" version="2.5">
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>base.web.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
jsp
<%@ page contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body style="font-size:30px;">
Hello,SmartMVC!
</body>
</html>
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!--
配置处理器
-->
<bean class="demo.HelloController"/>
</beans>
处理器
package demo;
import base.annotation.RequestMapping;
/**
* 处理器:
* 用于处理业务逻辑。
*/
public class HelloController {
@RequestMapping("/hello.do")
public String hello(){
System.out.println("处理hello.do请求");
//返回视图名
return "hello";
}
}