Vaadin23如何实现点击用户名跳转至对应用户ProfileView
Vaadin23 实现任意用户个人主页跳转方案
直接用Vaadin原生的路由模板+生命周期方法就能实现,不需要额外引入组件,分两步改代码即可。
第一步:改造ProfileView支持动态用户路由
首先修改路由注解,增加用户ID占位符,让页面支持/profile/123这种带用户标识的URL格式,同时实现BeforeEnterObserver接口,在页面进入前解析URL参数加载对应用户数据,替代原来硬编码加载当前登录用户的逻辑。
- 修改类上的@Route注解,同时实现生命周期接口:
// 占位符:userId就是URL里传的用户ID,支持数字格式 @Route(value = "profile/:userId", layout = MainLayout.class) @PageTitle("Profile Page") @PermitAll @Uses(Icon.class) public class ProfileView extends VerticalLayout implements BeforeEnterObserver { - 类里新增字段存储当前页面展示的用户对象:
private User displayedUser; - 重写beforeEnter方法,解析路由参数加载用户:
@Override public void beforeEnter(BeforeEnterEvent event) { Optional<String> userIdParam = event.getRouteParameters().get("userId"); if (userIdParam.isPresent()) { try { Long userId = Long.parseLong(userIdParam.get()); // 调用已有的userService方法查询目标用户,方法名和自身业务实现对齐即可 displayedUser = userService.getById(userId) .orElseThrow(() -> new NotFoundException("用户不存在")); } catch (NumberFormatException e) { // ID格式不合法直接跳404页面 event.rerouteToError(NotFoundException.class, "无效的用户地址"); return; } } else { // 没有传用户ID时默认加载当前登录用户的主页,兼容原有访问逻辑 displayedUser = authenticatedUser.get() .orElseThrow(() -> new AccessDeniedException("请先登录")); } // 加载完用户后填充页面数据 initPageContent(); } - 新增initPageContent方法,把原来构造方法里硬编码给表单赋值的逻辑移到这里,同时做权限适配:
private void initPageContent() { // 用binder自动绑定用户数据到表单,不用手动一个个setValue binder.setBean(displayedUser); // 动态修改页面标题和头部 UI.getCurrent().getPage().setTitle(displayedUser.getFirstname() + "的个人主页"); ((H3) getComponentAt(0)).setText("个人信息:" + displayedUser.getFirstname()); // 非本人访问主页时隐藏隐私设置按钮,避免越权 Long currentLoginUserId = authenticatedUser.get().get().getId(); privacy.setVisible(displayedUser.getId().equals(currentLoginUserId)); // 给功能按钮补全目标用户参数,跳转时也带用户ID,避免永远跳当前登录用户的子页面 watchedMovies.addClickListener(e -> UI.getCurrent().navigate(WatchedMoviesView.class, new RouteParameters("userId", displayedUser.getId().toString()))); watchList.addClickListener(e -> UI.getCurrent().navigate(Watchlist.class, new RouteParameters("userId", displayedUser.getId().toString()))); seeFriends.addClickListener(e -> UI.getCurrent().navigate(FriendlistView.class, new RouteParameters("userId", displayedUser.getId().toString()))); } - 把原来ProfileView构造方法里这三行硬编码赋值的代码删掉,否则会覆盖binder的绑定数据:
// 以下三行代码直接删除 // firstName.setValue(authenticatedUser.get().get().getFirstname()); // lastName.setValue(authenticatedUser.get().get().getLastname()); // email.setValue(authenticatedUser.get().get().getEmail());
第二步:修复SearchView的按钮跳转逻辑
之前的按钮列Renderer写法有问题:第二个参数不是UI对象,是Grid当前行绑定的User实体,直接拿这个对象的ID做路由跳转即可。
把configureGrid方法里的按钮列代码替换成下面的:
grid.addColumn( new ComponentRenderer<>(Button::new, (button, currentRowUser) -> { button.addThemeVariants(ButtonVariant.LUMO_ICON, ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY); // 点击时直接传当前行用户的ID跳转到对应ProfileView button.addClickListener(e -> UI.getCurrent().navigate(ProfileView.class, new RouteParameters("userId", currentRowUser.getId().toString()))); button.setIcon(new Icon(VaadinIcon.USER_CARD)); })).setHeader("查看资料");
把之前没实现的空switchTo()方法删掉即可。
补充说明
- 如果想要更友好的URL格式,可以把路由占位符从
:userId改成:username,查询用户时按用户名字段查即可,最终URL会变成/profile/xxx的格式 - 可以在beforeEnter方法里补隐私权限校验:如果目标用户开启了隐私保护,非好友访问直接提示无权限即可
- 其他子页面(看过的电影、片单、好友列表)如果要支持访问任意用户的数据,和ProfileView的改造逻辑一致,加路由参数、在beforeEnter里解析参数加载数据就行
内容的提问来源于stack exchange,提问作者RFK
相关产品推荐
相关产品推荐

