springMVC实现首页的重定向(<mvc:view-controller>以及<mvc:annotation-driven/>标签使用)

123 篇文章 0 订阅
27 篇文章 3 订阅

一、背景

由于web首页中的数据也需要从后台获取,因此需要走controller。环境myeclipse2014、gradle2.13、win7、tomcat7.0.30


二、实现方式

1. 采用controller方式

对路径“/”进行映射

@RequestMapping("/")
	public String indexPage() throws Exception {
		return "index";     或者为 return "redirect:/index"   重定向到index map中
	}

如果重定向到“/index”,则需要在程序中配置

@RequestMapping("/index")
	public String index() throws Exception {
		return "index";
	}

或者一步到位,对"/"和“/index”都进行配置

@RequestMapping({ "/", "/index" })
	public String index() throws Exception {
		return "index";
	}

2.使用mvc:view-controller标签

在springMVC servlet配置文件配置如下:

<mvc:view-controller path="/" view-name="redirect:/index" />

"/"是访问的path,"/index"是重定向后的path

该标签的解释:

This tag is a shorcut for defining a ParameterizableViewController that immediately forwards to a view when invoked. 
这个标签是为了简化ParameterizableViewController映射到视图的配置

Use it in static cases when there is no Java Controller logic to execute before the view generates the response. 
当响应视图是不需要执行控制器逻辑时使用

An example of view-controller that forwards to a home page is shown below: 
一个跳转到主页的配置例子

<mvc:view-controller path="/" view-name="home"/>

两种用法 
1)、重定向 
<mvc:view-controller path="/" view-name="redirect:/admin/index"/> 
即如果当前路径是/ 则重定向到/admin/index 
2)、view name 
<mvc:view-controller path="/" view-name=admin/index"/> 
如果当前路径是/ 则交给相应的视图解析器直接解析为视图 

三、遇到的问题

1.如果按照以上的配置失败了,请检查你的配置文件中最上方是否配置了相应的命名空间

 xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd"

2.配置成功之后,你可能会发现你访问其他的页面会失败

原因:如果没有<mvc:annotation-driven/>,那么所有的@Controller注解可能就没有解析,所有当有请求时候都没有匹配的处理请求类,就都去<mvc:default-servlet-handler/>即default servlet处理了。

在springmvc配置文件中加上<mvc:annotation-driven/>即可(使用注解方式设置的springMVC需要加上此设置)

该标签的作用:

This tag registers the DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter beans that are required for Spring MVC to dispatch requests to Controllers. 
这个标签注册了Spring MVC分发请求到控制器所必须的DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter实例,已经被RequestMappingHandlerMapping替代。

3.发现重定向没有成功

删除webapp下的index.jsp(可以不用删除,只要做了相关映射及视图配置)


将web.xml中的如下信息删除(可以不用删除,只要做了相关映射及视图配置)

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
</welcome-file-list>
将index放到springmvc配置的目录下

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> -->
		<!-- 前缀 -->	
		<property name="prefix" value="/WEB-INF/views/jsp/" />
		<!-- 后缀 -->
		<property name="suffix" value=".jsp" />
	</bean>


四、顺便附上解析<mvc:annotation-driven/>及<view-controller>自定义标签的源码

根据spring配置文件的解析原则,可参见Spring实战篇系列----Spring配置文件的解析 由springMVC中的META-INF/spring.handlers可知该自定义标签是在MvcNamespaceHandler中注册的

spring.handlers

http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler

MvcNamespaceHandler.java

/*
 * Copyright 2002-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet.config;

import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 * {@link NamespaceHandler} for Spring MVC configuration namespace.
 *
 * @author Keith Donald
 * @author Jeremy Grelle
 * @author Sebastien Deleuze
 * @since 3.0
 */
public class MvcNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
		registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
		registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
		registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
		registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
	}

}

1)<mvc:annotation-driven/>自定义标签的解析器为AnnotationDrivenBeanDefinitionParser,其中的parse函数为

