diff --git a/src/main/java/core/mvc/Controller.java b/src/main/java/core/mvc/Controller.java index df7b7f2ea..788045232 100644 --- a/src/main/java/core/mvc/Controller.java +++ b/src/main/java/core/mvc/Controller.java @@ -1,8 +1,10 @@ package core.mvc; +import core.mvc.modelandview.ModelAndView; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public interface Controller { - String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception; + ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception; } diff --git a/src/main/java/core/mvc/DispatcherServlet.java b/src/main/java/core/mvc/DispatcherServlet.java index 59e1a23ee..5f2e1944c 100644 --- a/src/main/java/core/mvc/DispatcherServlet.java +++ b/src/main/java/core/mvc/DispatcherServlet.java @@ -1,56 +1,40 @@ package core.mvc; -import java.io.IOException; +import core.mvc.modelandview.ModelAndView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - @WebServlet(name = "dispatcher", urlPatterns = "/", loadOnStartup = 1) public class DispatcherServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class); - private static final String DEFAULT_REDIRECT_PREFIX = "redirect:"; private RequestMapping rm; @Override - public void init() throws ServletException { + public void init() { rm = new RequestMapping(); rm.initMapping(); } @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException { String requestUri = req.getRequestURI(); logger.debug("Method : {}, Request URI : {}", req.getMethod(), requestUri); Controller controller = rm.findController(requestUri); try { - String viewName = controller.execute(req, resp); - if (viewName != null) { - move(viewName, req, resp); - } + ModelAndView modelAndView = controller.execute(req, resp); + modelAndView.render(req, resp); } catch (Throwable e) { logger.error("Exception : {}", e); throw new ServletException(e.getMessage()); } } - - private void move(String viewName, HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - if (viewName.startsWith(DEFAULT_REDIRECT_PREFIX)) { - resp.sendRedirect(viewName.substring(DEFAULT_REDIRECT_PREFIX.length())); - return; - } - - RequestDispatcher rd = req.getRequestDispatcher(viewName); - rd.forward(req, resp); - } } diff --git a/src/main/java/core/mvc/ForwardController.java b/src/main/java/core/mvc/ForwardController.java index 83c9d89f2..b1d6dfa5c 100644 --- a/src/main/java/core/mvc/ForwardController.java +++ b/src/main/java/core/mvc/ForwardController.java @@ -1,5 +1,7 @@ package core.mvc; +import core.mvc.modelandview.ModelAndView; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -14,7 +16,8 @@ public ForwardController(String forwardUrl) { } @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { - return forwardUrl; + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + return ModelAndView.builder() + .jspView(forwardUrl); } } diff --git a/src/main/java/core/mvc/modelandview/ModelAndView.java b/src/main/java/core/mvc/modelandview/ModelAndView.java new file mode 100644 index 000000000..6c75f9b74 --- /dev/null +++ b/src/main/java/core/mvc/modelandview/ModelAndView.java @@ -0,0 +1,52 @@ +package core.mvc.modelandview; + +import core.mvc.view.JsonView; +import core.mvc.view.JspView; +import core.mvc.view.View; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; +import java.util.Map; + +public class ModelAndView { + private final Map model; + private final View view; + + private ModelAndView(Map model, View view) { + this.model = model; + this.view = view; + } + + public void render(HttpServletRequest req, HttpServletResponse resp) throws Exception { + view.render(req, resp, model); + } + + public static ModelAndViewBuilder builder() { + return new ModelAndViewBuilder(); + } + + public static class ModelAndViewBuilder { + private final Map model; + private View view; + + public ModelAndViewBuilder() { + this.model = new HashMap<>(); + } + + public ModelAndViewBuilder addAttribute(String key, Object value) { + model.put(key, value); + return this; + } + + public ModelAndView jspView(String viewName) { + view = new JspView(viewName); + return new ModelAndView(model, view); + } + + public ModelAndView jsonView() { + view = new JsonView(); + return new ModelAndView(model, view); + } + } +} diff --git a/src/main/java/core/mvc/view/JsonView.java b/src/main/java/core/mvc/view/JsonView.java new file mode 100644 index 000000000..ffabb7891 --- /dev/null +++ b/src/main/java/core/mvc/view/JsonView.java @@ -0,0 +1,29 @@ +package core.mvc.view; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.PrintWriter; +import java.util.Enumeration; +import java.util.Map; + +public class JsonView implements View { + @Override + public void render(HttpServletRequest req, HttpServletResponse resp, Map model) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + resp.setContentType("application/json;charset=UTF-8"); + PrintWriter out = resp.getWriter(); + out.print(mapper.writeValueAsString(model)); + } + + private Map createModel(HttpServletRequest req, Map model) { + final Enumeration names = req.getAttributeNames(); + while (names.hasMoreElements()) { + final String name = names.nextElement(); + model.put(name, req.getAttribute(name)); + } + + return model; + } +} diff --git a/src/main/java/core/mvc/view/JspView.java b/src/main/java/core/mvc/view/JspView.java new file mode 100644 index 000000000..273dc2ade --- /dev/null +++ b/src/main/java/core/mvc/view/JspView.java @@ -0,0 +1,35 @@ +package core.mvc.view; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Map; + +public class JspView implements View { + private static final String DEFAULT_REDIRECT_PREFIX = "redirect:"; + + private final String url; + + public JspView(String url) { + this.url = url; + } + + @Override + public void render(HttpServletRequest req, HttpServletResponse resp, Map model) throws Exception { + model.forEach(req::setAttribute); + move(url, req, resp); + } + + private void move(String viewName, HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + if (viewName.startsWith(DEFAULT_REDIRECT_PREFIX)) { + resp.sendRedirect(viewName.substring(DEFAULT_REDIRECT_PREFIX.length())); + return; + } + + RequestDispatcher rd = req.getRequestDispatcher(viewName); + rd.forward(req, resp); + } +} diff --git a/src/main/java/core/mvc/view/View.java b/src/main/java/core/mvc/view/View.java new file mode 100644 index 000000000..c4e85fdeb --- /dev/null +++ b/src/main/java/core/mvc/view/View.java @@ -0,0 +1,9 @@ +package core.mvc.view; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +public interface View { + void render(HttpServletRequest req, HttpServletResponse resp, Map model) throws Exception; +} diff --git a/src/main/java/next/controller/HomeController.java b/src/main/java/next/controller/HomeController.java index d01c085a3..384a60944 100644 --- a/src/main/java/next/controller/HomeController.java +++ b/src/main/java/next/controller/HomeController.java @@ -1,16 +1,18 @@ package next.controller; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.dao.QuestionDao; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + public class HomeController implements Controller { @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { QuestionDao questionDao = new QuestionDao(); - req.setAttribute("questions", questionDao.findAll()); - return "home.jsp"; + return ModelAndView.builder() + .addAttribute("questions", questionDao.findAll()) + .jspView("home.jsp"); } } diff --git a/src/main/java/next/controller/qna/AddAnswerController.java b/src/main/java/next/controller/qna/AddAnswerController.java index e9c9acd40..3c86f4347 100644 --- a/src/main/java/next/controller/qna/AddAnswerController.java +++ b/src/main/java/next/controller/qna/AddAnswerController.java @@ -1,34 +1,29 @@ package next.controller.qna; -import java.io.PrintWriter; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.dao.AnswerDao; import next.model.Answer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; public class AddAnswerController implements Controller { private static final Logger log = LoggerFactory.getLogger(AddAnswerController.class); @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { Answer answer = new Answer(req.getParameter("writer"), req.getParameter("contents"), Long.parseLong(req.getParameter("questionId"))); log.debug("answer : {}", answer); AnswerDao answerDao = new AnswerDao(); Answer savedAnswer = answerDao.insert(answer); - ObjectMapper mapper = new ObjectMapper(); - resp.setContentType("application/json;charset=UTF-8"); - PrintWriter out = resp.getWriter(); - out.print(mapper.writeValueAsString(savedAnswer)); - return null; + + return ModelAndView.builder() + .addAttribute("savedAnswer", savedAnswer) + .jsonView(); } } diff --git a/src/main/java/next/controller/qna/DeleteAnswerController.java b/src/main/java/next/controller/qna/DeleteAnswerController.java index 169e3a617..32a452c72 100644 --- a/src/main/java/next/controller/qna/DeleteAnswerController.java +++ b/src/main/java/next/controller/qna/DeleteAnswerController.java @@ -1,28 +1,21 @@ package next.controller.qna; -import java.io.PrintWriter; +import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; +import next.dao.AnswerDao; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import com.fasterxml.jackson.databind.ObjectMapper; - -import core.mvc.Controller; -import next.dao.AnswerDao; -import next.model.Result; - public class DeleteAnswerController implements Controller { @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { Long answerId = Long.parseLong(req.getParameter("answerId")); AnswerDao answerDao = new AnswerDao(); answerDao.delete(answerId); - ObjectMapper mapper = new ObjectMapper(); - resp.setContentType("application/json;charset=UTF-8"); - PrintWriter out = resp.getWriter(); - out.print(mapper.writeValueAsString(Result.ok())); - return null; + return ModelAndView.builder() + .jsonView(); } } diff --git a/src/main/java/next/controller/qna/ShowController.java b/src/main/java/next/controller/qna/ShowController.java index bdb26e683..e7fab0630 100644 --- a/src/main/java/next/controller/qna/ShowController.java +++ b/src/main/java/next/controller/qna/ShowController.java @@ -1,20 +1,23 @@ package next.controller.qna; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.dao.AnswerDao; import next.dao.QuestionDao; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + public class ShowController implements Controller { @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { - Long questionId = Long.parseLong(req.getParameter("questionId")); + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + long questionId = Long.parseLong(req.getParameter("questionId")); QuestionDao questionDao = new QuestionDao(); AnswerDao answerDao = new AnswerDao(); - req.setAttribute("question", questionDao.findById(questionId)); - req.setAttribute("answers", answerDao.findAllByQuestionId(questionId)); - return "/qna/show.jsp"; + + return ModelAndView.builder() + .addAttribute("question", questionDao.findById(questionId)) + .addAttribute("answers", answerDao.findAllByQuestionId(questionId)) + .jspView("/qna/show.jsp"); } } diff --git a/src/main/java/next/controller/user/CreateUserController.java b/src/main/java/next/controller/user/CreateUserController.java index a5db3dc06..8d94e79dd 100644 --- a/src/main/java/next/controller/user/CreateUserController.java +++ b/src/main/java/next/controller/user/CreateUserController.java @@ -1,26 +1,27 @@ package next.controller.user; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.dao.UserDao; import next.model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; public class CreateUserController implements Controller { private static final Logger log = LoggerFactory.getLogger(CreateUserController.class); @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { User user = new User(req.getParameter("userId"), req.getParameter("password"), req.getParameter("name"), req.getParameter("email")); log.debug("User : {}", user); UserDao userDao = new UserDao(); userDao.insert(user); - return "redirect:/"; + return ModelAndView.builder() + .jspView("redirect:/"); } } diff --git a/src/main/java/next/controller/user/ListUserController.java b/src/main/java/next/controller/user/ListUserController.java index 90aec9081..e567473d9 100644 --- a/src/main/java/next/controller/user/ListUserController.java +++ b/src/main/java/next/controller/user/ListUserController.java @@ -1,21 +1,25 @@ package next.controller.user; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.controller.UserSessionUtils; import next.dao.UserDao; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + public class ListUserController implements Controller { @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { if (!UserSessionUtils.isLogined(req.getSession())) { - return "redirect:/users/loginForm"; + return ModelAndView.builder() + .jspView("redirect:/users/loginForm"); } UserDao userDao = new UserDao(); - req.setAttribute("users", userDao.findAll()); - return "/user/list.jsp"; + + return ModelAndView.builder() + .addAttribute("users", userDao.findAll()) + .jspView("/user/list.jsp"); } } diff --git a/src/main/java/next/controller/user/LoginController.java b/src/main/java/next/controller/user/LoginController.java index 343e91e6f..5eee7632a 100644 --- a/src/main/java/next/controller/user/LoginController.java +++ b/src/main/java/next/controller/user/LoginController.java @@ -1,32 +1,36 @@ package next.controller.user; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.controller.UserSessionUtils; import next.dao.UserDao; import next.model.User; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + public class LoginController implements Controller { @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { String userId = req.getParameter("userId"); String password = req.getParameter("password"); UserDao userDao = new UserDao(); User user = userDao.findByUserId(userId); if (user == null) { - req.setAttribute("loginFailed", true); - return "/user/login.jsp"; + return ModelAndView.builder() + .addAttribute("loginFailed", true) + .jspView("/user/login.js"); } if (user.matchPassword(password)) { HttpSession session = req.getSession(); session.setAttribute(UserSessionUtils.USER_SESSION_KEY, user); - return "redirect:/"; + return ModelAndView.builder() + .jspView("redirect:/"); } else { - req.setAttribute("loginFailed", true); - return "/user/login.jsp"; + return ModelAndView.builder() + .addAttribute("loginFailed", true) + .jspView("/user/login.jsp"); } } } diff --git a/src/main/java/next/controller/user/LogoutController.java b/src/main/java/next/controller/user/LogoutController.java index 08a8cee33..6648ae2e3 100644 --- a/src/main/java/next/controller/user/LogoutController.java +++ b/src/main/java/next/controller/user/LogoutController.java @@ -1,17 +1,19 @@ package next.controller.user; +import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; +import next.controller.UserSessionUtils; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import core.mvc.Controller; -import next.controller.UserSessionUtils; - public class LogoutController implements Controller { @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { HttpSession session = req.getSession(); session.removeAttribute(UserSessionUtils.USER_SESSION_KEY); - return "redirect:/"; + return ModelAndView.builder() + .jspView("redirect:/"); } } diff --git a/src/main/java/next/controller/user/ProfileController.java b/src/main/java/next/controller/user/ProfileController.java index cf529c3ff..44a2470e9 100644 --- a/src/main/java/next/controller/user/ProfileController.java +++ b/src/main/java/next/controller/user/ProfileController.java @@ -1,22 +1,25 @@ package next.controller.user; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.dao.UserDao; import next.model.User; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + public class ProfileController implements Controller { @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { String userId = req.getParameter("userId"); UserDao userDao = new UserDao(); User user = userDao.findByUserId(userId); if (user == null) { throw new NullPointerException("사용자를 찾을 수 없습니다."); } - req.setAttribute("user", user); - return "/user/profile.jsp"; + + return ModelAndView.builder() + .addAttribute("user", user) + .jspView("/user/profile.jsp"); } } diff --git a/src/main/java/next/controller/user/UpdateFormUserController.java b/src/main/java/next/controller/user/UpdateFormUserController.java index 3d8650f61..188ba6377 100644 --- a/src/main/java/next/controller/user/UpdateFormUserController.java +++ b/src/main/java/next/controller/user/UpdateFormUserController.java @@ -1,24 +1,26 @@ package next.controller.user; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.controller.UserSessionUtils; import next.dao.UserDao; import next.model.User; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + public class UpdateFormUserController implements Controller { @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { String userId = req.getParameter("userId"); UserDao userDao = new UserDao(); User user = userDao.findByUserId(userId); if (!UserSessionUtils.isSameUser(req.getSession(), user)) { throw new IllegalStateException("다른 사용자의 정보를 수정할 수 없습니다."); } - req.setAttribute("user", user); - return "/user/updateForm.jsp"; + return ModelAndView.builder() + .addAttribute("user", user) + .jspView("/user/updateForm.jsp"); } } diff --git a/src/main/java/next/controller/user/UpdateUserController.java b/src/main/java/next/controller/user/UpdateUserController.java index 64b1ebbc8..3d3910863 100644 --- a/src/main/java/next/controller/user/UpdateUserController.java +++ b/src/main/java/next/controller/user/UpdateUserController.java @@ -1,21 +1,21 @@ package next.controller.user; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import core.mvc.Controller; +import core.mvc.modelandview.ModelAndView; import next.controller.UserSessionUtils; import next.dao.UserDao; import next.model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; public class UpdateUserController implements Controller { private static final Logger log = LoggerFactory.getLogger(UpdateUserController.class); @Override - public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { + public ModelAndView execute(HttpServletRequest req, HttpServletResponse resp) throws Exception { UserDao userDao = new UserDao(); User user = userDao.findByUserId(req.getParameter("userId")); if (!UserSessionUtils.isSameUser(req.getSession(), user)) { @@ -26,6 +26,7 @@ public String execute(HttpServletRequest req, HttpServletResponse resp) throws E req.getParameter("email")); log.debug("Update User : {}", updateUser); user.update(updateUser); - return "redirect:/"; + return ModelAndView.builder() + .jspView("redirect:/"); } } diff --git a/webapp/js/scripts.js b/webapp/js/scripts.js index 25df2db84..a927751bd 100644 --- a/webapp/js/scripts.js +++ b/webapp/js/scripts.js @@ -16,9 +16,9 @@ function addAnswer(e) { }); } -function onSuccess(json, status){ +function onSuccess(resp, status){ var answerTemplate = $("#answerTemplate").html(); - var template = answerTemplate.format(json.writer, new Date(json.createdDate), json.contents, json.answerId, json.answerId); + var template = answerTemplate.format(resp.savedAnswer.writer, new Date(resp.savedAnswer.createdDate), resp.savedAnswer.contents, resp.savedAnswer.answerId, resp.savedAnswer.answerId); $(".qna-comment-slipp-articles").prepend(template); }