web封装, mvc封装
封装请求- 响应过程中的一些常用功能。
- 在没有web框架前
- 每次浏览器请求->服务器->参考web.xml找到与之匹配的servlet(controller)->调用service方法
- 这就使得n次不同的请求,需要调用n个不同的servlet,不方便维护管理
- 每次请求在servlet中都会有一些公共的操作
- 接收参数 : 普通参数,文件参数,单个参数,多个重复参数
- 类型处理 : 数字类型转换
- 数组组装 : 将参数组装对象
- 不同的请求具体的业务不同。
- 业务处理完成后,需要给与响应
- 直接响应
- 间接响应
- 转发(携带数据)
- 重定向
综上分析,我们对请求响应中的一些功能实现封装
封装后的效果包括以下特点:
多个请求,不再对应多个controller的方法,可以对应一个controller的多个方法。
- 思考: 如何处理这个映射,让框架实现请求与controller之间的匹配。
由框架负责接收参数
- 思考: 如何让框架知道需要获得哪个名字的参数呢
- 思考: 如果传递的是文件参数,框架由如何处理
由框架负责处理参数类型
- 思考: 如何让框架知道需要将参数转换成哪种类型
- 思考: 万一要转换的类型框架不会怎么办
由框架负责将参数组成对象
- 思考: 如何让框架知道需要将参数组成什么类型的对象 (反射)
由框架负责响应
- 思考: 如何让框架知道用哪种方式响应
- 思考: 如何让框架知道响应什么
由框架实现AOP
- 功能管理
- 不同用户会显示不同菜单
- 不同用户会显示不同按钮
- 设置功能表<br />fid , fname , ftype , fhref , fauth.
- 思考: 如何告诉框架增加了哪些自定义的切面功能
- 思考: 如何告诉框架新增加的切面都对哪些请求生效
- 思考: 框架如何实现AOP
- 反射
- 注解
- 动态代理
- 基于接口 Proxy
- 基于父类 cglib
- 使用注解和xml实现配置
- 复习: sax解析xml
==============================================================
- 原来浏览器发送请求到服务器
- 服务器接收请求
- 参考web.xml 或 @WebServlet 找到请求与controller之间的映射关系
- 现在浏览器发送请求到服务器
- 服务器接收请求
- 将请求交给web框架
- 框架根据一些请求映射关系,找到与之匹配的controller实现映调用。
- 正因为服务器现在将请求交给了web框架
- 所以才能在框架中完成一些常用功能的封装
- 多个请求,可以访问同一个controller对象的不同方法 (请求映射)。
- 框架负责接收参数(普通参数,文件参数)
- 框架负责传递参数 (类型转换)
【具体业务实现 - 业务程序实现】 - 框架负责响应
- 直接响应
- 间接响应
- 转发(携带数据)
- 重定向
——————————编码实现——————————
DispatcherServlet
- 按照上面的分析
- 有了web框架以后
- 浏览器给服务器的请求,服务器会交给框架
- 反之也就是说框架可以接收服务器的请求
- 从语法而言,可以接收服务器请求的组件:Servlet , Filter
- 所以框架需要一个请求入口
请求映射的配置
- 现在请求都交给了框架
- 所以需要框架实现请求映射
- 哪个请求对应哪个controller的方法需要业务程序员按照框架的要求配置
-
第1种,在xml文件中配置映射关系
- 在web.xml中配置DispatcherServlet时
- 通过设置servlet的参数指定框架的配置文件名称(默认要求配置文件必须放在src目录下)<br />mvc<br />org.duyi.web7.DispatcherServlet<br />classpath <br />mvc.xml
- 认为规定xml中的映射关系配置如下:<br />
<mapping path="/test11" class="com.controller.TestController" method="t1">
<type>int</type>
</mapping>
<mapping path="/test2" class="com.controller.TestController" method="t2">
<type>java.lang.String</type>
<type>com.domain.Car</type>
</mapping>
<mapping path="/test3" class="com.controller.TestController" method="t3" ></mapping>
第2种,在注解中配置映射关系
- 框架自定义[@RequestMapping ](/RequestMapping )
- 该注解作用controller的方法上,表示请求与方法的映射关系<br />@RequestMapping("/test2")<br />public void t2(String s , Car car){}
- 之前可以从xml文件中获得请求映射关系
- 现在需要从注解中获得映射关系
- 要想找到注解,就需要找到方法,需要找到controller类
- 为了更方便的找到controller类
1. 在web.xml文件中,指定寻找controller的基本包位置<br />controller-scan<br />com.controller,com.controller2
1. 框架自定义[@Controller ](/Controller ) <br />该注解作用在controller类上<br />具有该注解的controller类,才会通过反射寻找RequestMapping
初始化映射关系
- 有了框架以后
- 所有请求就会交给框架
- 框架会根据映射关系,最终调用controller的指定方法
- 映射关系可以使用xml配置,也可以使用注解配置
- 每次请求映射时都需要读取一次配置信息么?
- 当然不需要
- 只需在服务器启动时读取一次,并存储缓存即可
- static{}
- servlet.init
- 配置信息来自于2部分
- 配置文件
- 目前只有mapping请求映射信息
- 注解
- 配置文件
================================================================
- 初始化映射关系
- 有了框架以后
- 所有请求就会交给框架
- 框架会根据映射关系,最终调用controller的指定方法
- 映射关系可以使用xml配置,也可以使用注解配置
- 每次请求映射时都需要读取一次配置信息么?
- 当然不需要
- 只需在服务器启动时读取一次,并存储缓存即可
- static{}
- servlet.init
- 配置信息来自于2部分
- 配置文件
- 目前只有mapping请求映射信息
- 注解
- 根据web.xml配置的包路径 com.controller
- 获得对应的文件夹相对路径 com/controller
- 配合Thread.currentThread()…. 获得文件夹的绝对路径
- 创建File对象表示文件夹dir
- 获得文件夹中所有子内容名字(包括class文件名字)
- 获得类名(去掉.class后缀)
- 重新包装成完成的类路径 com.controller.TestController
- 反射获得类注解
- 反射获得类方法
- 反射获得方法注解
- 获得请求映射的信息:
@RequestMapping(“/test”) -> path
反射创建controller对象
Method
- 配置文件
- 映射请求
- 根据浏览器发送的请求,找到与之匹配的请求映射信息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);
- 如果找到映射关系(待续。。)
- 获取参数
- 处理参数
- 调用目标对象的方法,传递参数,完成请求映射过程。
- 如果没有找到映射关系
==============================================================
映射请求-映射动态资源-获取参数
- 按照我们之前所学
- 浏览器传递的参数主要包括两类
- 普通的请求传参
- 只传字符串
- 使用req.getParameter()
- 文件上传时的传参
- 传递2种参数: 普通参数(字符串),文件参数
- fileupload文件上传组件接收参数
- 普通的请求传参
- 浏览器传递的参数有可能存在同名的情况
url?hobby=zq&hobby=lq&hobby=pq
req.getParameter(“hobby”) —> zq
req.getParameterValues(“hobby”) ->[zq,lq,pq]- 文件上传时,也可能传递多个同名的参数
映射请求-映射动态资源-参数处理
- 框架获得参数后
- 需要按照请求映射关系,调用controller方法,同时为其传递参数
- 反之,在controller的方法,如果需要用哪些请求的参数
- 以前需要使用request方法获得
- 现在只需要在controller方法中定义方法参数列表
- 告诉看框架,需要哪些参数
原来需要 uname和upass
req.getParameter(“uname”);
req.getParameter(“upass”);
现在
public void t2(String uname , String upass){}
- 为什么写了t2方法,框架可以为其传递参数了
- 首先在读取映射关系时,调用的方法对象会存入MappingInfo
- 我们就可以根据请求获得info对象,从而获得要调用的method对象
- 获得method对象后,可以通过反射获得参数列表
- 参数的个数
- 参数类型
- 不能获得参数的名字,而框架需要通过名字key获得对应参数
- 由框架提供一个@RequestParam,作用在controller方法的参数上,指定其对应请求参数的名字<br />public void t2(@RequestParam("uname")String a , @RequestParam("upass")String b){}<br />告诉框架,需要获得uname和upass两个参数
- 注意: 有时,业务程序要让框架,将传递的多个参数组成对象<br />public void t3(Car car){}
- 不需要使用@RequestParam注解
- 告诉框架,将传递的参数组成Car对象
- 看框架会根据Car的属性名找到与之匹配的参数,组装成对象。
- 注意: 还有一种特殊情况,不需要请求传递参数,但需要request,response,session的对象<br />框架也会以方法传参的形式将上述对象传给controller方法。
==============================================================
映射请求-映射动态资源-参数处理
- 服务器接收参数后
- 需要按照映射关系调用controller的方法,同时将获取的请求参数,以方法参数的形式传递
- controller方法在接收参数时,希望框架可以按需求实现类型转换
- 框架在接收参数,传递参数中,还需按照controller的需求要处理参数
controller方法的参数列表
public void t1(String bname,@RequestParam(“num”)int num , int[] nums , HttpServletRequest req , Car car,MuliptartFile excel)
响应
- 框架参数处理完毕后,就可以根据映射关系调用controller方法,传参
- controller中获得参数后的业务处理,就有具体的业务程序完成(controller,service,dao)
业务程序处理完毕后,需要响应
- 直接响应
- 直接响应文本字符串
- 直接响应集合对象(需要转换成json格式的字符串再响应)
- 间接响应
- 转发 (携带数据)
- 重定向 (携带数据)
- 直接响应
原来响应直接在业务程序中完成
- 现在响应由框架完成
- 框架实现哪种响应,需要由业务程序告知
- 业务程序如何告知框架,需要按照框架的规则告知
- 响应内容以返回值的形式返回给框架
- 如果是间接响应,直接返回值
- 如果不需要携带数据
return “05.jsp” 转发
return “redirect:05.jsp” 重定向 - 如果需要携带数据
- 返回一个框架提供ModelAndView对象
- 转发: 数据会request.setAttribute()
- 重定向:数据会以?的形式跟在url的后面 (只支持String)
- 如果不需要携带数据
- 如果是直接响应,在返回值同时,需要为方法增加一个@ResponseBody的注解
- 如果返回String,int,double等简单类型,直接以String返回
- 如果是其他类型,则认为需要转换成json