JFinal使用技巧-javax-to-jakarta 桥接适配器

如题,前两天又看到群友说想JFinal支持Tomcat 10+,历史原因包名从 javax.servlet 变更为 jakarta.servlet 真是个糟糕的决定。所以波大新项目aifei直接无servlet~  老项目不愿意迁移的,还得在JF不是。以前看过一篇文章说Tomcat官方有桥接包,但是实际使用下来,并不方便,咱社区也有社友分享(右上角搜索Tomcat 10可见)。
但是并不是我想要的那种桥接方案,昨晚我把我的“装饰模式”想法给AI说了一遍,它用了2小时完成了编码与测试 并maven中心推送了。(具体时间没统计,中间忙其他的去了,它让我输入GPG密钥卡住了)

算了废话不多说 上 石马 ~

image.png

使用姿势 jfinal-javax-to-jakarta 的依赖:

<dependencies>
    <!-- JFinal 核心 -->
    <dependency>
        <groupId>com.jfinal</groupId>
        <artifactId>jfinal</artifactId>
        <version>5.2.7</version>
    </dependency>

    <!-- javax-to-jakarta 桥接适配器 -->
    <dependency>
        <groupId>top.myedu.maven</groupId>
        <artifactId>jfinal-javax-to-jakarta</artifactId>
        <version>1.0.0</version>
    </dependency>

    <!-- 桥接模块运行时依赖 javax.servlet-api (provided 不传递,需显式声明) -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>

    <!-- Tomcat 10 嵌入式 (Jakarta Servlet 6.0) -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>${tomcat.version}</version>
    </dependency>
</dependencies>


经典Demo输出 Hello JFinal World

public class HelloController extends Controller {
    public void index() {
        renderText("Hello JFinal World.");
    }
}
public class DemoConfig extends JFinalConfig {

    @Override
    public void configRoute(Routes me) {
        me.add("/", HelloController.class);
    }

    @Override
    public void configConstant(Constants me) {
        me.setDevMode(true);
    }

    @Override
    public void configInterceptor(Interceptors me) {
    }

    @Override
    public void configHandler(Handlers me) {
    }

    @Override
    public void configPlugin(Plugins me) {
    }

    @Override
    public void configEngine(Engine me) {
    }
}

这里我使用 嵌入式Tomcat10 方便调试:

/**
 * Embedded Tomcat 10 launcher for JFinal via JakartaBridgeFilter.
 *
 * Tomcat 10 uses jakarta.servlet namespace.
 * JakartaBridgeFilter bridges jakarta -> javax, so JFinal works unchanged.
 */
public class TomcatEmbedMain {

    public static void main(String[] args) throws Exception {
        int port = 8080;

        Tomcat tomcat = new Tomcat();
        tomcat.setPort(port);
        tomcat.getConnector(); // trigger default connector creation

        // Create webapp context
        String baseDir = System.getProperty("java.io.tmpdir");
        Context ctx = tomcat.addContext("", baseDir);
        // Use current classloader so Tomcat can find Maven dependencies
        ctx.setParentClassLoader(Thread.currentThread().getContextClassLoader());

        // Add a default servlet (required for filters to be invoked)
        Tomcat.addServlet(ctx, "default", "org.apache.catalina.servlets.DefaultServlet");
        ctx.addServletMappingDecoded("/*", "default");

        // Register JakartaBridgeFilter using Tomcat internal API
        // (ServletContext.addFilter() rejects after context init in Tomcat 10.1)
        FilterDef filterDef = new FilterDef();
        filterDef.setFilterName("jfinal");
        filterDef.setFilterClass("com.jfinal.jakarta.servlet.JakartaBridgeFilter");
        filterDef.addInitParameter("configClass", "com.example.DemoConfig");
        ctx.addFilterDef(filterDef);

        FilterMap filterMap = new FilterMap();
        filterMap.setFilterName("jfinal");
        filterMap.addURLPattern("/*");
        ctx.addFilterMap(filterMap);

        System.out.println("========================================");
        System.out.println("  JFinal on Tomcat 10 (Jakarta Servlet)");
        System.out.println("  http://localhost:" + port + "/");
        System.out.println("========================================");

        tomcat.start();
        tomcat.getServer().await();
    }
}


注意这里的关键 配置:

com.jfinal.core.JFinalFilter
改为了:
com.jfinal.jakarta.servlet.JakartaBridgeFilter

软件版的Tomcat 就是需要改 web.xml 配置了

<filter>
    <filter-name>jfinal</filter-name>
    <filter-class>com.jfinal.jakarta.servlet.JakartaBridgeFilter</filter-class>
    <init-param>
        <param-name>configClass</param-name>
        <param-value>com.example.MyJFinalConfig</param-value>
    </init-param></filter><filter-mapping>
    <filter-name>jfinal</filter-name>
    <url-pattern>/*</url-pattern></filter-mapping>


启动测试:

image.png

没问题~

放下源码地址:
https://gitee.com/bean80/jfinal-javax-to-jakarta

这个是我想要的桥接方案,JFianl 不用改,中间的Request、Response 这些类我自己进行一个转调,以及业务中的依赖,该取Jakarta对象的就用新的。
如果有用到这个项目方案的,当Request中有用到的方法没实现全的,可以直接把项目拉下来,让AI去改就可以了,我用的Qoder CN

评论区

天晴

2026-08-20 17:56

前排支持老杜

JFinal

2026-08-21 02:20

点赞收藏一波先,后面看看要不要升级,如果升的话不兼容老版本 tomcat 也是个麻烦

chcode

2026-08-22 15:11

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>shade-classes</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>jakarta</shadedClassifierName>
<createSourcesJar>true</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<relocations>
<relocation>
<pattern>javax.servlet</pattern>
<shadedPattern>jakarta.servlet</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
这段 Maven 配置是 maven-shade-plugin 的一个执行项,核心作用是将 javax.servlet 包重定位为 jakarta.servlet,并生成一个带 jakarta 分类器的附加 JAR 包
@杜福忠 这个我的方案无需改任何代码

杜福忠

2026-08-22 16:18

@chcode 是的,这个是字节码替换方案,编译需要在9-版本上面,适合通用项目。

而jfinal-javax-to-jakarta用的是装饰器 类中间桥接进行转调,并且只对jfinal用到的类进行了代理处理,JF专用。可以直接在Tomcat 10+上进行编译运行调试。并且这个方案兼容低高版本,也就加了个中间件。

两种方案都是可以实现业务升级的。

杜福忠

2026-08-22 16:23

@JFinal 确实,改名后就很麻烦,容器改名比fastjson1改fastjson2麻烦多了。。。不过也就老项目在用了。新项目得上aifei~ JdkHttpServer + 虚拟线程 也很能打

JFinal

2026-08-22 16:31

@杜福忠 aifei 的 JdkHttpServer 我写过一个初版,后来好像是因为 JDK 的 HTTP Server 在 open JDK 中没提供后来没再继续,你写的版本考虑开源啊

杜福忠

2026-08-23 11:12

@JFinal openjdk-26上面照样运行,我查了一下官方也没有说要移除这个,25年的时候是有更新一个说明JDK 的 HTTP Server是一个功能不全的HTTP Server,(只支持 HTTP/1.1,没有HTTP/2、WebSocket等高级特性,在现代Web服务中就是玩具级别),所以使用场景有限。比如一些小的内部管理系统,或者CMS系统+云CDN缓存代理之类的,教学场景。开源必须的~

JFinal

2026-08-23 15:13

@杜福忠 功能太受限制了,暂时不开发这个,先做更有价值的开发

热门分享

扫码入社