1. 概述
本文将介绍如何在 Spring 项目中结合 Thymeleaf 模板引擎,正确生成带有路径变量(Path Variables)的 URL。这是日常开发中非常常见的需求,比如 /users/123
这种 RESTful 风格的接口调用。
路径变量的核心作用是:✅ 把动态参数嵌入 URL 路径中,而不是放在查询字符串里(如 ?id=123
),更符合语义化设计。
在 Spring 控制器中,我们通过 @PathVariable
注解来提取这些路径中的值。而前端模板如何安全、简洁地拼接出正确 URL,就是本文的重点。
2. 单个路径变量的使用
先来看一个最基础的场景:点击商品列表,跳转到详情页 /pathvars/single/1
。
2.1 数据模型
定义一个简单的 Item
类:
public class Item {
private int id;
private String name;
// 构造函数、getter 和 setter 省略
public Item(int id, String name) {
this.id = id;
this.name = name;
}
// getter/setter...
}
2.2 控制器实现
@Controller
public class PathVariablesController {
private List<Item> items = Arrays.asList(
new Item(1, "First Item"),
new Item(2, "Second Item")
);
@GetMapping("/pathvars")
public String showList(Model model) {
model.addAttribute("items", items);
return "pathvariables/index";
}
@GetMapping("/pathvars/single/{id}")
public String viewItem(@PathVariable("id") int id, Model model) {
Item item = items.stream()
.filter(i -> i.getId() == id)
.findFirst()
.orElse(new Item(id, "Unknown Item"));
model.addAttribute("item", item);
return "pathvariables/view";
}
}
⚠️ 注意:生产环境应做更严谨的参数校验和异常处理,这里为简化逻辑略去。
2.3 Thymeleaf 模板写法
关键来了!如何在 HTML 中生成带 {id}
的链接?
✅ 推荐写法(类型安全、清晰):
<div th:each="item : ${items}">
<a th:href="@{/pathvars/single/{id}(id = ${item.id})}">
<span th:text="${item.name}"></span>
</a>
</div>
生成的 HTML 示例:
<a href="/pathvars/single/1">First Item</a>
<a href="/pathvars/single/2">Second Item</a>
❌ 不推荐拼接字符串(易出错、可读性差):
<a th:href="@{'/pathvars/single/' + ${item.id}}">...</a>
虽然也能工作,但一旦路径复杂或参数增多,就容易踩坑,比如编码问题、斜杠缺失等。
3. 多个路径变量的处理
实际项目中,经常需要嵌套资源路径,例如:
/pathvars/item/1/detail/101
表示“ID 为 1 的商品下的第 101 条详情”。
3.1 扩展数据结构
新增 Detail
类:
public class Detail {
private int id;
private String description;
public Detail(int id, String description) {
this.id = id;
this.description = description;
}
// getter/setter...
}
修改 Item
类:
public class Item {
private int id;
private String name;
private List<Detail> details;
// 构造函数等略
}
初始化数据时记得填充 details。
3.2 添加多变量接口
控制器新增方法:
@GetMapping("/pathvars/item/{itemId}/detail/{dtlId}")
public String viewDetail(
@PathVariable("itemId") int itemId,
@PathVariable("dtlId") int dtlId,
Model model) {
return items.stream()
.filter(item -> item.getId() == itemId)
.findFirst()
.map(item -> {
model.addAttribute("item", item);
item.getDetails().stream()
.filter(d -> d.getId() == dtlId)
.findFirst()
.ifPresent(detail -> model.addAttribute("detail", detail));
return "pathvariables/view";
})
.orElse("error/404");
}
3.3 模板中使用多个路径变量
在 Thymeleaf 中传多个参数非常直观:
<ul>
<li th:each="detail : ${item.details}">
<a th:href="@{/pathvars/item/{itemId}/detail/{dtlId}(itemId = ${item.id}, dtlId = ${detail.id})}">
<span th:text="${detail.description}"></span>
</a>
</li>
</ul>
📌 语法要点:
{}
定义路径占位符(key = value)
传入实际参数,顺序无关- 多个参数用逗号分隔
生成示例:
<a href="/pathvars/item/1/detail/101">Detail of Item 1</a>
4. 总结
通过本文你应该掌握:
✅ 标准写法:使用 @{/path/{var}(var = ${expr})}
是最安全、清晰的方式
✅ 避免字符串拼接:简单粗暴的 '/' + ${id}
写法虽快,但不利于维护
✅ 多变量支持良好:Thymeleaf 对复杂路径的支持很成熟,无需手动处理编码
示例代码已托管至 GitHub:https://github.com/spring-thymeleaf-pathvars-demo(模拟地址)
这类技巧看似小,但在团队协作和长期维护中能显著减少 bug,建议直接加入你的项目模板中。