表现层设计与不佳实践

会话管理

在客户端保存会话有以下优点:

  • 相对来说容易实现
  • 当保存的状态比较少时,效果很号

在客户端保存会话有两种常见策略:

  • HTML 隐藏字段
  • HTTP cookie

在客户端保存会话状态的时候会存在安全性的问题。

在表现层保存会话状态:

当会话状态由服务器管理,就可以只通过一个会话 ID (session id) 来获取状态,状态在下面的情况下会删除掉:

  • 会话超时
  • 人工指定会话无效
  • 一个状态从会话中被删除了

控制客户端访问

控制客户端访问就是保护视图或视图的一部分,当有些信息只有在登录后才可以访问,还有重复提交表单问题。

验证

提交表单时候会对表单进行验证:

  • 客户端验证
  • 服务端验证

表现层的一些问题:

  • 视图(jsp 页面)当中包含控制代码
  • 表现层数据结构暴露给业务层(HttpServletRequest)
  • 重复提交表单
  • 敏感资源暴露给客户端

重构表现层采购

引入控制器

在一起的代码当中,很多逻辑会存在 JSP 当中,我们要把它们进行分成 MVC,JSP 只用于来充当 View 层,所以我们需要将控制逻辑抽取到一个或多个控制器类中。

引入同步令牌

如果服务端不允许重复提交,那么我们需要引入同步令牌。一般令牌会加入到 HTML 当中的隐藏域。

当客户端当前请求携带的令牌与服务器在前一次响应时发送给客户端的令牌一致就说明当前请求不是重复提交。如果不一致就可能是重复提交。

对业务层隐藏表现细节

即是在业务处理的过程当中,可以将表现层的参数转换成通用的类型传递给业务对象,不要给业务对象暴露 HttpServletRequest 等类型的参数。

对客户端隐藏资源

客户端可以直接访问某些资源,例如:JSP 页面,但是这样访问是应该受限的。

将某些资源移动到 /WEB-INF/目录下就可以控制对他们的访问。

对这些资源的访问必须来通过控制器进行访问。

表现层模式

拦截过滤器

要在请求被处理之前、之后拦截并且操作一个请求和它的响应。适合拦截的有如下功能:

  • 客户端是否是一个有效会话
  • 请求的目录是否允许被访问
  • 响应和请求的编码方式

什么的这些问题都属于统一处理的问题,如果分散处理,就会存在很多相同的代码,并且这样也会增加预处理和后处理与核心逻辑的耦合。

前端控制器

系统需要一个集中的访问点来处理请求。使用前端控制器,作为请求的第一接触点,来处理所有相关请求。前端控制器集中了控制逻辑,避免了逻辑的重复,完成主要的请求处理操作。

前端控制器通常会使用应用控制器,后者负责操作和视图管理。

  • 操作管理,就是定位特定的操作,并且把实际操作路由到该操作上,由它处理请求。
  • 视图管理,找到合适的视图,并且分派到该视图上。

最常见的做法是由一个前端控制器处理所有请求,这种情况 web 服务器只需要注册一个组件。

处理请求需要两种操作:

  • 请求处理
  • 实图处理

请求处理又有如下几种操作:

  • 协议处理和上下文转换:例如将 HttpServletRequest 请求当中的参数,复制到更加通用的 bean 当中
  • 导航和路由
  • 核心处理
  • 分派

前端控制器的通常用法,是采用命令加控制器策略,把应用控制器、命令结合使用。一般前端控制器是负责处理请求的分发,把不同的请求分发到一个应用控制器当中。应用控制器负责操作和视图管理,命令一般是只应用控制器当中的某个方法。

Context 对象

使用 Context 对象,按照协议无关的方式封装状态,然后在整个应用系统中使用这种封装后的对象。

比如,可以使用 Context 对象来封装 HttpServletRequest。

实现方式,可以把一个 HttpServletRequest 对象封装成 RequestContext 请求对象,使用 ContextFactory 来创建一个 RequestContext 对象,并且把 HttpServletRequest 的状态传递给它,这里的 RequestContext 会初步检查字段是否为空,身份证位数是否正确。

另外的实现方式,可以把 Context 对象实现成一个 Map,把请求相关的状态放到其中,然后在系统内部使用这个 Context 对象。

使用 POJO 来封装 Context,这种做法有好处也有缺点,好处是可以对每一个参数进行强类型控制,缺点是需要对每个属性都定义访问的方法,如果某个应用有很多属性,也必须给每个属性定义多个访问方法。

还有一种混合的做法,使用 Map + POJO 的做法,这种方式是采用代码生成工具来生成 Context。

【参考资料】

  1. J2EE核心模式

—EOF—