设计模式基于网络的应用程序[英] Design Patterns web based applications

本文是小编为大家收集整理的关于设计模式基于网络的应用程序的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在设计一个简单的基于Web的应用程序.我是这个基于网络的域名的新手.我需要您关于设计模式的建议

实际上,我的主页上没有几个实体,与每个实体相对应,我们几乎没有添加,编辑和删除的选项.早些时候,我在每个选项(例如Servlet1)中使用一个Servlet for Add Entity1,Servlet2用于Edit Entity1等,依此类推,以此方式,我们最终拥有了大量的Servlet.

现在我们正在改变设计.我的问题是您如何准确选择如何选择servlet的责任.如果我们每个实体有一个servlet,它将处理所有选项并将请求转发到服务层.还是我们应该为整个页面有一个servlet,它将处理整个页面请求,然后将其转发到相应的服务层?另外,请求对象是否转发到服务层.

推荐答案

有些不错的Web应用程序由设计模式组成.我只提到最重要的.


模型视图Controller模式 H2>

您要使用的核心(架构)设计模式是模型视图对照器模式. Controller 将由(IN)直接创建/使用基于请求的特定 model 和 view 来表示. 模型将由Javabean类表示.这通常是在包含操作(行为)和包含数据(信息)的动作(行为)和数据模型的业务模型中进一步划分的. view 将由JSP文件表示,这些文件可以直接访问( data ) model by El(expression语言).

然后,基于如何处理动作和事件的方式存在变化.受欢迎的是:

  • 基于请求(操作)MVC :这是最简单的实现. (业务) model 直接与HttpServletRequest和HttpServletResponse对象一起工作.您必须(主要是)收集,转换和验证请求参数. View 可以由普通的香草html/css/js表示,并且不能在跨请求之间保持状态.这就是 spring mvc , struts stripes works.

  • 基于组件的MVC :这很难实现.但是您最终会获得一个更简单的模型,并查看其中所有"原始" servlet API完全被抽象出来.您无需亲自收集,转换和验证请求参数. Controller 执行此任务,并在 model 中设置收集,转换和验证的请求参数.您需要做的就是定义直接与模型属性合作的操作方法. View 由JSP Taglibs或XML元素的"组件"表示,后者又生成HTML/CSS/JS.会话中保留了后续请求的视图的状态.这对于服务器端转换,验证和值更改事件特别有用.这就是 jsf 检票口 play! works.

作为旁注,使用本土的MVC框架的爱好是一个非常好的学习练习,只要您保留它是出于个人/私人目的,我确实建议它.但是,一旦您变得专业,就强烈建议选择一个现有的框架而不是重新发明自己的框架.与自行开发和维护强大的框架相比,学习现有且发达的框架所花费的时间少.

在以下详细说明中,我将限制自己以基于请求的MVC,因为这更容易实现.


前控制器模式(中介图案)

