访问请求处理

当客户端发送一个请求,被自定义的过滤器MvcDispatcher拦截,解析请求地址和参数对象跳转到一个控制器的方法中,然后执行进行逻辑处理后返回响应内容给MvcDispatcher输出,这样MVC逻辑就走完了。前期的初始化过程是为这里做准备。当接收到请求以后,进行拦截的方法如插图所示。

doFilter()实际上主要做了几件事:

  • 首先,它会判断是否静态资源的请求,若是则不走后面的流程;
  • 其次,加入一些实用功能,例如增强request、response,把它们打包成更易使用的MvcRequest、MvcOutput对象;还有记录一下请求时间、把request、response保存ThreadLocal等等;
  • 然后,匹配路由路径找到控制器方法并执行;
  • 执行方法期间,会检查是否有FilterAction过滤器,有就执行;
  • 假如在上面的过程中出现异常,则会触发MvcDispatcher处理异常的过程。

针对以上几点下面展开来深入了解。

如何处理静态网页?

由于MVC系统试图将过滤器的url-pattern映射为“/”,即访问的 URL都将由 MvcDispatcher处理,包括所有静态文件。所谓静态文件就是将服务器本地的文件原样输出到客户端,例如静态HTML网页、JPG/PNG/GIF等的图片、CSS其他无须服务端动态处理内容的那些文件或资源。

如前面插图所示,早在doFilter()的第一步将试图按URL查找是否匹配静态文件,它是ServletHelper的isStaticAsset()方法。如插图所示,该方法非常简单,主要通过正则表达式来判断URL后缀是否静态文件。

对于正则对象,应尽早编译为Pattern对象并将它作为静态成员出现,只需要创建一次,可供之后反复使用。

增强MvcRequest、MvcOutput对象

毋庸多言Request、Response对象是Web开发中非常常见和熟悉的对象。为了避免直接使用Request、Response而产生重复代码,有必要把这些方法封装起来。可以写成一个个静态的小函数,不过我们建议那么做。事实上Servlet本身有个不错的方案,那便是利用HttpServletRequestWrapperHttpServletResponseWrapper包装了原Request、Response对象。虽说是包装器但它实际为装饰模式(Decorator Pattern)之应用。装饰模式是经典设计模式里的一种,指在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。所谓包装的实现是通过继承来实现的,如果要修改某个方法,通过覆盖旧方法即可。

MvcReqeust就是基于HttpServletRequest实现新功能的这么一个子类,它继承于HttpServletRequestWrapper,然后实例化时候必须对构造器传参,就是原来的HttpServletRequest对象,如插图所示。

下面通过一个获取当前URL请求路径的例子来说明该扩展模式。默认request的getRequestURI()可以获取请求地址,但如果在Servlet+JSP下,缺省的是JSP磁盘文件所在的地址。我们希望改过来,应是获取请求URL地址,如插图所示。

这个新的方法我们并不打算重新起名字,而是直接重写覆盖原先的HttpServletRequest的getRequestURI()方法,故打上@Override注解说明之。怎么获取真实请求地址呢?读取常量javax.servlet.forward.request_uri即可,这里调用了request另外一个方法getAttribute()获取常量。如果为空则读取父类的getRequestURI()方法,也就是说,虽然覆盖了getRequestURI()但通过super关键字还是可以调用父类的方法,那样就不影响了原对象的逻辑而又较清晰地实现了解耦。

ThreadLocal应用

前面我们说到,控制器方法需要什么参数,取决于开发者如何定义。假设一个控制器方法没有定义request参数,那该如何获取呢?request/response这类对象是如此地常用以致于把它们安排到ThreadLocal中,让控制器能轻易地访问到这些对象。向ThreadLocal这个容器存储的对象,在当前线程范围内都可以取得出来,类似于全局变量,如下例所示。

@Path("/bar")
public class BarController implements IController {@GETpublic String showHTML() {MvcRequest request = MvcRequest.getHttpServletRequest();return "html::Hello World! " + request.getParameter("foo");}
}

关于ThreadLocal的深入应用,在介绍数据库连接对象的时候还会再说。

仿AOP的过滤器

提到过滤器,我们第一时间可能会想到的是Servlet里面的Filter原生过滤器,而我们统一接受请求的MvcDispatcher也正是一个标准的过滤器应用——只不过它扮演了控制器也就是原先HttpServlet的作用。原先控制器是有了,那么过滤器本身这个功能点呢?虽然说在MVC框架仍旧可以使用标准的Servlet Filter,但是结合MVC框架而言,已经内置了过滤器的功能,和控制器本身结合更简单自然。实际上,这种过滤器更类似于AOP拦截器,它会在控制器执行之前发生(前置)又可以在执行控制器之后执行一个方法(后置),插入的时间点是方法执行的一前一后,而且另外不同的是,它基于Java注解的写法。所以综合来讲说有点像AOP。

