Ist es möglich die Request paramter auf "null" zu setzen?

tom6619

Grünschnabel
hallo,

ich programmiere gerade an einem Servlet, das Formularfelder mittels der Methode -neuerEintrag- einlesen und die eingelesenen Parameter in eine Datei schreiben soll, anschließend erfolgt mittels der Methode -leseEintraege- die Ausgabe aller gespeicherten Einträge auf einer Html Seite, die das Servlet selbst generiert.

Das Problem ist, dass bei der Aktualisierung der angezeigten Seite bzw. bei dem wiederholtem Aufruf des Servlets ohne Formulareintrag die Requestparameter des vorherigen Formulareintrags übernommen werden und die Datei bzw. html Ausgabe dadurch jedesmal um die vorherigen Einträge erweitert wird.
Meine Lösung wäre gewesen, die Request Parameter nach jedem Eintrag wieder auf null zu setzen, aber leider hat es nicht geklappt. Ich hatte es beispielsweise mit req.removeAttributes("artikelNr") ausprobiert, leider ohne Erfolg.

Danke vielmals für jederlei Hilfe.

Hier sind die Methoden neuerEintrag und leseEintraege:


Code:
 public void neuerEintrag(HttpServletRequest req, HttpServletResponse res,PrintWriter out) throws IOException{	
		String artikelNr=req.getParameter("artikelNr");
		String beschreibung=req.getParameter("beschreibung");
		String preis=req.getParameter("preis");		
		if((!(artikelNr==""||beschreibung==""||preis==""))){					
			artikelNr = URLEncoder.encode(req.getParameter("artikelNr"),"UTF-8");
			beschreibung = URLEncoder.encode(req.getParameter("beschreibung"),"UTF-8");
			preis = URLEncoder.encode(req.getParameter("preis"),"UTF-8");				
			String deleteLine=req.getParameter("delete");					
			try{				
				FileWriter fw= new FileWriter(f,true);
				PrintWriter pw= new PrintWriter(fw);
				pw.print(artikelNr+"|");
				pw.print(beschreibung+"|");
				pw.println(preis);
				pw.close();	            
			}// zu try
			catch(IOException e){
				res.sendError(500,"IO Fehler\n"+e.getMessage());			
			}			
			out.println("<h1>IM2 - Aufgabe 17: Artikelverwaltung</h1><form action='/IM2/servlet/A17' method='post' style='background-color:gray;width:300px'><table cellpadding='5' cellspacing='5' border='0' ><tr>	<td ><font color='#ffffff'>Artikel-Nummer</font></td>	<td><input type='text' name='artikelNr'></td></tr><tr>	<td><font color='#ffffff'>Beschreibung</font></td>	<td><input type='text' name='beschreibung'></td></tr><tr>	<td><font color='#ffffff'>Preis</font></td>	<td><input type='text' name='preis' style='width:80'>&nbsp;<font size='5' color='#ffffff'>€</font> </td></tr><tr>	<td></td>	<td style='vetical-align:bottom'><input type='submit' name='hinzufuegen' value='Hinzufuegen'>	<input type='reset' name='reset' value='Reset' style='width:50'></td></tr></table></form>");
			out.println("Danke für den Eintrag<br>");
			
		}//zu if artikelNr
		else{			
		out.println("<h1>IM2 - Aufgabe 17: Artikelverwaltung</h1><form action='/IM2/servlet/A17' method='post' style='background-color:gray;width:300px'><table cellpadding='5' cellspacing='5' border='0' ><tr>	<td ><font color='#ffffff'>Artikel-Nummer</font></td>	<td><input type='text' name='artikelNr'></td></tr><tr>	<td><font color='#ffffff'>Beschreibung</font></td>	<td><input type='text' name='beschreibung'></td></tr><tr>	<td><font color='#ffffff'>Preis</font></td>	<td><input type='text' name='preis' style='width:80'>&nbsp;<font size='5' color='#ffffff'>€</font> </td></tr><tr>	<td></td>	<td style='vetical-align:bottom'><input type='submit' name='hinzufuegen' value='Hinzufuegen'>	<input type='reset' name='reset' value='Reset' style='width:50'></td></tr></table></form>");
		out.println("Formular nicht vollständig ausgefüllt<br>");
		}
	}// zu neuer Eintrag

