Design Patterns web based applications
我正在设计一个简单的基于Web的应用程序。我是这个基于Web的领域的新手,我需要你关于设计模式的建议,比如责任应该如何分配给servlet,创建新servlet的标准等等。
实际上,我的主页上有几个实体,与它们对应,我们有几个选项,如添加、编辑和删除。早些时候,我为每个选项使用一个servlet,比如servlet1用于添加entity1,servlet2用于编辑entity1等等,这样我们就得到了大量的servlet。
现在我们正在改变我们的设计。我的问题是,您如何准确地选择如何选择servlet的职责。我们是否应该为每个实体提供一个servlet,它将处理所有的选项并将请求转发给服务层。或者我们应该为整个页面提供一个servlet来处理整个页面请求,然后将其转发到相应的服务层?另外,请求对象是否转发到服务层。
一个有点体面的Web应用程序由混合的设计模式组成。我只会提到最重要的那些。好的。模型视图控制器模式
您要使用的核心(体系结构)设计模式是模型-视图-控制器模式。控制器由servlet表示,servlet(in)根据请求直接创建/使用特定的模型和视图。模型将由JavaBean类表示。在包含操作(行为)的业务模型和包含数据(信息)的数据模型中,这通常可以进一步划分。视图由JSP文件表示,JSP文件通过EL(表达式语言)直接访问(数据)模型。好的。
然后,根据操作和事件的处理方式,会有一些变化。最受欢迎的是:好的。
基于请求(操作)的MVC:这是最简单的实现。(业务)模型直接与
HttpServletRequest 和HttpServletResponse 对象一起工作。您必须自己收集、转换和验证请求参数(大部分)。该视图可以用普通的HTML/CSS/JS表示,并且不在请求之间维护状态。这就是SpringMVC、Struts和Stripes的工作原理。好的。基于组件的MVC:这很难实现。但是您最终得到了一个更简单的模型和视图,其中所有"原始"servlet API都被完全抽象掉了。您不需要自己收集、转换和验证请求参数。控制器执行此任务,并在模型中设置收集、转换和验证的请求参数。您需要做的只是定义直接与模型属性一起工作的操作方法。视图由JSP标记库或XML元素风格的"组件"表示,后者反过来生成HTML/CSS/JS。在会话中维护后续请求的视图状态。这对于服务器端转换、验证和值更改事件特别有用。这就是JSF、Wicket和Play的方式!作品。好的。
另一点需要注意的是,使用国产的MVC框架是一个非常好的学习练习,我建议您只要将其用于个人/私人目的。但是一旦你变得专业了,强烈建议你选择一个现有的框架,而不是重新设计你自己的框架。与自己开发和维护一个健壮的框架相比,学习一个现有的、开发良好的框架需要的时间要短得多。好的。
在下面的详细解释中,我将限制自己使用基于请求的MVC,因为这更容易实现。好的。型前控制器模式(中介模式)
首先,控制器部分应该实现前端控制器模式(这是一种专门的中介模式)。它应该只包含一个servlet,它提供所有请求的集中入口点。它应该根据请求提供的信息创建模型,例如pathinfo或servletpath、方法和/或特定参数。在下面的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Action action = ActionFactory.getAction(request); String view = action.execute(request, response); if (view.equals(request.getPathInfo().substring(1)) { request.getRequestDispatcher("/WEB-INF/" + view +".jsp").forward(request, response); } else { response.sendRedirect(view); // We'd like to fire redirect in case of a view change as result of the action (PRG pattern). } } catch (Exception e) { throw new ServletException("Executing action failed.", e); } } |
执行操作应该返回一些标识符来定位视图。最简单的方法是将其用作JSP的文件名。将这个servlet映射到
对于前缀模式,例如
当您使用诸如
1 2 3 |
号
您可能想让
下面是一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class LoginAction implements Action { public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception { String username = request.getParameter("username"); String password = request.getParameter("password"); User user = userDAO.find(username, password); if (user != null) { request.getSession().setAttribute("user", user); // Login user. return"home"; // Redirect to home page. } else { request.setAttribute("error","Unknown username/password. Please retry."); // Store error message in request scope. return"login"; // Go back to redisplay login form with error. } } } |
工厂方法模式
1 2 3 | public static Action getAction(HttpServletRequest request) { return actions.get(request.getMethod() + request.getPathInfo()); } |
。
反过来,
1 2 3 4 | actions.put("POST/register", new RegisterAction()); actions.put("POST/login", new LoginAction()); actions.put("GET/logout", new LogoutAction()); // ... |
或者根据类路径中的属性/xml配置文件进行配置:(伪)好的。
1 2 3 | for (Entry entry : configuration) { actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance()); } |
或者动态地基于类路径中实现特定接口和/或注释的类的扫描:(伪)好的。
1 2 3 4 5 | for (ClassFile classFile : classpath) { if (classFile.isInstanceOf(Action.class)) { actions.put(classFile.getAnnotation("mapping"), classFile.newInstance()); } } |
记住要为没有映射的情况创建一个"不做任何事情"
到目前为止,这些都是重要的模式。好的。
为了更进一步,您可以使用facade模式创建一个
然后还有一个状态模式,您希望添加一个额外的抽象层来分割收集请求参数、转换它们、验证它们、更新模型值和执行操作的任务。在JSF术语中,这就是
然后是您想要创建一个基于组件的视图的情况的复合模式,该视图可以附加到模型中,其行为取决于基于请求的生命周期的状态。在JSF术语中,这就是
这样,您就可以一点一点地向基于组件的框架发展。好的。参见:
- Java核心库中GOF设计模式的实例
- 请求MVC和组件MVC之间的差异
- 使用MVC和DAO模式在JSP页面的HTML中显示JDBC结果集
- 什么组件是JSF MVC框架中的MVC?
- JSF控制器、服务和DAO
好啊。
在被敲打的MVC模式中,servlet是"C"控制器。
它的主要工作是进行初始请求评估,然后根据初始评估将处理发送给特定的工人。工作人员的职责之一可能是设置一些表示层bean,并将请求转发到JSP页面以呈现HTML。因此,仅出于这个原因,您需要将请求对象传递到服务层。
不过,我不会开始编写原始的
imho,如果从责任分配的角度来看,Web应用程序的情况没有太大的区别。但是,保持层中的清晰度。在表示层中保留任何纯粹用于表示目的的内容,例如特定于Web控件的控件和代码。只需将实体保留在业务层中,并将所有功能(如添加、编辑、删除)等保留在业务层中。但是,将它们呈现到浏览器上,以便在表示层中处理。对于.NET,ASP.NET MVC模式在保持层分离方面非常好。研究MVC模式。
Balusc优秀的答案涵盖了Web应用程序的大多数模式。
某些应用程序可能需要责任链模式
In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.
使用案例使用此模式:
当处理请求(命令)的处理程序未知并且此请求可以发送到多个对象时。一般情况下,您将"后续任务"设置为"对象"。如果当前对象无法处理请求或部分处理请求,则将同一请求转发给后续对象。
有用的SE问题/文章:
为什么我要用责任链来代替装饰师?
责任链的常见用法?
面向对象设计的责任链模式
来源责任链
我已经使用了Struts框架,并且发现它相当容易学习。使用Struts框架时,站点的每个页面都将包含以下项。
1)每次刷新HTML页面时都会调用所使用的操作。当第一次加载页面时,该操作应填充表单中的数据,并处理Web UI和业务层之间的交互。如果使用JSP页面修改可变Java对象,则Java对象的副本应该存储在表单中而不是原件中,这样原始数据不会被修改,除非用户保存页面。
2)用于在操作和JSP页面之间传输数据的表单。这个对象应该由一组getter和setter组成,用于JSP文件需要访问的属性。表单还具有一个方法,用于在数据持久化之前对其进行验证。
3)用于呈现页面最终HTML的JSP页面。JSP页面是HTML和用于访问和操作表单中数据的特殊struts标记的混合体。虽然Struts允许用户将Java代码插入到JSP文件中,但这样做会非常谨慎,因为这会使代码变得更难阅读。JSP文件内部的Java代码很难调试,不能进行单元测试。如果发现自己在JSP文件中编写了超过4-5行Java代码,则代码可能会被移动到操作中。