以下是关于“浅谈SpringMVC请求映射handler源码解读”的完整攻略,其中包含两个示例。
浅谈SpringMVC请求映射handler源码解读
SpringMVC是一个基于MVC模式的Web框架,它的核心是请求映射handler。在本文中,我们将深入了解SpringMVC请求映射handler的源代码。
步骤一:创建Maven项目
-
打开IntJ IDEA,选择“Create New Project”。
-
选择“Maven”并点击“Next”。
-
输入项目的GroupId、Id和Version,并选择项目的存储路径。点击“Next”。
-
选择项目的类型和模板。点击“Next”。
5.项目的名称和描述。点击“Finish”。
步骤二:添加Spring MVC依赖
-
开pom.xml。
-
在
标签中添加以下依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
步骤三:创建Controller
-
在src/main/java目录下创建一个名为com.example.controller的包。
-
在com.example.controller包创建一个名为HelloController的类。
-
在HelloController类中添加以下内容:
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String hello() {
return "Hello, World!";
}
}
在本示例中,我们实现了一个HelloController,用于处理/hello请求。我们使用@Controller注解来标识HelloController类。我们使用@RequestMapping注解来指定请求的URL。我们使用@ResponseBody注解来指定返回的内容。
步骤四:启动应用程序
-
在IntelliJ IDEA中,右键单击HelloController类,选择“Run HelloController.main()”。
-
在浏览器中输入http://localhost:8080/hello,应该会看到“Hello, World!”的输出。
步骤五:源码解读
- 打开HelloController类,找到@RequestMapping注解。
@RequestMapping("/hello")
@RequestMapping注解用于将请求URL映射到处理器方法。在本示例中,我们将/hello请求映射到hello方法。
- 打开DispatcherServlet类,找到doDispatch方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// Apply preHandle methods of registered interceptors.
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
// Apply postHandle methods of registered interceptors.
if (interceptors != null) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
}
}
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// Trigger afterCompletion callbacks on registered interceptors.
if (mappedHandler != null && interceptorIndex != -1) {
for (int i = interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(processedRequest, response, mappedHandler.getHandler(), dispatchException);
}
catch (Throwable ex) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex);
}
}
}
// If we already have a view, we're already rendering.
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, response);
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
else {
// We might still need view name translation for a redirect, even if we don't have a view instance to render yet.
if (multipartRequestParsed && !response.isCommitted() && mv != null && mv.hasView()) {
String viewName = mv.getViewName();
if (viewName.startsWith("redirect:")) {
render(mv, processedRequest, response);
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
}
}
if (asyncManager.isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
if (mv == null) {
mv = new ModelAndView();
}
if (!asyncManager.isConcurrentHandlingCompleted()) {
handleAsyncException(request, response, mappedHandler, dispatchException, mv);
return;
}
}
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, response);
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
catch (Exception ex) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
Exception ex = new NestedServletException("Handler processing failed", err);
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Restore the original request before handling the error.
if (processedRequest instanceof MultipartHttpServletRequest) {
restoreMultipart((MultipartHttpServletRequest) processedRequest);
}
}
}
}
doDispatch方法是DispatcherServlet的核心方法,它用于处理所有的请求。在本示例中,我们使用doDispatch方法来处理/hello请求。
- 打开RequestMappingHandlerMapping类,找到getHandlerInternal方法。
protected HandlerExecutionChain getHandlerInternal(HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request, LOOKUP_PATH);
List<T> directPathMatches = this.handlerMap.get(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.corsHandlerMappings, matches, request);
if (matches.isEmpty()) {
addMatchingMappings(this.handlerMappings, matches, request);
}
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() +
"': {" + m1 + ", " + m2 + "}");
}
}
HandlerMethod handlerMethod = bestMatch.handlerMethod;
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, handlerMethod);
HandlerInterceptor[] interceptors = handlerMethod.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
request.setAttribute(HANDLER_INTERCEPTOR_LIST_ATTRIBUTE, interceptors);
}
return bestMatch.handlerMethod.getHandlerExecutionChain();
}
else {
return null;
}
}
getHandlerInternal方法用于获取请求映射handler。在本示例中,我们使用getHandlerInternal方法来获取/hello请求的handler。
- 打开RequestMappingInfo类,找到getMatchingCondition方法。
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
return new RequestMappingInfo(this.patternsCondition.getMatchingCondition(request),
methods, params, headers, consumes, produces, custom);
}
getMatchingCondition方法用于获取请求映射条件。在本示例中,我们使用getMatchingCondition方法来获取/hello请求的请求映射条件。
示例
以下是另一个示例,演示如何使用@RequestMapping注解来指定多个URL:
@Controller
@RequestMapping({"/hello", "/hi"})
public class HelloController {
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public String hello() {
return "Hello, World!";
}
}
在本示例中,我们使用@RequestMapping注解来指定/hello和/hi两个URL。我们使用@RequestMapping注解来指定处理器方法的请求映射条件。
总结
SpringMVC请求映射handler是SpringMVC的核心。我们可以使用@RequestMapping注解来指定请求映射条件。我们可以使用DispatcherServlet类来处理所有的请求。我们可以使用RequestMappingHandlerMapping类来获取请求映射handler。我们可以使用RequestMappingInfo类来获取请求映射条件。在使用SpringMVC时,我们需要遵循SpringMVC规范,确保代码可维护性和可扩展性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈SpringMVC请求映射handler源码解读 - Python技术站