我有一个由不同片段组成的ListView,它包含文本和链接(在另一个片段中)。链接是可见的,具体取决于列表视图模型的状态。
为简单起见,假设链接是可见的,具体取决于listview模型的布尔字段,如果它是真的可见,否则是不可见的。
首先链接是可见的,我复制链接位置(加密),我等待我的模型更改(即布尔值为false),刷新页面后链接消失。 (正确!)
如果我尝试在浏览器中提供URL(之前复制过),我会收到WicketRuntimeException,告诉我找不到此链接的监听器。
为了更完整,链接在片段内:
<wicket:fragment wicket:id="reservationRatingFragment">
<li>
<div>
<img src="/img/good.png" />
</div>
<p>
<a wicket:id="ratingGoodLink" href="#"> <wicket:message
key="messaging.reservation.rating.good" />
</a>
</p>
</li>
</wicket:fragment>
当我说隐形时,我的意思是我将片段的标记容器设置为.setVisible(false);
为什么会这样?我想如果我回想起一个不再可见的链接,框架应该跳过它并刷新我当前所在的页面(或者将我重定向到基页)。
例如,如果我复制链接并更改了BasePage(例如转到主页),当我回忆起复制的URL时,异常仍然会发生。
编辑:
在第一个片段中:
WebMarkupContainer msgRatingContainer = new WebMarkupContainer("messageRatingContainer") {
private static final long serialVersionUID = 1L;
@Override
public void onConfigure() {
setVisible(message.getType() == MessageType.RATING);
}
};
if (msgRatingContainer.isVisible()) {
if (message.getType() == MessageType.RATING) {
msgRatingContainer.add(new ReservationRatingFragment("messageRatingSection",
"reservationRatingFragment", this, item, message));
}
嵌套片段(ReservationRatingFragment):
public ReservationRatingFragment(String id, String markupId,MarkupContainer markupContainer, Item item, Message msg) {
super(id, markupId, markupContainer, new Model<Message>(msg));
/* Avoid render container */
setRenderBodyOnly(true);
/* Load button components */
Link<Void> ratingGoodLink = new Link<Void>("ratingGoodLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick() {
processRating(ReservationEvaluationResult.GOOD);
}
};
add(ratingGoodLink);
Link<Void> ratingBadLink = new Link<Void>("ratingBadLink"){
private static final long serialVersionUID = 1L;
@Override
public void onClick() {
processRating(ReservationEvaluationResult.BAD);
}
};
add(ratingBadLink);
}
两个片段的标记:
<wicket:fragment wicket:id="messageFragment">
Some content...
<!-- Here goes my fragment with link -->
<ul wicket:id="messageRatingContainer">
<div wicket:id="messageRatingSection"></div>
</ul>
<wicket:fragment wicket:id="reservationRatingFragment">
<li><div>
<img src="/img/messaging/good.png" />
</div>
<p>
<a wicket:id="ratingGoodLink" href="#"> <wicket:message
key="messaging.reservation.rating.good" />
</a>
</p></li>
<li><div>
<img src="/img/messaging/bad.png" />
</div>
<p>
<a wicket:id="ratingBadLink" href="#"> <wicket:message
key="messaging.reservation.rating.bad" />
</a>
</p></li>
</wicket:fragment>
</wicket:fragment>
EDITED: processRating只是执行对控制器的调用(处理后端的更改)。在控制器中,我检查重放攻击(如果已执行此操作),如果是,则抛出运行时异常,将用户引导至警告页面(您已对此消息进行了评级)。事实是,在这种情况下,它没有达到这一点,因为链接不可用它不会调用控制器,它只是抛出InvalidUrlException,因为链接不可见。
Wicket版本:1.4.19
由于
答案 0 :(得分:5)
您认为忽略无效链接或将您重定向到基页是错误的。
为什么?
如果我们退后一步,点击链接会发生什么?您的应用程序状态发生了变化。但是,如果应用程序处于创建链接时的状态,则这样做是安全的。如果未强制执行此规则,则需要确保每个潜在的状态转换都可接受或明确标记为无效。如果在大多数系统中并非不可能,这将是非常不切实际的。但是忽略这一点不仅会带来安全风险,还会导致数据损坏。
最好将其视为乐观锁定的案例。 (主要是因为它:))创建链接时,会给出创建时内部状态的版本号。单击链接时,将该版本号与内部状态的当前版本进行比较。如果两者匹配,则链接被接受为有效,内部状态被更新并且其版本号递增。如果两个数字不匹配,则拒绝链接并抛出异常,因为无法忽略无效的状态转换尝试。
我不会解释如何绕过这个限制,因为它已在另一个答案中被告知,我只是想回答“为什么”的问题。
答案 1 :(得分:1)
我不确定我理解您实施的确切原因。也就是说,我建议使用带有PageParameters的BookmarkablePageLink()来加载目标页面时执行processRating()方法。
添加您的链接组件:
PageParameters ppGood = new PageParameters("0="+ReservationEvaluationResult.GOOD);
PageParameters ppBad = new PageParameters("0="+ReservationEvaluationResult.BAD);
add(new BookmarkablePageLink("ratingGoodLink", DestinationPage.class, ppGood));
add(new BookmarkablePageLink("ratingBadLink", DestinationPage.class, ppBad));
然后在DestinationPage中创建一个新的构造函数:
public class DestinationPage extends WebPage {
public DestinationPage(PageParameters param) {
if(param.getString("0")!=null){
String rating = param.getString("0");
processRating(rating);
}
...
这将为您提供一个持久的链接,并允许您复制和粘贴该网址。
答案 2 :(得分:1)
我发现唯一可行的解决方案是扩展RequestCycle并以这种方式覆盖onRuntimeException方法:
@Override
public Page onRuntimeException(Page page, RuntimeException e) {
if(e instanceof InvalidUrlException) {
return new HomePage();
} else {
return super.onRuntimeException(page, e);
}
}