diff --git a/app/src/main/java/com/techcourse/DispatcherServletInitializer.java b/app/src/main/java/com/techcourse/DispatcherServletInitializer.java index d444d2b28a..99ca799db3 100644 --- a/app/src/main/java/com/techcourse/DispatcherServletInitializer.java +++ b/app/src/main/java/com/techcourse/DispatcherServletInitializer.java @@ -4,10 +4,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import web.org.springframework.web.WebApplicationInitializer; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.mvc.DispatcherServlet; import webmvc.org.springframework.web.servlet.mvc.HandlerExecutionAdapter; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping; import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; +import webmvc.org.springframework.web.servlet.view.JspView; /** * Base class for {@link WebApplicationInitializer} @@ -18,15 +20,13 @@ public class DispatcherServletInitializer implements WebApplicationInitializer { private static final Logger log = LoggerFactory.getLogger(DispatcherServletInitializer.class); private static final String DEFAULT_SERVLET_NAME = "dispatcher"; - private static final String PACKAGE_TO_SEARCH_CONTROLLER = "com.techcourse"; @Override public void onStartup(final ServletContext servletContext) { final var dispatcherServlet = new DispatcherServlet(); - dispatcherServlet.addHandlerMapping(new ManualHandlerMapping()); - dispatcherServlet.addHandlerMapping(new AnnotationHandlerMapping(PACKAGE_TO_SEARCH_CONTROLLER)); + dispatcherServlet.addHandlerMapping(new AnnotationHandlerMapping(getClass().getPackageName())); + dispatcherServlet.addNotFoundModelAndView(new ModelAndView(new JspView("redirect:/404.jsp"))); dispatcherServlet.addHandlerAdapterType(HandlerExecution.class, HandlerExecutionAdapter.class); - dispatcherServlet.addHandlerAdapterType(Controller.class, ManualControllerHandlerAdapter.class); final var registration = servletContext.addServlet(DEFAULT_SERVLET_NAME, dispatcherServlet); if (registration == null) { diff --git a/app/src/main/java/com/techcourse/ManualControllerHandlerAdapter.java b/app/src/main/java/com/techcourse/ManualControllerHandlerAdapter.java deleted file mode 100644 index affdf3a005..0000000000 --- a/app/src/main/java/com/techcourse/ManualControllerHandlerAdapter.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.techcourse; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.mvc.HandlerAdapter; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; -import webmvc.org.springframework.web.servlet.view.JspView; - -public class ManualControllerHandlerAdapter implements HandlerAdapter { - - private final Controller controller; - - public ManualControllerHandlerAdapter(final Object controller) { - this.controller = (Controller) controller; - } - - @Override - public boolean isSupport(Object handler) { - return handler instanceof Controller; - } - - @Override - public ModelAndView handle(final HttpServletRequest request, final HttpServletResponse response) throws Exception { - final String path = controller.execute(request, response); - return new ModelAndView(new JspView(path)); - } -} diff --git a/app/src/main/java/com/techcourse/ManualHandlerMapping.java b/app/src/main/java/com/techcourse/ManualHandlerMapping.java deleted file mode 100644 index 4d80fcbebc..0000000000 --- a/app/src/main/java/com/techcourse/ManualHandlerMapping.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.techcourse; - -import com.techcourse.controller.LoginController; -import com.techcourse.controller.LoginViewController; -import com.techcourse.controller.LogoutController; -import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import webmvc.org.springframework.web.servlet.mvc.HandlerMapping; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; -import webmvc.org.springframework.web.servlet.mvc.asis.ForwardController; - -import java.util.HashMap; -import java.util.Map; - -public class ManualHandlerMapping implements HandlerMapping { - - private static final Logger log = LoggerFactory.getLogger(ManualHandlerMapping.class); - - private static final Map controllers = new HashMap<>(); - - @Override - public void initialize() { - controllers.put("/", new ForwardController("/index.jsp")); - controllers.put("/login", new LoginController()); - controllers.put("/login/view", new LoginViewController()); - controllers.put("/logout", new LogoutController()); - - log.info("Initialized Handler Mapping!"); - controllers.keySet() - .forEach(path -> log.info("Path : {}, Controller : {}", path, controllers.get(path).getClass())); - } - - @Override - public boolean isSupport(HttpServletRequest request) { - return controllers.containsKey(request.getRequestURI()); - } - - @Override - public Controller getHandler(final HttpServletRequest request) { - final String requestURI = request.getRequestURI(); - log.debug("Request Mapping Uri : {}", requestURI); - return controllers.get(requestURI); - } -} diff --git a/app/src/main/java/com/techcourse/controller/DefaultForwardController.java b/app/src/main/java/com/techcourse/controller/DefaultForwardController.java new file mode 100644 index 0000000000..529e9521a9 --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/DefaultForwardController.java @@ -0,0 +1,20 @@ +package com.techcourse.controller; + +import context.org.springframework.stereotype.Controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; + +@Controller +public class DefaultForwardController { + + private static final String INDEX = "/index.jsp"; + + @RequestMapping(value = "/", method = RequestMethod.GET) + public ModelAndView forward(final HttpServletRequest request, final HttpServletResponse response) { + return new ModelAndView(new JspView(INDEX)); + } +} diff --git a/app/src/main/java/com/techcourse/controller/LoginController.java b/app/src/main/java/com/techcourse/controller/LoginController.java index 0428fe109e..54763ce454 100644 --- a/app/src/main/java/com/techcourse/controller/LoginController.java +++ b/app/src/main/java/com/techcourse/controller/LoginController.java @@ -2,28 +2,34 @@ import com.techcourse.domain.User; import com.techcourse.repository.InMemoryUserRepository; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; -public class LoginController implements Controller { +@Controller +public class LoginController { private static final Logger log = LoggerFactory.getLogger(LoginController.class); - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { + @RequestMapping(value = "/login", method = RequestMethod.POST) + public ModelAndView doLogin(final HttpServletRequest req, final HttpServletResponse res) { if (UserSession.isLoggedIn(req.getSession())) { - return "redirect:/index.jsp"; + return new ModelAndView(new JspView("redirect:/index.jsp")); } - return InMemoryUserRepository.findByAccount(req.getParameter("account")) + final String redirectPath = InMemoryUserRepository.findByAccount(req.getParameter("account")) .map(user -> { log.info("User : {}", user); return login(req, user); }) .orElse("redirect:/401.jsp"); + return new ModelAndView(new JspView(redirectPath)); } private String login(final HttpServletRequest request, final User user) { @@ -34,4 +40,15 @@ private String login(final HttpServletRequest request, final User user) { } return "redirect:/401.jsp"; } + + @RequestMapping(value = "/login/view", method = RequestMethod.GET) + public ModelAndView loginView(final HttpServletRequest req, final HttpServletResponse res) { + final String redirectPath = UserSession.getUserFrom(req.getSession()) + .map(user -> { + log.info("logged in {}", user.getAccount()); + return "redirect:/index.jsp"; + }) + .orElse("/login.jsp"); + return new ModelAndView(new JspView(redirectPath)); + } } diff --git a/app/src/main/java/com/techcourse/controller/LoginViewController.java b/app/src/main/java/com/techcourse/controller/LoginViewController.java deleted file mode 100644 index 86ec26cdce..0000000000 --- a/app/src/main/java/com/techcourse/controller/LoginViewController.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.techcourse.controller; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; - -public class LoginViewController implements Controller { - - private static final Logger log = LoggerFactory.getLogger(LoginViewController.class); - - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { - return UserSession.getUserFrom(req.getSession()) - .map(user -> { - log.info("logged in {}", user.getAccount()); - return "redirect:/index.jsp"; - }) - .orElse("/login.jsp"); - } -} diff --git a/app/src/main/java/com/techcourse/controller/LogoutController.java b/app/src/main/java/com/techcourse/controller/LogoutController.java index 4642fd9450..390dd65451 100644 --- a/app/src/main/java/com/techcourse/controller/LogoutController.java +++ b/app/src/main/java/com/techcourse/controller/LogoutController.java @@ -1,15 +1,20 @@ package com.techcourse.controller; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; -public class LogoutController implements Controller { +@Controller +public class LogoutController { - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { + @RequestMapping(value = "/logout", method = RequestMethod.GET) + public ModelAndView execute(final HttpServletRequest req, final HttpServletResponse res) { final var session = req.getSession(); session.removeAttribute(UserSession.SESSION_KEY); - return "redirect:/"; + return new ModelAndView(new JspView("redirect:/")); } } diff --git a/app/src/main/java/com/techcourse/controller/RegisterController.java b/app/src/main/java/com/techcourse/controller/RegisterController.java index 7ab5a429a3..d89e69c57d 100644 --- a/app/src/main/java/com/techcourse/controller/RegisterController.java +++ b/app/src/main/java/com/techcourse/controller/RegisterController.java @@ -14,7 +14,7 @@ public class RegisterController { @RequestMapping(value = "/register", method = RequestMethod.POST) - public ModelAndView save(HttpServletRequest req, HttpServletResponse res) { + public ModelAndView save(final HttpServletRequest req, final HttpServletResponse res) { final var user = new User(2, req.getParameter("account"), req.getParameter("password"), @@ -24,7 +24,7 @@ public ModelAndView save(HttpServletRequest req, HttpServletResponse res) { } @RequestMapping(value = "/register/view", method = RequestMethod.GET) - public ModelAndView show(HttpServletRequest req, HttpServletResponse res) { + public ModelAndView show(final HttpServletRequest req, final HttpServletResponse res) { return new ModelAndView(new JspView("/register.jsp")); } } diff --git a/app/src/main/java/com/techcourse/controller/UserController.java b/app/src/main/java/com/techcourse/controller/UserController.java new file mode 100644 index 0000000000..da0c87c18b --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/UserController.java @@ -0,0 +1,34 @@ +package com.techcourse.controller; + +import com.techcourse.domain.User; +import com.techcourse.repository.InMemoryUserRepository; +import context.org.springframework.stereotype.Controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JsonView; + +@Controller +public class UserController { + + private static final Logger log = LoggerFactory.getLogger(UserController.class); + + @RequestMapping(value = "/api/user", method = RequestMethod.GET) + public ModelAndView show(final HttpServletRequest request, final HttpServletResponse response) { + final String account = request.getParameter("account"); + log.debug("user id : {}", account); + + final ModelAndView modelAndView = new ModelAndView(new JsonView()); + final User user = InMemoryUserRepository.findByAccount(account) + .orElseThrow(); + log.info("user : {}", user); + + modelAndView.addObject("user", user); + return modelAndView; + } +} + diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/ModelAndView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/ModelAndView.java index ff8e24553f..b6b7a66bff 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/ModelAndView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/ModelAndView.java @@ -1,5 +1,8 @@ package webmvc.org.springframework.web.servlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -19,6 +22,10 @@ public ModelAndView addObject(final String attributeName, final Object attribute return this; } + public void render(final HttpServletRequest request, HttpServletResponse response) throws Exception { + view.render(model, request, response); + } + public Object getObject(final String attributeName) { return model.get(attributeName); } diff --git a/app/src/main/java/com/techcourse/DispatcherServlet.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/DispatcherServlet.java similarity index 71% rename from app/src/main/java/com/techcourse/DispatcherServlet.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/DispatcherServlet.java index 6c52f79fc3..af267691c7 100644 --- a/app/src/main/java/com/techcourse/DispatcherServlet.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/DispatcherServlet.java @@ -1,4 +1,4 @@ -package com.techcourse; +package webmvc.org.springframework.web.servlet.mvc; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; @@ -7,13 +7,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.View; -import webmvc.org.springframework.web.servlet.mvc.HandlerAdapter; -import webmvc.org.springframework.web.servlet.mvc.HandlerAdapterFactory; -import webmvc.org.springframework.web.servlet.mvc.HandlerMapping; -import webmvc.org.springframework.web.servlet.mvc.HandlerMappings; - -import java.util.Map; public class DispatcherServlet extends HttpServlet { @@ -32,6 +25,10 @@ public void addHandlerMapping(final HandlerMapping handlerMapping) { handlerMappings.add(handlerMapping); } + public void addNotFoundModelAndView(final ModelAndView modelAndView) { + handlerMappings.addNotFoundHandlerMapping(new SimpleForwardingHandlerMapping(modelAndView)); + } + public void addHandlerAdapterType(final Class handlerType, final Class adapterType) { handlerAdapterFactory.addAdapterType(handlerType, adapterType); } @@ -49,16 +46,11 @@ protected void service(final HttpServletRequest request, final HttpServletRespon final Object handler = handlerMappings.getHandler(request); final HandlerAdapter adapter = handlerAdapterFactory.getAdapter(handler); final ModelAndView modelAndView = adapter.handle(request, response); - render(modelAndView, request, response); + modelAndView.render(request, response); + } catch (Exception e) { log.error("Exception : {}", e.getMessage(), e); throw new ServletException(e.getMessage()); } } - - private void render(final ModelAndView modelAndView, final HttpServletRequest request, final HttpServletResponse response) throws Exception { - final View view = modelAndView.getView(); - final Map model = modelAndView.getModel(); - view.render(model, request, response); - } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/ForwardingExecution.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/ForwardingExecution.java new file mode 100644 index 0000000000..ddc771a32c --- /dev/null +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/ForwardingExecution.java @@ -0,0 +1,21 @@ +package webmvc.org.springframework.web.servlet.mvc; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; + +public class ForwardingExecution extends HandlerExecution { + + private final ModelAndView modelAndView; + + public ForwardingExecution(final ModelAndView modelAndView) { + super(null, null); + this.modelAndView = modelAndView; + } + + @Override + public ModelAndView handle(HttpServletRequest request, HttpServletResponse response) throws Exception { + return modelAndView; + } +} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/HandlerMappings.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/HandlerMappings.java index f33c7150d6..91deed624e 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/HandlerMappings.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/HandlerMappings.java @@ -8,6 +8,7 @@ public class HandlerMappings { private final List handlerMappings; + private HandlerMapping notFoundHandlerMapping; public HandlerMappings() { this.handlerMappings = new ArrayList<>(); @@ -17,6 +18,10 @@ public void add(final HandlerMapping handlerMapping) { handlerMappings.add(handlerMapping); } + public void addNotFoundHandlerMapping(final HandlerMapping notFoundHandlerMapping) { + this.notFoundHandlerMapping = notFoundHandlerMapping; + } + public void initialize() { for (final HandlerMapping handlerMapping : handlerMappings) { handlerMapping.initialize(); @@ -27,7 +32,10 @@ public Object getHandler(final HttpServletRequest request) { final HandlerMapping handlerMapping = handlerMappings.stream() .filter(h -> h.isSupport(request)) .findAny() - .orElseThrow(() -> new RuntimeException("Could not find supporting hanlder for " + request.getMethod() + " " + request.getRequestURI())); + .orElse(notFoundHandlerMapping); + if (handlerMapping == null) { + throw new RuntimeException("Could not find supporting hanlder for " + request.getMethod() + " " + request.getRequestURI()); + } return handlerMapping.getHandler(request); } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/SimpleForwardingHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/SimpleForwardingHandlerMapping.java new file mode 100644 index 0000000000..103ed012f4 --- /dev/null +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/SimpleForwardingHandlerMapping.java @@ -0,0 +1,27 @@ +package webmvc.org.springframework.web.servlet.mvc; + +import jakarta.servlet.http.HttpServletRequest; +import webmvc.org.springframework.web.servlet.ModelAndView; + +public class SimpleForwardingHandlerMapping implements HandlerMapping { + + private final ForwardingExecution forwardingExecution; + + public SimpleForwardingHandlerMapping(final ModelAndView modelAndView) { + this.forwardingExecution = new ForwardingExecution(modelAndView); + } + + @Override + public void initialize() { + } + + @Override + public boolean isSupport(HttpServletRequest request) { + return true; + } + + @Override + public Object getHandler(HttpServletRequest request) { + return forwardingExecution; + } +} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java deleted file mode 100644 index bdd1fde780..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java +++ /dev/null @@ -1,8 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -public interface Controller { - String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception; -} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java deleted file mode 100644 index cd8f1ef371..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java +++ /dev/null @@ -1,20 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import java.util.Objects; - -public class ForwardController implements Controller { - - private final String path; - - public ForwardController(final String path) { - this.path = Objects.requireNonNull(path); - } - - @Override - public String execute(final HttpServletRequest request, final HttpServletResponse response) { - return path; - } -} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java index e2aaa1275e..c9efc51ab1 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java @@ -23,6 +23,7 @@ public class AnnotationHandlerMapping implements HandlerMapping { private final Object[] basePackage; private final Map handlerExecutions; + private HandlerExecution notFoundExecution; public AnnotationHandlerMapping(final Object... basePackage) { this.basePackage = basePackage; @@ -79,12 +80,18 @@ private void putHandler(final Object controller, final Method method) { @Override public boolean isSupport(final HttpServletRequest request) { + if (notFoundExecution != null) { + return true; + } return handlerExecutions.containsKey(getHandlerKey(request)); } @Override public Object getHandler(final HttpServletRequest request) { - return handlerExecutions.get(getHandlerKey(request)); + return handlerExecutions.getOrDefault( + getHandlerKey(request), + notFoundExecution + ); } private HandlerKey getHandlerKey(final HttpServletRequest request) { diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java index b42c3466f0..323252dab5 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java @@ -1,14 +1,47 @@ package webmvc.org.springframework.web.servlet.view; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import web.org.springframework.http.MediaType; import webmvc.org.springframework.web.servlet.View; +import java.io.IOException; +import java.io.PrintWriter; import java.util.Map; public class JsonView implements View { + private static final ObjectMapper objectMapper; + + static { + objectMapper = new ObjectMapper(); + objectMapper.setVisibility(objectMapper.getSerializationConfig() + .getDefaultVisibilityChecker() + .withFieldVisibility(JsonAutoDetect.Visibility.ANY)); + } + @Override public void render(final Map model, final HttpServletRequest request, HttpServletResponse response) throws Exception { + response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + + final String jsonString = writeModelToJsonString(model); + writeResponseBody(response, jsonString); + } + + private String writeModelToJsonString(final Map model) throws JsonProcessingException { + if (model.size() == 1) { + final Object value = model.values().iterator().next(); + return objectMapper.writeValueAsString(value); + } + return objectMapper.writeValueAsString(model); + } + + private void writeResponseBody(final HttpServletResponse response, final String body) throws IOException { + final PrintWriter out = response.getWriter(); + out.write(body); + out.flush(); } }