//跳转至login.html页面
@GetMapping("/login")
public String goToLogin(){
    return "login"
}

Thymeleaf是如何将String字符串"login"解析成"classpath:/templates/login.html"的?

一、前端控制器DispatcherServlet

前端控制器中的doDispacth在处理请求时,渲染页面过程:

先通过

//DispatcherServlet.class 1043行
mappedhandler = getHandler(processedrequest)

查找url是否存在,若存在则返回执行链和适配器,在

//DispatcherServlet.class 1067行
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

真正执行Handler

然后在

//DispatcherServlet.class 1084行
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

渲染视图,而Thymeleaf提供了视图解析器,所以在这里渲染视图的是Thymeleaf的视图解析器。

二、ThymeleafAutoConfiguration

ThymeleafAutoConfiguration中,SpringBoot2 就已经为我们默认注册了一个thymeleafViewResolver

@Bean
@ConditionalOnMissingBean(name = "thymeleafViewResolver")
ThymeleafViewResolver thymeleafViewResolver(ThymeleafProperties properties,
      SpringTemplateEngine templateEngine) {
   ......
   return resolver;
}

只要没有手动自己添加,则会默认使用该视图解析器。

ThymeleafViewResolver中的createView创建视图方法,会传入一个视图名称,如下代码所示的viewName

@Override
protected View createView(final String viewName, final Locale locale) throws Exception {
    ......
    }

然后通过viewName.startWith()方法截取

// Process redirects (HTTP redirects)
//此处的REDIRECT_URL_PREFIX的值为:
//public static final String REDIRECT_URL_PREFIX = "redirect:";
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
    vrlogger.trace("[THYMELEAF] View \"{}\" is a redirect, and will not be handled directly by ThymeleafViewResolver.", viewName);
    final String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length(), viewName.length());
    final RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
    return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, REDIRECT_URL_PREFIX);
}

然后通过RedirectView构建视图返回。forward前缀同理。

如果前缀不符合上述两种,则执行

return loadView(viewName, locale);
@Override
protected View loadView(final String viewName, final Locale locale) throws Exception {
        ......
    }

利用loadView最终实例化

view = (AbstractThymeleafView) beanFactory.initializeBean(viewInstance, viewName);

通过AbstractThymeleafView将例如"login"拼接完成。