1

提交表单后,数据被发送到 servlet 并存储在数据库中。T 然后我使用 arequest.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 错误...请求的资源 () 不可用。

我怎么解决这个问题?

更新:小服务程序代码:

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>
4

2 回答 2

1

您需要将用户重定向到列表页面。

最佳做法是在 POST 之后将用户重定向到 GET URL。 http://en.wikipedia.org/wiki/Post/Redirect/Get

由于 sendRedirect 接受相对 URL,我认为您不应该将上下文路径添加到要重定向到的 URL。该错误可能是因为您正在重定向到不存在的 URL。尝试直接在浏览器中访问网址,看看是否有效。

于 2013-06-29T05:42:16.003 回答
0

这种方法与您正在做的不同 - 这是同步器令牌模式。此解决方案要求您添加一种机制来识别重新提交的第一个请求。

想法:在呈现请求表单本身时使用隐藏令牌,并使用它来标记任何后续请求中的第一个请求。

收到第一个提交后,您将收到该令牌。使该令牌无效,以便您知道将来包含该令牌的任何请求都是重复请求。使用该信息,您可以阻止处理逻辑写入数据库。

令牌可以是随机数,也可以是时间戳。

一般流程:

  1. 用户点击您的网址。

  2. 它会触发一个 servlet,您可以在其中将令牌添加到会话中。

    session.setAttribute("TOKEN", “12345");  // some random number
    
  3. 将您的 servlet 重定向到 JSP(它成为用户的请求表单),然后在隐藏字段中准备令牌。

    <input type=hidden name=TOKEN value="<%= session.getAttribute("TOKEN") %>" />
    
  4. 用户提交。

  5. 您在会话中检查令牌。然后立即将其设置为其他内容。

    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:您正在做的是 Post-Redirect-Get (PRG) 方法,它需要额外的网络旅行,并且当刷新按下太快以致尚未触发重定向时,曝光量很小。上面的解决方案同时解决了这两个问题。

于 2013-06-29T06:49:44.250 回答