繁体   English   中英

如何以MVC方式在PRG中实现命令模式?

[英]How to implement Command pattern with PRG in MVC way?

我正在使用tomcat,jsp,servlet和log4j进行第一个Web项目,并且有一个我感兴趣的使用Command设计模式的演示。我有一个Controller接受doGet和doPost方法,然后将请求处理到CommandContainer查找适当的Command,执行它,获取资源的路径,并将客户端转发给它。

public abstract class Command implements Serializable { 
    private static final long serialVersionUID = 8879403039606311780L;
    public abstract String execute(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException;
}

管理命令的CommandContainer:

public class CommandContainer {
    private static final Logger LOG = Logger.getLogger(CommandContainer.class);
    private static Map<String, Command> commands = new TreeMap<String, Command>();
    static {
        // common commands
        commands.put("login", new LoginCommand());
        commands.put("logout", new LogoutCommand());
        commands.put("viewSettings", new ViewSettingsCommand());
        commands.put("noCommand", new NoCommand());

        // client commands
        commands.put("listMenu", new ListMenuCommand());

        // admin commands
        commands.put("listOrders", new ListOrdersCommand());

        LOG.debug("Command container was successfully initialized");
        LOG.trace("Number of commands --> " + commands.size());
    }

public static Command get(String commandName) {
    if (commandName == null || !commands.containsKey(commandName)) {
        LOG.trace("Command not found, name --> " + commandName);
        return commands.get("noCommand"); 
    }

    return commands.get(commandName);
}

我唯一的控制器:

public class Controller extends HttpServlet {

    private static final long serialVersionUID = 2423353715955164816L;

    private static final Logger LOG = Logger.getLogger(Controller.class);

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        process(request, response);
    }

    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        process(request, response);
    }

    private void process(HttpServletRequest request,
            HttpServletResponse response) throws IOException, ServletException {

        LOG.debug("Controller starts");

        // extract command name from the request
        String commandName = request.getParameter("command");
        LOG.trace("Request parameter: command --> " + commandName);

        // obtain command object by its name
        Command command = CommandContainer.get(commandName);
        LOG.trace("Obtained command --> " + command);

        // execute command and get forward address
        String forward = command.execute(request, response);
        LOG.trace("Forward address --> " + forward);

        LOG.debug("Controller finished, now go to forward address --> " + forward);

        // if the forward address is not null go to the address
        if (forward != null) {
            RequestDispatcher disp = request.getRequestDispatcher(forward);
            disp.forward(request, response);
        }
    }

}

我正在以以下方式在jsp中使用Controller:

...
    <form id="login_form" action="controller" method="post">
                    <input type="hidden" name="command" value="login"/>
...
    </form>

和web.xml文件:

<servlet>
    <servlet-name>Controller</servlet-name>
    <servlet-class>com.mycompany.web.Controller</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>Controller</servlet-name>
    <url-pattern>/controller</url-pattern>
</servlet-mapping>

我不明白如何用Command模式实现Post-Redirect-Get模式,因为每次请求到控制器时,它都使用process()方法,并且在JSP中似乎使用GET或POST都没有关系。 然后,您是否可以帮助理解使用Command模式的需求? 如果我将使用多个Servlet(例如LoginServlet,LogoutServlet,ViewSettingsServlet)而不是一个Controller怎么办?这是一个坏主意,因为然后我需要将它们以jsp形式硬编码为动作? 所有这些问题都让我感到困惑,因为我是一个初学者,所以请让我理解所有这些。

好吧,当前,您的命令返回一个String:要转发到的JSP的名称。 如果我理解正确,那么您还希望能够重定向而不是转发。 因此,如果不是返回的视图名称,而是重定向到的URL,则需要给返回值的servlet打电话。

有多种方法可以做到这一点。 例如,您可以返回一个对象,该对象包含要执行的操作类型(FORWARD或REDIRECT)以及视图名称或URL。 或者,您可以返回类似redirect:/ foo / bar的字符串,这意味着/ foo / bar是要重定向到的URL,而不是视图名称。

但是最好的解决方案可能是避免重新发明轮子,而是使用现有的MVC框架而不是自己实现:Spring MVC,Stripes,Struts等都以一种更好的方式提供了远远超过现有功能的东西。 特别是,使用请求参数选择命令不是一个很好的选择。 使用路径是一个更好的主意。

您还可以简单地使用多个servlet,这将比您当前的解决方案更好。 但是,您会丢失前端控制器,前端控制器通常包含所有命令通用的代码:国际化,安全检查等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM