자바생
article thumbnail
728x90

새싹 스터디 3주차 미션을 하다가 MVC 패턴에서 URI를 View에 쉽게 매핑하는 방법을 배웠다

예로 Form을 요청받을 때, 굳이 controller에서 매핑되는 메서드를 사용할 필요 없이WebMvcConfigurer를 사용하여 매핑을 해줄 수 있다.

하지만 코드 중에 setOrder라는 메서드를 사용했다.

오늘은 order는 어디에 사용되는지 알아보기 위해 글을 써보겠다!

해결해야 할 의문점

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.setOrder(Ordered.LOWEST_PRECEDENCE);

//        registry.addViewController("/user").setViewName("user/list"); 이 위치에 있으면 LOW, HIGH 모두 form이 나옴
        registry.addViewController("/user").setViewName("user/form");
        registry.addViewController("/users/login").setViewName("user/login");
        registry.addViewController("/questions/form").setViewName("qna/form");
        registry.addViewController("/user").setViewName("user/list"); //이 위치에 있으면 HIGH일 때 list가 나오고, LOW이면 form이 나옴
    }
}

//회원가입 폼
@GetMapping("/user")
public String createForm(Model model) {
    model.addAttribute("question", new User());
    return "/user/form";
}
  1. registry.addViewController("/user").setViewName("user/list");
    • 위 코드를 제일 위에 위치할 경우
      • LOWEST_PRECEDENCE
      • HIGHEST_PRECEDENCE
      • 모두 user/form.html
    • 위 코드를 제일 아래에 위치할 경우
      • LOWEST_PRECEDENCE
        • user/form.html
      • HIGHEST_PRECEDENCE
        • user/list.html
  2. 왜 위와 같은 결과가 나올까??

setOrder

공식문서의 setOrder에서는

Specify the order to use for the {@code HandlerMapping} used to map view controllers relative to other handler mappings configured in Spring MVC. By default this is set to 1, i.e. right after annotated controllers, which are ordered at 0.

  • Spring MVC에 구성된 다른 핸들러 매핑과 관련하여 뷰 컨트롤러를 매핑하는데 사용되는 HandlerMapping에 사용할 순서를 지정
  • 즉, HandlerMapping을 구현하는 여러 핸들러들이 존재하는데 뷰 컨트롤러를 HandlerMapping에서 몇 번쨰로 사용할 것인지 순서를 지정하는 것을 의미
  • 숫자가 작을수록 우선순위 높음

ViewControllerRegistry는 어떻게 동작할까?

addViewController

public ViewControllerRegistration addViewController(String urlPath) {
		ViewControllerRegistration registration = new ViewControllerRegistration(urlPath);
		registration.setApplicationContext(this.applicationContext);
		this.registrations.add(registration);
		return registration;
	}
  • URI를 필드로 가진 ViewControllerRegistration 객체를 생성하고 List에 넣어줌

buildHandlerMapping

	@Nullable
	protected SimpleUrlHandlerMapping buildHandlerMapping() {
		if (this.registrations.isEmpty() && this.redirectRegistrations.isEmpty()) {
			return null;
		}

		Map<String, Object> urlMap = new LinkedHashMap<>();
		for (ViewControllerRegistration registration : this.registrations) {
			urlMap.put(registration.getUrlPath(), registration.getViewController());
		}
		for (RedirectViewControllerRegistration registration : this.redirectRegistrations) {
			urlMap.put(registration.getUrlPath(), registration.getViewController());
		}

		SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
		handlerMapping.setUrlMap(urlMap);
		handlerMapping.setOrder(this.order);
		return handlerMapping;
	}
  • List에 저장된 ViewControllerRegistration를 Map의 value로 사용함
  • Map에 저장되는데 왜 순서가 필요할까? 라는 의문점을 가짐

그렇다면 이제 왜 처음과 같은 결과가 나오는지 파헤쳐보자!

처음과 같은 결과가 나온 이유

  • registry.addViewController("/user").setViewName("user/list");
    • 위 코드를 제일 위에 위치할 경우
      • LOWEST_PRECEDENCE
      • HIGHEST_PRECEDENCE
      • 모두 user/form.html
    • 위 코드를 제일 아래에 위치할 경우
      • LOWEST_PRECEDENCE
        • user/form.html
      • HIGHEST_PRECEDENCE
        • user/list.html
  1. registry.addViewController("/user").setViewName("user/list") 가 제일 위에 위치할 경우
    1. 앞서 buildHandlerMapping에서 Map을 이용하여 저장함
    2. Map은 같은 key가 나올 경우, 최근 값으로 덮어씌움
    3. 마지막에 저장된 값은 /user - user/form
    4. controller에서도 /user는 user/form으로 매핑되어있음
    5. 따라서 order가 LOWEST, HIGHEST 상관없이 form이 나오게 됨
  2. registry.addViewController("/user").setViewName("user/list") 가 제일 뒤에 위치할 경우
    1. 위와 같은 원리로 Map에는 /user - user/list 가 저장되있음
    2. controller에선 /user는 user/form으로 매핑되어있음
    3. order가 LOWEST일 경우 우선순위가 제일 낮아짐
      1. controller에 매핑된 메서드의 우선순위가 더 높아짐
      2. view는 form
    4. order가 HIGHEST일 경우 우선순위가 제일 높아짐
      1. controller에 매핑된 메서드보다 우선순위가 더 높아짐
      2. view는 list

createForm에 브레이크 포인트를 걸고 디버깅을 해봄

  • LOWEST일 경우 controller의 메서드에 걸림
  • HIGHEST일 경우 controller의 메서드에 걸리지 않음

HandlerMapping 구현체들이 많다고 했는데, 각 구현체들의 순서는 어떻게 되고, 누가 정하나요?

  • WebMvcConfigurationSupport 에서 구현체들의 순서를 setOrder를 통해 정함
  • 같은 order 값을 가질 때는 순서 보장이 되지 않음!
  • 해당 HandlerMapping에서 처리하지 못하면 다음 우선순위로 넘어감!

RequestMappingHandlerMapping

@Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping() {
		RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
		mapping.setOrder(0);

		//나머지 구현
}

BeanNameUrlHandlerMapping

@Bean
	public BeanNameUrlHandlerMapping beanNameHandlerMapping() {
		BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
		mapping.setOrder(2)

		//나머지 구현
}

 

REFERENCES

스프링 공식문서

728x90
profile

자바생

@자바생

틀린 부분이 있다면 댓글 부탁드립니다~😀

검색 태그