SpringMVC实现详解

ControllerServlet(Servlet)

创建一个servlet,没有注解,原因是要用户自定义url

  1. 第一步:接收到request的URI到beanNameurl进行查找(使用 url|类的限定名 的查找)
    注意:查找的时候要把url的前面的项目名称去掉,比如("/MyMVCFrameWork")

  2. 如果查到url

    1. 说明是beanNameMapping这种方式的handlemapping,然后就获得字节码对象,创建对象,
    2. 判断是否实现了controller接口,如果没有就抛错

      注意:controller接口定义了doGet(HttpServletRequest request,HttpServletResponse response)和doPost(HttpServletRequest request,HttpServletResponse response);

    3. 判断request.getMethod()是get还是post,创建接口引用调用doget和dopost方法,

      问题:实现controller接口的意义,为什么第二种不需要实现

      答:因为要创建接口调doget和dopost,不能做别的方法,如果没实现直接抛错了,做不了

  3. 如果没查到,说明是第二种annotationMethodMapping这种handlemapping

    1. 用第二种方式查找url(url在method里头) 没查到报错404
    2. 创建字节码对象,反射object对象,创建参数类型数组(大小等于参数数量)
    3. 拿到方法数组和方法名数组(paraclass构成是"方法名#方法的类型全限定名")
    4. 通过方法名和参数类型拿到方法getDeclaredMethod()(反射机制)

      调用此方法的时候,方法名要传,参数类型传的时候可以直接写数组{“String.class”,“Integer.class”}也可以分开写,因为是可变参方法 “…types”

    5. 拿到参数的value数组,用类型和方法(包括request, response, paramTypes, paramNames) <==> 拿到调用方法所需的参数值数组
    6. 调用方法,有可能有的方法不需要传参,所以两种方案
      1. result=method.invoke(object, null);
      2. result=method.invoke(object, values);
    7. 判断是action属性是json还是jsp
      1. 如果是json,调用JSONObject.fromObject(result);
      2. 如果报异常,调用JSONArray.fromObject(result);
      3. 写到out.write里
      4. 如果是jsp或者其他比如String,相应解析

HandleMapping(final class)---->解析xml(剥洋葱…)

  1. 得到xml文件路径()
    //得到绝对路径--前面有file:/六个字符,要去掉
    String path=HandleMapping.class.getClassLoader().getResource("").toString().substring(6);
    SAXBuilder builder = new SAXBuilder();  
    Document doc = builder.build(new File(path+"config/urlmappings.xml"));//写死的这里
    
  2. 得到根节点----调用doc.getRootElement()方法
  3. 拿到根节点的所有孩子节点 <==> beans–>bean
  4. 所有的孩子(一个孩子就是表里一行数据)循环提取内容
  5. 先按照beanNameMapping HashMap<String,String>解析,如果’url’拿不到(getattribute(‘url’)==null就滚到第6点
    1. beanNameMapping这种表–>存着url 和 类的全限定名
    2. 拿到’url’的value值和’class’的value值,调用put方法,加到当前hashmap里面
  6. 按照annotationMethodMapping HashMap<String,MethodInfo>解析
    1. 这种表是 url | 类的全限定名(class) | 方法名 这种格式
    2. 拿到类的全限定名,即className('class’的value)<==>class

      由于这种类型的url不在bean下,而在method下,所以这一步只能拿到类的全限定名(如com.yanqi.Demo)

    3. 创建list拿到所有孩子(方法)节点 <==> bean–>method
    4. 循环解析: 首先拿到’url’, ‘name’, ‘action’

      因为该表的类型是跟着方法的url走的,每个方法都有不同的url

    5. 拿到所有的孩子节点(参数) <==> method–>param
    6. 建一个数组,循环把参数名(‘name’)和参数类型(如’java.lang.String’)添加进去用’#'隔开
    7. 创建方法对象(methodInfo),把’url’,‘className’,‘methodName’,‘paramsList’,'action’都set进去
    8. 调用按照annotationMethodMapping.put(key,value)加到当前hashmap里面

MethodInfo

  • 方法对象,用于第二种handlemapping的value值
  • 参数: url(调用servlet的时候), methodName(方法名), action(返回方式json解析还是jsp或者基本类型), className(类的全限定名), []params(参数数组)

MyController

  • 接口类,实现doGet(HttpServletRequest request,HttpServletResponse response)和doPost(HttpServletRequest request,HttpServletResponse response)
  • 意义:为了让第一种handlemapping使用的时候必须调doget()或者dopost(), 如果没有实现该接口,就不能使用调servlet()–这里直接抛错

MyMvcException extends Exception

  • 自定义异常类,设置打印异常信息
  • 这里主要用于ControllerServlet里验证第一种handlemapping的反射找对象之后验证该类是否实现了controller接口

RequestDataHandler

方法类,提供三个方法供ControllerServlet调用

  1. Object[] handlerRequest(HttpServletRequest request,HttpServletResponse response,Class paramTypes[] ,String[] paramNames) 把参数合起来转化为对象数组以供controller反射去调用方法
    • 创建对象数组,长度为参数数组长度
    • 调用checkInterface方法,判断是哪种类型的参数,比如request就是用request.getclass().getinterfaces()去调用checkInterface去判断,和response都要用实现接口去判断,session用request.getsession().getclass()

      问题:为啥request这些要用接口判断

      答:因为本来就是HttpRequest和response就是接口

      • 如果是普通类型,就直接判断type[ i]==String.class类似这样就可以了
      • 如果是对象,调用toObject方法转为对象
  2. checkInterface(Class clz, Class interfaces[]) 判断是不是实现clz有没有实现接口,如果实现返回true
  3. Object toObject(Class clz, HttpServletRequest request) 转对象的,通过反射创建对象,打开权限set属性之后返回对象

    但是要注意,这里是拿到所有request.getParameterNames();的参数名来赋值,所以参数名和请求报文里的变量名要一样才能实现成功赋值


两种handlemapping的结构图表

  • 第一种handlemapping–beanNameMapping

    URL类的全限定名
    test.docom.yanqi.Demo
    test2.docom.yanqi.Demo
    test3.docom.yanqi.Demo
  • 第二种handlemapping–annotationMethodMapping

    URL类的全限定名方法名
    test.docom.yanqi.Demotest()
    test2.docom.yanqi.Demotest2()
    test3.docom.yanqi.Demotest3()

两种handlemapping对应的xml配置

  • 第一种handlemapping–beanNameMapping

    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
        <bean url="test1.do" class="my.com.Test"></bean>
        <bean url="test2.do" class="my.com.Demo"></bean>
    </beans>
    
  • 第二种handlemapping–annotationMethodMapping

    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
    	<beann class="my.com.Login">
    		<method url="login.do" name="login">
    			<param name="sno">java.lang.String</param>
    			<param name="owd">java.lang.String</param>
    		</method>
    		
    		<method url="reg.do" name="reg">
    			<param name="sno">java.lang.String</param>
    			<param name="pwd">java.lang.String</param>
    			<param name="sname">java.lang.String</param>
    		</method>
    	</beann>
    </beans>
    
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值