1. 概述

本文将带你快速搭建一个基于 Kotlin 的 Spring MVC 项目。重点在于 Spring MVC 的基础配置流程,适用于希望脱离 Spring Boot 自主掌控配置的场景。

需要说明的是,如果你更倾向于快速开发,推荐使用 Spring Boot 与 Kotlin 的组合,它能自动完成大部分配置。而本文则聚焦于手动配置 Spring MVC 的核心组件,帮助你理解底层原理——这在一些老项目迁移或定制化需求中非常实用,避免“只会用 Boot,一问三不知”的踩坑尴尬。

2. Maven 依赖配置

要让 Kotlin 在 Spring MVC 项目中正常工作,Maven 的依赖和插件配置是第一步。

Kotlin 标准库
必须引入 kotlin-stdlib-jdk(注意不是过时的 jre8),确保语言基础功能可用:

<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-stdlib-jdk</artifactId>
    <version>1.8.22</version>
</dependency>

Spring Web 核心依赖
虽然不用 Spring Boot,但仍需 Spring MVC 的核心支持:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>6.0.9</version>
</dependency>

⚠️ Kotlin 编译插件
这是关键!必须在 <build> 中配置 kotlin-maven-plugin,否则 Kotlin 文件无法被正确编译。注意指定 compiletest-compile 两个阶段:

<plugin>
    <artifactId>kotlin-maven-plugin</artifactId>
    <groupId>org.jetbrains.kotlin</groupId>
    <version>1.8.22</version>
    <executions>
        <execution>
            <id>compile</id>
            <phase>compile</phase>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
        <execution>
            <id>test-compile</id>
            <phase>test-compile</phase>
            <goals>
                <goal>test-compile</goal>
            </goals>
        </execution>
    </executions>
</plugin>

同时,确保你的源码目录结构为 src/main/kotlin,并在插件中通过 <sourceDirs> 显式声明。

3. Web 资源管理

Spring MVC 对静态资源和模板文件有默认的查找路径,了解这些约定能避免很多 404 问题。

3.1 静态资源

静态文件(HTML、CSS、JS、图片等)会按优先级顺序从以下四个 classpath 路径查找:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/

通常我们把 index.html 放在 src/main/resources/static/ 下:

<html>
    <head><title>首页</title></head>
    <body>
        <h1>This is the body of the index view</h1>
    </body>
</html>

启动应用后,访问 http://localhost:8080/ 即可看到页面。无需额外配置,Spring 会自动映射。

3.2 模板资源

对于动态页面,Spring 支持多种模板引擎。只需添加对应依赖即可集成:

添加 Thymeleaf 依赖:

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.1.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring6</artifactId>
    <version>3.1.1.RELEASE</version>
</dependency>

模板文件默认放在 classpath:/templates/,例如创建 welcome.html

<html>
    <head><title>欢迎页</title></head>
    <body>
        <h1>This is the body of the welcome view</h1>
    </body>
</html>

⚠️ 注意:templates 目录下的文件是受保护的,直接通过 URL 访问(如 /welcome.html)会返回 404。必须通过控制器或视图控制器暴露。

使用 Kotlin 配置一个视图映射:

@Configuration
open class ApplicationWebConfig : WebMvcConfigurer {
    override fun addViewControllers(registry: ViewControllerRegistry) {
        registry.addViewController("/welcome").setViewName("welcome")
    }
}

现在访问 http://localhost:8080/welcome 就能正确渲染模板了。

4. 不使用 Spring Boot 的纯 Spring MVC 配置

当你不想依赖 Spring Boot 的自动配置时,就需要手动完成上下文初始化和 MVC 组件注册。

4.1 Kotlin 注解配置方式

通过 @Configuration 类完成所有配置,包括视图解析器、模板引擎等。

@EnableWebMvc
@Configuration
open class ApplicationWebConfig : WebMvcConfigurer, ApplicationContextAware {

    private var applicationContext: ApplicationContext? = null

    override fun setApplicationContext(applicationContext: ApplicationContext) {
        this.applicationContext = applicationContext
    }

    override fun addViewControllers(registry: ViewControllerRegistry) {
        registry.addViewController("/welcome").setViewName("welcome")
    }

    @Bean
    open fun templateResolver(): SpringResourceTemplateResolver {
        return SpringResourceTemplateResolver().apply {
            prefix = "/WEB-INF/views/"
            suffix = ".html"
            templateMode = TemplateMode.HTML
            setApplicationContext(applicationContext)
        }
    }

    @Bean
    open fun templateEngine(): SpringTemplateEngine {
        return SpringTemplateEngine().apply {
            setTemplateResolver(templateResolver())
        }
    }

    @Bean
    open fun viewResolver(): ThymeleafViewResolver {
        return ThymeleafViewResolver().apply {
            templateEngine = templateEngine()
            order = 1
        }
    }
}

接着,创建 ServletInitializer 替代传统的 web.xml

class ApplicationWebInitializer : AbstractAnnotationConfigDispatcherServletInitializer() {

    override fun getRootConfigClasses(): Array<Class<*>>? = null

    override fun getServletConfigClasses(): Array<Class<*>> = 
        arrayOf(ApplicationWebConfig::class.java)

    override fun getServletMappings(): Array<String> = 
        arrayOf("/")
}

这个类会自动注册 DispatcherServlet 并加载配置类,是现代 Spring Web 应用的标准入口。

4.2 XML 配置方式

如果你的项目还在使用 XML,以下是等效配置。

spring-web-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.example.mvc" />

    <mvc:view-controller path="/welcome" view-name="welcome"/>
    <mvc:annotation-driven />

    <bean id="templateResolver"
          class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".html" />
        <property name="templateMode" value="HTML" />
    </bean>

    <bean id="templateEngine"
          class="org.thymeleaf.spring6.SpringTemplateEngine">
        <property name="templateResolver" ref="templateResolver" />
    </bean>

    <bean class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
        <property name="templateEngine" ref="templateEngine" />
        <property name="order" value="1" />
    </bean>
</beans>

配套的 web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">

    <display-name>Kotlin Spring MVC App</display-name>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-web-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

5. 总结

本文演示了如何在非 Spring Boot 环境下,使用 Kotlin 搭建 Spring MVC 项目。涵盖了 Maven 配置、静态资源处理、Thymeleaf 模板集成,以及注解和 XML 两种配置方式。

掌握这些内容,不仅能应对传统企业项目,也能加深对 Spring 容器启动机制的理解。避免过度依赖 Boot 的“魔法”,才能在复杂场景中游刃有余。

完整示例代码可在 GitHub 获取:https://github.com/Baeldung/kotlin-tutorials/tree/master/spring-mvc-kotlin


原始标题:Spring MVC Setup with Kotlin