web封装, mvc封装

封装请求- 响应过程中的一些常用功能。

  • 在没有web框架前
  • 每次浏览器请求->服务器->参考web.xml找到与之匹配的servlet(controller)->调用service方法
  • 这就使得n次不同的请求,需要调用n个不同的servlet,不方便维护管理
  • 每次请求在servlet中都会有一些公共的操作
    • 接收参数 : 普通参数,文件参数,单个参数,多个重复参数
    • 类型处理 : 数字类型转换
    • 数组组装 : 将参数组装对象
  • 不同的请求具体的业务不同。
  • 业务处理完成后,需要给与响应
    • 直接响应
    • 间接响应
      • 转发(携带数据)
      • 重定向

综上分析,我们对请求响应中的一些功能实现封装

封装后的效果包括以下特点:

多个请求,不再对应多个controller的方法,可以对应一个controller的多个方法。

  1. - 思考: 如何处理这个映射,让框架实现请求与controller之间的匹配。

由框架负责接收参数

  1. - 思考: 如何让框架知道需要获得哪个名字的参数呢
  2. - 思考: 如果传递的是文件参数,框架由如何处理

由框架负责处理参数类型

  1. - 思考: 如何让框架知道需要将参数转换成哪种类型
  2. - 思考: 万一要转换的类型框架不会怎么办

由框架负责将参数组成对象

  1. - 思考: 如何让框架知道需要将参数组成什么类型的对象 (反射)

由框架负责响应

  1. - 思考: 如何让框架知道用哪种方式响应
  2. - 思考: 如何让框架知道响应什么

由框架实现AOP

  1. - 功能管理
  2. - 不同用户会显示不同菜单
  3. - 不同用户会显示不同按钮
  4. - 设置功能表<br />fid , fname , ftype , fhref , fauth.
  5. - 思考: 如何告诉框架增加了哪些自定义的切面功能
  6. - 思考: 如何告诉框架新增加的切面都对哪些请求生效
  7. - 思考: 框架如何实现AOP
  8. - 反射
  9. - 注解
  10. - 动态代理
  11. - 基于接口 Proxy
  12. - 基于父类 cglib
  13. - 使用注解和xml实现配置
  14. - 复习: sax解析xml

==============================================================

  • 原来浏览器发送请求到服务器
  • 服务器接收请求
  • 参考web.xml 或 @WebServlet 找到请求与controller之间的映射关系
  • 现在浏览器发送请求到服务器
  • 服务器接收请求
  • 将请求交给web框架
  • 框架根据一些请求映射关系,找到与之匹配的controller实现映调用。
  • 正因为服务器现在将请求交给了web框架
  • 所以才能在框架中完成一些常用功能的封装
    1. 多个请求,可以访问同一个controller对象的不同方法 (请求映射)。
    2. 框架负责接收参数(普通参数,文件参数)
    3. 框架负责传递参数 (类型转换)
      【具体业务实现 - 业务程序实现】
    4. 框架负责响应
      • 直接响应
      • 间接响应
        • 转发(携带数据)
        • 重定向

——————————编码实现——————————

DispatcherServlet

  • 按照上面的分析
  • 有了web框架以后
  • 浏览器给服务器的请求,服务器会交给框架
  • 反之也就是说框架可以接收服务器的请求
  • 从语法而言,可以接收服务器请求的组件:Servlet , Filter
  • 所以框架需要一个请求入口

请求映射的配置

  • 现在请求都交给了框架
  • 所以需要框架实现请求映射
  • 哪个请求对应哪个controller的方法需要业务程序员按照框架的要求配置
  • 暂时有2种规范

    第1种,在xml文件中配置映射关系

    1. - web.xml中配置DispatcherServlet
    2. - 通过设置servlet的参数指定框架的配置文件名称(默认要求配置文件必须放在src目录下)<br />mvc<br />org.duyi.web7.DispatcherServlet<br />classpath <br />mvc.xml
    3. - 认为规定xml中的映射关系配置如下:<br />
    1. <mapping path="/test11" class="com.controller.TestController" method="t1">
    2. <type>int</type>
    3. </mapping>
    4. <mapping path="/test2" class="com.controller.TestController" method="t2">
    5. <type>java.lang.String</type>
    6. <type>com.domain.Car</type>
    7. </mapping>
    8. <mapping path="/test3" class="com.controller.TestController" method="t3" ></mapping>

