Spring MVC : ViewControllerRegistry/ViewControllerRegistration/RedirectViewControllerRegistration

本文详细解析了SpringMVC中ViewControllerRegistry、ViewControllerRegistration及RedirectViewControllerRegistration的概念与用法,阐述了如何通过这些类实现URL模式与视图控制器的映射,包括响应HTTP状态码、渲染特定视图及重定向。

ViewControllerRegistry/ViewControllerRegistration/RedirectViewControllerRegistrationSpring MVC关于URL pattern和视图控制器(view controller)之间映射的注册信息的概念模型类,它们配合使用。

ViewControllerRegistry表示一组URL pattern和视图控制器(view controller)映射关系的注册信息,这一组注册信息中的每一条信息通过一个ViewControllerRegistration或者一个RedirectViewControllerRegistration对象来保存。

一个ViewControllerRegistration表示某一个URL pattern和视图控制器(view controller)之间映射的注册信息,能处理如下两种情况 :

  • 映射一个URL pattern到某个HTTP状态字,也就是请求符合该URL pattern时,会返回给浏览器该HTTP状态字,而不写响应体;
  • 映射一个URL pattern到指定名称的视图。

一个RedirectViewControllerRegistration表示一个重定向视图控制器。

ViewControllerRegistry的典型用法是被某个WebMvcConfigurer实现类用于快捷配置视图控制器映射,使用例子如下所示 :

    /**
     * 初始化配置 ViewControllerRegistry registry
     *
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 请求匹配地址 /absent* 时,响应 HTTP代码403给浏览器端
        registry.addStatusController("/absent*", HttpStatus.FORBIDDEN);
        
        // 请求匹配地址 /fixed* 时,统一使用视图 fixed_content 进行渲染,
        // 适合不需要Web控制器业务逻辑,只需要基于数据模型直接渲染一个页面视图模板的情况
        registry.addViewController("/fixed*").setViewName("fixed_content");
        
        // 请求匹配地址 /home* 时,浏览器同意跳转到 /
        registry.addRedirectViewController("/home*", "/");        
    }

在上面的例子中,registry.addStatusController("/absent*", HttpStatus.FORBIDDEN)其实就是使用了ViewControllerRegistration,其具体用法如下 :

	// ViewControllerRegistry 源代码片段
	/**
	 * Map a simple controller to the given URL path (or pattern) in order to
	 * set the response status to the given code without rendering a body.
	 * @since 4.1
	 */
	public void addStatusController(String urlPath, HttpStatus statusCode) {
		ViewControllerRegistration registration = new ViewControllerRegistration(urlPath);
		registration.setApplicationContext(this.applicationContext);
		registration.setStatusCode(statusCode);
		registration.getViewController().setStatusOnly(true);
		this.registrations.add(registration);
	}

在上面的例子中,registry.addViewController("/fixed*").setViewName("fixed_content")也使用了ViewControllerRegistration,其具体用法如下 :

	// ViewControllerRegistry 源代码片段
	/**
	 * Map a view controller to the given URL path (or pattern) in order to render
	 * a response with a pre-configured status code and view.
	 * Patterns like "/admin/**" or "/articles/{articlename:\\w+}"
	 * are allowed. See org.springframework.util.AntPathMatcher for more details on the
	 * syntax.
	 */
	public ViewControllerRegistration addViewController(String urlPath) {
		ViewControllerRegistration registration = new ViewControllerRegistration(urlPath);
		registration.setApplicationContext(this.applicationContext);
		this.registrations.add(registration);
		return registration;
	}

registry.addRedirectViewController("/home*", "/")则使用到了RedirectViewControllerRegistration,其具体用法如下 :

	// ViewControllerRegistry 源代码片段
	/**
	 * Map a view controller to the given URL path (or pattern) in order to redirect
	 * to another URL. By default the redirect URL is expected to be relative to
	 * the current ServletContext, i.e. as relative to the web application root.
	 * @since 4.1
	 */
	public RedirectViewControllerRegistration addRedirectViewController(String urlPath, 
			String redirectUrl) {
		RedirectViewControllerRegistration registration = 
			new RedirectViewControllerRegistration(urlPath, redirectUrl);
		registration.setApplicationContext(this.applicationContext);
		this.redirectRegistrations.add(registration);
		return registration;
	}

从上面的代码可以看出,其实一个ViewControllerRegistry对象其实是一组ViewControllerRegistration对象,对应其属性registration,和一组RedirectViewControllerRegistration,对应其属性redirectRegistrations

	// ViewControllerRegistry 源代码片段
    // 属性定义
	private final List<ViewControllerRegistration> registrations = new ArrayList<>(4);

	private final List<RedirectViewControllerRegistration> redirectRegistrations = new ArrayList<>(10);

另外,一个ViewControllerRegistration/RedirectViewControllerRegistration最终都是一个这样的映射 :
<URL pattern, 一个 ParameterizableViewController 对象>

当应用开发人员通过上面的registry.addViewController/registry.addStatusController/registry.addRedirectViewController这种方式配置完视图映射关系之后,这些关系会被ViewControllerRegistration registry对象记录下来。然后在应用启动过程中,Spring MVC配置执行阶段,具体来讲,是bean resourceHandlerMapping实例化过程中,这些信息会被使用,如下代码所示 :

	// WebMvcConfigurationSupport 源代码片段
	/**
	 * Return a handler mapping ordered at 1 to map URL paths directly to
	 * view names. To configure view controllers, override
	 * #addViewControllers.
	 */
	@Bean
	@Nullable
	public HandlerMapping viewControllerHandlerMapping() {
       // 创建一个 ViewControllerRegistration registry 对象用于容纳 视图<=>控制器Handler映射 注册信息
		ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
       // 调用开发人员对 视图<=>控制器Handler映射  注册信息的定制逻辑 
		addViewControllers(registry);

        // 生成最终使用的 视图<=>控制器Handler映射  HandlerMapping 对象 : handlerMapping
		AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
		if (handlerMapping == null) {
			return null;
		}
		handlerMapping.setPathMatcher(mvcPathMatcher());
		handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
		handlerMapping.setInterceptors(getInterceptors());
		handlerMapping.setCorsConfigurations(getCorsConfigurations());
		return handlerMapping;
	}

ViewControllerRegistry的具体实现如下 :

	// ViewControllerRegistry 代码片段

	/**
	 * Return the HandlerMapping that contains the registered view
	 * controller mappings, or null for no registrations.
	 * @since 4.3.12
	 */
	@Nullable
	protected SimpleUrlHandlerMapping buildHandlerMapping() {
		if (this.registrations.isEmpty() && this.redirectRegistrations.isEmpty()) {
			return null;
		}

		Map<String, Object> urlMap = new LinkedHashMap<>();
		for (ViewControllerRegistration registration : this.registrations) {
			// 形成一条 url pattern <=>  ParameterizableViewController 映射关系
			// 针对状态字响应或者指定被渲染的视图名称
			urlMap.put(registration.getUrlPath(), registration.getViewController());
		}
		for (RedirectViewControllerRegistration registration : this.redirectRegistrations) {
			// 形成一条 url pattern <=>  ParameterizableViewController 映射关系
			// 针对浏览器端 redirect
			urlMap.put(registration.getUrlPath(), registration.getViewController());
		}

		SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
		handlerMapping.setUrlMap(urlMap);
		handlerMapping.setOrder(this.order);
		return handlerMapping;
	}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值