1

フォームを送信した後、データはサーブレットに送信され、データベースに保存されます。T 次にrequest.getRequestDispatcher("CTN/ListPage.jsp").forward(request, response);、ListPage.jsp ページのデータを一覧表示するために a を使用しますが、同じページを更新すると、ブラウザは警告メッセージでデータが再送信されることを通知し、最後に保存されたデータが複製されます..多くの検索の後、一般的な問題のようです。そこで、以下を変更して 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

0

このアプローチはあなたがやっていることとは異なります - これは Synchronizer Token Pattern です。このソリューションでは、再送信から最初のリクエストを識別するメカニズムを追加する必要があります。

アイデア: リクエスト フォーム自体を提示するときに隠しトークンを使用し、それを使用して後続のリクエストから最初のリクエストにフラグを立てます。

最初の送信が受信されると、そのトークンが返されます。そのトークンを無効にして、そのトークンを含む今後のリクエストが繰り返しリクエストであることを確認します。その情報を使用して、処理ロジックによるデータベースへの書き込みを停止できます。

トークンは、乱数またはタイムスタンプにすることができます。

一般的な流れ:

  1. ユーザーがあなたの URL にアクセスします。

  2. トークンをセッションに追加するサーブレットをトリガーします。

    session.setAttribute("TOKEN", “12345");  // some random number
    
  3. サーブレットを JSP (ユーザーのリクエスト フォームになる) にリダイレクトし、隠しフィールドにトークンを準備します。

    <input type=hidden name=TOKEN value="<%= session.getAttribute("TOKEN") %>" />
    
  4. ユーザーが送信します。

  5. セッションで 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:あなたが行っているのは Post-Redirect-Get (PRG) アプローチです。これは余分なネットワーク トリップを必要とし、リダイレクトがまだトリガーされていないほど高速に更新が押されたときに露出が少なくなります。上記のソリューションは両方に対応しています。

于 2013-06-29T06:49:44.250 に答える