@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		Object source = parserContext.extractSource(element);
		XmlReaderContext readerContext = parserContext.getReaderContext();

		CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
		parserContext.pushContainingComponent(compDefinition);

		RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);

		RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
		handlerMappingDef.setSource(source);
		handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		handlerMappingDef.getPropertyValues().add("order", 0);
		handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);

		if (element.hasAttribute("enable-matrix-variables")) {
			Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
			handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
		}
		else if (element.hasAttribute("enableMatrixVariables")) {
			Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables"));
			handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
		}

		configurePathMatchingProperties(handlerMappingDef, element, parserContext);
		readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef);

		RuntimeBeanReference corsConfigurationsRef = MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source);
		handlerMappingDef.getPropertyValues().add("corsConfigurations", corsConfigurationsRef);

		RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
		RuntimeBeanReference validator = getValidator(element, source, parserContext);
		RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);

		RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
		bindingDef.setSource(source);
		bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		bindingDef.getPropertyValues().add("conversionService", conversionService);
		bindingDef.getPropertyValues().add("validator", validator);
		bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);

		ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
		ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext);
		ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);
		String asyncTimeout = getAsyncTimeout(element);
		RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
		ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext);
		ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);

		RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
		handlerAdapterDef.setSource(source);
		handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
		handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
		handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
		addRequestBodyAdvice(handlerAdapterDef);
		addResponseBodyAdvice(handlerAdapterDef);

		if (element.hasAttribute("ignore-default-model-on-redirect")) {
			Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
			handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
		}
		else if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
			// "ignoreDefaultModelOnRedirect" spelling is deprecated
			Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));
			handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
		}

		if (argumentResolvers != null) {
			handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
		}
		if (returnValueHandlers != null) {
			handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
		}
		if (asyncTimeout != null) {
			handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
		}
		if (asyncExecutor != null) {
			handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
		}

		handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
		handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
		readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME , handlerAdapterDef);

		String uriCompContribName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
		RootBeanDefinition uriCompContribDef = new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
		uriCompContribDef.setSource(source);
		uriCompContribDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
		uriCompContribDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
		readerContext.getRegistry().registerBeanDefinition(uriCompContribName, uriCompContribDef);

		RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
		csInterceptorDef.setSource(source);
		csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
		RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
		mappedCsInterceptorDef.setSource(source);
		mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
		mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
		String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedCsInterceptorDef);

		RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
		exceptionHandlerExceptionResolver.setSource(source);
		exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
		exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
		exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);
		addResponseBodyAdvice(exceptionHandlerExceptionResolver);

		if (argumentResolvers != null) {
			exceptionHandlerExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
		}
		if (returnValueHandlers != null) {
			exceptionHandlerExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
		}

		String methodExceptionResolverName = readerContext.registerWithGeneratedName(exceptionHandlerExceptionResolver);

		RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
		responseStatusExceptionResolver.setSource(source);
		responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		responseStatusExceptionResolver.getPropertyValues().add("order", 1);
		String responseStatusExceptionResolverName =
				readerContext.registerWithGeneratedName(responseStatusExceptionResolver);

		RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
		defaultExceptionResolver.setSource(source);
		defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		defaultExceptionResolver.getPropertyValues().add("order", 2);
		String defaultExceptionResolverName =
				readerContext.registerWithGeneratedName(defaultExceptionResolver);

		parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
		parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
		parserContext.registerComponent(new BeanComponentDefinition(uriCompContribDef, uriCompContribName));
		parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName));
		parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
		parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
		parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));

		// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
		MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

		parserContext.popAndRegisterContainingComponent();

		return null;
	}

可知解析器注册了多个bean,RequestMappingHandlerMappingBeanNameUrlHandlerMappingRequestMappingHandlerAdapterHttpRequestHandlerAdapterSimpleControllerHandlerAdapterExceptionHandlerExceptionResolverResponseStatusExceptionResolverDefaultHandlerExceptionResolver  前两个是HandlerMapping接口的实现类,用来处理请求映射的。其中第一个是处理@RequestMapping注解的。第二个会将controller类的名字映射为请求url。中间三个是用来处理请求的。具体点说就是确定调用哪个controller的哪个方法来处理当前请求。第一个处理@Controller注解的处理器,支持自定义方法参数和返回值(很酷)。第二个是处理继承HttpRequestHandler的处理器。第三个处理继承自Controller接口的处理器。后面三个是用来处理异常的解析器。<context:component-scan/>标签是告诉Spring 来扫描指定包下的类,并注册被@Component,@Controller,@Service,@Repository等注解标记的组件。 而<mvc:annotation-driven/>是告知Spring,我们启用注解驱动。然后Spring会自动为我们注册上面说到的几个Bean到工厂中,来处理我们的请求。


