`

SpringMVC源码总结(二)mvc:annotation-driven以及@Controller和@RequestMapping的那些事

阅读更多
上一篇文章让我们了解HandlerMapping和HandlerAdapter以及默认采取的策略,这篇文章就要讲述mvc:annotation-driven对默认策略的改变。它背后到底注册了哪些HandlerMapping和HandlerAdapter。

首先可以在DispatcherServlet的initStrategies方法中的initHandlerMappings和initHandlerAdapters中打上断点,来查看注册了哪些HandlerMapping和HandlerAdapter

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

目前我的spring版本是4.0.5。我查看的结果:
HandlerMapping:注册了 RequestMappingHandlerMapping和BeanNameUrlHandlerMapping
HandlerAdapter:注册了 RequestMappingHandlerAdapter、HttpRequestHandlerAdapter和SimpleControllerHandlerAdapter
这几个HandlerMapping和HandlerAdapter上文都提到过。
下面就要查看下具体的注册过程:
在xml文件中配置mvc:annotation-driven,肯定有一个专门的类来解析处理这个东西。
会有这样的一个接口BeanDefinitionParser,它只有一个方法:

public interface BeanDefinitionParser {

	/**
	 * Parse the specified {@link Element} and register the resulting
	 * {@link BeanDefinition BeanDefinition(s)} with the
	 * {@link org.springframework.beans.factory.xml.ParserContext#getRegistry() BeanDefinitionRegistry}
	 * embedded in the supplied {@link ParserContext}.
	 * <p>Implementations must return the primary {@link BeanDefinition} that results
	 * from the parse if they will ever be used in a nested fashion (for example as
	 * an inner tag in a {@code <property/>} tag). Implementations may return
	 * {@code null} if they will <strong>not</strong> be used in a nested fashion.
	 * @param element the element that is to be parsed into one or more {@link BeanDefinition BeanDefinitions}
	 * @param parserContext the object encapsulating the current state of the parsing process;
	 * provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
	 * @return the primary {@link BeanDefinition}
	 */
	BeanDefinition parse(Element element, ParserContext parserContext);

}

它是用来专门处理<beans></beans>里面的配置元素。然后我们会找到这样的一个实现类AnnotationDrivenBeanDefinitionParser,它的文档介绍如下:
/**
 * 这里清清楚楚写着该类是专门处理 <mvc:annotation-driven/>标签的
 * A {@link BeanDefinitionParser} that provides the configuration for the
 * {@code <annotation-driven/>} MVC namespace  element.
 *
 * 这里说明了注册的HandlerMapping
 * <p>This class registers the following {@link HandlerMapping}s:</p>
 * <ul>
 * 	<li>{@link RequestMappingHandlerMapping}
 * 	ordered at 0 for mapping requests to annotated controller methods.
 * 	<li>{@link BeanNameUrlHandlerMapping}
 * 	ordered at 2 to map URL paths to controller bean names.
 * </ul>
 *
 * <p><strong>Note:</strong> Additional HandlerMappings may be registered
 * as a result of using the {@code <view-controller>} or the
 * {@code <resources>} MVC namespace elements.
 *
 * 这里说明了注册的HandlerAdapter
 * <p>This class registers the following {@link HandlerAdapter}s:
 * <ul>
 * 	<li>{@link RequestMappingHandlerAdapter}
 * 	for processing requests with annotated controller methods.
 * 	<li>{@link HttpRequestHandlerAdapter}
 * 	for processing requests with {@link HttpRequestHandler}s.
 * 	<li>{@link SimpleControllerHandlerAdapter}
 * 	for processing requests with interface-based {@link Controller}s.
 * </ul>
 *
 * <p>This class registers the following {@link HandlerExceptionResolver}s:
 * <ul>
 * 	<li>{@link ExceptionHandlerExceptionResolver} for handling exceptions
 * 	through @{@link ExceptionHandler} methods.
 * 	<li>{@link ResponseStatusExceptionResolver} for exceptions annotated
 * 	with @{@link ResponseStatus}.
 * 	<li>{@link DefaultHandlerExceptionResolver} for resolving known Spring
 * 	exception types
 * </ul>
 *
 * <p>Both the {@link RequestMappingHandlerAdapter} and the
 * {@link ExceptionHandlerExceptionResolver} are configured with instances of
 * the following by default:
 * <ul>
 * 	<li>A {@link ContentNegotiationManager}
 * 	<li>A {@link DefaultFormattingConversionService}
 * 	<li>A {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean}
 * 	if a JSR-303 implementation is available on the classpath
 * 	<li>A range of {@link HttpMessageConverter}s depending on what 3rd party
 * 	libraries are available on the classpath.
 * </ul>
 *
 * @author Keith Donald
 * @author Juergen Hoeller
 * @author Arjen Poutsma
 * @author Rossen Stoyanchev
 * @author Brian Clozel
 * @since 3.0
 */
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
          //先省略,请详细看下它的文档介绍
}

上面的文档对mvc:annotation-driven注册的东西都有详细的说明。
具体看解析过程的代码的内容:

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

		//省略
		RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
		
		RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
		
            //省略,
		// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
		MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

		parserContext.popAndRegisterContainingComponent();

		return null;
	}

MvcNamespaceUtils.registerDefaultComponents的内容如下:
public static void registerDefaultComponents(ParserContext parserContext, Object source) {
		registerBeanNameUrlHandlerMapping(parserContext, source);
		registerHttpRequestHandlerAdapter(parserContext, source);
		registerSimpleControllerHandlerAdapter(parserContext, source);
	}

至此所注册的HandlerMapping和HandlerAdapter我们都找到了。
然后我们就可以体验下RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,这两个HandlerMapping。由于上一篇文章已经体验过了BeanNameUrlHandlerMapping,接下来就要体验下RequestMappingHandlerMapping,然后你会发觉又有一系列的新名词走进我们的视野,需要我们去弄清楚。
先体验下:

首先还是web.xml的配置:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
		<servlet-name>mvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>mvc</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

最简单的配置,然后是[servlet-name]-servlet.xml,本工程即mvc-servlet.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
	http://www.springframework.org/schema/mvc
	http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
	http://www.springframework.org/schema/util
	http://www.springframework.org/schema/util/spring-util-2.0.xsd
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-3.2.xsd">
	
	
	<mvc:annotation-driven/>
	
	<bean class="com.lg.mvc.StringAction"/>
	<bean name="/index" class="com.lg.mvc.HomeAction"></bean>
	
	
	<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
		<property name="templateLoaderPath" value="/WEB-INF/views" />
		<property name="defaultEncoding" value="utf-8" />
		<property name="freemarkerSettings">
			<props>
				<prop key="locale">zh_CN</prop>
			</props>
		</property>
	</bean>
	<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
		<property name="suffix" value=".html" />
		<property name="contentType" value="text/html;charset=utf-8" />
		<property name="requestContextAttribute" value="request" />
		<property name="exposeRequestAttributes" value="true" />
		<property name="exposeSessionAttributes" value="true" />
	</bean>
</beans>

开启了<mvc:annotation-driven/>,同时注册了两个bean。有RequestMappingHandlerMapping和RequestMappingHandlerAdapter作为后盾支持,然后我们就可以在bean中使用@Controller和@RequestMapping两个标签了。@Controller本身其实与@RequestMapping无关的,它只是@Component中的一个重要的标签而已,但是我们会在源码里看到它对RequestMappingHandlerMapping也是挺重要的,但不是必须的。这里简单说明下:RequestMappingHandlerMapping它会判断一个bean是否含有@Controller标签或者@RequestMapping,如果有其一则会将该bean纳入作为它的处理对象,之后会进一步处理该类上含有@RequestMapping注解的方法。这样做主要是由于@RequestMapping可以配置在类上(作为基础地址),也可以配置在方法上,我们有时候会在类上配置@RequestMapping,有时候又不会,所以只要类含有@Controller或者含有@RequestMapping,RequestMappingHandlerMapping都会将他们纳入自己的handler管辖范围。所以仅仅在方法中含有@RequestMapping注解是不被处理的,必须在类上加入@RequestMapping或者@Controller,而@Controller又不是必须的,你可以试验下,稍后会做源代码说明。下面继续,列出使用了@Controller和@RequestMapping注解的StringAction类
package com.lg.mvc;

import java.io.UnsupportedEncodingException;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class StringAction {
	
	@ResponseBody
	@RequestMapping(value="/string",method=RequestMethod.GET)
	public String testMessageConverter(String name) throws UnsupportedEncodingException{
		System.out.println(name);
		return name;
	}
}

然后就可以运行一下,体验一下,先不要管乱码问题,这个问题引出了下一篇文章spring框架中的乱码问题。
运行结果如下:


证明整个流程跑通了。
首先@Controller使得StringAction这个handler纳入RequestMappingHandlerMapping管理,RequestMappingHandlerMapping会将这个handler和handler中的每一个含有@RequestMapping的方法都会构建成一个HandlerMethod对象,该类的构造函数为HandlerMethod(Object bean, Method method),经过这样的包装之后将构造的HandlerMethod对象作为新的handler,然后进行选择适配器,进行方法调用,当RequestMappingHandlerAdapter判断是否support一个类时,就是依据当前的handlelr是否是HandlerMethod类型。若是则由RequestMappingHandlerAdapter来调度执行该handler(handler为HandlerMethod类型)的中的method方法。以上就是整个大体的流程。下面就要用代码来事实说话:
第一步要弄清RequestMappingHandlerMapping在初始化时是如何寻找它所管辖的bean。说说我找代码的具体流程:
RequestMappingHandlerMapping的父类AbstractHandlerMethodMapping在初始化时,会调用到这样的一个方法initHandlerMethods,在该方法中,遍历所有的bean然后判断他们是不是含有@Controller或者@RequestMapping注解:

/**
	 * Scan beans in the ApplicationContext, detect and register handler methods.
	 * @see #isHandler(Class)
	 * @see #getMappingForMethod(Method, Class)
	 * @see #handlerMethodsInitialized(Map)
	 */
	protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}

		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		for (String beanName : beanNames) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&
					isHandler(getApplicationContext().getType(beanName))){
				detectHandlerMethods(beanName);
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

其中的isHandler的判断方法代码如下:
/**
	 * {@inheritDoc}
	 * Expects a handler to have a type-level @{@link Controller} annotation.
	 */
	@Override
	protected boolean isHandler(Class<?> beanType) {
		return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
				(AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
	}

如果handler含有了上述注解的其中之一,就会进一步处理该handler的方法中含有@RequestMapping的方法:
/**
	 * Look for handler methods in a handler.
	 * @param handler the bean name of a handler or a handler instance
	 */
	protected void detectHandlerMethods(final Object handler) {
		Class<?> handlerType =
				(handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());

		// Avoid repeated calls to getMappingForMethod which would rebuild RequestMappingInfo instances
		final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
		final Class<?> userType = ClassUtils.getUserClass(handlerType);

		Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
			@Override
			public boolean matches(Method method) {
				T mapping = getMappingForMethod(method, userType);
				if (mapping != null) {
					mappings.put(method, mapping);
					return true;
				}
				else {
					return false;
				}
			}
		});

		for (Method method : methods) {
			registerHandlerMethod(handler, method, mappings.get(method));
		}
	}

遍历这个handler类的所有方法,过滤条件就是这个内部类MethodFilter,其中的getMappingForMethod方法内容为:
/**
	 * Uses method and type-level @{@link RequestMapping} annotations to create
	 * the RequestMappingInfo.
	 * @return the created RequestMappingInfo, or {@code null} if the method
	 * does not have a {@code @RequestMapping} annotation.
	 * @see #getCustomMethodCondition(Method)
	 * @see #getCustomTypeCondition(Class)
	 */
	@Override
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		RequestMappingInfo info = null;
		RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
		if (methodAnnotation != null) {
			RequestCondition<?> methodCondition = getCustomMethodCondition(method);
			info = createRequestMappingInfo(methodAnnotation, methodCondition);
			RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
			if (typeAnnotation != null) {
				RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
				info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
			}
		}
		return info;
	}

如找到了含有RequestMapping注释的方法,则由这个注释的内容构建一个RequestMappingInfo对象:
/**
	 * Created a RequestMappingInfo from a RequestMapping annotation.
	 */
	protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {
		String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
		return new RequestMappingInfo(
				new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
						this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
				new RequestMethodsRequestCondition(annotation.method()),
				new ParamsRequestCondition(annotation.params()),
				new HeadersRequestCondition(annotation.headers()),
				new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
				new ProducesRequestCondition(annotation.produces(), annotation.headers(), this.contentNegotiationManager),
				customCondition);
	}

就是拿RequestMapping注释的内容进一步封装进RequestMappingInfo对象中。对handler的所有方法过滤完成之后,就要遍历这些方法,以一定的方式存储起来。
/**
	 * Register a handler method and its unique mapping.
	 * @param handler the bean name of the handler or the handler instance
	 * @param method the method to register
	 * @param mapping the mapping conditions associated with the handler method
	 * @throws IllegalStateException if another method was already registered
	 * under the same mapping
	 */
	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
		HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);
		if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
			throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() +
					"' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" +
					oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
		}

		this.handlerMethods.put(mapping, newHandlerMethod);
		if (logger.isInfoEnabled()) {
			logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
		}

		Set<String> patterns = getMappingPathPatterns(mapping);
		for (String pattern : patterns) {
			if (!getPathMatcher().isPattern(pattern)) {
				this.urlMap.add(pattern, mapping);
			}
		}
	}

这里的this.handlerMethods就包含了所有管辖的bean,key为RequestMappingInfo对象,value为handler和它中含有@RequestMapping注释的方法method构建的HandlerMethod。
如下所示:

/**
	 * Create the HandlerMethod instance.
	 * @param handler either a bean name or an actual handler instance
	 * @param method the target method
	 * @return the created HandlerMethod
	 */
	protected HandlerMethod createHandlerMethod(Object handler, Method method) {
		HandlerMethod handlerMethod;
		if (handler instanceof String) {
			String beanName = (String) handler;
			handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);
		}
		else {
			handlerMethod = new HandlerMethod(handler, method);
		}
		return handlerMethod;
	}

至此,RequestMappingHandlerMapping的初始化注册工作就完成了。然后就是等待请求,访问
http://localhost:8080/string?name=aa,RequestMappingHandlerMapping会匹配到由StringAction对象和它的包含注释的方法testMessageConverter构建的HandlerMethod对象,该对象将作为handler,然后再遍历HandlerAdapter判断它们是否支持这个handler,RequestMappingHandlerAdapter的判断依据为是否是HandlerMethod 类型(在AbstractHandlerMethodAdapter类中):

public final boolean supports(Object handler) {
		return handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler);
	}

然后将得到匹配,有了这个HandlerMethod对象,便可以通过RequestMappingHandlerAdapter来调度执行HandlerMethod其中的方法。
分享到:
评论

相关推荐

    SpringMVC源码总结(三)mvc:annotation-driven和mvc:message-converters简单介绍

    通过使用这个元素,我们可以启用Spring MVC自动扫描并处理带有`@Controller`注解的类,以及类中的`@RequestMapping`、`@RequestParam`等注解。这意味着我们无需手动配置处理器映射器(HandlerMapping)和处理器...

    SpringMVC源码总结(二)mvc:mvc:annotation-driven背后的那些事

    在Spring MVC框架中,`mvc:annotation-driven`是Spring MVC配置中的一个重要元素,它使得我们的应用能够支持基于注解的控制器、数据绑定、格式化转换器和服务端验证等功能。这篇博客将深入探讨`mvc:annotation-...

    (代码)SpringMVC第12讲:<mvc:annotation-driven/>

    首先,`&lt;mvc:annotation-driven/&gt;`的作用是自动配置Spring MVC,启用对处理方法注解的支持,如`@RequestMapping`、`@RequestParam`、`@ModelAttribute`等。通过这个元素,我们可以避免编写大量的XML配置,转而采用...

    license.txt

    &lt;mvc:annotation-driven&gt; &lt;/mvc:annotation-driven&gt; 中配置Json格式乱码。代码如下: &lt;!--json格式乱码处理--&gt; &lt;mvc:message-converters register-defaults="true"&gt; &lt;constructor-arg value="UTF-8"/&gt;

    SpringMVC中解决@ResponseBody注解返回中文乱码问题

    总的来说,解决SpringMVC中`@ResponseBody`注解返回中文乱码问题的关键在于正确配置`HttpMessageConverter`,确保其支持UTF-8编码,并将这些配置放在`&lt;mvc:annotation-driven&gt;`元素之前。通过上述方法,可以有效地...

    Spring源码学习十一:SpringMVC-@RequestBody接收json数据报4151

    深入源码分析,`&lt;mvc:annotation-driven /&gt;` 是Spring MVC中用于启用注解驱动的配置元素,它会自动配置一些关键组件,包括消息转换器。`MvcNamespaceHandler` 是处理这个注解的命名空间处理器,而`...

    SpringMVC------从HelloWorld开始

    它利用注解简化了控制器的配置,通过`@RequestMapping`将URL映射到处理方法,`@Controller`和`@ResponseBody`帮助我们管理请求和响应。此外,SpringMVC还支持视图解析、数据绑定、异常处理等功能,极大地提高了开发...

    一个简单的springMVC项目的配置文件 ---- 2016-05-31

    标签“源码”和“工具”表明这篇文章可能涉及到实际的代码示例以及可能使用的开发工具,如IDE或构建工具(如Maven或Gradle),这些工具在构建Spring MVC项目时是常见的。 由于没有具体的压缩包文件内容,我将基于...

    SpringMVC核心配置文件示例.rar

    开启`&lt;mvc:annotation-driven&gt;`可启用Spring MVC对注解的处理,比如@Controller、@RequestMapping等: ```xml &lt;mvc:annotation-driven/&gt; ``` 8. **静态资源处理**: 可以配置Spring MVC处理静态资源,例如...

    SPRING MVC3.2案例讲解---配置

    `mvc:annotation-driven`则是开启Spring MVC的注解驱动,支持我们在Controller方法上使用@RequestMapping等注解。 除了基本配置,我们还可以配置拦截器(Interceptor)、异常处理器(HandlerExceptionResolver)...

    SpringMVC关于json、xml自动转换的原理研究.pdf

    `&lt;mvc:annotation-driven&gt;`配置是这一过程的关键,它创建并配置了必要的组件,确保数据能够正确地序列化和反序列化。理解这个机制对于优化性能、处理复杂的数据格式转换以及扩展Spring MVC的功能至关重要。

    spring-mvc 注解方式xml配置

    在这里,`@RestController`注解表示这是一个RESTful风格的控制器,它结合了`@Controller`和`@ResponseBody`的功能,意味着该控制器方法的返回值会直接转换为HTTP响应体。`@RequestMapping("/model1")`注解定义了一个...

    Spring MVC--6.RESTful SpringMVC CRUD

    在实现上述功能时,Spring MVC提供了一些核心组件,如`DispatcherServlet`(负责分发请求)、`ModelAndView`(用于处理模型和视图)、`@Controller`和`@RequestMapping`(映射HTTP请求),以及`@PathVariable`、`@...

    springMVC.doc

    - `&lt;mvc:annotation-driven&gt;` 开启对注解的自动扫描,支持 @RequestMapping 等注解。 - `&lt;context:component-scan&gt;` 指定包扫描范围,找到带有 @Controller 注解的类。 例如: ```xml &lt;context:component-scan ...

    SSM笔记-SpringMVC基本使用

    3. **Spring MVC配置文件**:配置`&lt;mvc:annotation-driven/&gt;`来启用基于注解的配置,以及`&lt;mvc:default-servlet-handler/&gt;`来处理静态资源请求。 ```xml &lt;beans xmlns="http://...

    springMVC开发小例子

    总结起来,"springMVC开发小例子"涵盖了 Spring MVC 的基本使用,包括核心组件配置、注解驱动的控制器以及与 MyBatis 的集成。这个例子提供了一个良好的起点,帮助开发者理解如何利用 Spring MVC 构建一个简单的 Web...

    springmvc实例

    - Spring MVC 使用多种注解简化开发,如 `@Controller`、`@RequestMapping`、`@GetMapping`、`@PostMapping`、`@PathVariable`、`@RequestParam` 等。 - 这些注解使得开发者无需编写大量 XML 配置,就能实现路由和...

    黑马程序员SpringMVC课堂笔记

    例如,我们通常会定义一个`&lt;mvc:annotation-driven/&gt;`元素以启用基于注解的控制器和数据绑定功能。 二、SpringMVC第一天课堂笔记 `springmvc第一天课堂笔记.docx`可能涵盖了SpringMVC的基础概念和环境搭建。这包括...

    SpringMVC框架架构介绍

    该元素启用注解驱动的配置,支持@Controller、@RequestMapping以及其他注解,如自动数据绑定、转换服务等。 通过理解这些核心概念,开发者能够更好地理解和利用SpringMVC框架,构建高效、可扩展的Web应用程序。

    SpringMVC入门

    @Controller public class HelloWorldController { @RequestMapping(value = "/hello", method = RequestMethod.GET) public ModelAndView helloWorld() { ModelAndView modelAndView = new ModelAndView(); ...

Global site tag (gtag.js) - Google Analytics