3.初始化映射关系
    有了框架以后,所有请求都会交给框架,框架会根据映射关系调用controller的指定方法,前面我们说到映射关系可以使用xml配置,也可以使用注解配置,那么每次请求映射都需要读取一次配置信息吗?
    答案显然是不!我们只需要在服务器启动的时候读取一次,并存入缓存即可。
    * static{}
    * servlet.init
    配置信息来自两部分,①是配置文件,目前我们规定的只有mapping请求映射信息;
    ②是注解,详见下一文档
    image.png

    1. package web;
    2. import org.dom4j.Document;
    3. import org.dom4j.Element;
    4. import org.dom4j.io.SAXReader;
    5. import javax.servlet.ServletException;
    6. import javax.servlet.http.HttpServlet;
    7. import javax.servlet.http.HttpServletRequest;
    8. import javax.servlet.http.HttpServletResponse;
    9. import java.io.FileInputStream;
    10. import java.io.IOException;
    11. import java.io.InputStream;
    12. import java.lang.reflect.Method;
    13. import java.util.HashMap;
    14. import java.util.List;
    15. import java.util.Map;
    16. public class DispatcherServlet extends HttpServlet {
    17. /*
    18. 缓存请求映射信息
    19. key="/test1"
    20. */
    21. Map<String,MappingInfo> infoMap=new HashMap<>();
    22. /**
    23. * 读取各种配置信息
    24. * (目前只有请求映射信息)
    25. *
    26. * @throws ServletException
    27. */
    28. @Override
    29. public void init() throws ServletException {
    30. //目前配置信息来自于两个部分,而且两个部分都可能存在
    31. String xmlPath = super.getInitParameter("classpath");
    32. if (xmlPath != null && !"".equals(xmlPath)) {
    33. //指定了配置文件,需要读取配置文件
    34. readXml(xmlPath);
    35. }
    36. String packagePath = super.getInitParameter("controller-scan");
    37. if (packagePath != null && !"".equals(packagePath)) {
    38. //指定了包路径,需要读取包下类中的注解信息
    39. }
    40. }
    41. //读取xml配置文件
    42. public void readXml(String path) {
    43. //我们要的完整路径
    44. String realPath = Thread.currentThread().getContextClassLoader().getResource(path).getPath();
    45. try {
    46. InputStream is = new FileInputStream(realPath);
    47. //使用dom,sax读取xml内容
    48. SAXReader reader=new SAXReader();
    49. Document document=reader.read(is);
    50. //解析mapping标签
    51. parseMappingElement(document);
    52. //解析其他标签
    53. } catch (Exception e) {
    54. e.printStackTrace();
    55. }
    56. }
    57. //读取xml中<mapping>请求映射信息
    58. private void parseMappingElement(Document document)throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException {
    59. //按照标签的嵌套规则,找到需要的所有mapping标记
    60. List<Element> mappingElements = document.selectNodes("mvc/mapping");
    61. for (Element element : mappingElements) {
    62. /**
    63. * 获取标签指定的属性值,标签中记载着请求与响应对应关系
    64. * 此时(初始化)获得这个对应关系是为了后面请求的时候用
    65. * 所以需要存储起来
    66. */
    67. String path = element.attributeValue("path");
    68. String className = element.attributeValue("class");
    69. String methodName = element.attributeValue("method");
    70. //反射创建目标对象
    71. Class clazz = Class.forName(className);
    72. Object obj = clazz.newInstance();
    73. //通过反射,根据方法名获取方法对象,方法可能存在重载,参数在<type></type>标签里面
    74. List<Element> typeElements = element.selectNodes("type");
    75. Class[] types = new Class[typeElements.size()];
    76. int i=0;
    77. for (Element typeEle : typeElements) {
    78. String typeStr = typeEle.getText();
    79. types[i++]=castStringToClass(typeStr);
    80. }
    81. Method method = clazz.getMethod(methodName, types);
    82. MappingInfo info = new MappingInfo(path, obj, method);
    83. System.out.println(method);
    84. infoMap.put(path,info);
    85. }
    86. }
    87. //将字符串表示的类型转换成对应的Class
    88. private Class castStringToClass(String typeStr) throws ClassNotFoundException {
    89. if("int".equals(typeStr)){
    90. return int.class;
    91. }
    92. if("long".equals(typeStr)){
    93. return long.class;
    94. }
    95. if("double".equals(typeStr)){
    96. return double.class;
    97. }
    98. //除了8种基本类型(这里只列举了三种),其余引用类型写的都是全名,可以反射生成Class
    99. return Class.forName(typeStr);
    100. }
    101. //读取注解
    102. public void Annotation(String path) {
    103. //我么要的完整路径
    104. String realPath = Thread.currentThread().getContextClassLoader().getResource(path).getPath();
    105. }
    106. @Override
    107. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    108. //请求映射,根据请求调用controller的具体方法
    109. //获得请求 /test1
    110. //根据请求找到对应的mappinginfo 映射信息
    111. //获得参数--》处理参数--》调用mappinginfo中的对象的方法,传递参数
    112. }
    113. }
    1. package web;
    2. import java.lang.reflect.Method;
    3. /**
    4. * 存储请求映射关系
    5. */
    6. public class MappingInfo {
    7. private String path;//例如 /test1 请求命令
    8. private Object controller;//例如 TestController 目标对象
    9. private Method method;//例如 t1 目标方法
    10. public MappingInfo() {}
    11. public MappingInfo(String path, Object controller, Method method) {
    12. this.path = path;
    13. this.controller = controller;
    14. this.method = method;
    15. }
    16. public String getPath() {
    17. return path;
    18. }
    19. public void setPath(String path) {
    20. this.path = path;
    21. }
    22. public Object getController() {
    23. return controller;
    24. }
    25. public void setController(Object controller) {
    26. this.controller = controller;
    27. }
    28. public Method getMethod() {
    29. return method;
    30. }
    31. public void setMethod(Method method) {
    32. this.method = method;
    33. }
    34. }