You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Javalin运行时错误:未注册.vm扩展名渲染器的解决请求

问题:Javalin访问页面抛出"No Renderer registered for extension '.vm'"错误

环境与修改内容

  • 基于Javalin框架开发Web应用,以javalin-website-example为模板
  • 已做修改:
    • 将Javalin版本升级为5.6.3
    • 将Google Guava版本改为32.1.3-jre
    • 包名替换为org.nsorokin.tools.taskcontroller.clientweb.app
  • 开发环境:Eclipse 2023-09,Java 11(BellSoft JDK 11.0.15.1+2-LTS)

项目代码

ClientWeb.java

package org.nsorokin.tools.taskcontroller.clientweb.app;

import org.nsorokin.tools.taskcontroller.clientweb.app.util.Filters;
import org.nsorokin.tools.taskcontroller.clientweb.app.util.Path;

import org.nsorokin.tools.taskcontroller.clientweb.app.login.LoginController;
import org.nsorokin.tools.taskcontroller.clientweb.app.index.IndexController;

import org.nsorokin.tools.taskcontroller.clientweb.app.user.UserDao;
import org.nsorokin.tools.taskcontroller.clientweb.app.util.Filters;

import io.javalin.plugin.bundled.RouteOverviewPlugin;
//import io.javalin.rendering.JavalinRenderer;

import static io.javalin.apibuilder.ApiBuilder.before;
import static io.javalin.apibuilder.ApiBuilder.get;
import static io.javalin.apibuilder.ApiBuilder.post;

import io.javalin.Javalin;
import io.javalin.http.staticfiles.Location;

public class ClientWeb {

    public static UserDao userDao;

    public static void main(String[] args) {
        userDao = new UserDao();

        Javalin clientWebApp = Javalin.create(config -> {
            config.staticFiles.add("/public", Location.CLASSPATH);
            config.plugins.register(new RouteOverviewPlugin("/routes"));
        }).start(7000);

        clientWebApp.routes(() -> {
            before(Filters.handleLocaleChange);
            before(LoginController.ensureLoginBeforeViewingBooks);
            get(Path.Web.INDEX, IndexController.serveIndexPage);
            get(Path.Web.LOGIN, LoginController.serveLoginPage);
            post(Path.Web.LOGIN, LoginController.handleLoginPost);
            post(Path.Web.LOGOUT, LoginController.handleLogoutPost);
        });
        //ClientWeb cWeb = new ClientWeb();
        //cWeb.process(args);
    }

    protected void process(String[] args) {
    }
}

IndexController.java

package org.nsorokin.tools.taskcontroller.clientweb.app.index;

import static org.nsorokin.tools.taskcontroller.clientweb.app.ClientWeb.*;

import java.util.Map;

import org.nsorokin.tools.taskcontroller.clientweb.app.util.Path;
import org.nsorokin.tools.taskcontroller.clientweb.app.util.ViewUtil;
import io.javalin.http.Handler;

public class IndexController {

    public static Handler serveIndexPage = ctx -> {
        Map<String, Object> model = ViewUtil.baseModel(ctx);
        model.put("users", userDao.getAllUserNames());
        //model.put("book", bookDao.getRandomBook());
        ctx.render(Path.Template.INDEX, model);
    };
}

问题现象

项目构建成功,无编译错误,应用可正常启动,但访问登录页或首页时触发错误,错误信息为:

java.lang.IllegalArgumentException: No Renderer registered for extension '.vm'.

完整错误栈

Dec 14, 2023 10:47:40 AM io.javalin.util.JavalinLogger warn
WARNING: Uncaught exception
java.lang.IllegalArgumentException: No Renderer registered for extension '.vm'.
    at io.javalin.rendering.JavalinRenderer.renderBasedOnExtension(JavalinRenderer.kt:32)
    at io.javalin.rendering.LegacyFileRenderer.render(JavalinRenderer.kt:20)
    at io.javalin.http.Context.render(Context.kt:452)
    at org.nsorokin.tools.taskcontroller.clientweb.app.index.IndexController.lambda$0(IndexController.java:18)
    at io.javalin.routing.HandlerEntry.handle(HandlerEntry.kt:19)
    at io.javalin.http.servlet.DefaultTasks.HTTP$lambda$8$lambda$6$lambda$5(DefaultTasks.kt:39)
    at io.javalin.http.servlet.JavalinServlet.handleTask(JavalinServlet.kt:88)
    at io.javalin.http.servlet.JavalinServlet.handleSync(JavalinServlet.kt:53)
    at io.javalin.http.servlet.JavalinServlet.service(JavalinServlet.kt:41)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:587)
    at io.javalin.jetty.JavalinJettyServlet.service(JavalinJettyServlet.kt:58)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:587)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:764)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:529)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1570)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1381)
    at io.javalin.jetty.JettyServer$start$wsAndHttpHandler$1.doHandle(JettyServer.kt:61)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:176)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:484)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1543)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:174)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1303)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129)
    at org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:173)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
    at org.eclipse.jetty.server.Server.handle(Server.java:563)
    at org.eclipse.jetty.server.HttpChannel$RequestDispatchable.dispatch(HttpChannel.java:1598)
    at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:753)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:501)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:287)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:314)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
    at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:969)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1194)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1149)
    at java.base/java.lang.Thread.run(Thread.java:829)

原因分析

.vm是Velocity模板引擎的文件后缀,Javalin 5.x版本开始不再默认集成Velocity渲染器,原示例项目依赖的Velocity渲染支持在升级Javalin后缺失,导致框架无法找到对应后缀的模板渲染器,触发该错误。

解决方法

1. 添加必要依赖

如果使用Maven,在pom.xml中添加以下依赖:

<!-- Javalin渲染核心依赖 -->
<dependency>
    <groupId>io.javalin</groupId>
    <artifactId>javalin-rendering</artifactId>
    <version>5.6.3</version>
</dependency>
<!-- Velocity引擎核心依赖 -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>

2. 注册Velocity渲染器

在Javalin启动代码中注册Velocity渲染器,修改ClientWeb.java中的初始化逻辑:

import io.javalin.rendering.template.JavalinVelocity;

public static void main(String[] args) {
    userDao = new UserDao();

    Javalin clientWebApp = Javalin.create(config -> {
        config.staticFiles.add("/public", Location.CLASSPATH);
        config.plugins.register(new RouteOverviewPlugin("/routes"));
        // 注册Velocity渲染器
        config.registerPlugin(JavalinVelocity.create());
    }).start(7000);

    // ... 路由配置不变
}

或者手动注册渲染器(如果上述插件方式不生效):

import io.javalin.rendering.JavalinRenderer;
import io.javalin.rendering.template.VelocityRenderer;

public static void main(String[] args) {
    userDao = new UserDao();
    // 手动注册Velocity渲染器
    JavalinRenderer.register(new VelocityRenderer(), ".vm");

    Javalin clientWebApp = Javalin.create(config -> {
        config.staticFiles.add("/public", Location.CLASSPATH);
        config.plugins.register(new RouteOverviewPlugin("/routes"));
    }).start(7000);

    // ... 路由配置不变
}

内容的提问来源于stack exchange,提问作者Nick S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:00:59