Code:
  public void leseEintraege (HttpServletRequest req, HttpServletResponse res,PrintWriter out) throws IOException,ServletException{		
		try{			
			if (f.canRead()){				
				FileReader fr = new FileReader(f);
				LineNumberReader lnr = new LineNumberReader(fr);
				String line;
				StringTokenizer st;
				int i=1;
				String artNr;
				String artBesch;
				String artPreis;			
				while((line=lnr.readLine())!=null){						
					st= new StringTokenizer(line,"|");					
					while(st.hasMoreTokens()){
						artNr=URLDecoder.decode(st.nextToken(),"UTF-8");
						artBesch=URLDecoder.decode(st.nextToken(),"UTF-8");
						artPreis=URLDecoder.decode(st.nextToken(),"UTF-8");
						out.println("<tr>");
						out.println("<td>"+artNr+"</td>");
						out.println("<td>"+artBesch+"</td>");
						out.println("<td>"+artPreis+"</td>");
						out.println("<td>&nbsp;&nbsp;&nbsp;&nbsp;<a href='/IM2/servlet/A17?delete="+i+"'>Artikel löschen</a></td>");
						out.println("</tr>");						
						i++;						
					}				
				}				
				lnr.close();
				fTemp.renameTo(f);				
			}// zu if f.canread			
		}// zu try
			catch(IOException e){
				res.sendError(500,"IO Fehler\n"+e.getMessage());
			}			
		}// schließt leseEinträge
 
um meine Frage etwas zu präzisieren:

Beim Page-Releod (z.B. über die Taste F5 beim Internet Explorer) ohne Formulareintrag(Request Parameter müssten eigentlich null sein oder leerzeichen "") wird das Servlet neu geladen und dabei die alten Request parameter des Formulars übernommen und in meine Datei geschrieben.
Somit wird meine Datei größer und größer, obwohl keine neuen Einträge in die Formularfelder gemacht werden

die Methode neuerEintrag sollte eigentlich durch den "Artikel hinzufuegen Button " aufgerufen werden. Wenn die Formularfelder leer sind und der Button gedrückt wird werden Leerzeichen übergeben, welche ich mit if-else umleiten kann.

Aber nur beim Page-Reload ohne Formulareintrag über die Taste F5 beim IE z.B. werden keine Leerzeichen übergeben, sondern die vorherigen Einträge. Wenn z.B. vor dem Page-Reload artikelNr: 123 beschreibung:Monitor preis:190 war, werden diese alten Werte erneut übergeben und in meine Datei gespeichert.
 
Zuletzt bearbeitet:
Ich glaub du verstehst das etwas nicht 100% richtig. Ein F5 bedeutet nicht "Seite aktualisieren", wie man es vielleicht vermuten mag, sondern präziser "Schicke den letzten Request nochmal ab". Diese Problem löst man eigentlich durch ein sog. POST-REDIRECT-GET. d.h. auf POST Requests wird grundsätzlich mit einem Redirect geantwortet und zwar mit GET. Das hat zu Folge, dass ein F5 im Browser dann nur den GET neu auslöst und nicht der POST. Beispiel:

1. Formularanfrage per POST auf foo.com/bar
2. Der Controller verarbeitet die Daten und macht einen Redirect auf foo.com/barfoos

Gruß
Ollie
 
Danke erstmal für deine Antwort.

" Diese Problem löst man eigentlich durch ein sog. POST-REDIRECT-GET. d.h. auf POST Requests wird grundsätzlich mit einem Redirect geantwortet und zwar mit GET. Das hat zu Folge, dass ein F5 im Browser dann nur den GET neu auslöst und nicht der POST. Beispiel:"


Wie würde die Implementierung dazu aussehen?

Mein Formular benutzt die Post Methode. In meinem Servlet ruft die Methode doPost die Methode doGet auf:

Wie kann ich hier einen POST-REDIRECT-GET einbauen?

Code:
public void doPost (HttpServletRequest req,HttpServletResponse res)
						throws ServletException,IOException{
		
		doGet(req,res);
	}
	public void doGet (HttpServletRequest req,HttpServletResponse res)
						throws ServletException,IOException{

}
 
Kernschritt ist, den response nicht selbst zu erzeugen, sondern wie oben beschrieben per GET auf eine "andere Resource" zu redirecten, die dann die Darstellung rendert. Das kann im einfachsten Fall auch das gleiche Servlet sein - nur kannst du dann halt nicht den COde von oben benutzen.

Du könntest z.B. in der POST verarbeitung eine Datei erzeugen und den Dateinamen per GET Parameter dem Redirect mitgeben. Dieser lauscht dann eigentlich nur auf den Parameter und gibt stur die Datei unter dem Parameter zurück. (Mach das bitte nicht 1:1 so, dann hast du unter umständen Tür und Tor offen für Angreifer). Aber das Prinzip sollte doch klar sein, oder?

Gruß
Ollie
 
Hallo,