首先,控制器部分应实现前控制器模式 (这是一种专业的调解器模式).它应仅由单个servlet组成,该servlet提供所有请求的集中入口点.它应基于请求可用的信息(例如PathInfo或ServletPath,方法和/或特定参数)创建 model . 业务模型在以下 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映射到web.xml中的特定url-pattern上,例如/pages/*,*.do甚至只是*.html.

如果有前缀patterns,例如/pages/*您可以像 http:http://xplue example. com/pages/寄存器 http://example.com/pages/login 等并提供适当的GET和POST诉讼.然后,零件register,login等将由 request.getPathInfo() 如上所述.

当您使用*.do,*.html等的后缀 - patterns时,然后您可以像 http://example.com/register.do http://example.com/login . com/javaee/7/api/javax/servlet/http/httpservletrequest.html#getservletpath--" rel =" noreferrer"> request.getServletPath() 代替.


策略模式

Action应遵循策略模式.它需要定义为一种抽象/接口类型,该类型应基于抽象方法的传递参数来完成工作(这是与命令模式,其中摘要/接口类型应基于在 creation 创建期间传递的参数进行工作/em>实现).

public interface Action {
    public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

您可能需要使Exception更具体地使用自定义异常,例如ActionException.这只是一个基本的开球示例,其余的全部取决于您.

这是一个LoginAction的示例,该示例(顾名思义)在用户中登录. User本身又是数据模型. View 知道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 是请求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配置文件的可配置:( pseudo)

for (Entry entry : configuration) {
    actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}

或基于在类中的扫描中动态的类,以实现某个接口和/或注释:( pseudo)

for (ClassFile classFile : classpath) {
    if (classFile.isInstanceOf(Action.class)) {
       actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
    }
}

请记住要创建一个"无所事事" Action对于没有映射的情况.例如,让它直接返回request.getPathInfo().substring(1).


其他模式

这些是到目前为止的重要模式.

要进一步迈出一步,您可以使用 facade模式创建Context类又包含请求和响应对象,并提供了几种委派给请求和响应对象的便利方法,并将其作为参数传递到Action#execute()方法中.这添加了一个额外的抽象层来隐藏RAW Servlet API.然后,您应该基本上以每个Action实施中的声明 import javax.servlet.*声明.用JSF术语,这就是 a>和 ExternalContext 班级.您可以在中找到一个具体示例答案.

然后有状态模式您想添加额外的抽象分层以分配收集请求参数,转换它们,验证它们,更新模型值并执行操作的任务.用JSF术语,这就是 LifeCycle LifeCycle LifeCycle LifeCycle 正在做.

然后有复合模式您想创建基于组件的情况可以与模型附加的视图以及其行为取决于基于请求的生命周期的状态.用jsf术语,这就是 a>表示.

这样,您可以在基于组件的框架上进行一点进化.


另请参见:

其他推荐答案

在被打击的MVC模式中,servlet为" c" - 控制器.

其主要工作是进行初始请求评估,然后根据初始评估向特定工人派遣处理.工人的职责之一可能是设置一些演示层bean,然后将请求转发到JSP页面以渲染HTML.因此,仅出于这个原因,您需要将请求对象传递到服务层.

我不会开始编写RAW Servlet类.他们所做的工作非常可预测和样板,框架做得很好.幸运的是,有许多可用的,有时间考验的候选人(按字母顺序): apache检票口 java server faces 春天命名几个.

其他推荐答案

IMHO,如果您从责任分配角度看待Web应用程序的情况下,Web应用程序的情况没有太大差异.但是,将清晰度保持在层中.将任何内容保留在演示层中,例如特定于Web控件的控件和代码.只需将您的实体保留在业务层中,并将所有功能(例如添加,编辑,删除)等在业务层中.但是,将它们渲染到浏览器上以在演示层中处理.对于.net,在保持层分开方面,ASP.NET MVC模式非常好.查看MVC模式.

本文地址:https://www.itbaoku.cn/post/627432.html

问题描述

I am designing a simple web-based application. I am new to this web-based domain.I needed your advice regarding the design patterns like how responsibility should be distributed among Servlets, criteria to make new Servlet, etc.

Actually, I have few entities on my home page and corresponding to each one of them we have few options like add, edit and delete. Earlier I was using one Servlet per options like Servlet1 for add entity1, Servlet2 for edit entity1 and so on and in this way we ended up having a large number of servlets.

Now we are changing our design. My question is how you exactly choose how you choose the responsibility of a servlet. Should we have one Servlet per entity which will process all it's options and forward request to the service layer. Or should we have one servlet for the whole page which will process the whole page request and then forward it to the corresponding service layer? Also, should the request object forwarded to service layer or not.

推荐答案

A bit decent web application consists of a mix of design patterns. I'll mention only the most important ones.


Model View Controller pattern

The core (architectural) design pattern you'd like to use is the Model-View-Controller pattern. The Controller is to be represented by a Servlet which (in)directly creates/uses a specific Model and View based on the request. The Model is to be represented by Javabean classes. This is often further dividable in Business Model which contains the actions (behaviour) and Data Model which contains the data (information). The View is to be represented by JSP files which have direct access to the (Data) Model by EL (Expression Language).

Then, there are variations based on how actions and events are handled. The popular ones are:

  • Request (action) based MVC: this is the simplest to implement. The (Business) Model works directly with HttpServletRequest and HttpServletResponse objects. You have to gather, convert and validate the request parameters (mostly) yourself. The View can be represented by plain vanilla HTML/CSS/JS and it does not maintain state across requests. This is how among others Spring MVC, Struts and Stripes works.

  • Component based MVC: this is harder to implement. But you end up with a simpler model and view wherein all the "raw" Servlet API is abstracted completely away. You shouldn't have the need to gather, convert and validate the request parameters yourself. The Controller does this task and sets the gathered, converted and validated request parameters in the Model. All you need to do is to define action methods which works directly with the model properties. The View is represented by "components" in flavor of JSP taglibs or XML elements which in turn generates HTML/CSS/JS. The state of the View for the subsequent requests is maintained in the session. This is particularly helpful for server-side conversion, validation and value change events. This is how among others JSF, Wicket and Play! works.

As a side note, hobbying around with a homegrown MVC framework is a very nice learning exercise, and I do recommend it as long as you keep it for personal/private purposes. But once you go professional, then it's strongly recommended to pick an existing framework rather than reinventing your own. Learning an existing and well-developed framework takes in long term less time than developing and maintaining a robust framework yourself.

In the below detailed explanation I'll restrict myself to request based MVC since that's easier to implement.


Front Controller pattern (Mediator pattern)

First, the Controller part should implement the Front Controller pattern (which is a specialized kind of Mediator pattern). It should consist of only a single servlet which provides a centralized entry point of all requests. It should create the Model based on information available by the request, such as the pathinfo or servletpath, the method and/or specific parameters. The Business Model is called Action in the below HttpServlet example.

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);
    }
}

Executing the action should return some identifier to locate the view. Simplest would be to use it as filename of the JSP. Map this servlet on a specific url-pattern in web.xml, e.g. /pages/*, *.do or even just *.html.

In case of prefix-patterns as for example /pages/* you could then invoke URL's like http://example.com/pages/register, http://example.com/pages/login, etc and provide /WEB-INF/register.jsp, /WEB-INF/login.jsp with the appropriate GET and POST actions. The parts register, login, etc are then available by request.getPathInfo() as in above example.

When you're using suffix-patterns like *.do, *.html, etc, then you could then invoke URL's like http://example.com/register.do, http://example.com/login.do, etc and you should change the code examples in this answer (also the ActionFactory) to extract the register and login parts by request.getServletPath() instead.


Strategy pattern

The Action should follow the Strategy pattern. It needs to be defined as an abstract/interface type which should do the work based on the passed-in arguments of the abstract method (this is the difference with the Command pattern, wherein the abstract/interface type should do the work based on the arguments which are been passed-in during the creation of the implementation).

public interface Action {
    public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

You may want to make the Exception more specific with a custom exception like ActionException. It's just a basic kickoff example, the rest is all up to you.

Here's an example of a LoginAction which (as its name says) logs in the user. The User itself is in turn a Data Model. The View is aware of the presence of the 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.
        }
    }

}

Factory method pattern

The ActionFactory should follow the Factory method pattern. Basically, it should provide a creational method which returns a concrete implementation of an abstract/interface type. In this case, it should return an implementation of the Action interface based on the information provided by the request. For example, the method and pathinfo (the pathinfo is the part after the context and servlet path in the request URL, excluding the query string).

public static Action getAction(HttpServletRequest request) {
    return actions.get(request.getMethod() + request.getPathInfo());
}

The actions in turn should be some static/applicationwide Map<String, Action> which holds all known actions. It's up to you how to fill this map. Hardcoding:

actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...

Or configurable based on a properties/XML configuration file in the classpath: (pseudo)

for (Entry entry : configuration) {
    actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}

Or dynamically based on a scan in the classpath for classes implementing a certain interface and/or annotation: (pseudo)

for (ClassFile classFile : classpath) {
    if (classFile.isInstanceOf(Action.class)) {
       actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
    }
}

Keep in mind to create a "do nothing" Action for the case there's no mapping. Let it for example return directly the request.getPathInfo().substring(1) then.


Other patterns

Those were the important patterns so far.

To get a step further, you could use the Facade pattern to create a Context class which in turn wraps the request and response objects and offers several convenience methods delegating to the request and response objects and pass that as argument into the Action#execute() method instead. This adds an extra abstract layer to hide the raw Servlet API away. You should then basically end up with zero import javax.servlet.* declarations in every Action implementation. In JSF terms, this is what the FacesContext and ExternalContext classes are doing. You can find a concrete example in this answer.

Then there's the State pattern for the case that you'd like to add an extra abstraction layer to split the tasks of gathering the request parameters, converting them, validating them, updating the model values and execute the actions. In JSF terms, this is what the LifeCycle is doing.

Then there's the Composite pattern for the case that you'd like to create a component based view which can be attached with the model and whose behaviour depends on the state of the request based lifecycle. In JSF terms, this is what the UIComponent represent.

This way you can evolve bit by bit towards a component based framework.


See also:

其他推荐答案

In the beaten-up MVC pattern, the Servlet is "C" - controller.

Its main job is to do initial request evaluation and then dispatch the processing based on the initial evaluation to the specific worker. One of the worker's responsibilities may be to setup some presentation layer beans and forward the request to the JSP page to render HTML. So, for this reason alone, you need to pass the request object to the service layer.

I would not, though, start writing raw Servlet classes. The work they do is very predictable and boilerplate, something that framework does very well. Fortunately, there are many available, time-tested candidates ( in the alphabetical order ): Apache Wicket, Java Server Faces, Spring to name a few.

其他推荐答案

IMHO, there is not much difference in case of web application if you look at it from the angle of responsibility assignment. However, keep the clarity in the layer. Keep anything purely for the presentation purpose in the presentation layer, like the control and code specific to the web controls. Just keep your entities in the business layer and all features (like add, edit, delete) etc in the business layer. However rendering them onto the browser to be handled in the presentation layer. For .Net, the ASP.NET MVC pattern is very good in terms of keeping the layers separated. Look into the MVC pattern.