有点像样的Web应用程序由多种设计模式组成。我只会提到最重要的那些。
模型视图控制器模式
您要使用的核心(架构)设计模式是Model-View-
Controller模式。该
控制器 是由一个Servlet其中(在)直接创造来表示/使用特定的 模型 和 视图 基于该请求。该 模型
将由Javabean类表示。在包含动作(行为)的 业务模型 和包含数据(信息)的 数据模型中 ,这通常可以进一步划分。该 视图
是由具有对(直接访问JSP文件来表示 数据 ) 模型 由EL(表达式语言)。
然后,根据操作和事件的处理方式而有所不同。最受欢迎的是:
基于请求(动作)的MVC :这是最简单的实现。( 业务 ) 模型 直接与
HttpServletRequest
和HttpServletResponse
对象一起使用。您必须自己(主要)收集,转换和验证请求参数。该 视图 可以用普通的HTML / CSS / JS表示,并且不会在请求中保持状态。这就是Spring MVC,Struts和Stripes的工作方式。基于组件的MVC :这很难实现。但是最终您得到了一个更简单的模型和视图,其中所有“原始” Servlet API都被完全抽象了。您不需要自己收集,转换和验证请求参数。所述 控制器 执行此任务,并设置在所收集的,转换后的和验证请求参数 模型 。您需要做的就是定义直接与模型属性一起使用的操作方法。该 视图 是通过“组件”在JSP标记库或依次产生HTML / CSS / JS的XML元素的风味表示。 视图 的状态 __在会话中维护后续请求。这对于服务器端转换,验证和值更改事件特别有用。这就是JSF和Play的方式!作品。
附带说明一下,使用本地的MVC框架是一种非常不错的学习方法,只要您出于个人/私人目的保留它,我还是建议您这样做。但是一旦您成为专业人士,那么强烈建议您选择一个现有的框架,而不要重塑自己的框架。学习现有的和完善的框架要比自己开发和维护一个健壮的框架花费更少的时间。
在下面的详细说明中,我将自己限制为基于请求的MVC,因为它更易于实现。
前控制器模式(介体模式)
首先, Controller 部分应实现Front
Controller模式(这是一种专门的Mediator模式)。它应该仅包含一个servlet,该servlet提供所有请求的集中入口点。它应基于请求可用的信息来创建
模型 ,例如pathinfo或servletpath,方法和/或特定参数。该 商业模式
被称为
Action在下面的
HttpServlet例子。
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映射到特定
url-pattern的
web.xml,例如
/pages/*,
*.do甚至
*.html。
在前缀模式,例如情况下,
/pages/*你可以然后调用URL就像http://example.com/pages/register,http://example.com/pages/login等,提供
/WEB-INF/register.jsp,
/WEB-INF/login.jsp使用适当的GET和POST行为。然后,如上例所示,可以使用部件
register,
login等等
request.getPathInfo()。
当你使用后缀模式,比如
*.do,
*.html等等,那么你可以然后调用URL的喜欢http://example.com/register.do,http://example.com/login.do,等你应该改变此答案中的代码示例(也包括
ActionFactory)提取了
register和
login部分
request.getServletPath()。
策略模式
本
Action应遵循的策略模式。需要将其定义为抽象/接口类型,该类型应基于抽象方法的
传入
参数来完成工作(这与Command模式不同,其中命令
/抽象类型应基于在 创建 实现过程中传入的参数)。
public interface Action { public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;}您可能想
Exception使用自定义例外来使内容更加具体
ActionException。这只是一个基本的启动示例,其余的全由您决定。
这是一个
LoginAction(如其名称所示)登录用户的示例。该
User本身又一个 数据模型 。该 视图 是知道的存在
User。
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. } }}工厂方法模式
本
ActionFactory应遵循工厂方法模式。基本上,它应该提供一种创建方法,该方法返回抽象/接口类型的具体实现。在这种情况下,它应该
Action根据请求提供的信息返回接口的实现。例如,所述方法和PATHINFO(该PATHINFO是在请求URL中的上下文和servlet路径之后的部分,不包括查询字符串)。
public static Action getAction(HttpServletRequest request) { return actions.get(request.getMethod() + request.getPathInfo());}该
actions反过来应该是一些静态/应用程序范围
Map<String, Action>它包含所有已知的行动。如何填写这张地图由您决定。硬编码:
actions.put("POST/register", new RegisterAction());actions.put("POST/login", new LoginAction());actions.put("GET/logout", new LogoutAction());// ...或可基于类路径中的属性/ XML配置文件进行配置:(伪)
for (Entry entry : configuration) { actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());}或基于在类路径中的扫描来动态地实现实现特定接口和/或注释的类:(伪)
for (ClassFile classFile : classpath) { if (classFile.isInstanceOf(Action.class)) { actions.put(classFile.getAnnotation("mapping"), classFile.newInstance()); }}在
Action没有映射的情况下,请记住创建“不执行任何操作”
。让它例如直接返回
request.getPathInfo().substring(1)then。
其他图案
这些是到目前为止的重要模式。
要更进一步,您可以使用Facade模式创建一个
Context类,该类依次包装请求和响应对象,并提供几个委托给请求和响应对象的便捷方法,并将其作为参数传递给该
Action#execute()方法。这增加了一个额外的抽象层以隐藏原始Servlet
API。然后,您基本上应该在每个实现中都以 零
importjavax.servlet.*声明结束
Action。用JSF术语,这是
FacesContext和
ExternalContext类的作用。您可以在此答案中找到一个具体示例。
然后是一种情况下的状态模式,您想添加一个额外的抽象层以拆分收集请求参数,转换请求,验证请求,更新模型值和执行操作的任务。用JSF术语,这
LifeCycle就是这样做的。
然后是针对您想要创建一个基于组件的视图的Composite模式,该视图可以随模型一起附加,并且其行为取决于基于请求的生命周期的状态。用JSF术语
UIComponent表示。
通过这种方式,您可以逐步向基于组件的框架发展。



