Паттерн команда при проектировании web приложения. PRG
Пишу небольшое приложение servlets и jsp. В основе своей оно использует паттерн комманда в таком виде:
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);
}
/**
* Main method of this controller.
*/
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);
}
}}
Те команды которые отображают содержимое возвращают свой результат в таком виде:
return Path.PAGE__NON_AUTORIZED_USER_EXPOSITIONS;
Вопрос заключается в следующем - как используя паттерн комманда реализовать PRG(POST REDIRECT GET) если те команды которые создают сущности(Post запросом) должны делать sendRedirect на указанную jsp?
Ответы (1 шт):
Главное, что нужно сделать, это иметь возможность в process определить, что за результат вернула команда и в зависимости от этого возвращать результат по разному.
Как именно это делать - это уже дело вкуса. Вот несколько вариантов.
Форматированная строка
Подобное делает spring. Вместо Path.PAGE__NON_AUTORIZED_USER_EXPOSITIONS возвращайте "forward:" + Path.PAGE__NON_AUTORIZED_USER_EXPOSITIONS (для случая редиректа "redirect:" + url). process должен в зависимости от префикса делать либо forward либо редирект.
Удобно сделать вспомогательные функции:
public String forward(String to) {
return String.format("forward:%s", to);
}
public String redirect(String to) {
return String.format("redirect:%s", to);
}
чтобы в команде можно было писать:
return forward( Path.PAGE__NON_AUTORIZED_USER_EXPOSITIONS);
Типизированный результат
Вместо String возвращать объект своего класса.
interface CommandResult {
String getResource();
}
class ForwardResult implements CommandResult {
private String forwardResource;
public ForwardResource(String resource) {
this.forwardResource = resource;
}
public String getResource() {
return forwardResource;
}
}
class RedirectResult implements CommandResult {
public String getResource() {
}
}
process в зависимости от типа делает то, что нужно.
interface View {
void render(CommandResult result, HttpServletRequest request,
HttpServletResponse response);
}
class Controller {
private static Map<Class<?>, View> views = new HashMap<>();
static {
views.put(ForwardResult.class, (result, request, response) -> {
RequestDispatcher disp =
request.getRequestDispatcher(result.getResource());
disp.forward(request, response);
});
views.put(RedirectResult.class, (result, request, response) -> {
response.sendRedirect(request.getContextPath() + result.getResource());
});
}
void process(...) {
...
Command command = CommandContainer.get(commandName);
CommandResult result = command.execute(request, response);
views.get(result.getClass()).render(result, request, response);
}
}
В этом случае команда должна возвращать результат как-то так:
return new ForwardResult(Path.PAGE__NON_AUTORIZED_USER_EXPOSITIONS);