Reputation: 1337
After submitting a form, the data are sent to a servlet and stored in the database. T
Then i use a request.getRequestDispatcher("CTN/ListPage.jsp").forward(request, response);
to list the data on ListPage.jsp page but if I refresh that same page, the browser tell me that the data will be resent again in a warning message and then, the last stored data is duplicated,..
this seems to be a common problem after lot of search. So I try the RPG solution by changing:
request.getRequestDispatcher("CTN/ListPage.jsp").forward(request, response);
to
response.sendRedirect(request.getContextPath() + "CTN/ListPage.jsp");
but I get a 404 error ... The requested resource () is not available.
How can I solve this problem?
UPDATE: Servlet code:
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 Page:
<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>
Upvotes: 1
Views: 2820
Reputation: 22715
This approach is different from what you're doing - this is the Synchronizer Token Pattern. This solution requires you to add a mechanism to identify the first request from the resubmissions.
The idea: Use a hidden token while presenting the request form itself, and use it to flag out the first request from any succeeding requests.
Once the first submit is received, you will receive back that token. Invalidate that token, so that you'll know that any future requests containing that token are repeat requests. With that information, you can stop your processing logic from writing into the database.
The token can be a random number, or the timestamp.
General flow:
User hits your URL.
It triggers a servlet where you add the token into the session.
session.setAttribute("TOKEN", “12345"); // some random number
Redirect your servlet to a JSP (which becomes the request form for the user) and there, prepare the token in a hidden field.
<input type=hidden name=TOKEN value="<%= session.getAttribute("TOKEN") %>" />
User submits.
You check the TOKEN against that in the session. Then immediately set it to something else.
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: The one you're doing is the Post-Redirect-Get (PRG) Approach, that requires an extra network trip and has a small exposure when the refresh is pressed too fast such that the redirect has not yet been triggered. The solution above addresses both.
Upvotes: 0
Reputation: 18762
You need to redirect the user to list page.
It is a best practice to redirect user to a GET URL after POST. http://en.wikipedia.org/wiki/Post/Redirect/Get
Since sendRedirect accepts relative URL, I don't think you should add the context path to the URL to which you are redirecting. The error probably is because you are redirecting to a non existing URL. Try visiting the URL in browser directly and see whether it works.
Upvotes: 1