# URL bei WebApp wird immer laenger



## Niki (13. Mai 2008)

Hallo Forum!

Ich versuche gerade anhand eines kleinen Beispiels das MVC Prinzip bei einer WebApp zu verstehen.
Ich habe ein zentrales ControllerServlet welches die Requests dispatched.
Die jeweilige Klassen sollen dann ein Model befüllen und mittels forward die View erneut anzeigen.
Das funktioniert auch zwar, jedoch wird die URL bei einer falschen Eingabe beim Login immer länger.
Hier ist mal der Code:

Controller

```
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import controller.login.LoginBean;

public class ControllerServlet extends HttpServlet {
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doGet(req, resp);
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		String action = req.getParameter("action");
		if("logon".equals(action))
			new LoginBean().login(req.getParameter("user"), req.getParameter("pwd"), req, resp);

	}
}
```


LoginBean zum validieren der LoginDaten

```
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import model.Model;

public class LoginBean {
	public void login(String user, String pwd, HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException{		
		HttpSession session = request.getSession();
		if("admin".equals(user) && "master".equals(pwd)){
			Model model = new Model();
			model.setUser(user);
			session.setAttribute("model", model);
			request.getRequestDispatcher("/jsps/greeting.jsp").forward(request, resp);
		} else {
			request.getRequestDispatcher("/index.jsp").forward(request, resp);
		}
	}
}
```

Model

```
public class Model {
	private String user = null;

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}
	
}
```

web.xml:

```
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>WebappMVC</display-name>
  
  <servlet>
		<description></description>
		<display-name>Controller</display-name>
		<servlet-name>ControllerServlet</servlet-name>
		<servlet-class>controller.ControllerServlet</servlet-class>		
	</servlet>
	<servlet-mapping>
		<servlet-name>ControllerServlet</servlet-name>
		<url-pattern>/servlets/*</url-pattern>
	</servlet-mapping>
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>  
  </welcome-file-list>
</web-app>
```

index.jsp

```
<html>
<body>
<form action="servlets/logon" method="post">
	<table>
		<tr>
		<td>UserID:</td>
		<td><input type="text" maxlength="6" name="user"></td>
		</tr>
		<tr>
		<td>PWD:</td>
		<td><input type="password" maxlength="8" name="pwd"></td>
		</tr>	
	</table>
	<input type="hidden" name="action" value="logon"/>
	<input type="submit" value="Anmelden" />
</form>
</body>
</html>
```

greeting.jsp

```
<%@ page import="model.Model"%>
<html>
<body>
<%
	Model model = (Model) request.getSession().getAttribute("model");
%>
<h3>Hallo <%= model.getUser() %></h3>
</body>
</html>
```

Das man keine Scriptlets verwenden soll ist mir schon klar. Mir gings nur darum schnell einmal das MVC abzubilden.

Ruf ich das ganze so auf:
*http://localhost:8080/webappmvc/index.jsp*
wird die Seite angezeigt, trage ich was falsches ein erzeugt er mir im Browser diese URL:
*http://localhost:8080/webappmvc/servlets/logon*
wird jedoch wieder etwas falschen eingegeben, wird diese URL angezeigt:
*http://localhost:8080/webappmvc/servlets/servlets/logon*

Hatte jemand schon mal dieses Problem? Ist wahrscheinlich nur ein kleiner Einstellungsfehler.

Danke schon mal für Hilfe!


----------



## Niki (13. Mai 2008)

Habs selber gelöst. In der index.jsp gehört der Contextpath hinzugefügt:

```
<html>
<body>
<form action="<%=request.getContextPath() %>/servlets/logon" method="post">
	<table>
		<tr>
		<td>UserID:</td>
		<td><input type="text" maxlength="6" name="user"></td>
		</tr>
		<tr>
		<td>PWD:</td>
		<td><input type="password" maxlength="8" name="pwd"></td>
		</tr>	
	</table>
	<input type="hidden" name="action" value="logon"/>
	<input type="submit" value="Anmelden" />
</form>
</body>
</html>
```


----------



## maki (13. Mai 2008)

```
..
<servlet-mapping>
      <servlet-name>ControllerServlet</servlet-name>
      <url-pattern>/servlets/*</url-pattern>
   </servlet-mapping> 

...
<%=request.getContextPath() %>/servlets/logon
..
```
Nur so am Rande, wieso mappst du /servlets/ auf dein Servlet?
Der servlets path ist soz. der Weg um alle Servlets anzusprechen laut spec.

An deiner Stelle würde ich einfach ein Mapping in der Art

```
...
   <servlet-mapping>
      <servlet-name>ControllerServlet</servlet-name>
      <url-pattern>/controller/*</url-pattern>
   </servlet-mapping> 
...
```
erstellen und es dann auch nutzen:

```
...
<%=request.getContextPath() %>/controller/
...
```
Den Namen der Aktion kannst du dann auch per Post mitschicken, so wird der User bei einem Refresh(F5) gleich gewarnt, auch wenn ihn das nicht unbedingt abhält es trotzdem zu versuchen.


----------



## Niki (13. Mai 2008)

Da hast du recht, wäre natürlich sprechender. Den Namen der Aktion schick ich als hidden-Field im Form mit. Gibts dafür eine elegantere Möglichkeit?


----------



## maki (13. Mai 2008)

Hidden Field im Formular ist gut, eine andere Möglichkeit wäre ein Button, sogar einfacher, vom Servlet aus sieht man den Unterschied nicht mal.

Wenn du es ohne Form machen willst musst du viel mit JS anbieten, nicht so dolle.

Und dann?

Dann könnte man sicn überlegen, wie man die Namen der Aktionen zu den Action-Klassen mappt.

Am Anfang reicht es, wenn der Controller mit einem if-else Konstrukt prüft und dann die Klasse aufruft.

Später jedoch willst du bestimmt den Namen der Aktion mit der Aktion-Klasse in einer Datei Mappen (per konfiguration).
Ein gemeinsames Interface für alle Aktion-Klassen welches nur eine Methode definiert (zB. execute) macht das Leben hier einfacher.
Da wären wir dann beim Command Handler Pattern angekommen, wir sind fast bei struts 

Ich finde es gut das du dich der Sache von Anfang an annimmst, fördert das Verständnis, danach hast du wenig Probleme mit Frameworks.


----------



## Niki (13. Mai 2008)

Genau darum geht es mir eben. JS hört sich gar nicht gut an, ich bin Applikationsentwickler und will daher möglichst wenig mit JS/html zutun haben. Daher finde ich ja eigentlich JSF sehr nett. Das mit einer dynamischen Actionmap, welche sich über eine properties Datei konfigurieren lässt habe ich des öfteren schon umgesetzt. Auch mit einem gemeinsamen Interface. Dabei hab ich immer die Actionklassen in einem ContextListener beim Starten der Applikation geladen, fand ich eigentlich sehr schön gelöst, da diese nur einmalig geladen werden.


----------

