3.初始化映射关系
有了框架以后,所有请求都会交给框架,框架会根据映射关系调用controller的指定方法,前面我们说到映射关系可以使用xml配置,也可以使用注解配置,那么每次请求映射都需要读取一次配置信息吗?
答案显然是不!我们只需要在服务器启动的时候读取一次,并存入缓存即可。
* static{}
* servlet.init
配置信息来自两部分,①是配置文件,目前我们规定的只有mapping请求映射信息;
②是注解,详见下一文档
package web;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DispatcherServlet extends HttpServlet {
/*
缓存请求映射信息
key="/test1"
*/
Map<String,MappingInfo> infoMap=new HashMap<>();
/**
* 读取各种配置信息
* (目前只有请求映射信息)
*
* @throws ServletException
*/
@Override
public void init() throws ServletException {
//目前配置信息来自于两个部分,而且两个部分都可能存在
String xmlPath = super.getInitParameter("classpath");
if (xmlPath != null && !"".equals(xmlPath)) {
//指定了配置文件,需要读取配置文件
readXml(xmlPath);
}
String packagePath = super.getInitParameter("controller-scan");
if (packagePath != null && !"".equals(packagePath)) {
//指定了包路径,需要读取包下类中的注解信息
}
}
//读取xml配置文件
public void readXml(String path) {
//我们要的完整路径
String realPath = Thread.currentThread().getContextClassLoader().getResource(path).getPath();
try {
InputStream is = new FileInputStream(realPath);
//使用dom,sax读取xml内容
SAXReader reader=new SAXReader();
Document document=reader.read(is);
//解析mapping标签
parseMappingElement(document);
//解析其他标签
} catch (Exception e) {
e.printStackTrace();
}
}
//读取xml中<mapping>请求映射信息
private void parseMappingElement(Document document)throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException {
//按照标签的嵌套规则,找到需要的所有mapping标记
List<Element> mappingElements = document.selectNodes("mvc/mapping");
for (Element element : mappingElements) {
/**
* 获取标签指定的属性值,标签中记载着请求与响应对应关系
* 此时(初始化)获得这个对应关系是为了后面请求的时候用
* 所以需要存储起来
*/
String path = element.attributeValue("path");
String className = element.attributeValue("class");
String methodName = element.attributeValue("method");
//反射创建目标对象
Class clazz = Class.forName(className);
Object obj = clazz.newInstance();
//通过反射,根据方法名获取方法对象,方法可能存在重载,参数在<type></type>标签里面
List<Element> typeElements = element.selectNodes("type");
Class[] types = new Class[typeElements.size()];
int i=0;
for (Element typeEle : typeElements) {
String typeStr = typeEle.getText();
types[i++]=castStringToClass(typeStr);
}
Method method = clazz.getMethod(methodName, types);
MappingInfo info = new MappingInfo(path, obj, method);
System.out.println(method);
infoMap.put(path,info);
}
}
//将字符串表示的类型转换成对应的Class
private Class castStringToClass(String typeStr) throws ClassNotFoundException {
if("int".equals(typeStr)){
return int.class;
}
if("long".equals(typeStr)){
return long.class;
}
if("double".equals(typeStr)){
return double.class;
}
//除了8种基本类型(这里只列举了三种),其余引用类型写的都是全名,可以反射生成Class
return Class.forName(typeStr);
}
//读取注解
public void Annotation(String path) {
//我么要的完整路径
String realPath = Thread.currentThread().getContextClassLoader().getResource(path).getPath();
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//请求映射,根据请求调用controller的具体方法
//获得请求 /test1
//根据请求找到对应的mappinginfo 映射信息
//获得参数--》处理参数--》调用mappinginfo中的对象的方法,传递参数
}
}
package web;
import java.lang.reflect.Method;
/**
* 存储请求映射关系
*/
public class MappingInfo {
private String path;//例如 /test1 请求命令
private Object controller;//例如 TestController 目标对象
private Method method;//例如 t1 目标方法
public MappingInfo() {}
public MappingInfo(String path, Object controller, Method method) {
this.path = path;
this.controller = controller;
this.method = method;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Object getController() {
return controller;
}
public void setController(Object controller) {
this.controller = controller;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}