2)自定义标签<view-controller>、<redirect-view-controller>,<status-controller>的解析器ViewControllerBeanDefinitionParser.java
public BeanDefinition parse(Element element, ParserContext parserContext) {
		Object source = parserContext.extractSource(element);

		// Register SimpleUrlHandlerMapping for view controllers
		BeanDefinition hm = registerHandlerMapping(parserContext, source);

		// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
		MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

		// Create view controller bean definition
		RootBeanDefinition controller = new RootBeanDefinition(ParameterizableViewController.class);
		controller.setSource(source);

		HttpStatus statusCode = null;
		if (element.hasAttribute("status-code")) {
			int statusValue = Integer.valueOf(element.getAttribute("status-code"));
			statusCode = HttpStatus.valueOf(statusValue);
		}

		String name = element.getLocalName();
		if (name.equals("view-controller")) {
			if (element.hasAttribute("view-name")) {
				controller.getPropertyValues().add("viewName", element.getAttribute("view-name"));
			}
			if (statusCode != null) {
				controller.getPropertyValues().add("statusCode", statusCode);
			}
		}
		else if (name.equals("redirect-view-controller")) {
			controller.getPropertyValues().add("view", getRedirectView(element, statusCode, source));
		}
		else if (name.equals("status-controller")) {
			controller.getPropertyValues().add("statusCode", statusCode);
			controller.getPropertyValues().add("statusOnly", true);
		}
		else {
			// Should never happen...
			throw new IllegalStateException("Unexpected tag name: " + name);
		}

		Map<String, BeanDefinition> urlMap;
		if (hm.getPropertyValues().contains("urlMap")) {
			urlMap = (Map<String, BeanDefinition>) hm.getPropertyValues().getPropertyValue("urlMap").getValue();
		}
		else {
			urlMap = new ManagedMap<String, BeanDefinition>();
			hm.getPropertyValues().add("urlMap", urlMap);
		}
		urlMap.put(element.getAttribute("path"), controller);

		return null;
	}

private BeanDefinition registerHandlerMapping(ParserContext context, Object source) {
		if (context.getRegistry().containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) {
			return context.getRegistry().getBeanDefinition(HANDLER_MAPPING_BEAN_NAME);
		}
		RootBeanDefinition beanDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
		beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		context.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, beanDef);
		context.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_BEAN_NAME));

		beanDef.setSource(source);
		beanDef.getPropertyValues().add("order", "1");
		beanDef.getPropertyValues().add("pathMatcher", MvcNamespaceUtils.registerPathMatcher(null, context, source));
		beanDef.getPropertyValues().add("urlPathHelper", MvcNamespaceUtils.registerUrlPathHelper(null, context, source));
		RuntimeBeanReference corsConfigurationsRef = MvcNamespaceUtils.registerCorsConfigurations(null, context, source);
		beanDef.getPropertyValues().add("corsConfigurations", corsConfigurationsRef);

		return beanDef;
	}

	private RootBeanDefinition getRedirectView(Element element, HttpStatus status, Object source) {
		RootBeanDefinition redirectView = new RootBeanDefinition(RedirectView.class);
		redirectView.setSource(source);
		redirectView.getConstructorArgumentValues().addIndexedArgumentValue(0, element.getAttribute("redirect-url"));

		if (status != null) {
			redirectView.getPropertyValues().add("statusCode", status);
		}

		if (element.hasAttribute("context-relative")) {
			redirectView.getPropertyValues().add("contextRelative", element.getAttribute("context-relative"));
		}
		else {
			redirectView.getPropertyValues().add("contextRelative", true);
		}

		if (element.hasAttribute("keep-query-params")) {
			redirectView.getPropertyValues().add("propagateQueryParams", element.getAttribute("keep-query-params"));
		}

		return redirectView;
	}





  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值