跳到内容

View Starter

受众:开发者 摘要:Thymeleaf 视图 + 本地前端资源(Vue 3 / Pico CSS WebJar)+ public/ 挂载 + SPA 入口 + 根路径智能路由。

何时使用

场景建议
Payment mock 支付调试页View starter
Storage 上传 / Notification / Queue / Scheduler 轻量运维页View starter
Starter 样板预览页View starter
大型后台管理前端独立 Vue / React 工程,用 View
重交互 SPA 主应用 / 用户侧正式门户独立前端工程,用 View
安装向导临时入口View starter + ViewRootRouteTargetProvider 接管 /

主线仍是前后端分离。View 只解决「启动后立刻能访问一个小页面」的开发体验问题。

快速开始

xml
<dependency>
    <groupId>com.springopen</groupId>
    <artifactId>spring-open-starter-view</artifactId>
</dependency>

模板:

text
src/main/resources/templates/sample/index.html
html
<!doctype html>
<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <title>Sample</title>
  <link rel="stylesheet" th:href="@{/webjars/picocss__pico/2.1.1/css/pico.min.css}">
</head>
<body>
<main id="app" class="container">
  <h1>{{ title }}</h1>
</main>
<script th:src="@{/webjars/vue/3.5.17/dist/vue.global.prod.js}"></script>
<script>
const { createApp } = Vue;
createApp({
  data() { return { title: 'Hello View' }; }
}).mount('#app');
</script>
</body>
</html>

Controller:

java
@Controller
@PublicApi
@IgnoreResponseWrapper
public class SamplePageController {

    @GetMapping("/sample.html")
    public String sample() {
        return "sample/index";
    }
}

访问 GET /sample.html

Facade / 编程入口

View 提供 Facade。能力通过:

  • Spring MVC @Controller + Thymeleaf 模板
  • ViewRootRouteTargetProvider SPI:业务模块在特定状态接管 /
  • ViewVendorResourceHandler:自定义 vendor 资源映射

业务模块按需注册 ViewRootRouteTargetProvider Bean 即可参与根路径路由。

配置项

yaml
spring:
  open:
    view:
      enabled: true
      root:
        enabled: true
        mode: auto
        target: /index.html
        desktop-target: /pc
        mobile-target: /app
        preserve-query-string: true
        database-enabled: true
        external-redirect-enabled: false
        allowed-redirect-hosts: []
      spa:
        enabled: true
        paths: [admin, app, pc]
      vendor:
        enabled: false
        vue: true
        pico: true
