在前后端技术栈日益分化的今天,使用 Vue 3 作为前端视图层、JFinal 作为后端服务底座的组合并不少见。JFinal 是国内开发者设计的极速 Web 开发框架,以零配置理念和简洁的 ORM 受到不少团队青睐;而 Vue 3 借助 Composition API 与 Vite 构建工具,在工程化方面有着成熟的生态。要让两者在一个项目里有序协作,核心并不在于写多少粘合代码,而在于如何划分模块边界与串联构建流程。

工程结构划分与 Maven 聚合设计
最常见的误区是把 Vue 3 的源码直接塞进 JFinal 的 WebContent 目录,用传统 Servlet 容器去托管静态文件。这种做法在小型演示里可行,却会让前端失去独立的依赖管理与热更新能力。更合理的做法是采用 Maven 聚合工程:父 pom 之下建立 backend 模块承载 JFinal 应用,frontend 模块承载 Vue 3 源码,两者通过约定好的接口契约通信。
在父工程中,我们可以利用 maven-frontend-plugin 调用 Node 环境执行 Vite 构建,将产物输出到 JFinal 的 resources/static 目录,也可以保持前后端各自打包、由 Nginx 做反向代理。下面的 pom 片段展示了如何在前端模块绑定构建生命周期:
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.12.1</version>
<executions>
<execution>
<id>install-node</id>
<goals><goal>install-node-and-npm</goal></goals>
<configuration>
<nodeVersion>v18.19.0</nodeVersion>
</configuration>
</execution>
<execution>
<id>build-vue</id>
<goals><goal>npm</goal></goals>
<configuration>
<arguments>run build</arguments>
</configuration>
</execution>
</executions>
</plugin>
这种结构下,JFinal 的 configRoute 只需映射 API 前缀,静态资源由框架自动处理。团队可以独立给前端模块配 ESLint 与单元测试,后端模块照常写 Controller 与 Model,互不干扰。缺点是初次构建需要下载 Node 工具链,CI 环境要缓存依赖。
开发期接口联调与 Vite 代理配置
开发阶段如果前端跑在 Vite 的 5173 端口,后端 JFinal 跑在 8080 端口,浏览器会因为同源策略拦截请求。很多初学者直接在 Vue 代码里写死 http://localhost:8080/api,这会让工程在部署时难以切换环境。正确方式是在 Vite 配置文件中使用 server.proxy 将 /api 转发到 JFinal 服务。
示例配置如下,其中 changeOrigin 保证主机头被正确改写,rewrite 可按需剥离前缀:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
'/api': {
target: 'http://127.0.0.1:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^/api/, '')
}
}
}
})
JFinal 侧则保持路由简洁,例如在 configRoute 中写 me.add("/api/user", UserController.class)。联调时前端用相对路径 /api/user/list 即可,构建后若采用同源部署则无需改动,若采用分离部署则仅靠环境变量切换 baseURL。这种方案明显优于在代码里散落绝对地址,也方便后端用 Postman 单独验证。
另外要注意 JFinal 默认未开启跨域头,若分离部署且不用代理,需在拦截器里补 Access-Control-Allow-Origin。但工程化推荐用代理或网关解决,而不是在每个 Controller 写 CORS 逻辑,那样会污染业务代码。
生产镜像构建与部署形态对比
到了交付环节,有两种主流形态。其一是前后端完全分离:Vue 3 产出静态文件传 CDN 或 Nginx,JFinal 打为 FatJar 跑在独立容器。其二是同源打包:前端构建完拷贝进 JFinal 的 static 目录,最终只有一个 Jar 兼顾页面与接口。我们用一张简表比较二者:
| 维度 | 分离部署 | 同源打包 |
|---|---|---|
| 构建速度 | 并行,互不影响 | 串行,后端等前端 |
| 运维复杂度 | 需维护两个服务与域名 | 单服务,易分发 |
| 灰度发布 | 前后端可独立发 | 必须一起发 |
若选同源打包,可写 Dockerfile 用多阶段构建:第一阶段用 Node 镜像构建 Vue,第二阶段用 JDK 镜像运行 Maven 打包的 JFinal。关键指令是把前端 dist 目录复制到后端 static 路径再打包,避免运行时依赖 Node。
FROM node:18 AS fe WORKDIR /app/frontend COPY frontend/ ./ RUN npm install && npm run build FROM maven:3.9-jdk17 AS be WORKDIR /app/backend COPY backend/ ./ COPY --from=fe /app/frontend/dist ./src/main/resources/static RUN mvn -q package -DskipTests FROM eclipse-temurin:17-jre COPY --from=be /app/backend/target/app.jar /app.jar ENTRYPOINT ["java","-jar","/app.jar"]
这种工程化方式让国产 JFinal 框架能平滑接入现代前端体系,既保留其开发效率,又获得 Vue 3 的组件化优势。实际落地时建议接口契约先用 OpenAPI 描述,前后端依此并行,能进一步降低联调成本。