简体   繁体   中英

How to implement Command pattern with PRG in MVC way?

I'm working on my first web project using tomcat, jsp, servlets and log4j and I have a demo of using Command design pattern, which I'm interested in. I have one Controller which accepts doGet and doPost methods and then proccesses requests to CommandContainer which finds appropriate Command, executes it, gets path to resource and forwards the client to it.

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

CommandContainer which manages Commands:

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

The only Controller I have:

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

}

I'am using Controller in jsp in the next way:

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

And web.xml file:

<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>

I don't understand how to implement Post-Redirect-Get pattern with Command pattern, because every time request comes to controller it uses process() method and seems that it doesnt matter GET or POST is used in JSP. And then would you help understand the need of use Command pattern ? What if I will use multiple servlets like LoginServlet, LogoutServlet, ViewSettingsServlet instead of one Controller - is it would be a bad idea because then I need to hardcode them in jsp forms as actions ? All this questions just confusing me, cos I'm a starter, so please jelp me understand all this.

Well, currently, your command returns a String: the name of the JSP to forward to. If I understand correctly, you also want to be able to redirect instead of forwarding. So you need to tel the servlet that the returned value if not a view name to forward to, but a URL to redirect to.

There are various ways to do that. You could for example return an object containing the type of action to do (FORWARD or REDIRECT), and the view name or URL. Or you could return a String like redirect:/foo/bar, which means that /foo/bar is a URL to redirect to, and not a view name.

But the best solution would probably to avoid reinventing the wheel, and use an existing MVC framework rather than implementing one yourself: Spring MVC, Stripes, Struts, etc. all provide much more than what you have there, and in a much better way. In particular, using a request parameter to choose the command is not a very good choice. Using the path is a much better idea.

You could also simply use multiple servlets, which would be better than your current solution. You would lose the front controller though, which typically contains code that is common to all commands: internationalization, security checks, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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