第2种,在注解中配置映射关系

  1. - 框架自定义[@RequestMapping ](/RequestMapping )
  2. - 该注解作用controller的方法上,表示请求与方法的映射关系<br />@RequestMapping("/test2")<br />public void t2(String s , Car car){}
  3. - 之前可以从xml文件中获得请求映射关系
  4. - 现在需要从注解中获得映射关系
  5. - 要想找到注解,就需要找到方法,需要找到controller
  6. - 为了更方便的找到controller
  7. 1. web.xml文件中,指定寻找controller的基本包位置<br />controller-scan<br />com.controller,com.controller2
  8. 1. 框架自定义[@Controller ](/Controller ) <br />该注解作用在controller类上<br />具有该注解的controller类,才会通过反射寻找RequestMapping

初始化映射关系

  • 有了框架以后
  • 所有请求就会交给框架
  • 框架会根据映射关系,最终调用controller的指定方法
  • 映射关系可以使用xml配置,也可以使用注解配置
  • 每次请求映射时都需要读取一次配置信息么?
    • 当然不需要
    • 只需在服务器启动时读取一次,并存储缓存即可
      • static{}
      • servlet.init
  • 配置信息来自于2部分
    1. 配置文件
      • 目前只有mapping请求映射信息
    2. 注解

================================================================

  1. 初始化映射关系
    • 有了框架以后
    • 所有请求就会交给框架
    • 框架会根据映射关系,最终调用controller的指定方法
    • 映射关系可以使用xml配置,也可以使用注解配置
    • 每次请求映射时都需要读取一次配置信息么?
      • 当然不需要
      • 只需在服务器启动时读取一次,并存储缓存即可
        • static{}
        • servlet.init
    • 配置信息来自于2部分
      1. 配置文件
        • 目前只有mapping请求映射信息
      2. 注解
        • 根据web.xml配置的包路径 com.controller
        • 获得对应的文件夹相对路径 com/controller
        • 配合Thread.currentThread()…. 获得文件夹的绝对路径
        • 创建File对象表示文件夹dir
        • 获得文件夹中所有子内容名字(包括class文件名字)
        • 获得类名(去掉.class后缀)
        • 重新包装成完成的类路径 com.controller.TestController
        • 反射获得类注解
        • 反射获得类方法
        • 反射获得方法注解
        • 获得请求映射的信息:
          @RequestMapping(“/test”) -> path
          反射创建controller对象
          Method
  2. 映射请求
    • 根据浏览器发送的请求,找到与之匹配的请求映射信息MappingInfo(目标对象,目标方法)
    • 浏览器请求至服务器,服务器参考web.xml,将请求交给框架,调用框架的service方法
    • 获得此次请求
      String uri = req.getRequestURI() ;// /web-demo/test1
      String root = req.getContextPath() ;// /web-demo
      String path = uri.replace(root,””); // /test1
    • 根据请求找到与之匹配的映射关系
      • 如果没有找到映射关系
        • 表示不是一个操作资源
        • 有可能是一个文件资源
        • 使用io流读取文件并响应给浏览器
        • 注意:找到资源文件的服务器路径
          //path =”F:\dmc\idea_workspace\web-demo\out\artifacts\web_demo_war_exploded\index.html”
          String fpath = req.getServletContext().getRealPath(path);
      • 如果找到映射关系(待续。。)
        • 获取参数
        • 处理参数
        • 调用目标对象的方法,传递参数,完成请求映射过程。

==============================================================

  1. 映射请求-映射动态资源-获取参数

    • 按照我们之前所学
    • 浏览器传递的参数主要包括两类
      1. 普通的请求传参
        • 只传字符串
        • 使用req.getParameter()
      2. 文件上传时的传参
        • 传递2种参数: 普通参数(字符串),文件参数
        • fileupload文件上传组件接收参数
    • 浏览器传递的参数有可能存在同名的情况
      url?hobby=zq&hobby=lq&hobby=pq
      req.getParameter(“hobby”) —> zq
      req.getParameterValues(“hobby”) ->[zq,lq,pq]
      • 文件上传时,也可能传递多个同名的参数
  2. 映射请求-映射动态资源-参数处理

    • 框架获得参数后
    • 需要按照请求映射关系,调用controller方法,同时为其传递参数
    • 反之,在controller的方法,如果需要用哪些请求的参数
      • 以前需要使用request方法获得
      • 现在只需要在controller方法中定义方法参数列表
      • 告诉看框架,需要哪些参数
        原来需要 uname和upass
        req.getParameter(“uname”);
        req.getParameter(“upass”);

现在
public void t2(String uname , String upass){}

  1. - 为什么写了t2方法,框架可以为其传递参数了
  2. - 首先在读取映射关系时,调用的方法对象会存入MappingInfo
  3. - 我们就可以根据请求获得info对象,从而获得要调用的method对象
  4. - 获得method对象后,可以通过反射获得参数列表
  5. - 参数的个数
  6. - 参数类型
  7. - 不能获得参数的名字,而框架需要通过名字key获得对应参数
  8. - 由框架提供一个@RequestParam,作用在controller方法的参数上,指定其对应请求参数的名字<br />public void t2(@RequestParam("uname")String a , @RequestParam("upass")String b){}<br />告诉框架,需要获得unameupass两个参数
  9. - 注意: 有时,业务程序要让框架,将传递的多个参数组成对象<br />public void t3(Car car){}
  10. - 不需要使用@RequestParam注解
  11. - 告诉框架,将传递的参数组成Car对象
  12. - 看框架会根据Car的属性名找到与之匹配的参数,组装成对象。
  13. - 注意: 还有一种特殊情况,不需要请求传递参数,但需要requestresponsesession的对象<br />框架也会以方法传参的形式将上述对象传给controller方法。

==============================================================

  1. 映射请求-映射动态资源-参数处理

    • 服务器接收参数后
    • 需要按照映射关系调用controller的方法,同时将获取的请求参数,以方法参数的形式传递
    • controller方法在接收参数时,希望框架可以按需求实现类型转换
    • 框架在接收参数,传递参数中,还需按照controller的需求要处理参数
      controller方法的参数列表
      public void t1(String bname,@RequestParam(“num”)int num , int[] nums , HttpServletRequest req , Car car,MuliptartFile excel)
  2. 响应

    • 框架参数处理完毕后,就可以根据映射关系调用controller方法,传参
    • controller中获得参数后的业务处理,就有具体的业务程序完成(controller,service,dao)
    • 业务程序处理完毕后,需要响应

      • 直接响应
        • 直接响应文本字符串
        • 直接响应集合对象(需要转换成json格式的字符串再响应)
      • 间接响应
        • 转发 (携带数据)
        • 重定向 (携带数据)
    • 原来响应直接在业务程序中完成

    • 现在响应由框架完成
    • 框架实现哪种响应,需要由业务程序告知
    • 业务程序如何告知框架,需要按照框架的规则告知
      1. 响应内容以返回值的形式返回给框架
      2. 如果是间接响应,直接返回值
        • 如果不需要携带数据
          return “05.jsp” 转发
          return “redirect:05.jsp” 重定向
        • 如果需要携带数据
          • 返回一个框架提供ModelAndView对象
          • 转发: 数据会request.setAttribute()
          • 重定向:数据会以?的形式跟在url的后面 (只支持String)
      3. 如果是直接响应,在返回值同时,需要为方法增加一个@ResponseBody的注解
        • 如果返回String,int,double等简单类型,直接以String返回
        • 如果是其他类型,则认为需要转换成json