JSF避免URL Manipulation:视图切换向ViewScoped Bean传参不显示URL参数
解决ViewScoped Bean跨视图传参且隐藏URL参数的方案
我之前也跟你一样,折腾了好几天想解决这个ViewScoped传参又不暴露URL的问题,试过Pretty Faces没达到预期,后来靠几个原生JSF的方案解决了,完全满足防URL篡改的需求,给你详细说说:
方案1:用JSF原生Flash Scope(最推荐)
Flash Scope是JSF专门设计用来跨重定向传参且不暴露在URL中的机制,参数会存在服务器端的Flash存储里,仅在一次重定向请求后失效,完美匹配你的需求。
实现步骤:
- 发起跳转的源Bean(比如RequestScoped):
@ManagedBean @RequestScoped public class SourceBean implements Serializable { public String navigateToTarget() { // 把参数存入Flash FacesContext.getCurrentInstance().getExternalContext().getFlash().put("secretParam", "你的敏感参数值"); // 如果需要强制保留参数到下一次请求(避免某些JSF版本重定向后丢失) FacesContext.getCurrentInstance().getExternalContext().getFlash().keep("secretParam"); // 重定向到目标视图 return "targetView?faces-redirect=true"; } }
- 目标ViewScoped Bean:
@ManagedBean @ViewScoped public class TargetBean implements Serializable { private String receivedParam; @PostConstruct public void init() { // 从Flash中取出参数 receivedParam = (String) FacesContext.getCurrentInstance().getExternalContext().getFlash().get("secretParam"); // 可选:取出后立即移除,避免后续请求意外获取到 FacesContext.getCurrentInstance().getExternalContext().getFlash().remove("secretParam"); } // getter & setter for receivedParam }
注意事项:
- 不需要额外依赖,完全原生JSF支持,兼容性好(JSF 2.0+都能用)
- 参数不会出现在URL里,也不会被客户端篡改
- 如果是JSF 2.3+,还可以用
@Flash注解直接注入参数,代码更简洁:
@Inject @Flash private Flash flash;
方案2:用Session Scope临时存储参数(适合简单场景)
如果你的参数比较简单,也可以用Session Scope存临时参数,不过要注意用完立即清理,避免Session污染。
实现步骤:
- 创建一个SessionScoped的临时存储Bean:
@ManagedBean @SessionScoped public class TempSessionStorage implements Serializable { private String tempParam; // getter & setter }
- 源Bean中设置参数:
@ManagedBean @RequestScoped public class SourceBean { @ManagedProperty("#{tempSessionStorage}") private TempSessionStorage tempStorage; public String navigate() { tempStorage.setTempParam("你的参数值"); return "targetView?faces-redirect=true"; } // getter & setter for tempStorage }
- 目标ViewScoped Bean中获取并清理参数:
@ManagedBean @ViewScoped public class TargetBean implements Serializable { @ManagedProperty("#{tempSessionStorage}") private TempSessionStorage tempStorage; private String receivedParam; @PostConstruct public void init() { receivedParam = tempStorage.getTempParam(); // 关键:取出后立即清空,避免后续请求拿到旧参数 tempStorage.setTempParam(null); } // getter & setter }
注意事项:
- 必须记得清理参数,否则多个用户或者多次请求会导致参数混乱
- 不适合存敏感参数(虽然URL看不到,但Session里会留痕迹,直到清理)
方案3:CDI Conversation Scope(适合多步骤流程)
如果你的场景是多步骤的视图切换(比如表单分步提交),可以用CDI的@ConversationScoped,它的生命周期可以手动控制,参数完全隐藏在服务器端。不过这个方案相对重一些,适合复杂场景。
核心思路:
- 启动一个Conversation,把参数存入Conversation Bean
- 跨视图跳转时保持Conversation的ID(这个ID会出现在URL里,但只是一个标识,不是实际参数,无法篡改)
- 完成操作后结束Conversation
关于手册推荐
如果想深入了解这些Scope的细节,推荐查阅:
- JSF 2.3 Specification:里面详细定义了Flash Scope、各种Bean Scope的行为
- Oracle JSF Developer Guide:有很多实用的示例和最佳实践
内容的提问来源于stack exchange,提问作者abbr
相关产品推荐
相关产品推荐