过滤器本身,常常被用来实现下面的功能:1、页面授权根,据登录用户的权限,阻止或许可用户访问特定的页面;2、日志和审计记录和检查用户访问WEB应用的情况;3、本地化,显示本地语言和风格的页面;4、高速缓存,页面静态化,提高响应速度。

客户端发起一次HTTP请求,对应查找有Action对象,Action返回控制器实例和控制器方法,有这两个条件就可以执行控制器方法了吗?还不行,因为还需要执行方法的参数。

学写一个 Java Web MVC 框架(四)相关推荐

  1. 学写一个 Java Web MVC 框架(一)

    当前我们介绍的是一个简单的MVC,用8个类即实现完整Spring MVC核心功能,外加其他实用的小功能.它是怎么实现的呢?让我们来一探究竟! 源码在:https://gitee.com/sp42_ad ...

  2. 自己动手写一个简单的MVC框架(第一版)

    一.MVC概念回顾 路由(Route).控制器(Controller).行为(Action).模型(Model).视图(View) 用一句简单地话来描述以上关键点: 路由(Route)就相当于一个公司 ...

  3. 仿照源码,手写一个自定义 Spring MVC 框架

    毫无疑问,Spring 框架目前已经成为 Java 开发的行业标准,Spring MVC 作为其 Web 解决方案,是所有 Java 开发者都必须掌握的基本技能,理解其底层原理,才能更好地应用它进行实 ...

  4. 自己动手写一个简单的MVC框架(第二版)

    一.ASP.NET MVC核心机制回顾 在ASP.NET MVC中,最核心的当属"路由系统",而路由系统的核心则源于一个强大的System.Web.Routing.dll组件. 在 ...

  5. 手把手教你写一个Java的orm框架(4)

    开始准备生成sql 在上一篇里,我们已经取到了我们在生成sql语句中所需要的信息,这一篇里我们开始根据class来生成我们需要的sql.在这之前我们先确认几件事情 sql里的参数我们使用占位符的形式. ...

  6. java web mvc spring_Java下Web MVC的领跑者:SpringMVC

    比较常用的MVC框架有Struts 和 SpringMVC. Struts 是Java Web MVC框架中曾经不争的王者.经过长达九年的发展,Struts占有了MVC框架中最大的市场份额.但是Str ...

  7. 太恐怖了 两天搞定一个项目 Java Web MVC 网络商城教程+源代码

    两天搞定一个项目 Java Web MVC 网络商城教程+源代码 最近自学做了一个网络商城将以下是代码和教程 环境搭建–数据库设计–页面设计-后台设计 本项目使用的jdk版本是 运行项目前需要先配置好 ...

  8. 在Java中搭建一个简单的MVC框架

    搭建一个简单的Java MVC框架 一 . 前言 二. 代码实现 1. 思路分析 2. 代码实现 2.1 Controller注解 2.2 RequestMapping注解 2.3 UserContr ...

  9. 一个JAVA WEB伪全栈的VUE入坑随笔,从零点零五学起

    开始时间:3.26日 接触Vue,先在官网十目一行学完了基本特性:http://cn.vuejs.org/v2/guide/,作为一个JAVA WEB的伪全栈,用Myclipse感受了一把双向绑定,感 ...

最新文章

  1. 【js】内置对象array的常见方法的使用
  2. 递归 尾递归_代码简报:递归,递归,递归
  3. [转]iPhone本地化总结
  4. Redis工作笔记-spring整合jedis
  5. Centos7选定默认启动的内核版本
  6. onvif学习笔记6:onvif的OSD坐标小记
  7. cin.ignore()函数的使用
  8. python实现k core算法_python实现k-近邻算法
  9. Dreamer 框架 比Struts2 更加灵活
  10. 存储过程中进行循环处理数据
  11. Filter过滤指定ip地址
  12. 左撇子的成长指南:我是左撇子.TXT
  13. android简单小程序课程设计,微信小程序课程设计报告
  14. 解决video标签在部分安卓默认浏览器上的播放样式问题
  15. 腾讯云服务器高性能云盘和SSD云硬盘区别及选择
  16. ps中解决标点符号在行开头的问题
  17. MAC修改主机名、计算机名
  18. Python关于生日悖论分析
  19. 文墨绘学21天习惯养成方法,学好就会优秀
  20. Java面试题大全(2020版)

热门文章

  1. CListCtrl 应用
  2. actor-critic 相关算法简述
  3. Npm发布到私库去的操作
  4. Apache DbUtils工具类初学
  5. js实现周历插件方法
  6. 教你快速认识通讯光纤(缆)
  7. WPF 自定义模板 Button闪亮效果
  8. A New Multiple Folded Successive Cancellation Decoder for Polar Codes
  9. jsp页面 用c标签来循环遍历数据库某表中里面的数据 但是页面不显示数据
  10. SnackBar源码解析及封装