관심쟁이 영호

[#7 SpringBoot 정주행] ViewResolver를 만들어보자! 본문

Bank-End/Spring Boot

[#7 SpringBoot 정주행] ViewResolver를 만들어보자!

관심쟁이 영호 2021. 9. 13. 14:42
반응형

 

 

[#6-2 Spring Boot 정주행] View Path를 없애보자! ㅣ MVC 프레임워크 만들기

이전 포스팅에서 FrontController를 통해서 공통 처리를 가능하게 하였다. 하지만 View의 Path를 설정하는 부분과, Servlet에서 View & 또 다른 Servlet으로 넘겨주는 함수가 모든 컨트롤러에 적용된다는 것

bestkingit.tistory.com

이전 포스팅에 문제점이 있었다.

문제는

- path에 "/WEB-INF/views/"와 ". jsp"의 중복

- HttpServletRequest, HttpServletResponse의 불필요한 사용

이번 포스팅에서 viewResolver를 통해서 위의 문제를 해결해볼 것이다.

 


목차

  • Model 추가
  • Controller 수정
  • FrontController 수정

 


Model 추가

지금까지는 서블릿에 종속적인 HttpServletRequest를 사용해왔다! 또한 Model도 request에 저장했다. 이제 서블릿에 종속적인 성격을 없애고, view path까지 전달하는 Model을 생성해보자!

 

Model 코드는 다음과 같다.

Model.java

public class Model {
    private String viewTitle;
    private Map<String, Object> model = new HashMap<>();
    public Model(String viewTitle) {
        this.viewTitle = viewTitle;
    }
    public String getViewName() {
        return viewTitle;
    }
    public void setViewName(String viewName) {
        this.viewTitle = viewName;
    }
    public Map<String, Object> getModel() {
        return model;
    }
    public void setModel(Map<String, Object> model) {
        this.model = model;
    }
};
  • viewTitle : Controller가 반환하는 view의 이름이다.
  • model    : Controller가 View에 전달하려는 데이터이다.

Controller 수정

다음으로는 Controller가 Model객체를 이용하도록 바꾸어주어야 한다.

 

UserRegisterController.java 수정

public class UserRegisterController implements TestController{

    private UserRepository userRepository = UserRepository.getInstance();

    @Override
    public Model logic(Map<String, String> requestResponseMap) throws ServletException, IOException {
		
        /*
        * 서블릿으로 넘어온 내용 파싱
        */
        String username = (String) requestResponseMap.get("username"); 
        int age = Integer.parseInt((String) requestResponseMap.get("age"));
 
 
 		//이 부분에서 validation 처리 해야 함! (인터셉터나 필터링으로 낚아채서 해도되고..)
		
        /*
        * Repository에 User 정보 저장
        */
        User user = new User(Long.parseLong(username), age);
        userRepository.save(user);
		
        /*
        * 사용자에게 반환할 View의 정보를 담고있는 Model 생성 후 반환
        */
        Model model = new Model("userList");
        model.getModel().put("user", user);

        return model;

    }

 

UserListController.java 수정

public class UserListController implements TestController{

    private UserRepository userRepository = UserRepository.getInstance();
    @Override
    public Model logic(Map<String, String> requestResponseMap) throws ServletException, IOException {
        List<User> users = userRepository.findAll();

        Model model = new Model("users");
        model.getModel().put("users", users);

        return model;
    }
};

 

BoardListController.java 수정

public class BoardListController implements TestController{

    //board Repository 필요

    @Override
    public Model logic(Map requestResponseMap) throws ServletException, IOException {

        String path = "boardlist";
        
        //board Repository에서 board정보를 찾고 Model의 Map에 해당 Object를 저장해야함
        return new Model(path);
    }
};

 

이 전에는 View를 직접 만들어 넘겨주었다.

하지만 이제는 Model이라는 객체를 따로 만들어서 반환을 해준다.

 


FrontController 수정

Controller가 반환하는 타입이 바뀌었으니, FrontController에도 적용해주어야 한다. 그리고 pathTitle로 반환이 되므로, FrontController에서 suffix, prefix를 더해주는 작업을 해야 한다.

 

다음 코드는 해당 기능들을 적용한 코드이다.

 

FrontController.java

//servlet/test로 시작하는 모든 URI요청은 여기로 받는다.
@WebServlet(name = "frontController", urlPatterns = "servlet/test/*")
public class FrontController extends HttpServlet {

    private Map<String, TestController> controllerList = new HashMap<>();

// Controller는 총 3개이다.
    public FrontController(){
        controllerList.put("servlet/test/boardList", new
                BoardListController());
        controllerList.put("servlet/test/register", new
                UserRegisterController());
        controllerList.put("servlet/test/Users", new
                UserListController());
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse
            resp)
            throws ServletException, IOException {
        String requestURI = req.getRequestURI();
        TestController controller = controllerList.get(requestURI);
        if (controller == null) {
            resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

		// 서블릿에서 넘어온 request와 response를 Map에 담아준다.
        Map<String, String> requestResponseMap = createParamMap(req);
        
        // Contrller에서 반환하는 Model을 받는다.
        Model afterControllerModel= controller.logic(requestResponseMap);
		
        // Model에 있는 viewTitle을 받는다.
        // getter에 오타가 있다.. (예제 코드를 보며 쓰다보니..)
        String viewName = afterControllerModel.getViewName();
		
        // viewTitle에 suffix와 prefix를 붙이는 viewResolver를 동작시킨다.
        View view = viewResolver(viewName);
        
        // view로 넘겨준다.
        view.render(afterControllerModel.getModel(), req, resp);


    }
    
    // 서블릿으로부터 넘어오는 req, resp를 Map에 파싱해주는 메소드
    private Map<String, String> createParamMap(HttpServletRequest request) {
        Map<String, String> requestResponseMap = new HashMap<>();
        request.getParameterNames().asIterator()
                .forEachRemaining(paramName -> requestResponseMap.put(paramName,
                        request.getParameter(paramName)));
        return requestResponseMap;
    }
    
    // viewTitle에 suffix와 prefix를 붙여주는 메소드
    private View viewResolver(String viewName) {
        return new View("/WEB-INF/views/" + viewName + ".jsp");
    }
}

 

주석을 하나씩 달아두었다.

 

전체적인 흐름을 순서대로 보자!

 

  1. 사용자의 요청이 온다.
  2. FrontController로 가장 먼 저 도착한다.
  3. FC는 요청 정보를 보고 해당하는 Controller의 logic 함수를 실행한다.
  4. Controller는 로직을 수행하고 Model 객체(이제.. view 데이터, view title을 곁들인)를 반환한다.
  5. FC는 Model을 받고 model의 view title을 view Resolver를 통해 suffix, prefix를 붙여준다.
  6. view를 실행한다.

글을 마치며..

 

  • 서블릿 종속성을 제거했다!
  • view 코드 중복 문제를 해결했다!

또또또또또또 문제가 있다..ㅋㅋㅋㅋ

 

문제는

개발자가 귀찮다. Model - View구조를 생각하며 하기엔 너무 힘겹다.

매번 객체를 만들어주고 객체를 반환해주고..

 

그래서 다음 포스팅에서는 개발자가 편하게 개발할 수 있는 방향으로 코드를 수정해보자!

 

 

 

 

 

300x250
Comments