1. 概述
Hilla 是一个基于 Java 的全栈 Web 框架。它允许我们在 Spring Boot 应用中添加 React 视图,并通过类型安全的 RPC 从 TypeScript 调用后端 Java 服务。
该框架使用 Vaadin UI 组件集,并与 Vaadin Flow 兼容。两者都属于 Vaadin 平台。本教程将介绍 Hilla 开发的基础知识。
2. 创建 Hilla 项目
可通过以下两种方式创建项目:
- 在 Spring Initializr 添加 Vaadin 依赖
- 在 Vaadin Start 下载定制启动器
若需将 Hilla 集成到现有 Spring Boot 项目,需在 Maven 的 pom.xml
中添加以下 BOM(物料清单):
<properties>
<vaadin.version>24.4.10</vaadin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>${vaadin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后添加包含 Hilla 的 Vaadin 平台依赖:
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
</dependency>
最后创建主题配置文件 src/main/frontend/themes/hilla/theme.json
:
{
"lumoImports" : [ "typography", "color", "sizing", "spacing", "utility" ]
}
更新 Spring Boot 主类,添加 @Theme
注解并实现 AppShellConfigurator
:
@Theme("hilla") // 需与主题文件夹名称匹配
@SpringBootApplication
public class DemoApplication implements AppShellConfigurator {
// 应用代码省略
}
3. 启动应用
Hilla 将 React 视图和 Java 后端源码统一在一个全栈项目中。视图需定义在 src/main/frontend/views
目录下。
创建 src/main/frontend/views/@index.tsx
文件:
export default function Index() {
return (
<h1>Hello world</h1>
);
}
通过 mvn spring-boot:run
或 IDE 启动应用:
⚠️ 首次启动较慢(需下载 Maven/npm 依赖并启动 Vite 开发服务器),后续启动会更快。
访问 localhost:8080
可看到 "Hello world":
4. 使用 @BrowserCallable 调用服务端方法
Hilla 的独特之处在于前后端通信方式。与传统 Spring Boot + React 分离架构不同,Hilla 采用统一的 RPC 调用 Java 服务,遵循 BFF 架构。
以 Contact
实体为例:
@Entity
public class Contact {
@Id
@GeneratedValue
private Long id;
@Size(min = 2)
private String name;
@Email
private String email;
private String phone;
// 构造器、getter/setter 省略
}
配合 Spring Data JPA 仓库:
public interface ContactRepository extends
JpaRepository<Contact, Long>,
JpaSpecificationExecutor<Contact> {
}
用 @BrowserCallable
注解服务类,@AnonymousAllowed
允许匿名访问:
@BrowserCallable
@AnonymousAllowed
public class ContactService {
private final ContactRepository contactRepository;
public ContactService(ContactRepository contactRepository) {
this.contactRepository = contactRepository;
}
public List<Contact> findAll() {
return contactRepository.findAll();
}
public Contact findById(Long id) {
return contactRepository.findById(id).orElseThrow();
}
public Contact save(Contact contact) {
return contactRepository.save(contact);
}
}
✅ 空值处理优化:在服务包中创建 package-info.java
简化 TypeScript 类型:
@NonNullApi
package com.example.application;
import org.springframework.lang.NonNullApi;
更新 @index.tsx
显示联系人列表:
export default function Contacts() {
const contacts = useSignal<Contact[]>([]);
async function fetchContacts() {
contacts.value = await ContactService.findAll();
}
useEffect(() => {
fetchContacts();
}, []);
return (
<div className="p-m flex flex-col gap-m">
<h2>Contacts</h2>
<Grid items={contacts.value}>
<GridSortColumn path="name">
{({item}) => <NavLink to={`contacts/${item.id}/edit`}>{item.name}</NavLink>}
</GridSortColumn>
<GridSortColumn path="email"/>
<GridSortColumn path="phone"/>
</Grid>
</div>
);
}
从
Frontend/generated
导入Contact
和ContactService
,Hilla 使用基于 Preact signals 的信号机制。
5. 配置视图与布局
Hilla 采用基于文件的路由系统,所有视图位于 src/main/frontend/views
目录。
5.1 视图命名规范
文件/文件夹名 | 路由映射 | 说明 |
---|---|---|
@index.tsx |
/ |
目录首页 |
@layout.tsx |
- | 目录布局文件 |
view-name.tsx |
/view-name |
普通视图 |
{parameter} |
- | 路径参数捕获 |
{parameter}.tsx |
/:parameter |
参数化视图 |
{{parameter}}.tsx |
/:parameter? |
可选参数视图 |
{...wildcard}.tsx |
/* |
通配符匹配 |
5.2 视图配置
导出 ViewConfig
类型的 config
常量:
export const config: ViewConfig = {
title: "Contact List",
menu: {
order: 1,
}
}
export default function Index() {
// 代码省略
}
5.3 定义布局
在 src/main/frontend/views
创建 @layout.tsx
:
export default function MainLayout() {
return (
<div className="p-m h-full flex flex-col box-border">
<header className="flex gap-m pb-m">
<h1 className="text-l m-0">My Hilla App</h1>
{createMenuItems().map(({to, title}) => (
<NavLink to={to} key={to}>{title}</NavLink>
))}
</header>
<Suspense>
<Outlet/>
</Suspense>
</div>
);
}
createMenuItems()
自动生成导航菜单。
6. 构建表单与输入验证
创建编辑视图 views/contacts/{id}/edit.tsx
:
export default function ContactEditor() {
const {id} = useParams();
const navigate = useNavigate();
const {field, model, submit, read} = useForm(ContactModel, {
onSubmit: async contact => {
await ContactService.save(contact);
navigate('/');
}
})
async function loadUser(id: number) {
read(await ContactService.findById(id))
}
useEffect(() => {
if (id) {
loadUser(parseInt(id))
}
}, [id]);
return (
<div className="flex flex-col items-start gap-m">
<TextField label="Name" {...field(model.name)}/>
<TextField label="Email" {...field(model.email)}/>
<TextField label="Phone" {...field(model.phone)}/>
<div className="flex gap-s">
<Button onClick={submit} theme="primary">Save</Button>
<Button onClick={() => navigate('/')} theme="tertiary">Cancel</Button>
</div>
</div>
);
}
关键点:
useForm
自动绑定字段和验证规则field()
方法同步 Java 实体验证注解submit()
触发表单提交
7. 使用 AutoCrud 实现自动化 CRUD
Hilla 作为全栈框架,可自动化生成 CRUD 操作。更新服务类:
@BrowserCallable
@AnonymousAllowed
public class ContactService extends CrudRepositoryService<Contact, Long, ContactRepository> {
public List<Contact> findAll() {
return getRepository().findAll();
}
public Contact findById(Long id) {
return getRepository().findById(id).orElseThrow();
}
}
创建 frontend/views/auto-crud.tsx
:
export default function AutoCrudView() {
return <AutoCrud service={ContactService} model={ContactModel} className="h-full"/>
}
仅需一行代码即可生成完整的增删改查界面!
替代方案:
- 仅需列表:使用
AutoGrid
组件 - 仅需表单:使用
AutoForm
组件
8. 生产环境构建
使用 production
Maven 配置文件构建:
<profile>
<id>production</id>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-dev</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.version}</version>
<executions>
<execution>
<goals>
<goal>build-frontend</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
执行构建命令:
./mvnw package -Pproduction
构建效果:
✅ 优化前端 JavaScript 包
❌ 禁用开发调试功能
9. 总结
本文介绍了 Hilla 框架的核心特性:
- 在 Spring Boot 中集成 React 视图
- 通过
@BrowserCallable
实现类型安全的 RPC 通信 - 基于文件的路由系统
- 自动化表单验证和 CRUD 生成
- 生产环境优化方案
Hilla 简化了全栈开发流程,特别适合需要快速构建企业级应用的场景。完整代码示例可在 GitHub 获取。