提交表单后,数据将被发送到servlet并存储在数据库中。 Ť
然后我使用request.getRequestDispatcher("CTN/ListPage.jsp").forward(request, response);
列出ListPage.jsp页面上的数据,但是如果我刷新同一页面,浏览器告诉我数据将在警告消息中再次重新发送,然后,最后存储的数据被复制,..
经过大量搜索,这似乎是一个常见的问题。所以我通过改变来尝试RPG解决方案:
request.getRequestDispatcher("CTN/ListPage.jsp").forward(request, response);
到
response.sendRedirect(request.getContextPath() + "CTN/ListPage.jsp");
但我收到404错误... 请求的资源()不可用。
我该如何解决这个问题?
更新: Servlet代码:
package com.CTN.controller;
import com.CTN.dao.MatiereDaoLocal;
import com.CTN.dao.SeanceDaoLocal;
import com.CTN.dao.SemestreDaoLocal;
import com.CTN.model.Matiere;
import com.CTN.model.Seance;
import java.io.IOException;
import java.util.List;
import javax.ejb.EJB;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author WORK
*/
@WebServlet(name = "NewSeanceAjouterServlet", urlPatterns = {"/NewSeanceAjouterServlet"})
public class NewSeanceAjouterServlet extends HttpServlet {
@EJB
private MatiereDaoLocal MatiereDao;
@EJB
private SeanceDaoLocal SeanceDao;
@EJB
private SemestreDaoLocal SemestreDao;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int matiereId = Integer.parseInt(request.getParameter("matiereId"));
String seanceTitre = request.getParameter("seanceTitre");
String seanceContenue = request.getParameter("seanceContenue");
String seanceType = request.getParameter("seanceType");
Matiere matiere = MatiereDao.getMatiere(matiereId);
Seance nouveauSeance = new Seance();
nouveauSeance.setSeanceTitre(seanceTitre);
nouveauSeance.setSeanceContenue(seanceContenue);
nouveauSeance.setSeanceType(seanceType);
nouveauSeance.setMatiere(matiere);
nouveauSeance.setSeanceTitre(seanceTitre);
nouveauSeance.setSeanceContenue(seanceContenue);
SeanceDao.addSeance(nouveauSeance);
List<Seance> seances = SeanceDao.getAllSeanceByMatiereId(matiereId);
List<Matiere> matieres = MatiereDao.getAllMatiereBySemestreId(matiere.getSemestre().getSemestreId());
request.setAttribute("matieres", matieres);
request.setAttribute("seances", seances);
response.sendRedirect("CTN/ListPage.jsp");
}
JSP页面:
<div class="box">
<form action="./NewSeanceAjouterServlet" method="POST">
<input id="texthidden" type="text" name="matiereId" value="${matiere.matiereId}" readonly="readonly" />
<p><span>titre</span></p>
<p>
<textarea name="seanceTitre"class="courstitre" id=""></textarea>
<br/>
</p>
<div class="ajouter" >
<textarea class="courstext" name="seanceContenue"> </textarea>
<select name="seanceType" selected="selected">
<option value="Cours">Cours</option>
<option value="Voyage d'Etude">Voyage d'Etude</option>
<option value="Devoir">Devoir</option>
<option value="Examen">Examen</option>
</select>
<input class="button" type="submit" name="action" value="AJOUTER" />
</div>
</form>
</div>
答案 0 :(得分:1)
您需要将用户重定向到列表页面。
最佳做法是在POST后将用户重定向到GET URL。 http://en.wikipedia.org/wiki/Post/Redirect/Get
由于sendRedirect接受相对URL,因此我认为您不应将上下文路径添加到要重定向的URL。该错误可能是因为您重定向到不存在的URL。尝试直接访问浏览器中的URL,看看它是否有效。
答案 1 :(得分:0)
这种方法与您正在做的不同 - 这是同步器令牌模式。此解决方案要求您添加一种机制来识别重新提交的第一个请求。
想法:在呈现请求表单时使用隐藏令牌,并使用它来标记来自任何后续请求的第一个请求。
收到第一次提交后,您将收到该令牌。使该令牌无效,以便您知道包含该令牌的任何未来请求都是重复请求。有了这些信息,您就可以停止处理逻辑写入数据库。
令牌可以是随机数,也可以是时间戳。
一般流程:
用户点击您的网址。
它会触发一个servlet,您可以在其中将令牌添加到会话中。
session.setAttribute("TOKEN", “12345"); // some random number
将您的servlet重定向到JSP(它成为用户的请求表单),然后在隐藏字段中准备令牌。
<input type=hidden name=TOKEN value="<%= session.getAttribute("TOKEN") %>" />
用户提交。
您在会话中检查TOKEN。然后立即将其设置为其他内容。
if (tokenFromRequest == tokenFromSession) {
session.setAttribute("TOKEN", "INVALID"); // or null
// do your database activities
} else {
// this is a resubmission, do nothing. Simply redirect to display page.
}
PS:你正在做的是后重定向 - 获取(PRG)方法,它需要额外的网络旅行,并且当按下刷新太快时具有小曝光,使得重定向尚未触发。上面的解决方案解决了这两个问题。