配置默认值说明
enabledtrue启用开关
root.enabledtrue根路径智能入口
root.modeautoauto / file / forward / redirect / disabled
root.target/index.html根路径目标
root.desktop-target/pcroot.target 为空或 / 时的电脑端跳转
root.mobile-target/approot.target 为空或 / 时的手机 / 平板跳转
root.preserve-query-stringtrue保留原始 query
root.database-enabledtrue数据库配置覆盖根路径
root.external-redirect-enabledfalse外部 URL 重定向
root.allowed-redirect-hosts[]外部重定向白名单
spa.enabledtrueSPA 目录入口转发到 index.html
spa.paths[admin, app, pc]参与转发的目录名
vendor.enabledfalse/vendor/** 自定义资源映射
vendor.vuetrue/vendor/vue/**
vendor.picotrue/vendor/pico/css/**

环境变量:

dotenv
SPRING_OPEN_VIEW_ENABLED=true
SPRING_OPEN_VIEW_ROOT_DESKTOP_TARGET=/pc
SPRING_OPEN_VIEW_ROOT_MOBILE_TARGET=/app
SPRING_OPEN_VIEW_VENDOR_ENABLED=false
SPRING_OPEN_VIEW_VENDOR_VUE=true
SPRING_OPEN_VIEW_VENDOR_PICO=true

Thymeleaf 配置仍用 Spring Boot 标准:

yaml
spring:
  thymeleaf:
    enabled: true
    cache: false
    check-template-location: false

根路径智能路由

根路径用低优先级映射:

  • 业务项目已提供 GET / Controller → 业务优先
  • 否则用 public/index.html 或配置的 forward / redirect 目标
  • target 为空或 / → 按设备跳转(电脑 /pc,手机 / 平板 /app),保留 query
  • 外部重定向默认关闭,开启需配 allowed-redirect-hosts 防开放重定向

开启首页设备分流:

yaml
spring:
  open:
    view:
      root:
        target: /
        desktop-target: /pc
        mobile-target: /app

业务模块通过 ViewRootRouteTargetProvider 在特定状态接管根路径。例如 install.md 在未安装且未锁定时把 / 转入 /install/,安装完成后自动失效。

机制说明

View starter 的路由机制分成三层,避免把轻量页面、三端 SPA 和安装向导入口混在一个 Controller 中:

层级组件说明
根路径解析ViewRootRouteResolver读取本地配置和数据库配置,先让 ViewRootRouteTargetProvider 接管,再生成 file / forward / redirect 目标
根路径执行ViewRootRouteHandlerMapping + ViewRootRouteHandler使用低优先级映射处理 GET /HEAD /,用户项目自定义根路由优先;目标禁用时返回 404
SPA 入口ViewSpaForwardingConfigurer + ViewSpaRouteHandlerMapping/admin/app/pc 转发到各自 index.html;深层无扩展名路由兜底到 index.html,静态资源请求不兜底

根路径安全边界:

  • 站内目标必须以 / 开头,拒绝协议、协议相对 URL、反斜杠、路径穿越、控制字符和脚本 URL。
  • 外部重定向默认关闭;开启后必须命中 allowed-redirect-hosts,只允许 http / https
  • target 为空或 / 时按 User-Agent 跳转到 desktop-target / mobile-target,并按配置保留 query string。
  • ViewRootRouteTargetProvider 只负责在特定业务状态下提供目标,例如安装模块未安装时接管 /;正常上线后的 PC / App 入口仍由 View 根路由配置控制。

SPA 目录入口

spa.paths 列出的目录入口会转发到各自的 index.html,支持前端 history 路由直接刷新子路径:

text
/admin   → /admin/index.html
/app     → /app/index.html
/pc      → /pc/index.html

默认 [admin, app, pc],覆盖三端 SPA 静态产物挂载目录。/admin/admin/ 两种写法都会处理。需要新增前端入口(如 /h5)时追加到 spa.paths;完全自管路由时设 spa.enabled: false

Provider

View 提供 Provider 切换。扩展点:

扩展点用途
ViewRootRouteTargetProvider SPI业务模块接管根路径
ViewVendorResourceHandler自定义 vendor 资源映射
Thymeleaf 标准扩展(dialect / processor / template resolver)模板增强

本地前端资源

内置 WebJar:

资源WebJar默认路径
Vue 3org.webjars.npm:vue/webjars/vue/3.5.17/dist/vue.global.prod.js
Pico CSSorg.webjars.npm:picocss__pico/webjars/picocss__pico/2.1.1/css/pico.min.css

默认优先用 Spring Boot / WebJars 原生路径,离线、内网也能打开样板页。

手工复制 CDN 文件到项目。升级 Vue / Pico 时同步更新 Maven 依赖版本、模板引用、ViewVendorResourceHandler 常量和测试断言。

可选 /vendor/**

默认关闭,避免两套静态资源路径。需要隐藏版本号或统一前缀时开启:

yaml
spring:
  open:
    view:
      vendor:
        enabled: true
text
/vendor/vue/vue.global.prod.js
/vendor/pico/css/pico.min.css
html
<link rel="stylesheet" th:href="@{/vendor/pico/css/pico.min.css}">
<script th:src="@{/vendor/vue/vue.global.prod.js}"></script>

新页面默认用 /webjars/**;除非迁移旧页面或有 vendor 前缀需求,同时混用两套路径。

CDN 处理

样板页默认不能依赖 CDN。可保留注释方便临时调试:

html
<!-- CDN fallback: <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script> -->
<script th:src="@{/webjars/vue/3.5.17/dist/vue.global.prod.js}"></script>

生效的 <script> / <link> 指向公网 CDN,确保离线开发、内网部署和安全扫描稳定。

页面 Controller 规范

页面用 @Controller@RestController

java
@Controller
@PublicApi
@IgnoreResponseWrapper
public class SamplePageController {

    @GetMapping("/samples/preview.html")
    public String page(Model model) {
        model.addAttribute("title", "Preview");
        return "samples/preview";
    }
}
规范说明
返回模板名返回 Result<T>
不写业务逻辑只组装页面 model
JSON API 分开仍放 @RestController
公开访问@PublicApi
避免响应封装@IgnoreResponseWrapper

验证命令

bash
./mvnw -pl spring-open-starters/spring-open-starter-view -am test -DskipITs

相关

Released under the Apache License 2.0.