Kernschritt ist, den response nicht selbst zu erzeugen, sondern wie oben beschrieben per GET auf eine "andere Resource" zu redirecten, die dann die Darstellung rendert.
Du könntest z.B. in der POST verarbeitung eine Datei erzeugen und den Dateinamen per GET Parameter dem Redirect mitgeben.
Gruß
Ollie

ja das Prinzip ist zwar so weit klar, nur hänge ich weiterhin an dieser Übergabe der response per Get mittels beispielsweise res.senRedirect(MeinServlet), wenns das selbe Servlet sein soll.

Würde res.sendRedirect (MeinServlet) nicht den gesamten Prozess, sprich den doPost -Aufruf wiederholen?
Die Methode leseEinträge,auch zuständig für die html-Ausgabe, wird ja anfangs in der doPost aufgerufen, wie kann ich nun den out.println() beispielsweise übergeben mittels res.sendRedirect(), wie müsste dieser Aufruf aussehen?

Danke
 
Wenn du den Code für das verarbeiten den POST Request fälschlicherweise über so eine Konstruktion wie oben machst, wird der code natürlich doppelt ausgeführt... Lass halt doPost den POST verarbeiten, doGet den GET.

Objekte per GET übergeben ist keine gute Idee, direkt in den PrintWriter zu schreiben eigentlich auch nicht. Entweder du tust den String in die Session und räumst im darauffolgenden GET wieder auf, oder schreibst in ein File und liest danach wieder. (Wobei die Session der deutlich performantere Weg sein sollte.)

Grundsätzlich sind solcherlei Geschichten mit plain Servlets natürlcih relativ mühsam. Die meisten Webframeworks können sowas eleganter. Den ganzen HTML Kram im Code zusammenzubasteln halte ich auch für suboptimal. Wenn du da noch ein wenig Zeit / Freiheit hast, solltest evtl nochmal überdenken, ob es nicht Sinn macht, was vorgefertigtes zu nutzen bzw. zumindest das HTML in JSPs auszulagern.

Gruß
Ollie
 
Ja du hast schon recht, Servlets sind wirklich ungeeignet für so etwas und jsp wäre schon eleganter. Werde mich bei Gelgenheit damit befassen.

Die Problematik habe ich auch im Wesentlichen erfasst.

Doch ein kleines technisches Verständnisproblem bleibt noch:


" Lass halt doPost den POST verarbeiten, doGet den GET."

Undzwar genau an dieser Stelle nämlich, denn mein Formular benutzt method = post, so dass doPost im Servlet aufgerufen wird. DoPost ruft doGet auf und das ganze spielt sich dann im doGet Teil ab,
Wie komme ich dann von doGet in doPost hinein oder umgekehrt?. Oder verstehe ich da etwas nicht richtig....:confused:

Kann man einfach hin und her switchen:

public void doPost t(HttpServletRequest req,HttpServletResponse res)
throws ServletException,IOException{

neuerEintrag (req,res,out);
doGet (req, res); // Wechsel in doGet

}

public void doGet t(HttpServletRequest req,HttpServletResponse res)
throws ServletException,IOException{

leseEintraege(req, res, out); // Eintäge aus Datei lesen und html-ausgabe
}
 
Zuletzt bearbeitet:
Dein doGet aufruf in doPost ist halt grundverkehrt für sowas... Implementier doch in doPost das Verarbeiten der Daten und leite dann mit sendRedirect(..) auf das gleiche Servlet weiter. Kann sein, dass du dem Redirect noch extra sagen musst, dass er GET sein soll. So genau hab ichs grad nicht im Kopf. Das geht - wenn denn überhaupt nötig - aber durch recht simples manipulieren des Headers.

In doGet implementierst du dann die eigentliche Ausgabe, die an den Browser zurück soll.

Ein einfaches aufrufen von doGet von doPost aus erzeugt ja keinen neuen Request. Der Kern ist, dass du für jeden POST Request nach der Verarbeitung einen GET Request auf die anzuzeigende Seite auslöst.

Gruß
Ollie
 
zu Header-Manipulation auf Get habe ich nichts gefunden. Der Request Header müsste doch auf Get manipuliert werden in so einem Fall oder?

Wärs denn auch möglich mit dem Aufruf res.sendRedirect(MeinServlet?artikelNr=x&beschreibung=x&preis=x) den Aufruf von doGet zu erzwingen. Also indem ich an die URL die Parameter anhänge, welche nur doGet verarbeiten kann. Obwohl, dass würde auch keinen neuen Request erzeugen, nehme ich an.

Ansonsten bin ich ratlos, was die Header Manipulation auf Get angeht.

Bräuchte einfach mal ein konkretes Beispiel dazu..

Danke vielmals dafür...
 
Zuletzt bearbeitet:
Zurück